diff --git a/src/java.desktop/share/legal/harfbuzz.md b/src/java.desktop/share/legal/harfbuzz.md index 448de3faee1..e0df8484f40 100644 --- a/src/java.desktop/share/legal/harfbuzz.md +++ b/src/java.desktop/share/legal/harfbuzz.md @@ -1,4 +1,4 @@ -## Harfbuzz v14.2.0 +## Harfbuzz v15.0.0 ### Harfbuzz License @@ -9,16 +9,16 @@ For parts of HarfBuzz that are licensed under different licenses see individual files names COPYING in subdirectories where applicable. Copyright © 2010-2024 Google, Inc. -Copyright © 2018-2020 Ebrahim Byagowi +Copyright © 2018-2026 Ebrahim Byagowi Copyright © 2004-2013 Red Hat, Inc. Copyright © 2019 Facebook, Inc. Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com) Copyright © 2007 Chris Wilson -Copyright © 2018-2019 Adobe Inc. +Copyright © 2018-2024 Adobe Inc. Copyright © 2006-2025 Behdad Esfahbod Copyright © 1998-2004 David Turner and Werner Lemberg Copyright © 2009 Keith Stribley -Copyright © 2018 Khaled Hosny +Copyright © 2018-2026 Khaled Hosny Copyright © 2016 Elie Roux Copyright © 2016 Igalia S.L. Copyright © 2015 Mozilla Foundation. @@ -75,10 +75,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. The below applies to the following file(s): libharfbuzz/hb-unicode-emoji-table.hh -© 2025 Unicode®, Inc. +© 2026 Unicode®, Inc. -Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. -in the U.S. and other countries. +Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. For terms of use and license, see https://www.unicode.org/terms_of_use.html diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh index b8f6fa4054b..8e395bb7020 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh @@ -44,6 +44,67 @@ namespace OT { +/* Tracks image data blocks emitted into the subset CBDT table so that + * identical subtables (for example the same bitmaps used by several strikes) + * can share a single copy. */ +struct cbdt_dedup_context_t +{ + struct entry_t + { + unsigned int base; /* Offset of the data in cbdt_prime. */ + unsigned int lstart; /* Start index in lengths. */ + unsigned int lcount; /* Number of length entries. */ + }; + + static uint64_t hash (unsigned int image_format, + const hb_vector_t &data, + const hb_vector_t &lengths) + { + uint32_t h = hb_hash (hb_bytes_t (data.arrayZ, data.length)); + h = h * 31 + hb_hash (hb_bytes_t ((const char *) lengths.arrayZ, + lengths.length * sizeof (unsigned int))); + return ((uint64_t) image_format << 32) | h; + } + + bool find (uint64_t key, + const hb_vector_t &data, + const hb_vector_t &lengths, + const hb_vector_t &cbdt_prime, + unsigned int *base /* OUT */) const + { + unsigned int *idx_p = nullptr; + if (!map.has (key, &idx_p)) return false; + const entry_t &e = entries[*idx_p]; + /* The data and the per-glyph lengths must both match, otherwise the + * glyph extents implied by the offset array would differ. */ + if (e.lcount != lengths.length) return false; + if (unlikely (e.base + data.length > (unsigned int) cbdt_prime.length)) return false; + if (hb_memcmp (cbdt_prime.arrayZ + e.base, data.arrayZ, data.length)) return false; + if (hb_memcmp (this->lengths.arrayZ + e.lstart, + lengths.arrayZ, lengths.length * sizeof (unsigned int))) + return false; + *base = e.base; + return true; + } + + bool add (uint64_t key, + unsigned int base, + const hb_vector_t &lengths) + { + if (unlikely (entries.in_error () || this->lengths.in_error () || map.in_error ())) + return false; + entry_t e = {base, this->lengths.length, lengths.length}; + if (unlikely (!entries.push_or_fail (e))) return false; + for (unsigned int length : lengths) + if (unlikely (!this->lengths.push_or_fail (length))) return false; + return map.set (key, entries.length - 1); + } + + hb_hashmap_t map; + hb_vector_t entries; + hb_vector_t lengths; /* Concatenated per-entry lengths. */ +}; + struct cblc_bitmap_size_subset_context_t { const char *cbdt; @@ -59,6 +120,7 @@ struct cblc_bitmap_size_subset_context_t */ hb_codepoint_t start_glyph; /* OUT */ hb_codepoint_t end_glyph; /* OUT */ + cbdt_dedup_context_t *dedup; /* Shared across strikes; may be null. */ }; static inline bool @@ -207,26 +269,26 @@ struct IndexSubtable hb_barrier (); switch (u.header.indexFormat) { - case 1: return_trace (u.format1.sanitize (c, glyph_count)); - case 3: return_trace (u.format3.sanitize (c, glyph_count)); + case 1: hb_barrier (); return_trace (u.format1.sanitize (c, glyph_count)); + case 3: hb_barrier (); return_trace (u.format3.sanitize (c, glyph_count)); default:return_trace (true); } } bool finish_subtable (hb_serialize_context_t *c, - unsigned int cbdt_prime_len, + unsigned int end_offset, unsigned int num_glyphs, unsigned int *size /* OUT (accumulated) */) { TRACE_SERIALIZE (this); - unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset; switch (u.header.indexFormat) { - case 1: return_trace (u.format1.add_offset (c, local_offset, size)); + case 1: hb_barrier (); return_trace (u.format1.add_offset (c, end_offset, size)); case 3: { - if (!u.format3.add_offset (c, local_offset, size)) + hb_barrier (); + if (!u.format3.add_offset (c, end_offset, size)) return_trace (false); if (!(num_glyphs & 0x01)) // Pad to 32-bit alignment if needed. return_trace (u.format3.add_offset (c, 0, size)); @@ -239,63 +301,6 @@ struct IndexSubtable } } - bool - fill_missing_glyphs (hb_serialize_context_t *c, - unsigned int cbdt_prime_len, - unsigned int num_missing, - unsigned int *size /* OUT (accumulated) */, - unsigned int *num_glyphs /* OUT (accumulated) */) - { - TRACE_SERIALIZE (this); - - unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset; - switch (u.header.indexFormat) - { - case 1: { - for (unsigned int i = 0; i < num_missing; i++) - { - if (unlikely (!u.format1.add_offset (c, local_offset, size))) - return_trace (false); - *num_glyphs += 1; - } - return_trace (true); - } - case 3: { - for (unsigned int i = 0; i < num_missing; i++) - { - if (unlikely (!u.format3.add_offset (c, local_offset, size))) - return_trace (false); - *num_glyphs += 1; - } - return_trace (true); - } - // TODO: implement 2, 4, 5. - case 2: // Add empty space in cbdt_prime?. - case 4: case 5: // No-op as sparse is supported. - default: return_trace (false); - } - } - - bool - copy_glyph_at_idx (hb_serialize_context_t *c, unsigned int idx, - const char *cbdt, unsigned int cbdt_length, - hb_vector_t *cbdt_prime /* INOUT */, - IndexSubtable *subtable_prime /* INOUT */, - unsigned int *size /* OUT (accumulated) */) const - { - TRACE_SERIALIZE (this); - - unsigned int offset, length, format; - if (unlikely (!get_image_data (idx, &offset, &length, &format))) return_trace (false); - if (unlikely (offset > cbdt_length || cbdt_length - offset < length)) return_trace (false); - - auto *header_prime = subtable_prime->get_header (); - unsigned int new_local_offset = cbdt_prime->length - (unsigned int) header_prime->imageDataOffset; - if (unlikely (!_copy_data_to_cbdt (cbdt_prime, cbdt + offset, length))) return_trace (false); - - return_trace (subtable_prime->add_offset (c, new_local_offset, size)); - } - bool add_offset (hb_serialize_context_t *c, unsigned int local_offset, unsigned int *size /* OUT (accumulated) */) @@ -303,8 +308,8 @@ struct IndexSubtable TRACE_SERIALIZE (this); switch (u.header.indexFormat) { - case 1: return_trace (u.format1.add_offset (c, local_offset, size)); - case 3: return_trace (u.format3.add_offset (c, local_offset, size)); + case 1: hb_barrier (); return_trace (u.format1.add_offset (c, local_offset, size)); + case 3: hb_barrier (); return_trace (u.format3.add_offset (c, local_offset, size)); // TODO: Implement tables 2, 4, 5 case 2: // Should be a no-op. case 4: case 5: // Handle sparse cases. @@ -329,8 +334,8 @@ struct IndexSubtable *format = u.header.imageFormat; switch (u.header.indexFormat) { - case 1: return u.format1.get_image_data (idx, offset, length); - case 3: return u.format3.get_image_data (idx, offset, length); + case 1: hb_barrier (); return u.format1.get_image_data (idx, offset, length); + case 3: hb_barrier (); return u.format3.get_image_data (idx, offset, length); default: return false; } } @@ -403,12 +408,13 @@ struct IndexSubtableRecord auto *old_subtable = get_subtable (base); auto *old_header = old_subtable->get_header (); + unsigned int image_format = old_header->imageFormat; - subtable->populate_header (old_header->indexFormat, - old_header->imageFormat, - bitmap_size_context->cbdt_prime->length, - &bitmap_size_context->size); - + /* Collect this subtable's image data and the length of each glyph's block + * (zero for glyphs without data). This allows an earlier identical + * subtable to share the same data. */ + hb_vector_t data; + hb_vector_t lengths; unsigned int num_glyphs = 0; bool early_exit = false; for (unsigned int i = *start; i < lookup->length; i++) @@ -424,12 +430,9 @@ struct IndexSubtableRecord break; } unsigned int num_missing = record->add_glyph_for_subset (new_gid); - if (unlikely (!subtable->fill_missing_glyphs (c->serializer, - bitmap_size_context->cbdt_prime->length, - num_missing, - &bitmap_size_context->size, - &num_glyphs))) - return_trace (false); + for (unsigned int j = 0; j < num_missing; j++) + if (unlikely (!c->serializer->check_success (lengths.push_or_fail (0)))) + return_trace (false); hb_codepoint_t old_gid = 0; c->plan->old_gid_for_new_gid (new_gid, &old_gid); @@ -437,20 +440,65 @@ struct IndexSubtableRecord return_trace (false); unsigned int old_idx = (unsigned int) old_gid - next_record->firstGlyphIndex; - if (unlikely (!next_subtable->copy_glyph_at_idx (c->serializer, - old_idx, - bitmap_size_context->cbdt, - bitmap_size_context->cbdt_length, - bitmap_size_context->cbdt_prime, - subtable, - &bitmap_size_context->size))) + unsigned int offset, length, format; + if (unlikely (!next_subtable->get_image_data (old_idx, &offset, &length, &format))) + return_trace (false); + if (unlikely (offset > bitmap_size_context->cbdt_length || + bitmap_size_context->cbdt_length - offset < length)) + return_trace (false); + if (unlikely (!c->serializer->check_success ( + _copy_data_to_cbdt (&data, + bitmap_size_context->cbdt + offset, + length)))) return_trace (false); - num_glyphs += 1; + if (unlikely (!c->serializer->check_success (lengths.push_or_fail (length)))) + return_trace (false); + num_glyphs += 1 + num_missing; } if (!early_exit) *start = lookup->length; + + /* Find or append the data block for this subtable. */ + unsigned int image_data_offset; + cbdt_dedup_context_t *dedup = bitmap_size_context->dedup; + bool shared = false; + uint64_t key = 0; + if (dedup && data.length) + { + key = cbdt_dedup_context_t::hash (image_format, data, lengths); + shared = dedup->find (key, data, lengths, + *bitmap_size_context->cbdt_prime, + &image_data_offset); + } + if (!shared) + { + image_data_offset = bitmap_size_context->cbdt_prime->length; + if (unlikely (!c->serializer->check_success ( + _copy_data_to_cbdt (bitmap_size_context->cbdt_prime, + data.arrayZ, data.length)))) + return_trace (false); + if (dedup && data.length) + /* The bitmap data is already copied; caching is best-effort. */ + (void) dedup->add (key, image_data_offset, lengths); + } + + subtable->populate_header (old_header->indexFormat, + image_format, + image_data_offset, + &bitmap_size_context->size); + + /* Glyphs without data use the offset of the following block's start, + * which yields a zero length span, matching the old behavior. */ + unsigned int cumulative = 0; + for (unsigned int length : lengths) + { + if (unlikely (!subtable->add_offset (c->serializer, cumulative, + &bitmap_size_context->size))) + return_trace (false); + cumulative += length; + } if (unlikely (!subtable->finish_subtable (c->serializer, - bitmap_size_context->cbdt_prime->length, + cumulative, num_glyphs, &bitmap_size_context->size))) return_trace (false); @@ -653,7 +701,8 @@ struct BitmapSizeTable bool subset (hb_subset_context_t *c, const void *base, const char *cbdt, unsigned int cbdt_length, - hb_vector_t *cbdt_prime /* INOUT */) const + hb_vector_t *cbdt_prime /* INOUT */, + cbdt_dedup_context_t *dedup /* INOUT */) const { TRACE_SUBSET (this); auto *out_table = c->serializer->embed (this); @@ -667,6 +716,7 @@ struct BitmapSizeTable bitmap_size_context.num_tables = numberOfIndexSubtables; bitmap_size_context.start_glyph = 1; bitmap_size_context.end_glyph = 0; + bitmap_size_context.dedup = dedup; if (!out_table->indexSubtableArrayOffset.serialize_subset (c, indexSubtableArrayOffset, @@ -764,7 +814,8 @@ struct CBLC bool subset_size_table (hb_subset_context_t *c, const BitmapSizeTable& table, const char *cbdt /* IN */, unsigned int cbdt_length, - CBLC *cblc_prime /* INOUT */, hb_vector_t *cbdt_prime /* INOUT */) const + CBLC *cblc_prime /* INOUT */, hb_vector_t *cbdt_prime /* INOUT */, + cbdt_dedup_context_t *dedup /* INOUT */) const { TRACE_SUBSET (this); cblc_prime->sizeTables.len++; @@ -772,7 +823,7 @@ struct CBLC auto snap = c->serializer->snapshot (); auto cbdt_prime_len = cbdt_prime->length; - if (!table.subset (c, this, cbdt, cbdt_length, cbdt_prime)) + if (!table.subset (c, this, cbdt, cbdt_length, cbdt_prime, dedup)) { cblc_prime->sizeTables.len--; c->serializer->revert (snap); @@ -882,10 +933,10 @@ struct CBDT { float x_scale = upem / (float) strike.ppemX; float y_scale = upem / (float) strike.ppemY; - extents->x_bearing = roundf (extents->x_bearing * x_scale); - extents->y_bearing = roundf (extents->y_bearing * y_scale); - extents->width = roundf (extents->width * x_scale); - extents->height = roundf (extents->height * y_scale); + extents->x_bearing = hb_clamp_to (roundf (extents->x_bearing * x_scale)); + extents->y_bearing = hb_clamp_to (roundf (extents->y_bearing * y_scale)); + extents->width = hb_clamp_to (roundf (extents->width * x_scale)); + extents->height = hb_clamp_to (roundf (extents->height * y_scale)); } return true; @@ -1015,8 +1066,9 @@ CBLC::subset (hb_subset_context_t *c) const } _copy_data_to_cbdt (&cbdt_prime, cbdt, CBDT::min_size); + cbdt_dedup_context_t dedup; for (const BitmapSizeTable& table : + sizeTables.iter ()) - subset_size_table (c, table, (const char *) cbdt, cbdt_length, cblc_prime, &cbdt_prime); + subset_size_table (c, table, (const char *) cbdt, cbdt_length, cblc_prime, &cbdt_prime, &dedup); hb_blob_destroy (cbdt_blob); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh index 37bb8a8f945..b62d63a478f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh @@ -35,7 +35,9 @@ #include "../../../hb-paint.hh" #include "../../../hb-paint-bounded.hh" #include "../../../hb-paint-extents.hh" +#include "../../../hb-depend-data.hh" +#include "../../../hb-ot-dual.hh" #include "../CPAL/CPAL.hh" /* @@ -119,6 +121,14 @@ public: hb_font_destroy (font); } + static unsigned + color_alpha (hb_color_t color, float alpha) + { + /* Font-supplied alpha is F2DOT14 plus variation deltas, so it can be + * negative or greater than one; converting that to unsigned is UB. */ + return roundf (hb_color_get_alpha (color) * hb_clamp (alpha, 0.f, 1.f)); + } + hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground) { hb_color_t color = foreground; @@ -136,7 +146,7 @@ public: return HB_COLOR (hb_color_get_blue (color), hb_color_get_green (color), hb_color_get_red (color), - hb_color_get_alpha (color) * alpha); + color_alpha (color, alpha)); } inline void recurse (const Paint &paint); @@ -219,6 +229,58 @@ struct hb_colrv1_closure_context_t : {} }; + +struct hb_colrv1_depend_context_t : + hb_dispatch_context_t +{ + template + return_t dispatch (const T &obj) + { + if (unlikely (nesting_level_left == 0)) + return hb_empty_t (); + + if (paint_visited (&obj)) + return hb_empty_t (); + + nesting_level_left--; + obj.dependv1 (this); + nesting_level_left++; + return hb_empty_t (); + } + static return_t default_return_value () { return hb_empty_t (); } + + bool paint_visited (const void *paint) + { + hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) colr); + if (visited_paint.in_error() || visited_paint.has (delta)) + return true; + + visited_paint.add (delta); + if (unlikely (visited_paint.in_error ())) + depend_data->fail (); + return false; + } + + const COLR* get_colr_table () const + { return colr; } + + public: + const COLR *colr; + hb_depend_data_builder_t *depend_data; + hb_set_t visited_paint; + unsigned nesting_level_left; + hb_codepoint_t source_gid; + + hb_colrv1_depend_context_t (const COLR *colr_, + hb_depend_data_builder_t *depend_data_, + unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) : + colr (colr_), + depend_data (depend_data_), + nesting_level_left (nesting_level_left_), + source_gid (0) + {} +}; + struct LayerRecord { operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; } @@ -274,12 +336,17 @@ struct Variable { static constexpr bool is_variable = true; + const T& get_value () const { return value; } + Variable* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); return_trace (c->embed (this)); } + void dependv1 (hb_colrv1_depend_context_t* c) const + { value.dependv1 (c); } + void closurev1 (hb_colrv1_closure_context_t* c) const { c->num_var_idxes = 0; @@ -329,6 +396,12 @@ struct Variable value.get_color_stop (c, stop, varIdxBase, instancer); } + void get_solid_color (hb_paint_context_t *c, + hb_bool_t *is_foreground, hb_color_t *color) const + { + value.get_solid_color (c, varIdxBase, is_foreground, color); + } + hb_paint_extend_t get_extend () const { return value.get_extend (); @@ -347,6 +420,8 @@ struct NoVariable { static constexpr bool is_variable = false; + const T& get_value () const { return value; } + static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION; NoVariable* copy (hb_serialize_context_t *c) const @@ -355,6 +430,9 @@ struct NoVariable return_trace (c->embed (this)); } + void dependv1 (hb_colrv1_depend_context_t* c) const + { value.dependv1 (c); } + void closurev1 (hb_colrv1_closure_context_t* c) const { value.closurev1 (c); } @@ -384,6 +462,12 @@ struct NoVariable value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer); } + void get_solid_color (hb_paint_context_t *c, + hb_bool_t *is_foreground, hb_color_t *color) const + { + value.get_solid_color (c, VarIdx::NO_VARIATION, is_foreground, color); + } + hb_paint_extend_t get_extend () const { return value.get_extend (); @@ -396,8 +480,18 @@ struct NoVariable // Color structures +template +static void +set_fixed_clamped (HBFixed &out, float value) +{ + // Variation deltas are unbounded; clamp before the implicit integer cast. + out.set_int (hb_clamp_to (roundf ((value / HBFixed::mult)))); +} + struct ColorStop { + void dependv1 (hb_colrv1_depend_context_t * c) const {} + void closurev1 (hb_colrv1_closure_context_t* c) const { c->add_palette_index (paletteIndex); @@ -414,8 +508,12 @@ struct ColorStop if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0))); - out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1))); + set_fixed_clamped (out->stopOffset, stopOffset.to_float(instancer (varIdxBase, 0))); + float a = alpha.to_float (instancer (varIdxBase, 1)); + /* Partial instances must keep the unclamped base: retained axes can + * bring the alpha back into range. Clamp before narrowing a full + * instance so overflow cannot wrap an opaque alpha to transparent. */ + set_fixed_clamped (out->alpha, c->plan->all_axes_pinned ? hb_clamp (a, 0.f, 1.f) : a); } return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), @@ -460,6 +558,8 @@ struct Extend : HBUINT8 template class Var> struct ColorLine { + void dependv1 (hb_colrv1_depend_context_t * c) const {} + void closurev1 (hb_colrv1_closure_context_t* c) const { for (const auto &stop : stops.iter ()) @@ -555,44 +655,6 @@ struct ColorLine // or all of the specified modes. struct CompositeMode : HBUINT8 { - enum { - // Porter-Duff modes - // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators - COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear - COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src - COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst - COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover - COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover - COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin - COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin - COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout - COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout - COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop - COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop - COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor - COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus - - // Blend modes - // https://www.w3.org/TR/compositing-1/#blending - COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen - COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay - COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken - COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten - COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge - COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn - COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight - COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight - COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference - COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion - COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply - - // Modes that, uniquely, do not operate on components - // https://www.w3.org/TR/compositing-1/#blendingnonseparable - COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue - COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation - COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor - COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity - }; public: DEFINE_SIZE_STATIC (1); }; @@ -605,6 +667,8 @@ struct Affine2x3 return_trace (c->check_struct (this)); } + void dependv1 (hb_colrv1_depend_context_t* c) const {} + void closurev1 (hb_colrv1_closure_context_t* c) const { c->num_var_idxes = 6; } @@ -617,12 +681,17 @@ struct Affine2x3 if (unlikely (!out)) return_trace (false); if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->xx.set_float (xx.to_float(instancer (varIdxBase, 0))); - out->yx.set_float (yx.to_float(instancer (varIdxBase, 1))); - out->xy.set_float (xy.to_float(instancer (varIdxBase, 2))); - out->yy.set_float (yy.to_float(instancer (varIdxBase, 3))); - out->dx.set_float (dx.to_float(instancer (varIdxBase, 4))); - out->dy.set_float (dy.to_float(instancer (varIdxBase, 5))); + auto fold = [&] (F16DOT16 &target, F16DOT16 source, unsigned offset) { + // Keep the stored integer precise while applying the float delta. + target.set_int (hb_clamp_to (roundf ((double) source.to_int () + + (double) instancer (varIdxBase, offset)))); + }; + fold (out->xx, xx, 0); + fold (out->yx, yx, 1); + fold (out->xy, xy, 2); + fold (out->yy, yy, 3); + fold (out->dx, dx, 4); + fold (out->dy, dy, 5); } return_trace (true); } @@ -651,7 +720,8 @@ struct Affine2x3 struct PaintColrLayers { - void closurev1 (hb_colrv1_closure_context_t* c) const; + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, const ItemVarStoreInstancer &instancer HB_UNUSED) const @@ -682,6 +752,7 @@ struct PaintColrLayers struct PaintSolid { + void dependv1 (hb_colrv1_depend_context_t* c) const {} void closurev1 (hb_colrv1_closure_context_t* c) const { c->add_palette_index (paletteIndex); @@ -697,7 +768,10 @@ struct PaintSolid if (unlikely (!out)) return_trace (false); if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) - out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0))); + { + float a = alpha.to_float (instancer (varIdxBase, 0)); + set_fixed_clamped (out->alpha, c->plan->all_axes_pinned ? hb_clamp (a, 0.f, 1.f) : a); + } if (format == 3 && c->plan->all_axes_pinned) out->format = 2; @@ -712,15 +786,21 @@ struct PaintSolid return_trace (c->check_struct (this)); } + void get_solid_color (hb_paint_context_t *c, uint32_t varIdxBase, + hb_bool_t *is_foreground, hb_color_t *color) const + { + *color = c->get_color (paletteIndex, + alpha.to_float (c->instancer (varIdxBase, 0)), + is_foreground); + } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { TRACE_PAINT (this); hb_bool_t is_foreground; hb_color_t color; - color = c->get_color (paletteIndex, - alpha.to_float (c->instancer (varIdxBase, 0)), - &is_foreground); + get_solid_color (c, varIdxBase, &is_foreground, &color); c->funcs->color (c->data, is_foreground, color); } @@ -734,6 +814,8 @@ struct PaintSolid template class Var> struct PaintLinearGradient { + void dependv1 (hb_colrv1_depend_context_t* c) const {} + void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); @@ -750,12 +832,12 @@ struct PaintLinearGradient if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0)); - out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1)); - out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2)); - out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3)); - out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4)); - out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5)); + out->x0 = hb_clamp_to ((double) x0 + (double) roundf (instancer (varIdxBase, 0))); + out->y0 = hb_clamp_to ((double) y0 + (double) roundf (instancer (varIdxBase, 1))); + out->x1 = hb_clamp_to ((double) x1 + (double) roundf (instancer (varIdxBase, 2))); + out->y1 = hb_clamp_to ((double) y1 + (double) roundf (instancer (varIdxBase, 3))); + out->x2 = hb_clamp_to ((double) x2 + (double) roundf (instancer (varIdxBase, 4))); + out->y2 = hb_clamp_to ((double) y2 + (double) roundf (instancer (varIdxBase, 5))); } if (format == 5 && c->plan->all_axes_pinned) @@ -804,28 +886,189 @@ struct PaintLinearGradient template class Var> struct PaintRadialGradient { + bool constant_after_pinning (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + if (c->plan->has_avar2) return false; + const auto ®ions = instancer.varStore->get_region_list (); + for (unsigned i = 0; i < regions.regionCount; i++) + { + hb_hashmap_t axes; + if (!regions.get_var_region (i, c->plan->axes_old_index_tag_map, axes)) + { + c->serializer->err (HB_SERIALIZE_ERROR_OUT_OF_ROOM); + return false; + } + for (auto axis : axes) + { + Triple *limit; + if (!c->plan->user_axes_location.has (axis.first, &limit) || + limit->minimum != limit->maximum) + return false; + } + } + return true; + } + + void dependv1 (hb_colrv1_depend_context_t* c) const {} + void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); c->num_var_idxes = 6; } + bool subset_nonnegative (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + double source[6] = { + x0 + (double) roundf (instancer (varIdxBase, 0)), + y0 + (double) roundf (instancer (varIdxBase, 1)), + radius0 + (double) roundf (instancer (varIdxBase, 2)), + x1 + (double) roundf (instancer (varIdxBase, 3)), + y1 + (double) roundf (instancer (varIdxBase, 4)), + radius1 + (double) roundf (instancer (varIdxBase, 5)) + }; + auto transparent = [&] { + auto *out = c->serializer->allocate_size (5); + if (!out) return false; + out->format = 2; out->paletteIndex = 0xFFFF; out->alpha.set_float (0); + return true; + }; + const auto &line = this+colorLine; + if (source[2] == source[5] || !line.stops.len) return transparent (); + struct stop_t { double offset, alpha; unsigned palette, order; }; + hb_vector_t stops; + if (!stops.alloc (line.stops.len)) return false; + unsigned order = 0; + for (const auto &entry : line.stops.iter ()) + { + const auto &stop = entry.get_value (); + stops.push (stop_t {(double) roundf (stop.stopOffset.to_float (instancer (entry.varIdxBase, 0)) * 16384.f) / 16384., + (double) hb_clamp (stop.alpha.to_float (instancer (entry.varIdxBase, 1)), 0.f, 1.f), + stop.paletteIndex, order++}); + } + if (stops.in_error ()) return false; + stops.qsort ([] (const stop_t &a, const stop_t &b) { + return a.offset < b.offset ? -1 : a.offset > b.offset ? 1 : + a.order < b.order ? -1 : a.order > b.order ? 1 : 0; + }); + double dr = source[5] - source[2]; + // Fractional shifts must preserve both integer circles and F2Dot14 stops. + unsigned lattice = 16384; + for (unsigned j = 0; j < 3; j++) + { + double remainder = fmod (fabs (source[j + 3] - source[j]), 16384.); + if (!(remainder >= 0 && remainder < 16384)) + { + c->serializer->err (HB_SERIALIZE_ERROR_INT_OVERFLOW); + return false; + } + unsigned right = (unsigned) remainder; + while (right) { unsigned r = lattice % right; lattice = right; right = r; } + } + for (unsigned shift = 0; shift < 16; shift++) + { + double b = 1u << shift; + double coarse = dr > 0 ? ceil (-source[2] / dr) : floor (source[2] / -dr) - b; + double fine = dr > 0 ? ceil (-source[2] / dr * lattice) / lattice : + floor (source[2] / -dr * lattice) / lattice - b; + double candidates[] = {coarse, fine}; + for (double a : candidates) + { + // omega = a + b*q. Positive b preserves the largest valid root. + double geometry[6]; + bool fits = true; + for (unsigned j = 0; j < 3; j++) + { + double difference = source[j + 3] - source[j]; + geometry[j] = source[j] + a * difference; + geometry[j + 3] = source[j] + (a + b) * difference; + double low = j == 2 ? 0 : -32768, high = j == 2 ? 65535 : 32767; + fits &= geometry[j] >= low && geometry[j] <= high && + geometry[j + 3] >= low && geometry[j + 3] <= high; + } + if (!fits) continue; + unsigned first = 0, count = stops.length; + double min = (stops[0].offset - a) / b, max = (stops.tail ().offset - a) / b; + double bias = 0; + bool constant = false; + if (line.extend == Extend::EXTEND_PAD) + { + double tip = -geometry[2] / (b * dr); + if ((dr > 0 && max <= tip) || (dr < 0 && min > tip)) + { + first = dr > 0 ? stops.length - 1 : 0; + count = 1; constant = true; + } + } + else + { + double period = max - min; + if (line.extend == Extend::EXTEND_REFLECT) period *= 2; + if (period <= 0) return transparent (); + double n = ceil ((-2 - min) / period); + if (n > floor ((32767. / 16384. - max) / period)) continue; + bias = n * period; + } + for (unsigned j = 0; j < count; j++) + { + double bits = constant ? 0 : ((stops[first + j].offset - a) / b + bias) * 16384; + fits &= bits >= -32768 && bits <= 32767 && bits == round (bits); + } + if (!fits) continue; + auto *out = c->serializer->allocate_size> (16); + if (!out) return false; + out->format = 6; + out->x0 = (int) geometry[0]; out->y0 = (int) geometry[1]; out->radius0 = (unsigned) geometry[2]; + out->x1 = (int) geometry[3]; out->y1 = (int) geometry[4]; out->radius1 = (unsigned) geometry[5]; + c->serializer->push (); + auto *out_line = c->serializer->allocate_size> (3 + count * ColorStop::static_size); + if (!out_line) { c->serializer->pop_discard (); return false; } + out_line->extend = line.extend; + out_line->stops.len = count; + for (unsigned j = 0; j < count; j++) + { + const auto &stop = stops[first + j]; + auto &out_stop = out_line->stops[j].value; + out_stop.stopOffset.set_float ((float) (constant ? 0 : (stop.offset - a) / b + bias)); + out_stop.alpha.set_float ((float) stop.alpha); + if (!c->serializer->check_assign (out_stop.paletteIndex, c->plan->colr_palettes.get (stop.palette), + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + { c->serializer->pop_discard (); return false; } + } + c->serializer->add_link (out->colorLine, c->serializer->pop_pack ()); + return !c->serializer->in_error (); + } + } + // Reject an unrepresentable static result instead of changing its colors. + c->serializer->err (HB_SERIALIZE_ERROR_INT_OVERFLOW); + return false; + } + bool subset (hb_subset_context_t *c, const ItemVarStoreInstancer &instancer, uint32_t varIdxBase) const { TRACE_SUBSET (this); + if (instancer && !c->plan->pinned_at_default && + (c->plan->all_axes_pinned || constant_after_pinning (c, instancer)) && + varIdxBase != VarIdx::NO_VARIATION && + (radius0 + (double) roundf (instancer (varIdxBase, 2)) < 0 || + radius1 + (double) roundf (instancer (varIdxBase, 5)) < 0)) + return_trace (subset_nonnegative (c, instancer, varIdxBase)); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0)); - out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1)); - out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2)); - out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3)); - out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4)); - out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5)); + out->x0 = hb_clamp_to ((double) x0 + (double) roundf (instancer (varIdxBase, 0))); + out->y0 = hb_clamp_to ((double) y0 + (double) roundf (instancer (varIdxBase, 1))); + out->radius0 = hb_clamp_to ((double) radius0 + (double) roundf (instancer (varIdxBase, 2))); + out->x1 = hb_clamp_to ((double) x1 + (double) roundf (instancer (varIdxBase, 3))); + out->y1 = hb_clamp_to ((double) y1 + (double) roundf (instancer (varIdxBase, 4))); + out->radius1 = hb_clamp_to ((double) radius1 + (double) roundf (instancer (varIdxBase, 5))); } if (format == 7 && c->plan->all_axes_pinned) @@ -874,6 +1117,8 @@ struct PaintRadialGradient template class Var> struct PaintSweepGradient { + void dependv1 (hb_colrv1_depend_context_t* c) const {} + void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); @@ -890,10 +1135,10 @@ struct PaintSweepGradient if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0)); - out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1)); - out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2))); - out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3))); + out->centerX = hb_clamp_to ((double) centerX + (double) roundf (instancer (varIdxBase, 0))); + out->centerY = hb_clamp_to ((double) centerY + (double) roundf (instancer (varIdxBase, 1))); + set_fixed_clamped (out->startAngle, startAngle.to_float (instancer (varIdxBase, 2))); + set_fixed_clamped (out->endAngle, endAngle.to_float (instancer (varIdxBase, 3))); } if (format == 9 && c->plan->all_axes_pinned) @@ -936,9 +1181,13 @@ struct PaintSweepGradient }; // Paint a non-COLR glyph, filled as indicated by paint. +template struct PaintGlyph { - void closurev1 (hb_colrv1_closure_context_t* c) const; + using HBGlyphID = typename Types::HBGlyphID; + + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, const ItemVarStoreInstancer &instancer) const @@ -960,28 +1209,19 @@ struct PaintGlyph return_trace (c->check_struct (this) && paint.sanitize (c, this)); } - void paint_glyph (hb_paint_context_t *c) const - { - TRACE_PAINT (this); - c->funcs->push_inverse_font_transform (c->data, c->font); - c->funcs->push_clip_glyph (c->data, gid, c->font); - c->funcs->push_font_transform (c->data, c->font); - c->recurse (this+paint); - c->funcs->pop_transform (c->data); - c->funcs->pop_clip (c->data); - c->funcs->pop_transform (c->data); - } + inline void paint_glyph (hb_paint_context_t *c) const; - HBUINT8 format; /* format = 10 */ + HBUINT8 format; /* format = 10 or 33 */ Offset24To paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ - HBUINT16 gid; + HBGlyphID gid; public: - DEFINE_SIZE_STATIC (6); + DEFINE_SIZE_STATIC (4 + HBGlyphID::static_size); }; struct PaintColrGlyph { - void closurev1 (hb_colrv1_closure_context_t* c) const; + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, const ItemVarStoreInstancer &instancer HB_UNUSED) const @@ -1011,6 +1251,7 @@ struct PaintColrGlyph template class Var> struct PaintTransform { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1050,6 +1291,7 @@ struct PaintTransform struct PaintTranslate { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1062,8 +1304,8 @@ struct PaintTranslate if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->dx = dx + (int) roundf (instancer (varIdxBase, 0)); - out->dy = dy + (int) roundf (instancer (varIdxBase, 1)); + out->dx = hb_clamp_to ((double) dx + (double) roundf (instancer (varIdxBase, 0))); + out->dy = hb_clamp_to ((double) dy + (double) roundf (instancer (varIdxBase, 1))); } if (format == 15 && c->plan->all_axes_pinned) @@ -1097,8 +1339,73 @@ struct PaintTranslate DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size); }; +template +static bool serialize_scale_transform (hb_subset_context_t *c, + float sx, float sy, float dx, float dy, + const Source &source) +{ + auto *out = c->serializer->allocate_size> (7); + if (unlikely (!out)) return false; + out->format = 12; + + c->serializer->push (); + auto *transform = c->serializer->allocate_size (Affine2x3::static_size); + if (unlikely (!transform)) + { + c->serializer->pop_discard (); + return false; + } + set_fixed_clamped (transform->xx, sx); + transform->yx.set_float (0); + transform->xy.set_float (0); + set_fixed_clamped (transform->yy, sy); + set_fixed_clamped (transform->dx, dx); + set_fixed_clamped (transform->dy, dy); + c->serializer->add_link (out->transform, c->serializer->pop_pack ()); + + c->serializer->push (); + bool ret = source (); + if (ret) + c->serializer->add_link (out->src, c->serializer->pop_pack ()); + else + c->serializer->pop_discard (); + return ret; +} + +template +static bool subset_scale_as_transform (hb_subset_context_t *c, + const Base *base, + const Offset24To &src, + const ItemVarStoreInstancer &instancer, + float sx, float sy, + float cx = 0, float cy = 0) +{ + if (src.is_null ()) return false; + auto source = [&] { return c->dispatch (base+src, instancer); }; + float dx = cx * (1 - sx), dy = cy * (1 - sy); + if (dx >= -32768 && dx < 32768 && dy >= -32768 && dy < 32768) + return serialize_scale_transform (c, sx, sy, dx, dy, source); + + // Preserve the center as separate translations when the combined matrix + // exceeds Fixed. Splitting also makes the inverse of -32768 representable. + auto inner = [&] { + return serialize_scale_transform (c, 1, 1, -cx / 2, -cy / 2, source); + }; + auto inverse = [&] { + return serialize_scale_transform (c, 1, 1, -cx / 2, -cy / 2, inner); + }; + auto scale = [&] { + return serialize_scale_transform (c, sx, sy, 0, 0, inverse); + }; + auto outer = [&] { + return serialize_scale_transform (c, 1, 1, cx / 2, cy / 2, scale); + }; + return serialize_scale_transform (c, 1, 1, cx / 2, cy / 2, outer); +} + struct PaintScale { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1106,13 +1413,21 @@ struct PaintScale uint32_t varIdxBase) const { TRACE_SUBSET (this); + if (c->plan->all_axes_pinned && instancer && + !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + float sx = roundf (scaleX.to_float (instancer (varIdxBase, 0)) * 16384) / 16384; + float sy = roundf (scaleY.to_float (instancer (varIdxBase, 1)) * 16384) / 16384; + if (sx < -2 || sx >= 2 || sy < -2 || sy >= 2) + return_trace (subset_scale_as_transform (c, this, src, instancer, sx, sy)); + } auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0))); - out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1))); + set_fixed_clamped (out->scaleX, scaleX.to_float (instancer (varIdxBase, 0))); + set_fixed_clamped (out->scaleY, scaleY.to_float (instancer (varIdxBase, 1))); } if (format == 17 && c->plan->all_axes_pinned) @@ -1148,6 +1463,7 @@ struct PaintScale struct PaintScaleAroundCenter { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1155,15 +1471,26 @@ struct PaintScaleAroundCenter uint32_t varIdxBase) const { TRACE_SUBSET (this); + if (c->plan->all_axes_pinned && instancer && + !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + float sx = roundf (scaleX.to_float (instancer (varIdxBase, 0)) * 16384) / 16384; + float sy = roundf (scaleY.to_float (instancer (varIdxBase, 1)) * 16384) / 16384; + if (sx < -2 || sx >= 2 || sy < -2 || sy >= 2) + return_trace (subset_scale_as_transform ( + c, this, src, instancer, sx, sy, + centerX + roundf (instancer (varIdxBase, 2)), + centerY + roundf (instancer (varIdxBase, 3)))); + } auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0))); - out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1))); - out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2)); - out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3)); + set_fixed_clamped (out->scaleX, scaleX.to_float (instancer (varIdxBase, 0))); + set_fixed_clamped (out->scaleY, scaleY.to_float (instancer (varIdxBase, 1))); + out->centerX = hb_clamp_to ((double) centerX + (double) roundf (instancer (varIdxBase, 2))); + out->centerY = hb_clamp_to ((double) centerY + (double) roundf (instancer (varIdxBase, 3))); } if (format == 19 && c->plan->all_axes_pinned) @@ -1203,6 +1530,7 @@ struct PaintScaleAroundCenter struct PaintScaleUniform { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1210,11 +1538,18 @@ struct PaintScaleUniform uint32_t varIdxBase) const { TRACE_SUBSET (this); + if (c->plan->all_axes_pinned && instancer && + !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + float s = roundf (scale.to_float (instancer (varIdxBase, 0)) * 16384) / 16384; + if (s < -2 || s >= 2) + return_trace (subset_scale_as_transform (c, this, src, instancer, s, s)); + } auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) - out->scale.set_float (scale.to_float (instancer (varIdxBase, 0))); + set_fixed_clamped (out->scale, scale.to_float (instancer (varIdxBase, 0))); if (format == 21 && c->plan->all_axes_pinned) out->format = 20; @@ -1247,6 +1582,7 @@ struct PaintScaleUniform struct PaintScaleUniformAroundCenter { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1254,14 +1590,24 @@ struct PaintScaleUniformAroundCenter uint32_t varIdxBase) const { TRACE_SUBSET (this); + if (c->plan->all_axes_pinned && instancer && + !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + float s = roundf (scale.to_float (instancer (varIdxBase, 0)) * 16384) / 16384; + if (s < -2 || s >= 2) + return_trace (subset_scale_as_transform ( + c, this, src, instancer, s, s, + centerX + roundf (instancer (varIdxBase, 1)), + centerY + roundf (instancer (varIdxBase, 2)))); + } auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->scale.set_float (scale.to_float (instancer (varIdxBase, 0))); - out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1)); - out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2)); + set_fixed_clamped (out->scale, scale.to_float (instancer (varIdxBase, 0))); + out->centerX = hb_clamp_to ((double) centerX + (double) roundf (instancer (varIdxBase, 1))); + out->centerY = hb_clamp_to ((double) centerY + (double) roundf (instancer (varIdxBase, 2))); } if (format == 23 && c->plan->all_axes_pinned) @@ -1299,6 +1645,7 @@ struct PaintScaleUniformAroundCenter struct PaintRotate { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1310,7 +1657,7 @@ struct PaintRotate if (unlikely (!out)) return_trace (false); if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) - out->angle.set_float (angle.to_float (instancer (varIdxBase, 0))); + set_fixed_clamped (out->angle, angle.to_float (instancer (varIdxBase, 0))); if (format == 25 && c->plan->all_axes_pinned) out->format = 24; @@ -1343,6 +1690,7 @@ struct PaintRotate struct PaintRotateAroundCenter { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1355,9 +1703,9 @@ struct PaintRotateAroundCenter if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->angle.set_float (angle.to_float (instancer (varIdxBase, 0))); - out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1)); - out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2)); + set_fixed_clamped (out->angle, angle.to_float (instancer (varIdxBase, 0))); + out->centerX = hb_clamp_to ((double) centerX + (double) roundf (instancer (varIdxBase, 1))); + out->centerY = hb_clamp_to ((double) centerY + (double) roundf (instancer (varIdxBase, 2))); } if (format ==27 && c->plan->all_axes_pinned) @@ -1395,6 +1743,7 @@ struct PaintRotateAroundCenter struct PaintSkew { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1407,8 +1756,8 @@ struct PaintSkew if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0))); - out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1))); + set_fixed_clamped (out->xSkewAngle, xSkewAngle.to_float (instancer (varIdxBase, 0))); + set_fixed_clamped (out->ySkewAngle, ySkewAngle.to_float (instancer (varIdxBase, 1))); } if (format == 29 && c->plan->all_axes_pinned) @@ -1444,6 +1793,7 @@ struct PaintSkew struct PaintSkewAroundCenter { + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, @@ -1456,10 +1806,10 @@ struct PaintSkewAroundCenter if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0))); - out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1))); - out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2)); - out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3)); + set_fixed_clamped (out->xSkewAngle, xSkewAngle.to_float (instancer (varIdxBase, 0))); + set_fixed_clamped (out->ySkewAngle, ySkewAngle.to_float (instancer (varIdxBase, 1))); + out->centerX = hb_clamp_to ((double) centerX + (double) roundf (instancer (varIdxBase, 2))); + out->centerY = hb_clamp_to ((double) centerY + (double) roundf (instancer (varIdxBase, 3))); } if (format == 31 && c->plan->all_axes_pinned) @@ -1499,7 +1849,8 @@ struct PaintSkewAroundCenter struct PaintComposite { - void closurev1 (hb_colrv1_closure_context_t* c) const; + HB_INTERNAL void dependv1 (hb_colrv1_depend_context_t* c) const; + HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; bool subset (hb_subset_context_t *c, const ItemVarStoreInstancer &instancer) const @@ -1526,11 +1877,49 @@ struct PaintComposite void paint_glyph (hb_paint_context_t *c) const { TRACE_PAINT (this); + hb_paint_composite_mode_t composite_mode; + switch ((unsigned int) mode) + { + case HB_PAINT_COMPOSITE_MODE_CLEAR: + case HB_PAINT_COMPOSITE_MODE_SRC: + case HB_PAINT_COMPOSITE_MODE_DEST: + case HB_PAINT_COMPOSITE_MODE_SRC_OVER: + case HB_PAINT_COMPOSITE_MODE_DEST_OVER: + case HB_PAINT_COMPOSITE_MODE_SRC_IN: + case HB_PAINT_COMPOSITE_MODE_DEST_IN: + case HB_PAINT_COMPOSITE_MODE_SRC_OUT: + case HB_PAINT_COMPOSITE_MODE_DEST_OUT: + case HB_PAINT_COMPOSITE_MODE_SRC_ATOP: + case HB_PAINT_COMPOSITE_MODE_DEST_ATOP: + case HB_PAINT_COMPOSITE_MODE_XOR: + case HB_PAINT_COMPOSITE_MODE_PLUS: + case HB_PAINT_COMPOSITE_MODE_SCREEN: + case HB_PAINT_COMPOSITE_MODE_OVERLAY: + case HB_PAINT_COMPOSITE_MODE_DARKEN: + case HB_PAINT_COMPOSITE_MODE_LIGHTEN: + case HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: + case HB_PAINT_COMPOSITE_MODE_COLOR_BURN: + case HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: + case HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: + case HB_PAINT_COMPOSITE_MODE_DIFFERENCE: + case HB_PAINT_COMPOSITE_MODE_EXCLUSION: + case HB_PAINT_COMPOSITE_MODE_MULTIPLY: + case HB_PAINT_COMPOSITE_MODE_HSL_HUE: + case HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: + case HB_PAINT_COMPOSITE_MODE_HSL_COLOR: + case HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: + composite_mode = (hb_paint_composite_mode_t) (unsigned int) mode; + break; + default: + composite_mode = HB_PAINT_COMPOSITE_MODE_CLEAR; + break; + } + c->funcs->push_group_for (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); c->recurse (this+backdrop); - c->funcs->push_group_for (c->data, (hb_paint_composite_mode_t) (int) mode); + c->funcs->push_group_for (c->data, composite_mode); c->recurse (this+src); - c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode); + c->funcs->pop_group (c->data, composite_mode); c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); } @@ -1573,10 +1962,10 @@ struct ClipBoxFormat1 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) { - out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0)); - out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1)); - out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2)); - out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3)); + out->xMin = hb_clamp_to ((double) xMin + (double) floorf (instancer (varIdxBase, 0))); + out->yMin = hb_clamp_to ((double) yMin + (double) floorf (instancer (varIdxBase, 1))); + out->xMax = hb_clamp_to ((double) xMax + (double) ceilf (instancer (varIdxBase, 2))); + out->yMax = hb_clamp_to ((double) yMax + (double) ceilf (instancer (varIdxBase, 3))); } if (format == 2 && c->plan->all_axes_pinned) @@ -1602,10 +1991,10 @@ struct ClipBoxFormat2 : Variable value.get_clip_box(clip_box, instancer); if (instancer) { - clip_box.xMin += roundf (instancer (varIdxBase, 0)); - clip_box.yMin += roundf (instancer (varIdxBase, 1)); - clip_box.xMax += roundf (instancer (varIdxBase, 2)); - clip_box.yMax += roundf (instancer (varIdxBase, 3)); + clip_box.xMin = hb_saturate_add (clip_box.xMin, hb_clamp_to (floorf (instancer (varIdxBase, 0)))); + clip_box.yMin = hb_saturate_add (clip_box.yMin, hb_clamp_to (floorf (instancer (varIdxBase, 1)))); + clip_box.xMax = hb_saturate_add (clip_box.xMax, hb_clamp_to (ceilf (instancer (varIdxBase, 2)))); + clip_box.yMax = hb_saturate_add (clip_box.yMax, hb_clamp_to (ceilf (instancer (varIdxBase, 3)))); } } @@ -1620,8 +2009,8 @@ struct ClipBox { TRACE_SUBSET (this); switch (u.format.v) { - case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION)); - case 2: return_trace (u.format2.subset (c, instancer)); + case 1: hb_barrier (); return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION)); + case 2: hb_barrier (); return_trace (u.format2.subset (c, instancer)); default:return_trace (c->default_return_value ()); } } @@ -1629,7 +2018,7 @@ struct ClipBox void closurev1 (hb_colrv1_closure_context_t* c) const { switch (u.format.v) { - case 2: u.format2.closurev1 (c); return; + case 2: hb_barrier (); u.format2.closurev1 (c); return; default:return; } } @@ -1640,8 +2029,8 @@ struct ClipBox if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -1652,9 +2041,11 @@ struct ClipBox ClipBoxData clip_box; switch (u.format.v) { case 1: + hb_barrier (); u.format1.get_clip_box (clip_box, instancer); break; case 2: + hb_barrier (); u.format2.get_clip_box (clip_box, instancer); break; default: @@ -1663,8 +2054,8 @@ struct ClipBox extents->x_bearing = clip_box.xMin; extents->y_bearing = clip_box.yMax; - extents->width = clip_box.xMax - clip_box.xMin; - extents->height = clip_box.yMin - clip_box.yMax; + extents->width = hb_saturate_sub (clip_box.xMax, clip_box.xMin); + extents->height = hb_saturate_sub (clip_box.yMin, clip_box.yMax); return true; } @@ -1850,42 +2241,55 @@ struct Paint if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.paintformat1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.paintformat2, std::forward (ds)...)); - case 3: return_trace (c->dispatch (u.paintformat3, std::forward (ds)...)); - case 4: return_trace (c->dispatch (u.paintformat4, std::forward (ds)...)); - case 5: return_trace (c->dispatch (u.paintformat5, std::forward (ds)...)); - case 6: return_trace (c->dispatch (u.paintformat6, std::forward (ds)...)); - case 7: return_trace (c->dispatch (u.paintformat7, std::forward (ds)...)); - case 8: return_trace (c->dispatch (u.paintformat8, std::forward (ds)...)); - case 9: return_trace (c->dispatch (u.paintformat9, std::forward (ds)...)); - case 10: return_trace (c->dispatch (u.paintformat10, std::forward (ds)...)); - case 11: return_trace (c->dispatch (u.paintformat11, std::forward (ds)...)); - case 12: return_trace (c->dispatch (u.paintformat12, std::forward (ds)...)); - case 13: return_trace (c->dispatch (u.paintformat13, std::forward (ds)...)); - case 14: return_trace (c->dispatch (u.paintformat14, std::forward (ds)...)); - case 15: return_trace (c->dispatch (u.paintformat15, std::forward (ds)...)); - case 16: return_trace (c->dispatch (u.paintformat16, std::forward (ds)...)); - case 17: return_trace (c->dispatch (u.paintformat17, std::forward (ds)...)); - case 18: return_trace (c->dispatch (u.paintformat18, std::forward (ds)...)); - case 19: return_trace (c->dispatch (u.paintformat19, std::forward (ds)...)); - case 20: return_trace (c->dispatch (u.paintformat20, std::forward (ds)...)); - case 21: return_trace (c->dispatch (u.paintformat21, std::forward (ds)...)); - case 22: return_trace (c->dispatch (u.paintformat22, std::forward (ds)...)); - case 23: return_trace (c->dispatch (u.paintformat23, std::forward (ds)...)); - case 24: return_trace (c->dispatch (u.paintformat24, std::forward (ds)...)); - case 25: return_trace (c->dispatch (u.paintformat25, std::forward (ds)...)); - case 26: return_trace (c->dispatch (u.paintformat26, std::forward (ds)...)); - case 27: return_trace (c->dispatch (u.paintformat27, std::forward (ds)...)); - case 28: return_trace (c->dispatch (u.paintformat28, std::forward (ds)...)); - case 29: return_trace (c->dispatch (u.paintformat29, std::forward (ds)...)); - case 30: return_trace (c->dispatch (u.paintformat30, std::forward (ds)...)); - case 31: return_trace (c->dispatch (u.paintformat31, std::forward (ds)...)); - case 32: return_trace (c->dispatch (u.paintformat32, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.paintformat1, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.paintformat2, std::forward (ds)...)); + case 3: hb_barrier (); return_trace (c->dispatch (u.paintformat3, std::forward (ds)...)); + case 4: hb_barrier (); return_trace (c->dispatch (u.paintformat4, std::forward (ds)...)); + case 5: hb_barrier (); return_trace (c->dispatch (u.paintformat5, std::forward (ds)...)); + case 6: hb_barrier (); return_trace (c->dispatch (u.paintformat6, std::forward (ds)...)); + case 7: hb_barrier (); return_trace (c->dispatch (u.paintformat7, std::forward (ds)...)); + case 8: hb_barrier (); return_trace (c->dispatch (u.paintformat8, std::forward (ds)...)); + case 9: hb_barrier (); return_trace (c->dispatch (u.paintformat9, std::forward (ds)...)); + case 10: hb_barrier (); return_trace (c->dispatch (u.paintformat10, std::forward (ds)...)); + case 11: hb_barrier (); return_trace (c->dispatch (u.paintformat11, std::forward (ds)...)); + case 12: hb_barrier (); return_trace (c->dispatch (u.paintformat12, std::forward (ds)...)); + case 13: hb_barrier (); return_trace (c->dispatch (u.paintformat13, std::forward (ds)...)); + case 14: hb_barrier (); return_trace (c->dispatch (u.paintformat14, std::forward (ds)...)); + case 15: hb_barrier (); return_trace (c->dispatch (u.paintformat15, std::forward (ds)...)); + case 16: hb_barrier (); return_trace (c->dispatch (u.paintformat16, std::forward (ds)...)); + case 17: hb_barrier (); return_trace (c->dispatch (u.paintformat17, std::forward (ds)...)); + case 18: hb_barrier (); return_trace (c->dispatch (u.paintformat18, std::forward (ds)...)); + case 19: hb_barrier (); return_trace (c->dispatch (u.paintformat19, std::forward (ds)...)); + case 20: hb_barrier (); return_trace (c->dispatch (u.paintformat20, std::forward (ds)...)); + case 21: hb_barrier (); return_trace (c->dispatch (u.paintformat21, std::forward (ds)...)); + case 22: hb_barrier (); return_trace (c->dispatch (u.paintformat22, std::forward (ds)...)); + case 23: hb_barrier (); return_trace (c->dispatch (u.paintformat23, std::forward (ds)...)); + case 24: hb_barrier (); return_trace (c->dispatch (u.paintformat24, std::forward (ds)...)); + case 25: hb_barrier (); return_trace (c->dispatch (u.paintformat25, std::forward (ds)...)); + case 26: hb_barrier (); return_trace (c->dispatch (u.paintformat26, std::forward (ds)...)); + case 27: hb_barrier (); return_trace (c->dispatch (u.paintformat27, std::forward (ds)...)); + case 28: hb_barrier (); return_trace (c->dispatch (u.paintformat28, std::forward (ds)...)); + case 29: hb_barrier (); return_trace (c->dispatch (u.paintformat29, std::forward (ds)...)); + case 30: hb_barrier (); return_trace (c->dispatch (u.paintformat30, std::forward (ds)...)); + case 31: hb_barrier (); return_trace (c->dispatch (u.paintformat31, std::forward (ds)...)); + case 32: hb_barrier (); return_trace (c->dispatch (u.paintformat32, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 33: hb_barrier (); return_trace (c->dispatch (u.paintformat33, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } + bool get_solid_color (hb_paint_context_t *c, + hb_bool_t *is_foreground, hb_color_t *color) const + { + switch (u.format.v) { + case 2: hb_barrier (); u.paintformat2.get_solid_color (c, is_foreground, color); return true; + case 3: hb_barrier (); u.paintformat3.get_solid_color (c, is_foreground, color); return true; + default: return false; + } + } + protected: union { struct { HBUINT8 v; } format; @@ -1898,7 +2302,7 @@ struct Paint Variable> paintformat7; NoVariable> paintformat8; Variable> paintformat9; - PaintGlyph paintformat10; + PaintGlyph paintformat10; PaintColrGlyph paintformat11; PaintTransform paintformat12; PaintTransform paintformat13; @@ -1921,6 +2325,9 @@ struct Paint NoVariable paintformat30; Variable paintformat31; PaintComposite paintformat32; +#ifndef HB_NO_BEYOND_64K + PaintGlyph paintformat33; +#endif } u; public: DEFINE_SIZE_MIN (2); @@ -2115,7 +2522,7 @@ struct COLR hb_array_t all_layers = (this+layersZ).as_array (numLayers); hb_array_t glyph_layers = all_layers.sub_array (record.firstLayerIdx, record.numLayers); - if (count) + if (count && layers) { + glyph_layers.sub_array (start_offset, count) | hb_sink (hb_array (layers, *count)) @@ -2178,6 +2585,12 @@ struct COLR bool is_valid () { return colr.get_blob ()->length; } + void depend (hb_depend_data_builder_t *depend_data) const + { + if (!has_data ()) return; + colr->depend (depend_data); + } + void closure_glyphs (hb_codepoint_t glyph, hb_set_t *related_ids /* OUT */) const { colr->closure_glyphs (glyph, related_ids); } @@ -2239,6 +2652,35 @@ struct COLR mutable hb_atomic_t cached_scratch; }; + void depend (hb_depend_data_builder_t *depend_data) const + { + // v0 + hb_array_t baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs); + for (const BaseGlyphRecord &record : baseGlyphs) + { + auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record.firstLayerIdx, + record.numLayers); + for (const LayerRecord layer : glyph_layers) + depend_data->add_depend(record.glyphId, HB_OT_TAG_COLR, layer.glyphId); + } + + if (!has_v1_data()) + return; + + // v1 + hb_colrv1_depend_context_t c (this, depend_data); + const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; + + for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ()) + { + c.source_gid = baseglyph_paintrecord.glyphId; + c.visited_paint.clear (); + + const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint; + paint.dispatch (&c); + } + } + void closure_glyphs (hb_codepoint_t glyph, hb_set_t *related_ids /* OUT */) const { @@ -2405,10 +2847,11 @@ struct COLR const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const { - const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid); - if ((record && (hb_codepoint_t) record->glyphId != gid)) - record = nullptr; - return record; + const BaseGlyphList &list = this+baseGlyphList; + unsigned int i; + if (!list.bfind ((unsigned) gid, &i)) + return nullptr; + return &list[i]; } bool downgrade_to_V0 (const hb_set_t &glyphset) const @@ -2473,9 +2916,17 @@ struct COLR } else { + /* avar2 partial instancing: cull unreachable regions. */ + hb_set_t dead_regions; + if (c->plan->has_avar2) + var_store.collect_dead_regions (c->plan->axes_old_index_tag_map, + c->plan->avar2_reachable_ranges, + dead_regions); + if (unlikely (!out->varStore.serialize_serialize (c->serializer, &var_store, - c->plan->colrv1_varstore_inner_maps.as_array ()))) + c->plan->colrv1_varstore_inner_maps.as_array (), + dead_regions.get_population () ? &dead_regions : nullptr))) return_trace (false); } @@ -2580,8 +3031,8 @@ struct COLR * after instancing */ if (!subset_varstore (c, colr_prime)) return_trace (false); - ItemVarStoreInstancer instancer (get_var_store_ptr (), - get_delta_set_index_map_ptr (), + ItemVarStoreInstancer instancer (c->plan->normalized_coords ? get_var_store_ptr () : nullptr, + c->plan->normalized_coords ? get_delta_set_index_map_ptr () : nullptr, c->plan->normalized_coords.as_array ()); if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer)) @@ -2637,12 +3088,7 @@ struct COLR extents->height = 0; } else - { - extents->x_bearing = e.xmin; - extents->y_bearing = e.ymax; - extents->width = e.xmax - e.xmin; - extents->height = e.ymin - e.ymax; - } + *extents = e.to_glyph_extents (); return ret; } @@ -2700,19 +3146,10 @@ struct COLR // COLRv1 glyph bool is_bounded = true; + hb_glyph_extents_t extents = {}; if (clip) { - hb_glyph_extents_t extents; - if (get_clip (glyph, &extents, instancer)) - { - font->scale_glyph_extents (&extents); - c.funcs->push_clip_rectangle (c.data, - extents.x_bearing, - extents.y_bearing + extents.height, - extents.x_bearing + extents.width, - extents.y_bearing); - } - else + if (!get_clip (glyph, &extents, instancer)) { clip = false; is_bounded = false; @@ -2735,14 +3172,21 @@ struct COLR c.funcs->push_font_transform (c.data, font); + if (clip) + c.funcs->push_clip_rectangle (c.data, + (float) extents.x_bearing, + (float) extents.y_bearing + extents.height, + (float) extents.x_bearing + extents.width, + (float) extents.y_bearing); + if (is_bounded) c.recurse (*paint); - c.funcs->pop_transform (c.data); - if (clip) c.funcs->pop_clip (c.data); + c.funcs->pop_transform (c.data); + return true; } } @@ -2756,9 +3200,7 @@ struct COLR { hb_bool_t is_foreground; hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground); - c.funcs->push_clip_glyph (c.data, r.glyphId, c.font); - c.funcs->color (c.data, is_foreground, color); - c.funcs->pop_clip (c.data); + c.funcs->fill_glyph (c.data, r.glyphId, c.font, is_foreground, color); } return true; @@ -2800,6 +3242,33 @@ hb_paint_context_t::recurse (const Paint &paint) depth_left++; } +template +void PaintGlyph::paint_glyph (hb_paint_context_t *c) const +{ + TRACE_PAINT (this); + + hb_bool_t is_foreground; + hb_color_t color; + /* Optimize cases that can use a simple fill-glyph operation. */ + if (likely (c->depth_left > 0 && c->edge_count > 0) && + (this+paint).get_solid_color (c, &is_foreground, &color)) + { + c->edge_count--; + c->funcs->push_inverse_font_transform (c->data, c->font); + c->funcs->fill_glyph (c->data, gid, c->font, is_foreground, color); + c->funcs->pop_transform (c->data); + return; + } + + c->funcs->push_inverse_font_transform (c->data, c->font); + c->funcs->push_clip_glyph (c->data, gid, c->font); + c->funcs->push_font_transform (c->data, c->font); + c->recurse (this+paint); + c->funcs->pop_transform (c->data); + c->funcs->pop_clip (c->data); + c->funcs->pop_transform (c->data); +} + void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const { TRACE_PAINT (this); @@ -2839,10 +3308,10 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const if (has_clip_box) c->funcs->push_clip_rectangle (c->data, - extents.x_bearing, - extents.y_bearing + extents.height, - extents.x_bearing + extents.width, - extents.y_bearing); + (float) extents.x_bearing, + (float) extents.y_bearing + extents.height, + (float) extents.x_bearing + extents.width, + (float) extents.y_bearing); if (paint) c->recurse (*paint); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/colrv1-closure.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/colrv1-closure.hh index 9ed0aa5632a..f94ce070cf0 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/colrv1-closure.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/colrv1-closure.hh @@ -42,12 +42,13 @@ HB_INTERNAL void PaintColrLayers::closurev1 (hb_colrv1_closure_context_t* c) con const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList (); for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++) { - const Paint &paint = std::addressof (paint_offset_lists) + paint_offset_lists[i]; + const Paint &paint = paint_offset_lists.get_paint (i); paint.dispatch (c); } } -HB_INTERNAL void PaintGlyph::closurev1 (hb_colrv1_closure_context_t* c) const +template +HB_INTERNAL void PaintGlyph::closurev1 (hb_colrv1_closure_context_t* c) const { c->add_glyph (gid); (this+paint).dispatch (c); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh index f79e236bce9..b0c91ab3f3a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh @@ -209,7 +209,7 @@ struct CPAL hb_array_t all_colors ((this+colorRecordsZ).arrayZ, numColorRecords); hb_array_t palette_colors = all_colors.sub_array (start_index, numColors); - if (color_count) + if (color_count && colors) { + palette_colors.sub_array (start_offset, color_count) | hb_sink (hb_array (colors, *color_count)) @@ -300,25 +300,50 @@ struct CPAL hb_vector_t first_color_index_for_layer; hb_map_t first_color_to_layer_index; + /* Two palettes that retain exactly the same color records can share the + * same block of color records. This commonly happens after subsetting + * when the colors that distinguished the palettes are dropped. Map from + * a layer's retained colors to its index to find equal layers without + * scanning all of them. The keys point into layer_retained_colors, + * which keeps them alive. */ + hb_hashmap_t, unsigned> retained_colors_to_layer_index; + hb_vector_t> layer_retained_colors; + + const hb_array_t all_color_records = (this+colorRecordsZ).as_array (numColorRecords); const hb_array_t colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes); for (const auto first_color_record_idx : colorRecordIndices) { if (first_color_to_layer_index.has (first_color_record_idx)) continue; - first_color_index_for_layer.push (first_color_record_idx); - if (unlikely (!c->serializer->propagate_error (first_color_index_for_layer))) return_trace (false); - first_color_to_layer_index.set (first_color_record_idx, - first_color_index_for_layer.length - 1); + hb_vector_t retained_colors; + if (unlikely (!retained_colors.alloc (retained_color_indices.get_population ()))) return_trace (false); + for (hb_codepoint_t color_index : retained_color_indices) + retained_colors.push (all_color_records[first_color_record_idx + color_index]); + + unsigned layer_index = first_color_index_for_layer.length; + unsigned *candidate_layer_index = nullptr; + if (retained_colors_to_layer_index.has (retained_colors.as_array (), &candidate_layer_index)) + layer_index = *candidate_layer_index; + else + { + first_color_index_for_layer.push (first_color_record_idx); + if (unlikely (!c->serializer->propagate_error (first_color_index_for_layer))) return_trace (false); + + if (unlikely (!layer_retained_colors.push_or_fail (std::move (retained_colors)))) return_trace (false); + if (unlikely (!retained_colors_to_layer_index.set (layer_retained_colors.tail ().as_array (), layer_index))) + return_trace (false); + } + first_color_to_layer_index.set (first_color_record_idx, layer_index); + if (unlikely (!c->serializer->propagate_error (first_color_to_layer_index))) return_trace (false); } out->numColorRecords = first_color_index_for_layer.length * retained_color_indices.get_population (); - const hb_array_t color_records = (this+colorRecordsZ).as_array (numColorRecords); if (!out->serialize (c->serializer, colorRecordIndices, - color_records, + all_color_records, first_color_index_for_layer, first_color_to_layer_index, retained_color_indices)) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh index f6e6c5e3a9d..0eefe9cada9 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh @@ -337,18 +337,18 @@ struct sbix } extents->x_bearing = x_offset; - extents->y_bearing = png.IHDR.height + y_offset; - extents->width = png.IHDR.width; - extents->height = -1 * png.IHDR.height; + extents->y_bearing = hb_clamp_to ((int64_t) (unsigned int) png.IHDR.height + y_offset); + extents->width = (hb_position_t) (unsigned int) png.IHDR.width; + extents->height = -(hb_position_t) (unsigned int) png.IHDR.height; /* Convert to font units. */ if (strike_ppem && scale) { float scale = font->face->get_upem () / (float) strike_ppem; - extents->x_bearing = roundf (extents->x_bearing * scale); - extents->y_bearing = roundf (extents->y_bearing * scale); - extents->width = roundf (extents->width * scale); - extents->height = roundf (extents->height * scale); + extents->x_bearing = hb_clamp_to (roundf (extents->x_bearing * scale)); + extents->y_bearing = hb_clamp_to (roundf (extents->y_bearing * scale)); + extents->width = hb_clamp_to (roundf (extents->width * scale)); + extents->height = hb_clamp_to (roundf (extents->height * scale)); } if (scale) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh index a0fd2c88d0a..6be0bc85706 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh @@ -499,7 +499,7 @@ parse_cache_entries_linear (const char *svg, while (p + name_len < gt) { unsigned char c = (unsigned char) name[name_len]; - if (!(isalnum (c) || c == '_' || c == '-' || c == ':')) + if (!(ISALNUM (c) || c == '_' || c == '-' || c == ':')) break; name_len++; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh index 28678856373..80be3339099 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh @@ -29,7 +29,7 @@ #ifndef OT_LAYOUT_COMMON_COVERAGE_HH #define OT_LAYOUT_COMMON_COVERAGE_HH -#include "../types.hh" +#include "../../../hb-ot-dual.hh" #include "CoverageFormat1.hh" #include "CoverageFormat2.hh" @@ -67,11 +67,11 @@ struct Coverage hb_barrier (); switch (u.format.v) { - case 1: return_trace (u.format1.sanitize (c)); - case 2: return_trace (u.format2.sanitize (c)); + case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); + case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); #ifndef HB_NO_BEYOND_64K - case 3: return_trace (u.format3.sanitize (c)); - case 4: return_trace (u.format4.sanitize (c)); + case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); + case 4: hb_barrier (); return_trace (u.format4.sanitize (c)); #endif default:return_trace (true); } @@ -87,11 +87,11 @@ struct Coverage unsigned int get_coverage (hb_codepoint_t glyph_id) const { switch (u.format.v) { - case 1: return u.format1.get_coverage (glyph_id); - case 2: return u.format2.get_coverage (glyph_id); + case 1: hb_barrier (); return u.format1.get_coverage (glyph_id); + case 2: hb_barrier (); return u.format2.get_coverage (glyph_id); #ifndef HB_NO_BEYOND_64K - case 3: return u.format3.get_coverage (glyph_id); - case 4: return u.format4.get_coverage (glyph_id); + case 3: hb_barrier (); return u.format3.get_coverage (glyph_id); + case 4: hb_barrier (); return u.format4.get_coverage (glyph_id); #endif default:return NOT_COVERED; } @@ -104,9 +104,9 @@ struct Coverage coverage = get_coverage (glyph_id); if (cache) { if (coverage == NOT_COVERED) - cache->set_unchecked (glyph_id, cache->MAX_VALUE); + cache->set (glyph_id, cache->MAX_VALUE); else if (likely (coverage < cache->MAX_VALUE)) - cache->set_unchecked (glyph_id, coverage); + cache->set (glyph_id, coverage); } return coverage; } @@ -119,9 +119,9 @@ struct Coverage coverage = get_coverage (glyph_id); if (cache) { if (coverage == NOT_COVERED) - cache->set_unchecked (glyph_id, cache->MAX_VALUE); + cache->set (glyph_id, cache->MAX_VALUE); else - cache->set_unchecked (glyph_id, 0); + cache->set (glyph_id, 0); } return coverage; } @@ -129,11 +129,11 @@ struct Coverage unsigned get_population () const { switch (u.format.v) { - case 1: return u.format1.get_population (); - case 2: return u.format2.get_population (); + case 1: hb_barrier (); return u.format1.get_population (); + case 2: hb_barrier (); return u.format2.get_population (); #ifndef HB_NO_BEYOND_64K - case 3: return u.format3.get_population (); - case 4: return u.format4.get_population (); + case 3: hb_barrier (); return u.format3.get_population (); + case 4: hb_barrier (); return u.format4.get_population (); #endif default:return NOT_COVERED; } @@ -146,12 +146,12 @@ struct Coverage TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - unsigned count = hb_len (glyphs); + unsigned count = hb_len (+ glyphs); unsigned num_ranges = 0; hb_codepoint_t last = (hb_codepoint_t) -2; hb_codepoint_t max = 0; bool unsorted = false; - for (auto g: glyphs) + for (auto g: + glyphs) { if (last != (hb_codepoint_t) -2 && g < last) unsorted = true; @@ -176,11 +176,11 @@ struct Coverage switch (u.format.v) { - case 1: return_trace (u.format1.serialize (c, glyphs)); - case 2: return_trace (u.format2.serialize (c, glyphs)); + case 1: hb_barrier (); return_trace (u.format1.serialize (c, glyphs)); + case 2: hb_barrier (); return_trace (u.format2.serialize (c, glyphs)); #ifndef HB_NO_BEYOND_64K - case 3: return_trace (u.format3.serialize (c, glyphs)); - case 4: return_trace (u.format4.serialize (c, glyphs)); + case 3: hb_barrier (); return_trace (u.format3.serialize (c, glyphs)); + case 4: hb_barrier (); return_trace (u.format4.serialize (c, glyphs)); #endif default:return_trace (false); } @@ -189,10 +189,13 @@ struct Coverage bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); + const hb_subset_plan_t *plan = c->plan; auto it = + iter () - | hb_take (c->plan->source->get_num_glyphs ()) - | hb_map_retains_sorting (c->plan->glyph_map_gsub) + | hb_take (plan->source->get_num_glyphs ()) + | hb_map_retains_sorting ([plan] (hb_codepoint_t g) { + return plan->map_gsub_glyph (g); + }) | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; }) ; @@ -207,11 +210,11 @@ struct Coverage { switch (u.format.v) { - case 1: return u.format1.intersects (glyphs); - case 2: return u.format2.intersects (glyphs); + case 1: hb_barrier (); return u.format1.intersects (glyphs); + case 2: hb_barrier (); return u.format2.intersects (glyphs); #ifndef HB_NO_BEYOND_64K - case 3: return u.format3.intersects (glyphs); - case 4: return u.format4.intersects (glyphs); + case 3: hb_barrier (); return u.format3.intersects (glyphs); + case 4: hb_barrier (); return u.format4.intersects (glyphs); #endif default:return false; } @@ -220,11 +223,11 @@ struct Coverage { switch (u.format.v) { - case 1: return u.format1.intersects_coverage (glyphs, index); - case 2: return u.format2.intersects_coverage (glyphs, index); + case 1: hb_barrier (); return u.format1.intersects_coverage (glyphs, index); + case 2: hb_barrier (); return u.format2.intersects_coverage (glyphs, index); #ifndef HB_NO_BEYOND_64K - case 3: return u.format3.intersects_coverage (glyphs, index); - case 4: return u.format4.intersects_coverage (glyphs, index); + case 3: hb_barrier (); return u.format3.intersects_coverage (glyphs, index); + case 4: hb_barrier (); return u.format4.intersects_coverage (glyphs, index); #endif default:return false; } @@ -250,11 +253,11 @@ struct Coverage { switch (u.format.v) { - case 1: return u.format1.collect_coverage (glyphs); - case 2: return u.format2.collect_coverage (glyphs); + case 1: hb_barrier (); return u.format1.collect_coverage (glyphs); + case 2: hb_barrier (); return u.format2.collect_coverage (glyphs); #ifndef HB_NO_BEYOND_64K - case 3: return u.format3.collect_coverage (glyphs); - case 4: return u.format4.collect_coverage (glyphs); + case 3: hb_barrier (); return u.format3.collect_coverage (glyphs); + case 4: hb_barrier (); return u.format4.collect_coverage (glyphs); #endif default:return false; } @@ -266,11 +269,11 @@ struct Coverage { switch (u.format.v) { - case 1: return u.format1.intersect_set (glyphs, intersect_glyphs); - case 2: return u.format2.intersect_set (glyphs, intersect_glyphs); + case 1: hb_barrier (); return u.format1.intersect_set (glyphs, intersect_glyphs); + case 2: hb_barrier (); return u.format2.intersect_set (glyphs, intersect_glyphs); #ifndef HB_NO_BEYOND_64K - case 3: return u.format3.intersect_set (glyphs, intersect_glyphs); - case 4: return u.format4.intersect_set (glyphs, intersect_glyphs); + case 3: hb_barrier (); return u.format3.intersect_set (glyphs, intersect_glyphs); + case 4: hb_barrier (); return u.format4.intersect_set (glyphs, intersect_glyphs); #endif default:return ; } @@ -285,11 +288,11 @@ struct Coverage format = c_.u.format.v; switch (format) { - case 1: u.format1.init (c_.u.format1); return; - case 2: u.format2.init (c_.u.format2); return; + case 1: hb_barrier (); u.format1.init (c_.u.format1); return; + case 2: hb_barrier (); u.format2.init (c_.u.format2); return; #ifndef HB_NO_BEYOND_64K - case 3: u.format3.init (c_.u.format3); return; - case 4: u.format4.init (c_.u.format4); return; + case 3: hb_barrier (); u.format3.init (c_.u.format3); return; + case 4: hb_barrier (); u.format4.init (c_.u.format4); return; #endif default: return; } @@ -298,11 +301,11 @@ struct Coverage { switch (format) { - case 1: return u.format1.__more__ (); - case 2: return u.format2.__more__ (); + case 1: hb_barrier (); return u.format1.__more__ (); + case 2: hb_barrier (); return u.format2.__more__ (); #ifndef HB_NO_BEYOND_64K - case 3: return u.format3.__more__ (); - case 4: return u.format4.__more__ (); + case 3: hb_barrier (); return u.format3.__more__ (); + case 4: hb_barrier (); return u.format4.__more__ (); #endif default:return false; } @@ -311,11 +314,11 @@ struct Coverage { switch (format) { - case 1: u.format1.__next__ (); break; - case 2: u.format2.__next__ (); break; + case 1: hb_barrier (); u.format1.__next__ (); break; + case 2: hb_barrier (); u.format2.__next__ (); break; #ifndef HB_NO_BEYOND_64K - case 3: u.format3.__next__ (); break; - case 4: u.format4.__next__ (); break; + case 3: hb_barrier (); u.format3.__next__ (); break; + case 4: hb_barrier (); u.format4.__next__ (); break; #endif default: break; } @@ -327,11 +330,11 @@ struct Coverage { switch (format) { - case 1: return u.format1.get_glyph (); - case 2: return u.format2.get_glyph (); + case 1: hb_barrier (); return u.format1.get_glyph (); + case 2: hb_barrier (); return u.format2.get_glyph (); #ifndef HB_NO_BEYOND_64K - case 3: return u.format3.get_glyph (); - case 4: return u.format4.get_glyph (); + case 3: hb_barrier (); return u.format3.get_glyph (); + case 4: hb_barrier (); return u.format4.get_glyph (); #endif default:return 0; } @@ -341,11 +344,11 @@ struct Coverage if (unlikely (format != o.format)) return true; switch (format) { - case 1: return u.format1 != o.u.format1; - case 2: return u.format2 != o.u.format2; + case 1: hb_barrier (); return u.format1 != o.u.format1; + case 2: hb_barrier (); return u.format2 != o.u.format2; #ifndef HB_NO_BEYOND_64K - case 3: return u.format3 != o.u.format3; - case 4: return u.format4 != o.u.format4; + case 3: hb_barrier (); return u.format3 != o.u.format3; + case 4: hb_barrier (); return u.format4 != o.u.format4; #endif default:return false; } @@ -356,11 +359,11 @@ struct Coverage it.format = format; switch (format) { - case 1: it.u.format1 = u.format1.__end__ (); break; - case 2: it.u.format2 = u.format2.__end__ (); break; + case 1: hb_barrier (); it.u.format1 = u.format1.__end__ (); break; + case 2: hb_barrier (); it.u.format2 = u.format2.__end__ (); break; #ifndef HB_NO_BEYOND_64K - case 3: it.u.format3 = u.format3.__end__ (); break; - case 4: it.u.format4 = u.format4.__end__ (); break; + case 3: hb_barrier (); it.u.format3 = u.format3.__end__ (); break; + case 4: hb_barrier (); it.u.format4 = u.format4.__end__ (); break; #endif default: break; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh index 122326e3024..addce14ce7a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh @@ -43,10 +43,10 @@ struct CoverageFormat1_3 public: HBUINT16 coverageFormat; /* Format identifier--format = 1 */ - SortedArray16Of + typename Types::template SortedArrayOf glyphArray; /* Array of GlyphIDs--in numerical order */ - DEFINE_SIZE_ARRAY (4, glyphArray); + DEFINE_SIZE_ARRAY (2 + Types::HBUINT::static_size, glyphArray); private: bool sanitize (hb_sanitize_context_t *c) const diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh index 8287c8d4d4d..51360f85575 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh @@ -39,15 +39,16 @@ template struct CoverageFormat2_4 { friend struct Coverage; + using CoverageRangeRecord = RangeRecord; public: HBUINT16 coverageFormat; /* Format identifier--format = 2 */ - SortedArray16Of> + typename Types::template SortedArrayOf rangeRecord; /* Array of glyph ranges--ordered by * Start GlyphID. rangeCount entries * long */ public: - DEFINE_SIZE_ARRAY (4, rangeRecord); + DEFINE_SIZE_ARRAY (2 + Types::HBUINT::static_size, rangeRecord); private: @@ -59,7 +60,7 @@ struct CoverageFormat2_4 unsigned int get_coverage (hb_codepoint_t glyph_id) const { - const RangeRecord &range = rangeRecord.bsearch (glyph_id); + const CoverageRangeRecord &range = rangeRecord.bsearch (glyph_id); return likely (range.first <= range.last) ? (unsigned int) range.value + (glyph_id - range.first) : NOT_COVERED; @@ -113,7 +114,7 @@ struct CoverageFormat2_4 } if (unlikely (unsorted)) - rangeRecord.as_array ().qsort (RangeRecord::cmp_range); + rangeRecord.as_array ().qsort (CoverageRangeRecord::cmp_range); return_trace (true); } @@ -129,7 +130,7 @@ struct CoverageFormat2_4 } return hb_any (+ hb_iter (rangeRecord) - | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (*glyphs); })); + | hb_map ([glyphs] (const CoverageRangeRecord &range) { return range.intersects (*glyphs); })); } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { @@ -139,6 +140,19 @@ struct CoverageFormat2_4 return false; } + static void add_intersected_bits (hb_set_t &set, hb_codepoint_t base, uint64_t bits) + { set.add_bits (base, bits); } + + template + static void add_intersected_bits (IterableOut&& out, hb_codepoint_t base, uint64_t bits) + { + while (bits) + { + out << base + hb_ctz (bits); + bits &= bits - 1; + } + } + template void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const @@ -151,9 +165,18 @@ struct CoverageFormat2_4 if (unlikely (range.first < last)) break; last = range.last; - for (hb_codepoint_t g = range.first - 1; - glyphs.next (&g) && g <= last;) - intersect_glyphs << g; + hb_codepoint_t cursor = range.first & ~hb_bit_page_t::ELT_MASK; + cursor = cursor ? cursor - 1 : HB_SET_VALUE_INVALID; + uint64_t bits; + while (glyphs.next_bits (&cursor, &bits) && cursor <= last) + { + if (range.first > cursor) + bits &= UINT64_MAX << (range.first - cursor); + unsigned int end = last - cursor; + if (end < hb_bit_page_t::ELT_BITS - 1) + bits &= (uint64_t (1) << (end + 1)) - 1; + add_intersected_bits (intersect_glyphs, cursor, bits); + } } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh index 85aacace9a7..ad9a637d6a0 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh @@ -33,14 +33,14 @@ namespace OT { namespace Layout { namespace Common { -template +template struct RangeRecord { typename Types::HBGlyphID first; /* First GlyphID in the range */ typename Types::HBGlyphID last; /* Last GlyphID in the range */ - HBUINT16 value; /* Value */ + Value value; /* Value */ - DEFINE_SIZE_STATIC (2 + 2 * Types::size); + DEFINE_SIZE_STATIC (2 * Types::size + Value::static_size); bool sanitize (hb_sanitize_context_t *c) const { @@ -86,10 +86,10 @@ struct RangeRecord // but that only works when there is only a single namespace level. // The macro should probably be fixed so it can work in this situation. extern HB_INTERNAL const unsigned char _hb_Null_OT_RangeRecord[9]; -template -struct Null> { - static OT::Layout::Common::RangeRecord const & get_null () { - return *reinterpret_cast *> (_hb_Null_OT_RangeRecord); +template +struct Null> { + static OT::Layout::Common::RangeRecord const & get_null () { + return *reinterpret_cast *> (_hb_Null_OT_RangeRecord); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh index 23412914feb..c6dbceef8bb 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh @@ -53,6 +53,9 @@ struct AttachPoint : Array16Of } }; +/* AttachList is referenced by both GDEF attachListOffset and + * attachListOffset2. The v1.4 top-level offset widens, but the + * AttachList table itself keeps Offset16 internals. */ struct AttachList { unsigned int get_attach_points (hb_codepoint_t glyph_id, @@ -70,7 +73,7 @@ struct AttachList const AttachPoint &points = this+attachPoint[index]; - if (point_count) + if (point_count && point_array) { + points.as_array ().sub_array (start_offset, point_count) | hb_sink (hb_array (point_array, *point_count)) @@ -192,8 +195,8 @@ struct CaretValueFormat3 const ItemVariationStore &var_store) const { return HB_DIRECTION_IS_HORIZONTAL (direction) ? - font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : - font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); + hb_saturate_add (font->em_scale_x (coordinate), (this+deviceTable).get_x_delta (font, var_store)) : + hb_saturate_add (font->em_scale_y (coordinate), (this+deviceTable).get_y_delta (font, var_store)); } bool subset (hb_subset_context_t *c) const @@ -253,9 +256,9 @@ struct CaretValue const ItemVariationStore &var_store) const { switch (u.format.v) { - case 1: return u.format1.get_caret_value (font, direction); - case 2: return u.format2.get_caret_value (font, direction, glyph_id); - case 3: return u.format3.get_caret_value (font, direction, var_store); + case 1: hb_barrier (); return u.format1.get_caret_value (font, direction); + case 2: hb_barrier (); return u.format2.get_caret_value (font, direction, glyph_id); + case 3: hb_barrier (); return u.format3.get_caret_value (font, direction, var_store); default:return 0; } } @@ -266,9 +269,9 @@ struct CaretValue if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); - case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -280,6 +283,7 @@ struct CaretValue case 2: return; case 3: + hb_barrier (); u.format3.collect_variation_indices (c); return; default: return; @@ -292,9 +296,9 @@ struct CaretValue if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); switch (u.format.v) { - case 1: return_trace (u.format1.sanitize (c)); - case 2: return_trace (u.format2.sanitize (c)); - case 3: return_trace (u.format3.sanitize (c)); + case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); + case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); + case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); default:return_trace (true); } } @@ -320,7 +324,7 @@ struct LigGlyph unsigned *caret_count /* IN/OUT */, hb_position_t *caret_array /* OUT */) const { - if (caret_count) + if (caret_count && caret_array) { + carets.as_array ().sub_array (start_offset, caret_count) | hb_map (hb_add (this)) @@ -366,6 +370,9 @@ struct LigGlyph DEFINE_SIZE_ARRAY (2, carets); }; +/* LigCaretList2 widens the LigCaretList coverage, count, and LigGlyph + * offsets. The LigGlyph table itself keeps Offset16 caretValueOffsets. */ +template struct LigCaretList { unsigned int get_lig_carets (hb_font_t *font, @@ -425,16 +432,21 @@ struct LigCaretList } protected: - Offset16To + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of LigCaretList table */ - Array16OfOffset16To + typename Types::template ArrayOf> ligGlyph; /* Array of LigGlyph tables * in Coverage Index order */ public: - DEFINE_SIZE_ARRAY (4, ligGlyph); + DEFINE_SIZE_ARRAY (Types::LOffset::static_size + Types::HBUINT::static_size, ligGlyph); }; +#ifndef HB_NO_BEYOND_64K +static_assert (LigCaretList::min_size == + Offset32::static_size + HBUINT24::static_size, ""); +#endif + struct MarkGlyphSetsFormat1 { @@ -520,7 +532,7 @@ struct MarkGlyphSets bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const { switch (u.format.v) { - case 1: return u.format1.covers (set_index, glyph_id); + case 1: hb_barrier (); return u.format1.covers (set_index, glyph_id); default:return false; } } @@ -529,7 +541,7 @@ struct MarkGlyphSets void collect_coverage (hb_vector_t &sets) const { switch (u.format.v) { - case 1: u.format1.collect_coverage (sets); return; + case 1: hb_barrier (); u.format1.collect_coverage (sets); return; default:return; } } @@ -538,7 +550,7 @@ struct MarkGlyphSets hb_set_t& used_mark_sets /* OUT */) const { switch (u.format.v) { - case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return; + case 1: hb_barrier (); u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return; default:return; } } @@ -547,7 +559,7 @@ struct MarkGlyphSets { TRACE_SUBSET (this); switch (u.format.v) { - case 1: return_trace (u.format1.subset (c)); + case 1: hb_barrier (); return_trace (u.format1.subset (c)); default:return_trace (false); } } @@ -558,7 +570,7 @@ struct MarkGlyphSets if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); switch (u.format.v) { - case 1: return_trace (u.format1.sanitize (c)); + case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); default:return_trace (true); } } @@ -579,86 +591,73 @@ struct MarkGlyphSets */ -template -struct GDEFVersion1_2 +struct GDEF { - friend struct GDEF; + static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; - protected: - FixedVersion<>version; /* Version of the GDEF table--currently - * 0x00010003u */ - typename Types::template OffsetTo - glyphClassDef; /* Offset to class definition table - * for glyph type--from beginning of - * GDEF header (may be Null) */ - typename Types::template OffsetTo - attachList; /* Offset to list of glyphs with - * attachment points--from beginning - * of GDEF header (may be Null) */ - typename Types::template OffsetTo - ligCaretList; /* Offset to list of positioning points - * for ligature carets--from beginning - * of GDEF header (may be Null) */ - typename Types::template OffsetTo - markAttachClassDef; /* Offset to class definition table for - * mark attachment type--from beginning - * of GDEF header (may be Null) */ - typename Types::template OffsetTo - markGlyphSetsDef; /* Offset to the table of mark set - * definitions--from beginning of GDEF - * header (may be NULL). Introduced - * in version 0x00010002. */ - Offset32To - varStore; /* Offset to the table of Item Variation - * Store--from beginning of GDEF - * header (may be NULL). Introduced - * in version 0x00010003. */ - public: - DEFINE_SIZE_MIN (4 + 4 * Types::size); + enum GlyphClasses { + UnclassifiedGlyph = 0, + BaseGlyph = 1, + LigatureGlyph = 2, + MarkGlyph = 3, + ComponentGlyph = 4 + }; size_t get_size () const { + if (version.major != 1) return version.static_size; + return min_size + (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + - (version.to_int () >= 0x00010003u ? varStore.static_size : 0); + (version.to_int () >= 0x00010003u ? varStore.static_size : 0) + +#ifndef HB_NO_BEYOND_64K + (version.to_int () >= 0x00010004u ? 5 * Offset32::static_size : 0) +#else + 0 +#endif + ; } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (version.sanitize (c) && - glyphClassDef.sanitize (c, this) && - attachList.sanitize (c, this) && - ligCaretList.sanitize (c, this) && - markAttachClassDef.sanitize (c, this) && - hb_barrier () && - ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) && - ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this))); - } + if (unlikely (!version.sanitize (c) || + version.major != 1 || + !c->check_range (this, get_size ()))) + return_trace (false); + hb_barrier (); - static void remap_varidx_after_instantiation (const hb_map_t& varidx_map, - hb_hashmap_t>& layout_variation_idx_delta_map /* IN/OUT */) - { - /* varidx_map is empty which means varstore is empty after instantiation, - * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX. - * varidx_map doesn't have original varidx, indicating delta row is all - * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ - for (auto _ : layout_variation_idx_delta_map.iter_ref ()) + bool glyph_class_def_ok = glyphClassDef.sanitize (c, this); + bool attach_list_ok = attachList.sanitize (c, this); + bool lig_caret_list_ok = ligCaretList.sanitize (c, this); + bool mark_attach_class_def_ok = markAttachClassDef.sanitize (c, this); + bool mark_glyph_sets_def_ok = version.to_int () < 0x00010002u || + markGlyphSetsDef.sanitize (c, this); + +#ifndef HB_NO_BEYOND_64K + if (version.to_int () >= 0x00010004u) { - /* old_varidx->(varidx, delta) mapping generated for subsetting, then this - * varidx is used as key of varidx_map during instantiation */ - uint32_t varidx = _.second.first; - uint32_t *new_varidx; - if (varidx_map.has (varidx, &new_varidx)) - _.second.first = *new_varidx; - else - _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + if (glyphClassDef2) glyph_class_def_ok = glyphClassDef2.sanitize (c, this); + if (attachList2) attach_list_ok = attachList2.sanitize (c, this); + if (ligCaretList2) lig_caret_list_ok = ligCaretList2.sanitize (c, this); + if (markAttachClassDef2) mark_attach_class_def_ok = markAttachClassDef2.sanitize (c, this); + if (markGlyphSetsDef2) mark_glyph_sets_def_ok = markGlyphSetsDef2.sanitize (c, this); } +#endif + + return_trace (glyph_class_def_ok && + attach_list_ok && + lig_caret_list_ok && + mark_attach_class_def_ok && + mark_glyph_sets_def_ok && + (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); + if (version.major != 1) return_trace (false); + auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); @@ -667,15 +666,29 @@ struct GDEFVersion1_2 // the end of the GDEF table. // See: https://github.com/harfbuzz/harfbuzz/issues/4636 auto snapshot_version0 = c->serializer->snapshot (); - if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef))) + if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && + !c->serializer->embed (markGlyphSetsDef))) + return_trace (false); + + auto snapshot_version2 = c->serializer->snapshot (); + if (unlikely (version.to_int () >= 0x00010003u && hb_barrier () && + !c->serializer->embed (varStore))) return_trace (false); + bool use_v14 = false; +#ifndef HB_NO_BEYOND_64K + use_v14 = version.to_int () >= 0x00010004u && + (glyphClassDef2 || attachList2 || ligCaretList2 || + markAttachClassDef2 || markGlyphSetsDef2); + if (unlikely (version.to_int () >= 0x00010004u && hb_barrier () && + !c->serializer->extend_size (out, get_size ()))) + return_trace (false); +#endif + bool subset_varstore = false; unsigned varstore_index = (unsigned) -1; - auto snapshot_version2 = c->serializer->snapshot (); if (version.to_int () >= 0x00010003u && hb_barrier ()) { - if (unlikely (!c->serializer->embed (varStore))) return_trace (false); if (c->plan->all_axes_pinned) out->varStore = 0; else if (c->plan->normalized_coords) @@ -683,22 +696,26 @@ struct GDEFVersion1_2 if (varStore) { item_variations_t item_vars; - if (item_vars.instantiate (this+varStore, c->plan, true, true, - c->plan->gdef_varstore_inner_maps.as_array ())) { - subset_varstore = out->varStore.serialize_serialize (c->serializer, - item_vars.has_long_word (), - c->plan->axis_tags, - item_vars.get_region_list (), - item_vars.get_vardata_encodings ()); - varstore_index = c->serializer->last_added_child_index(); - } + if (unlikely (!c->serializer->check_success ( + item_vars.instantiate (this+varStore, c->plan, true, true, + c->plan->gdef_varstore_inner_maps.as_array (), true)))) + return_trace (false); + subset_varstore = out->varStore.serialize_serialize (c->serializer, + item_vars.has_long_word (), + c->plan->axis_tags, + item_vars.get_region_list (), + item_vars.get_vardata_encodings ()); + varstore_index = c->serializer->last_added_child_index(); remap_varidx_after_instantiation (item_vars.get_varidx_map (), c->plan->layout_variation_idx_delta_map); + remap_varidx_after_instantiation (item_vars.get_varidx_map (), + c->plan->layout_condition_idx_value_map); } } else { - subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ()); + subset_varstore = out->varStore.serialize_subset (c, varStore, this, + c->plan->gdef_varstore_inner_maps.as_array ()); varstore_index = c->serializer->last_added_child_index(); } } @@ -706,20 +723,39 @@ struct GDEFVersion1_2 out->version.major = version.major; out->version.minor = version.minor; - if (!subset_varstore && version.to_int () >= 0x00010002u) { + if (!subset_varstore && version.to_int () >= 0x00010002u && !use_v14) { c->serializer->revert (snapshot_version2); } + if (!subset_varstore) + out->varStore = 0; + else + c->plan->has_gdef_varstore = true; bool subset_markglyphsetsdef = false; if (version.to_int () >= 0x00010002u && hb_barrier ()) { - subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); +#ifndef HB_NO_BEYOND_64K + if (use_v14 && markGlyphSetsDef2) + { + out->markGlyphSetsDef = 0; + subset_markglyphsetsdef = serialize_subset_offset (c, out->markGlyphSetsDef2, + markGlyphSetsDef2, this); + } + else +#endif + { +#ifndef HB_NO_BEYOND_64K + if (use_v14) out->markGlyphSetsDef2 = 0; +#endif + subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); + } } - if (subset_varstore) + if (use_v14) { + out->version.minor = 4; + } else if (subset_varstore) { out->version.minor = 3; - c->plan->has_gdef_varstore = true; } else if (subset_markglyphsetsdef) { out->version.minor = 2; } else { @@ -727,193 +763,160 @@ struct GDEFVersion1_2 c->serializer->revert (snapshot_version0); } - bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true); - bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); - bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true); - bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); + bool subset_glyphclassdef = false; + bool subset_attachlist = false; + bool subset_markattachclassdef = false; + bool subset_ligcaretlist = false; - if (subset_varstore && varstore_index != (unsigned) -1) { - c->serializer->repack_last(varstore_index); +#ifndef HB_NO_BEYOND_64K + if (use_v14 && glyphClassDef2) + { + out->glyphClassDef = 0; + subset_glyphclassdef = serialize_subset_offset (c, out->glyphClassDef2, + glyphClassDef2, this, nullptr, false, true); + } + else +#endif + { +#ifndef HB_NO_BEYOND_64K + if (use_v14) out->glyphClassDef2 = 0; +#endif + subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true); } - return_trace (subset_glyphclassdef || subset_attachlist || - subset_ligcaretlist || subset_markattachclassdef || - (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || - (out->version.to_int () >= 0x00010003u && subset_varstore)); - } -}; - -struct GDEF -{ - static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; - - enum GlyphClasses { - UnclassifiedGlyph = 0, - BaseGlyph = 1, - LigatureGlyph = 2, - MarkGlyph = 3, - ComponentGlyph = 4 - }; - - size_t get_size () const - { - switch (u.version.major) { - case 1: return u.version1.get_size (); #ifndef HB_NO_BEYOND_64K - case 2: return u.version2.get_size (); + if (use_v14 && attachList2) + { + out->attachList = 0; + subset_attachlist = serialize_subset_offset (c, out->attachList2, attachList2, this); + } + else #endif - default: return u.version.static_size; + { +#ifndef HB_NO_BEYOND_64K + if (use_v14) out->attachList2 = 0; +#endif + subset_attachlist = out->attachList.serialize_subset (c, attachList, this); } - } - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!u.version.sanitize (c))) return_trace (false); - hb_barrier (); - switch (u.version.major) { - case 1: return_trace (u.version1.sanitize (c)); #ifndef HB_NO_BEYOND_64K - case 2: return_trace (u.version2.sanitize (c)); + if (use_v14 && markAttachClassDef2) + { + out->markAttachClassDef = 0; + subset_markattachclassdef = serialize_subset_offset (c, out->markAttachClassDef2, + markAttachClassDef2, this, nullptr, false, true); + } + else +#endif + { +#ifndef HB_NO_BEYOND_64K + if (use_v14) out->markAttachClassDef2 = 0; #endif - default: return_trace (true); + subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, + this, nullptr, false, true); } - } - bool subset (hb_subset_context_t *c) const - { - switch (u.version.major) { - case 1: return u.version1.subset (c); #ifndef HB_NO_BEYOND_64K - case 2: return u.version2.subset (c); + if (use_v14 && ligCaretList2) + { + out->ligCaretList = 0; + subset_ligcaretlist = serialize_subset_offset (c, out->ligCaretList2, ligCaretList2, this); + } + else +#endif + { +#ifndef HB_NO_BEYOND_64K + if (use_v14) out->ligCaretList2 = 0; #endif - default: return false; + subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); } + + if (subset_varstore && varstore_index != (unsigned) -1) { + c->serializer->repack_last(varstore_index); + } + + return_trace (subset_glyphclassdef || subset_attachlist || + subset_ligcaretlist || subset_markattachclassdef || + (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || + (out->version.to_int () >= 0x00010003u && subset_varstore)); } bool has_glyph_classes () const { - switch (u.version.major) { - case 1: return u.version1.glyphClassDef != 0; #ifndef HB_NO_BEYOND_64K - case 2: return u.version2.glyphClassDef != 0; + if (version.to_int () >= 0x00010004u && glyphClassDef2) return true; #endif - default: return false; - } + return glyphClassDef != 0; } const ClassDef &get_glyph_class_def () const { - switch (u.version.major) { - case 1: return this+u.version1.glyphClassDef; #ifndef HB_NO_BEYOND_64K - case 2: return this+u.version2.glyphClassDef; + if (version.to_int () >= 0x00010004u && glyphClassDef2) return this+glyphClassDef2; #endif - default: return Null(ClassDef); - } + return this+glyphClassDef; } bool has_attach_list () const { - switch (u.version.major) { - case 1: return u.version1.attachList != 0; #ifndef HB_NO_BEYOND_64K - case 2: return u.version2.attachList != 0; + if (version.to_int () >= 0x00010004u && attachList2) return true; #endif - default: return false; - } + return attachList != 0; } const AttachList &get_attach_list () const { - switch (u.version.major) { - case 1: return this+u.version1.attachList; #ifndef HB_NO_BEYOND_64K - case 2: return this+u.version2.attachList; + if (version.to_int () >= 0x00010004u && attachList2) return this+attachList2; #endif - default: return Null(AttachList); - } + return this+attachList; } bool has_lig_carets () const { - switch (u.version.major) { - case 1: return u.version1.ligCaretList != 0; #ifndef HB_NO_BEYOND_64K - case 2: return u.version2.ligCaretList != 0; + if (version.to_int () >= 0x00010004u && ligCaretList2) return true; #endif - default: return false; - } - } - const LigCaretList &get_lig_caret_list () const - { - switch (u.version.major) { - case 1: return this+u.version1.ligCaretList; -#ifndef HB_NO_BEYOND_64K - case 2: return this+u.version2.ligCaretList; -#endif - default: return Null(LigCaretList); - } + return ligCaretList != 0; } bool has_mark_attachment_types () const { - switch (u.version.major) { - case 1: return u.version1.markAttachClassDef != 0; #ifndef HB_NO_BEYOND_64K - case 2: return u.version2.markAttachClassDef != 0; + if (version.to_int () >= 0x00010004u && markAttachClassDef2) return true; #endif - default: return false; - } + return markAttachClassDef != 0; } const ClassDef &get_mark_attach_class_def () const { - switch (u.version.major) { - case 1: return this+u.version1.markAttachClassDef; #ifndef HB_NO_BEYOND_64K - case 2: return this+u.version2.markAttachClassDef; + if (version.to_int () >= 0x00010004u && markAttachClassDef2) return this+markAttachClassDef2; #endif - default: return Null(ClassDef); - } + return this+markAttachClassDef; } bool has_mark_glyph_sets () const { - switch (u.version.major) { - case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0; + if (version.to_int () < 0x00010002u) return false; #ifndef HB_NO_BEYOND_64K - case 2: return u.version2.markGlyphSetsDef != 0; + if (version.to_int () >= 0x00010004u && markGlyphSetsDef2) return true; #endif - default: return false; - } + return markGlyphSetsDef != 0; } const MarkGlyphSets &get_mark_glyph_sets () const { - switch (u.version.major) { - case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets); + if (version.to_int () < 0x00010002u) return Null(MarkGlyphSets); #ifndef HB_NO_BEYOND_64K - case 2: return this+u.version2.markGlyphSetsDef; + if (version.to_int () >= 0x00010004u && markGlyphSetsDef2) return this+markGlyphSetsDef2; #endif - default: return Null(MarkGlyphSets); - } + return this+markGlyphSetsDef; } bool has_var_store () const { - switch (u.version.major) { - case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0; -#ifndef HB_NO_BEYOND_64K - case 2: return u.version2.varStore != 0; -#endif - default: return false; - } + return version.to_int () >= 0x00010003u && hb_barrier () && varStore != 0; } const ItemVariationStore &get_var_store () const { - switch (u.version.major) { - case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore); -#ifndef HB_NO_BEYOND_64K - case 2: return this+u.version2.varStore; -#endif - default: return Null(ItemVariationStore); - } + return version.to_int () >= 0x00010003u && hb_barrier () ? this+varStore : Null(ItemVariationStore); } - bool has_data () const { return u.version.to_int (); } + bool has_data () const { return version.to_int (); } unsigned int get_glyph_class (hb_codepoint_t glyph) const { return get_glyph_class_def ().get_class (glyph); } void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const @@ -934,9 +937,15 @@ struct GDEF unsigned int start_offset, unsigned int *caret_count /* IN/OUT */, hb_position_t *caret_array /* OUT */) const - { return get_lig_caret_list ().get_lig_carets (font, - direction, glyph_id, get_var_store(), - start_offset, caret_count, caret_array); } + { +#ifndef HB_NO_BEYOND_64K + if (version.to_int () >= 0x00010004u && ligCaretList2) + return (this+ligCaretList2).get_lig_carets (font, direction, glyph_id, get_var_store (), + start_offset, caret_count, caret_array); +#endif + return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, get_var_store (), + start_offset, caret_count, caret_array); + } bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return get_mark_glyph_sets ().covers (set_index, glyph_id); } @@ -977,7 +986,39 @@ struct GDEF } #ifndef HB_NO_GDEF_CACHE - table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets); + /* Flatten each mark set whose glyphs span fewer than PAGE_BITS + * gids into a single bit-page biased at its first glyph, for + * O(1) exact answers. Wider sets, or on allocation failure, + * fall back to the table. */ + { + hb_vector_t sets; + table->get_mark_glyph_sets ().collect_coverage (sets); + if (!sets.in_error () && + mark_glyph_set_bitmaps.resize (sets.length)) + for (unsigned i = 0; i < sets.length; i++) + { + auto &bitmap = mark_glyph_set_bitmaps.arrayZ[i]; + bitmap.bias = HB_SET_VALUE_INVALID; + const auto &set = sets.arrayZ[i]; + if (unlikely (set.in_error ())) continue; + hb_codepoint_t min_gid = HB_SET_VALUE_INVALID; + hb_codepoint_t max_gid = HB_SET_VALUE_INVALID; + hb_set_next (&set, &min_gid); + hb_set_previous (&set, &max_gid); + if (max_gid == HB_SET_VALUE_INVALID) + continue; + if (max_gid - min_gid >= hb_bit_page_t::PAGE_BITS) + { + /* Too wide for one page; a digest pre-filter instead. */ + for (hb_codepoint_t gid : set) + bitmap.u.digest.add (gid); + continue; + } + bitmap.bias = min_gid; + for (hb_codepoint_t gid : set) + bitmap.u.page.add (gid - min_gid); + } + } #endif } ~accelerator_t () { table.destroy (); } @@ -1005,20 +1046,37 @@ struct GDEF HB_ALWAYS_INLINE bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const { - return #ifndef HB_NO_GDEF_CACHE - // We can access arrayZ directly because of sanitize_lookup_props() guarantee. - mark_glyph_sets.arrayZ[set_index].may_have (glyph_id) && + // We can access arrayZ directly because of sanitize_lookup_props() guarantee. + const auto &bitmap = mark_glyph_set_bitmaps.arrayZ[set_index]; + if (likely (bitmap.bias != HB_SET_VALUE_INVALID)) + { + hb_codepoint_t biased = glyph_id - bitmap.bias; + return biased < hb_bit_page_t::PAGE_BITS && + bitmap.u.page.get (biased); + } + return mark_set_covers_slow (set_index, glyph_id); +#else + return table->mark_set_covers (set_index, glyph_id); #endif - table->mark_set_covers (set_index, glyph_id) - ; } +#ifndef HB_NO_GDEF_CACHE + HB_NEVER_INLINE + bool mark_set_covers_slow (unsigned int set_index, hb_codepoint_t glyph_id) const + { + const auto &bitmap = mark_glyph_set_bitmaps.arrayZ[set_index]; + if (!bitmap.u.digest.may_have (glyph_id)) + return false; + return table->mark_set_covers (set_index, glyph_id); + } +#endif + unsigned sanitize_lookup_props (unsigned lookup_props) const { #ifndef HB_NO_GDEF_CACHE if (lookup_props & LookupFlag::UseMarkFilteringSet && - (lookup_props >> 16) >= mark_glyph_sets.length) + (lookup_props >> 16) >= mark_glyph_set_bitmaps.length) { // Invalid mark filtering set index; unset the flag. lookup_props &= ~LookupFlag::UseMarkFilteringSet; @@ -1029,25 +1087,128 @@ struct GDEF hb_blob_ptr_t table; #ifndef HB_NO_GDEF_CACHE - hb_vector_t mark_glyph_sets; + struct mark_glyph_set_bitmap_t + { + /* Gid of the first bit (not page-aligned) for an exact one-page + * set, or HB_SET_VALUE_INVALID; then digest is a pre-filter for + * the table. The all-zeros state is valid for both members. */ + hb_codepoint_t bias = HB_SET_VALUE_INVALID; + union u_t { + u_t () : page () {} + hb_bit_page_t page; + hb_set_digest_t digest; + } u; + }; + + hb_vector_t mark_glyph_set_bitmaps; mutable hb_cache_t<21, 3> glyph_props_cache; static_assert (sizeof (glyph_props_cache) == 512, ""); #endif }; void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { get_lig_caret_list ().collect_variation_indices (c); } + { +#ifndef HB_NO_BEYOND_64K + if (version.to_int () >= 0x00010004u && ligCaretList2) + { + (this+ligCaretList2).collect_variation_indices (c); + return; + } +#endif + (this+ligCaretList).collect_variation_indices (c); + } protected: - union { - FixedVersion<> version; /* Version identifier */ - GDEFVersion1_2 version1; + template + static void remap_varidx_after_instantiation (const hb_map_t& varidx_map, + hb_hashmap_t>& layout_variation_idx_delta_map /* IN/OUT */) + { + /* varidx_map is empty which means varstore is empty after instantiation, + * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX. + * varidx_map doesn't have original varidx, indicating delta row is all + * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ + for (auto _ : layout_variation_idx_delta_map.iter_ref ()) + { + /* old_varidx->(varidx, delta) mapping generated for subsetting, then this + * varidx is used as key of varidx_map during instantiation */ + uint32_t varidx = _.second.first; + uint32_t *new_varidx; + if (varidx_map.has (varidx, &new_varidx)) + _.second.first = *new_varidx; + else + _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + } + } + + template + static bool serialize_subset_offset (hb_subset_context_t *c, + OffsetOut& out, + const OffsetIn& in, + const Base *base, + Ts&&... ds) + { + out = 0; + if (in.is_null ()) return false; + + auto *s = c->serializer; + s->push (); + bool ret = c->dispatch (base+in, std::forward (ds)...); + if (ret) s->add_link (out, s->pop_pack ()); + else s->pop_discard (); + return ret; + } + + FixedVersion<>version; /* Version of the GDEF table--currently + * 0x00010004u */ + Offset16To + glyphClassDef; /* Offset to class definition table + * for glyph type--from beginning of + * GDEF header (may be Null) */ + Offset16To + attachList; /* Offset to list of glyphs with + * attachment points--from beginning + * of GDEF header (may be Null) */ + Offset16To> + ligCaretList; /* Offset to list of positioning points + * for ligature carets--from beginning + * of GDEF header (may be Null) */ + Offset16To + markAttachClassDef; /* Offset to class definition table for + * mark attachment type--from beginning + * of GDEF header (may be Null) */ + Offset16To + markGlyphSetsDef; /* Offset to the table of mark set + * definitions--from beginning of GDEF + * header (may be NULL). Introduced + * in version 0x00010002. */ + Offset32To + varStore; /* Offset to the table of Item Variation + * Store--from beginning of GDEF + * header (may be NULL). Introduced + * in version 0x00010003. */ #ifndef HB_NO_BEYOND_64K - GDEFVersion1_2 version2; + Offset32To + glyphClassDef2; /* 32-bit offset to class definition + * table for glyph type. Introduced + * in version 0x00010004. */ + Offset32To + attachList2; /* 32-bit offset to list of glyphs + * with attachment points. Introduced + * in version 0x00010004. */ + Offset32To> + ligCaretList2; /* 32-bit offset to LigCaretList2. + * Introduced in version 0x00010004. */ + Offset32To + markAttachClassDef2; /* 32-bit offset to class definition + * table for mark attachment type. + * Introduced in version 0x00010004. */ + Offset32To + markGlyphSetsDef2; /* 32-bit offset to the table of mark + * set definitions. Introduced in + * version 0x00010004. */ #endif - } u; public: - DEFINE_SIZE_MIN (4); + DEFINE_SIZE_MIN (12); }; struct GDEF_accelerator_t : GDEF::accelerator_t { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh index 1938803fa7c..48c509c25d2 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh @@ -27,9 +27,9 @@ struct Anchor if (!u.format.v.sanitize (c)) return_trace (false); hb_barrier (); switch (u.format.v) { - case 1: return_trace (u.format1.sanitize (c)); - case 2: return_trace (u.format2.sanitize (c)); - case 3: return_trace (u.format3.sanitize (c)); + case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); + case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); + case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); default:return_trace (true); } } @@ -39,9 +39,9 @@ struct Anchor { *x = *y = 0; switch (u.format.v) { - 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; + case 1: hb_barrier (); u.format1.get_anchor (c, glyph_id, x, y); return; + case 2: hb_barrier (); u.format2.get_anchor (c, glyph_id, x, y); return; + case 3: hb_barrier (); u.format3.get_anchor (c, glyph_id, x, y); return; default: return; } } @@ -50,8 +50,9 @@ struct Anchor { TRACE_SUBSET (this); switch (u.format.v) { - case 1: return_trace (bool (reinterpret_cast (u.format1.copy (c->serializer)))); + case 1: hb_barrier (); return_trace (bool (reinterpret_cast (u.format1.copy (c->serializer)))); case 2: + hb_barrier (); if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) { // AnchorFormat 2 just containins extra hinting information, so @@ -59,7 +60,7 @@ struct Anchor return_trace (bool (reinterpret_cast (u.format1.copy (c->serializer)))); } return_trace (bool (reinterpret_cast (u.format2.copy (c->serializer)))); - case 3: return_trace (u.format3.subset (c)); + case 3: hb_barrier (); return_trace (u.format3.subset (c)); default:return_trace (false); } } @@ -70,6 +71,7 @@ struct Anchor case 1: case 2: return; case 3: + hb_barrier (); u.format3.collect_variation_indices (c); return; default: return; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh index c49705bea0e..1bf4b92b037 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh @@ -40,12 +40,12 @@ struct AnchorFormat3 if ((font->x_ppem || font->has_nonzero_coords) && xDeviceTable.sanitize (&c->sanitizer, this)) { hb_barrier (); - *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); + *x += (this+xDeviceTable).get_x_delta_f (font, c->var_store, c->var_store_cache); } if ((font->y_ppem || font->has_nonzero_coords) && yDeviceTable.sanitize (&c->sanitizer, this)) { hb_barrier (); - *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); + *y += (this+yDeviceTable).get_y_delta_f (font, c->var_store, c->var_store_cache); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh index 128ced6c176..6ef66701c25 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh @@ -5,14 +5,87 @@ namespace OT { namespace Layout { namespace GPOS_impl { +HB_INTERNAL inline +void collect_ligature_anchor_indexes (unsigned rows, + unsigned class_count, + const hb_map_t &klass_mapping, + hb_sorted_vector_t &indexes) +{ + for (unsigned row = 0; row < rows; row++) + for (unsigned col = 0; col < class_count; col++) + if (klass_mapping.has (col)) + indexes.push (row * class_count + col); +} + +HB_INTERNAL inline +void collect_anchor_variation_indices (hb_collect_variation_indices_context_t *c, + const void *base, + glyph_data_t offsets, + hb_array_t indexes) +{ + for (unsigned i : indexes) + { + unsigned offset = offsets[i]; + if (offset) + StructAtOffset (base, offset).collect_variation_indices (c); + } +} + +HB_INTERNAL inline +void collect_anchor_indexes (const Coverage &coverage, + unsigned rows, + unsigned class_count, + const hb_set_t &glyphset, + const hb_map_t &klass_mapping, + hb_sorted_vector_t &indexes) +{ + for (const auto _ : hb_zip (coverage, hb_range (rows))) + if (glyphset.has (_.first)) + for (unsigned col = 0; col < class_count; col++) + if (klass_mapping.has (col)) + indexes.push (_.second * class_count + col); +} + +HB_INTERNAL inline +void collect_subset_anchor_indexes (const Coverage &coverage, + unsigned rows, + unsigned class_count, + glyph_data_t offsets, + const hb_set_t &glyphset, + const hb_map_t &glyph_map, + const hb_map_t &klass_mapping, + hb_sorted_vector_t &new_coverage, + hb_sorted_vector_t &indexes) +{ + for (const auto _ : hb_zip (coverage, hb_range (rows))) + { + if (!glyphset.has (_.first)) continue; + unsigned row = _.second; + bool non_empty = false; + for (unsigned col = 0; col < class_count; col++) + if (klass_mapping.has (col) && offsets[row * class_count + col]) + { + non_empty = true; + break; + } + if (!non_empty) continue; + + new_coverage.push (glyph_map.get (_.first)); + for (unsigned col = 0; col < class_count; col++) + if (klass_mapping.has (col)) + indexes.push (row * class_count + col); + } +} + +template struct AnchorMatrix { - HBUINT16 rows; /* Number of rows */ - UnsizedArrayOf> + RowCount rows; /* Number of rows */ + UnsizedArrayOf> matrixZ; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ public: - DEFINE_SIZE_ARRAY (2, matrixZ); + DEFINE_SIZE_ARRAY (sizeof (RowCount), matrixZ); bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const { @@ -45,13 +118,10 @@ struct AnchorMatrix return this+offset; } - template void collect_variation_indices (hb_collect_variation_indices_context_t *c, - Iterator index_iter) const + hb_array_t indexes) const { - for (unsigned i : index_iter) - (this+matrixZ[i]).collect_variation_indices (c); + collect_anchor_variation_indices (c, this, matrixZ.arrayZ, indexes); } template +struct ValueBase; +struct ValueFormat; + +template static void SinglePos_serialize (hb_serialize_context_t *c, - const SrcLookup *src, + const ValueBase *src, + ValueFormat src_format, Iterator it, const hb_hashmap_t> *layout_variation_idx_delta_map, unsigned new_format); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh index 38a29dd9ed5..06209558105 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh @@ -12,7 +12,10 @@ struct CursivePos protected: union { struct { HBUINT16 v; } format; /* Format identifier */ - CursivePosFormat1 format1; + CursivePosFormat1_2 format1; +#ifndef HB_NO_BEYOND_64K + CursivePosFormat1_2 format2; +#endif } u; public: @@ -22,7 +25,10 @@ struct CursivePos if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh index c96f66da9b3..184dc3a70c5 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh @@ -2,30 +2,35 @@ #define OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH #include "Anchor.hh" +#include "../../../hb-limits.hh" namespace OT { namespace Layout { namespace GPOS_impl { +template +struct CursivePosFormat1_2; + +template struct EntryExitRecord { - friend struct CursivePosFormat1; + template friend struct CursivePosFormat1_2; - bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1 *base) const + bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1_2 *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 struct CursivePosFormat1 *src_base) const + const struct CursivePosFormat1_2 *src_base) const { (src_base+entryAnchor).collect_variation_indices (c); (src_base+exitAnchor).collect_variation_indices (c); } bool subset (hb_subset_context_t *c, - const struct CursivePosFormat1 *src_base) const + const struct CursivePosFormat1_2 *src_base) const { TRACE_SERIALIZE (this); auto *out = c->serializer->embed (this); @@ -38,16 +43,16 @@ struct EntryExitRecord } protected: - Offset16To + typename Types::template OffsetTo> entryAnchor; /* Offset to EntryAnchor table--from * beginning of CursivePos * subtable--may be NULL */ - Offset16To + typename Types::template OffsetTo> exitAnchor; /* Offset to ExitAnchor table--from * beginning of CursivePos * subtable--may be NULL */ public: - DEFINE_SIZE_STATIC (4); + DEFINE_SIZE_STATIC (2 * Types::size); }; static inline void @@ -55,8 +60,12 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int len, unsigned int i, hb_direction_t direction, - unsigned int new_parent) + unsigned int new_parent, + unsigned nesting_level = 0) { + if (nesting_level > HB_MAX_NESTING_LEVEL) + return; + int chain = pos[i].attach_chain(), type = pos[i].attach_type(); if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE))) return; @@ -79,30 +88,155 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, if (unlikely (reversed_chain != -chain)) return; - reverse_cursive_minor_offset (pos, len, j, direction, new_parent); + reverse_cursive_minor_offset (pos, len, j, direction, new_parent, nesting_level + 1); if (HB_DIRECTION_IS_HORIZONTAL (direction)) - pos[j].y_offset = -pos[i].y_offset; + pos[j].y_offset = hb_saturate_neg (pos[i].y_offset); else - pos[j].x_offset = -pos[i].x_offset; + pos[j].x_offset = hb_saturate_neg (pos[i].x_offset); pos[j].attach_chain() = reversed_chain; pos[j].attach_type() = type; } -struct CursivePosFormat1 +static inline bool +apply_cursive_attachment (hb_ot_apply_context_t *c, + const Anchor &exit_anchor, + const Anchor &entry_anchor, + unsigned i) { + hb_buffer_t *buffer = c->buffer; + unsigned int j = buffer->idx; + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "cursive attaching glyph at %u to glyph at %u", + i, j); + } + + buffer->unsafe_to_break (i, j + 1); + float entry_x, entry_y, exit_x, exit_y; + exit_anchor.get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); + entry_anchor.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 = hb_saturate_add ((hb_position_t) roundf (exit_x), pos[i].x_offset); + + d = hb_saturate_add ((hb_position_t) roundf (entry_x), pos[j].x_offset); + pos[j].x_advance = hb_saturate_sub (pos[j].x_advance, d); + pos[j].x_offset = hb_saturate_sub (pos[j].x_offset, d); + break; + case HB_DIRECTION_RTL: + d = hb_saturate_add ((hb_position_t) roundf (exit_x), pos[i].x_offset); + pos[i].x_advance = hb_saturate_sub (pos[i].x_advance, d); + pos[i].x_offset = hb_saturate_sub (pos[i].x_offset, d); + + pos[j].x_advance = hb_saturate_add ((hb_position_t) roundf (entry_x), pos[j].x_offset); + break; + case HB_DIRECTION_TTB: + pos[i].y_advance = hb_saturate_add ((hb_position_t) roundf (exit_y), pos[i].y_offset); + + d = hb_saturate_add ((hb_position_t) roundf (entry_y), pos[j].y_offset); + pos[j].y_advance = hb_saturate_sub (pos[j].y_advance, d); + pos[j].y_offset = hb_saturate_sub (pos[j].y_offset, d); + break; + case HB_DIRECTION_BTT: + d = hb_saturate_add ((hb_position_t) roundf (exit_y), pos[i].y_offset); + pos[i].y_advance = hb_saturate_sub (pos[i].y_advance, d); + pos[i].y_offset = hb_saturate_sub (pos[i].y_offset, d); + + pos[j].y_advance = (hb_position_t) 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 = (hb_position_t) roundf (entry_x - exit_x); + hb_position_t y_offset = (hb_position_t) roundf (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, buffer->len, child, c->direction, parent); + + pos[child].attach_chain() = (int) parent - (int) child; + if (pos[child].attach_chain() != (int) parent - (int) child) + { + pos[child].attach_chain() = 0; + goto overflow; + } + pos[child].attach_type() = ATTACH_TYPE_CURSIVE; + 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; + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) + pos[parent].y_offset = 0; + else + pos[parent].x_offset = 0; + } + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "cursive attached glyph at %u to glyph at %u", + i, j); + } + +overflow: + buffer->idx++; + return true; +} + +template +struct CursivePosFormat1_2 +{ + protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To - coverage; /* Offset to Coverage table--from - * beginning of subtable */ - Array16Of + typename Types::template LOffsetTo + coverage; /* Offset to Coverage table--from beginning of subtable */ + typename Types::template ArrayOf> entryExitRecord; /* Array of EntryExit records--in * Coverage Index order */ public: - DEFINE_SIZE_ARRAY (6, entryExitRecord); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + Types::HBUINT::static_size, entryExitRecord); bool sanitize (hb_sanitize_context_t *c) const { @@ -126,13 +260,16 @@ struct CursivePosFormat1 + 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); }) + | 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; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { (this+coverage).collect_coverage (digest); } + const Coverage &get_coverage () const { return this+coverage; } bool apply (hb_ot_apply_context_t *c) const @@ -140,7 +277,7 @@ struct CursivePosFormat1 TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; - const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; + const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; if (!this_record.entryAnchor || unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false); hb_barrier (); @@ -154,7 +291,7 @@ struct CursivePosFormat1 return_trace (false); } - const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; + const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; if (!prev_record.exitAnchor || unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this))) { @@ -163,136 +300,24 @@ struct CursivePosFormat1 } hb_barrier (); - unsigned int i = skippy_iter.idx; - unsigned int j = buffer->idx; - - if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) - { - c->buffer->message (c->font, - "cursive attaching glyph at %u to glyph at %u", - i, j); - } - - buffer->unsafe_to_break (i, j + 1); - 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 = roundf (entry_x - exit_x); - hb_position_t y_offset = roundf (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, buffer->len, child, c->direction, parent); - - pos[child].attach_chain() = (int) parent - (int) child; - if (pos[child].attach_chain() != (int) parent - (int) child) - { - pos[child].attach_chain() = 0; - goto overflow; - } - pos[child].attach_type() = ATTACH_TYPE_CURSIVE; - 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; - if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) - pos[parent].y_offset = 0; - else - pos[parent].x_offset = 0; - } - - if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) - { - c->buffer->message (c->font, - "cursive attached glyph at %u to glyph at %u", - i, j); - } - - overflow: - buffer->idx++; - return_trace (true); + return_trace (apply_cursive_attachment (c, + this+prev_record.exitAnchor, + this+this_record.entryAnchor, + skippy_iter.idx)); } template void serialize (hb_subset_context_t *c, Iterator it, - const struct CursivePosFormat1 *src_base) + const struct CursivePosFormat1_2 *src_base) { if (unlikely (!c->serializer->extend_min ((*this)))) return; - this->format = 1; + this->format = src_base->format; this->entryExitRecord.len = it.len (); - for (const EntryExitRecord& entry_record : + it - | hb_map (hb_second)) + for (const EntryExitRecord& entry_record : + it + | hb_map (hb_second)) entry_record.subset (c, src_base); auto glyphs = @@ -314,7 +339,8 @@ struct CursivePosFormat1 auto it = + hb_zip (this+coverage, entryExitRecord) | hb_filter (glyphset, hb_first) - | hb_map_retains_sorting ([&] (hb_pair_t p) -> hb_pair_t + | hb_map_retains_sorting ([&] (hb_pair_t&> p) + -> hb_pair_t&> { return hb_pair (glyph_map[p.first], p.second);}) ; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh index b80f606f7b5..8748250b946 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh @@ -101,14 +101,16 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, if (type & GPOS_impl::ATTACH_TYPE_CURSIVE) { if (HB_DIRECTION_IS_HORIZONTAL (direction)) - pos[i].y_offset += pos[j].y_offset; + pos[i].y_offset = hb_saturate_add (pos[i].y_offset, pos[j].y_offset); else - pos[i].x_offset += pos[j].x_offset; + pos[i].x_offset = hb_saturate_add (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; + if (HB_DIRECTION_IS_HORIZONTAL (direction)) + pos[i].x_offset = hb_saturate_add (pos[i].x_offset, pos[j].x_offset); + else + pos[i].y_offset = hb_saturate_add (pos[i].y_offset, pos[j].y_offset); // i is the position of the mark; j is the base. if (j < i) @@ -117,13 +119,13 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, * And currently the only way in OpenType. */ 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; + pos[i].x_offset = hb_saturate_sub (pos[i].x_offset, pos[k].x_advance); + pos[i].y_offset = hb_saturate_sub (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; + pos[i].x_offset = hb_saturate_add (pos[i].x_offset, pos[k].x_advance); + pos[i].y_offset = hb_saturate_add (pos[i].y_offset, pos[k].y_advance); } } else // j > i @@ -132,13 +134,13 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, * to a base after it in the logical order. */ if (HB_DIRECTION_IS_FORWARD (direction)) for (unsigned int k = i; k < j; k++) { - pos[i].x_offset += pos[k].x_advance; - pos[i].y_offset += pos[k].y_advance; + pos[i].x_offset = hb_saturate_add (pos[i].x_offset, pos[k].x_advance); + pos[i].y_offset = hb_saturate_add (pos[i].y_offset, pos[k].y_advance); } else for (unsigned int k = i + 1; k < j + 1; k++) { - pos[i].x_offset -= pos[k].x_advance; - pos[i].y_offset -= pos[k].y_advance; + pos[i].x_offset = hb_saturate_sub (pos[i].x_offset, pos[k].x_advance); + pos[i].y_offset = hb_saturate_sub (pos[i].y_offset, pos[k].y_advance); } } } @@ -191,7 +193,8 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) * as it gets weird otherwise. */ for (unsigned i = 0; i < len; i++) if (unlikely (pos[i].y_offset)) - pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset); + pos[i].x_offset = hb_clamp_to ((double) pos[i].x_offset + + (double) roundf (font->slant_xy * pos[i].y_offset)); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh index 113b693dc3e..a04267aee8a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh @@ -5,15 +5,69 @@ namespace OT { namespace Layout { namespace GPOS_impl { +HB_INTERNAL inline +void collect_ligature_variation_indices (hb_collect_variation_indices_context_t *c, + const Coverage &coverage, + const void *base, + glyph_data_t offsets, + unsigned count, + unsigned class_count, + const hb_map_t &klass_mapping) +{ + for (const auto _ : hb_zip (coverage, hb_range (count))) + { + if (!c->glyph_set->has (_.first)) continue; + hb_barrier (); + unsigned offset = offsets[_.second]; + if (!offset) continue; + + const void *matrix = &StructAtOffset (base, offset); + /* LigatureAttach always has a 16-bit component count; its anchor + * offsets have the same width as the LigatureArray offsets. */ + unsigned rows = *static_cast (matrix); + glyph_data_t anchors = offsets; + anchors.data = (const char *) matrix + HBUINT16::static_size; + + hb_sorted_vector_t indexes; + collect_ligature_anchor_indexes (rows, class_count, klass_mapping, indexes); + collect_anchor_variation_indices (c, matrix, anchors, indexes.iter ()); + } +} -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 +template +struct LigatureArray : + Types::template ArrayOf>> { + typedef AnchorMatrix LigatureAttach; + typedef typename Types::template OffsetTo LigatureAttachOffset; + typedef typename Types::template ArrayOf Super; + + const LigatureAttach& operator [] (int i_) const + { + unsigned int i = (unsigned int) i_; + if (unlikely (i >= this->len)) return Null (LigatureAttach); + hb_barrier (); + return this+this->arrayZ[i]; + } + + template + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const + { + TRACE_SANITIZE (this); + return_trace (Super::sanitize (c, this, std::forward (ds)...)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const Coverage &coverage, + unsigned class_count, + const hb_map_t &klass_mapping) const + { + collect_ligature_variation_indices (c, coverage, this, this->arrayZ, + this->len, class_count, klass_mapping); + } + template bool subset (hb_subset_context_t *c, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh index bddc5e7fe9e..512ce3954dc 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh @@ -8,22 +8,128 @@ namespace OT { namespace Layout { namespace GPOS_impl { -struct MarkArray : Array16Of /* Array of MarkRecords--in Coverage order */ +static inline hb_position_t +resolve_cross_offset (const hb_glyph_position_t *pos, + unsigned int len, + unsigned int glyph_pos, + hb_direction_t direction) { + bool horizontal = HB_DIRECTION_IS_HORIZONTAL (direction); + hb_position_t offset = horizontal ? pos[glyph_pos].y_offset : pos[glyph_pos].x_offset; + while (pos[glyph_pos].attach_type() & ATTACH_TYPE_CURSIVE) + { + int chain = pos[glyph_pos].attach_chain(); + if (!chain) + break; + unsigned int parent = (int) glyph_pos + chain; + if (unlikely (parent >= len)) + break; + glyph_pos = parent; + offset = hb_saturate_add (offset, + horizontal ? pos[glyph_pos].y_offset : pos[glyph_pos].x_offset); + } + return offset; +} + +static inline bool +apply_mark_attachment (hb_ot_apply_context_t *c, + const Anchor &mark_anchor, + const Anchor &glyph_anchor, + unsigned glyph_pos) +{ + hb_buffer_t *buffer = c->buffer; + 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); + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "attaching mark glyph at %u to glyph at %u", + c->buffer->idx, glyph_pos); + } + + hb_position_t base_offset = resolve_cross_offset (buffer->pos, buffer->len, glyph_pos, + buffer->props.direction); + + hb_glyph_position_t &mark = buffer->cur_pos(); + mark.attach_chain() = (int) glyph_pos - (int) buffer->idx; + if (mark.attach_chain() != (int) glyph_pos - (int) buffer->idx) + { + mark.attach_chain() = 0; + goto overflow; + } + mark.attach_type() = ATTACH_TYPE_MARK; + mark.x_offset = roundf (base_x - mark_x); + mark.y_offset = roundf (base_y - mark_y); + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + mark.y_offset = hb_saturate_add (mark.y_offset, base_offset); + else + mark.x_offset = hb_saturate_add (mark.x_offset, base_offset); + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "attached mark glyph at %u to glyph at %u", + c->buffer->idx, glyph_pos); + } + +overflow: + buffer->idx++; + return true; +} + +HB_INTERNAL inline +void collect_mark_variation_indices (hb_collect_variation_indices_context_t *c, + const Coverage &coverage, + const void *base, + glyph_data_t anchors, + unsigned count, + unsigned record_size) +{ + for (const auto _ : hb_zip (coverage, hb_range (count))) + { + if (!c->glyph_set->has (_.first)) continue; + glyph_data_t anchor = anchors; + anchor.data = (const char *) anchors.data + _.second * record_size; + unsigned offset = anchor[0]; + if (offset) + StructAtOffset (base, offset).collect_variation_indices (c); + } +} + +template +struct MarkArray : Types::template ArrayOf> + /* Array of MarkRecords--in Coverage order */ +{ + typedef typename Types::template ArrayOf> Super; + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (Array16Of::sanitize (c, this)); + return_trace (Super::sanitize (c, this)); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const Coverage &coverage) const + { + if (!this->len) return; + collect_mark_variation_indices (c, coverage, this, + &this->arrayZ[0].markAnchor, + this->len, MarkRecord::static_size); + } + + template bool apply (hb_ot_apply_context_t *c, unsigned int mark_index, unsigned int glyph_index, - const AnchorMatrix &anchors, unsigned int class_count, + const AnchorMatrixType &anchors, unsigned int class_count, unsigned int glyph_pos) const { TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - const MarkRecord &record = Array16Of::operator[](mark_index); + const MarkRecord &record = Super::operator[](mark_index); unsigned int mark_class = record.klass; const Anchor& mark_anchor = this + record.markAnchor; @@ -33,41 +139,7 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove * 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); - - if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) - { - c->buffer->message (c->font, - "attaching mark glyph at %u to glyph at %u", - c->buffer->idx, glyph_pos); - } - - hb_glyph_position_t &o = buffer->cur_pos(); - o.attach_chain() = (int) glyph_pos - (int) buffer->idx; - if (o.attach_chain() != (int) glyph_pos - (int) buffer->idx) - { - o.attach_chain() = 0; - goto overflow; - } - o.attach_type() = ATTACH_TYPE_MARK; - o.x_offset = roundf (base_x - mark_x); - o.y_offset = roundf (base_y - mark_y); - buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; - - if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) - { - c->buffer->message (c->font, - "attached mark glyph at %u to glyph at %u", - c->buffer->idx, glyph_pos); - } - - overflow: - buffer->idx++; - return_trace (true); + return_trace (apply_mark_attachment (c, mark_anchor, glyph_anchor, glyph_pos)); } template /* Array of MarkRecords--in Cove }; HB_INTERNAL inline -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 */) +void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, + const void *mark_records, + unsigned count, + unsigned record_size, + const hb_set_t &glyphset, + hb_map_t *klass_mapping) { 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) - ; + for (const auto _ : hb_zip (mark_coverage, hb_range (count))) + if (glyphset.has (_.first)) + { + const auto *klass = reinterpret_cast + ((const char *) mark_records + _.second * record_size); + orig_classes.add (*klass); + } unsigned idx = 0; for (auto klass : orig_classes.iter ()) @@ -127,6 +201,19 @@ void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, } } +template +HB_INTERNAL inline +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 */) +{ + Markclass_closure_and_remap_indexes (mark_coverage, + mark_array.arrayZ, mark_array.len, + MarkRecord::static_size, + glyphset, klass_mapping); +} + } } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh index 65f343bda8b..f86a5291295 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh @@ -25,9 +25,9 @@ struct MarkBasePos if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh index ad071f327ea..c23f388526f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh @@ -7,32 +7,27 @@ namespace OT { namespace Layout { namespace GPOS_impl { -typedef AnchorMatrix BaseArray; /* base-major-- - * in order of BaseCoverage Index--, - * mark-minor-- - * ordered by class--zero-based. */ - template struct MarkBasePosFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo markCoverage; /* Offset to MarkCoverage table--from * beginning of MarkBasePos subtable */ - typename Types::template OffsetTo + typename Types::template LOffsetTo baseCoverage; /* Offset to BaseCoverage table--from * beginning of MarkBasePos subtable */ HBUINT16 classCount; /* Number of classes defined for marks */ - typename Types::template OffsetTo + typename Types::template LOffsetTo> markArray; /* Offset to MarkArray table--from * beginning of MarkBasePos subtable */ - typename Types::template OffsetTo + typename Types::template LOffsetTo> baseArray; /* Offset to BaseArray table--from * beginning of MarkBasePos subtable */ public: - DEFINE_SIZE_STATIC (4 + 4 * Types::size); + DEFINE_SIZE_STATIC (4 + 4 * Types::LOffset::static_size); bool sanitize (hb_sanitize_context_t *c) const { @@ -54,31 +49,15 @@ struct MarkBasePosFormat1_2 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)); }) - ; + (this+markArray).collect_variation_indices (c, this+markCoverage); 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 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) - ; - } + collect_anchor_indexes (this+baseCoverage, (this+baseArray).rows, + classCount, *c->glyph_set, klass_mapping, + base_indexes); (this+baseArray).collect_variation_indices (c, base_indexes.iter ()); } @@ -88,6 +67,9 @@ struct MarkBasePosFormat1_2 if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { (this+baseCoverage).collect_coverage (digest); } + const Coverage &get_coverage () const { return this+markCoverage; } static inline bool accept (hb_buffer_t *buffer, unsigned idx) @@ -202,35 +184,13 @@ struct MarkBasePosFormat1_2 &klass_mapping))) return_trace (false); - unsigned basecount = (this+baseArray).rows; - auto base_iter = - + hb_zip (this+baseCoverage, hb_range (basecount)) - | hb_filter (glyphset, hb_first) - ; - new_coverage.reset (); hb_sorted_vector_t base_indexes; - auto &base_array = (this+baseArray); - for (const auto _ : + base_iter) - { - unsigned row = _.second; - bool non_empty = + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return !base_array.offset_is_null (row, col, (unsigned) classCount); }) - | hb_any - ; - - if (!non_empty) continue; - - hb_codepoint_t new_g = glyph_map.get ( _.first); - new_coverage.push (new_g); - - + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) - | hb_sink (base_indexes) - ; - } + const auto &base_array = this+baseArray; + collect_subset_anchor_indexes (this+baseCoverage, base_array.rows, + classCount, base_array.matrixZ.arrayZ, + glyphset, glyph_map, klass_mapping, + new_coverage, base_indexes); if (!new_coverage) return_trace (false); if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh index ee237eb479f..c860dc0a79c 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh @@ -25,9 +25,9 @@ struct MarkLigPos if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh index 509a26c2485..a38b4929f35 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh @@ -13,22 +13,22 @@ struct MarkLigPosFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo markCoverage; /* Offset to Mark Coverage table--from * beginning of MarkLigPos subtable */ - typename Types::template OffsetTo + typename Types::template LOffsetTo ligatureCoverage; /* Offset to Ligature Coverage * table--from beginning of MarkLigPos * subtable */ HBUINT16 classCount; /* Number of defined mark classes */ - typename Types::template OffsetTo + typename Types::template LOffsetTo> markArray; /* Offset to MarkArray table--from * beginning of MarkLigPos subtable */ - typename Types::template OffsetTo + typename Types::template LOffsetTo> ligatureArray; /* Offset to LigatureArray table--from * beginning of MarkLigPos subtable */ public: - DEFINE_SIZE_STATIC (4 + 4 * Types::size); + DEFINE_SIZE_STATIC (4 + 4 * Types::LOffset::static_size); bool sanitize (hb_sanitize_context_t *c) const { @@ -50,38 +50,13 @@ struct MarkLigPosFormat1_2 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)); }) - ; + (this+markArray).collect_variation_indices (c, this+markCoverage); 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 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 ()); - } + (this+ligatureArray).collect_variation_indices (c, this+ligatureCoverage, + classCount, klass_mapping); } void collect_glyphs (hb_collect_glyphs_context_t *c) const @@ -90,8 +65,22 @@ struct MarkLigPosFormat1_2 if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { (this+ligatureCoverage).collect_coverage (digest); } + const Coverage &get_coverage () const { return this+markCoverage; } + static inline bool accept (hb_buffer_t *buffer, unsigned idx) + { + /* We only want to attach to the first of a MultipleSubst sequence, + * which might have been ligated into a preceding ligature, and in that + * case the mark should attach to that ligature. + * https://github.com/harfbuzz/harfbuzz/issues/4969 + * Reject others... */ + return !_hb_glyph_info_multiplied (&buffer->info[idx]) || + 0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]); + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -114,6 +103,13 @@ struct MarkLigPosFormat1_2 { auto match = skippy_iter.match (buffer->info[j - 1]); if (match == skippy_iter.MATCH) + { + // https://github.com/harfbuzz/harfbuzz/issues/4124 + if (!accept (buffer, j - 1) && + NOT_COVERED == (this+ligatureCoverage).get_coverage (buffer->info[j - 1].codepoint)) + match = skippy_iter.SKIP; + } + if (match == skippy_iter.MATCH) { c->last_base = (signed) j - 1; break; @@ -138,8 +134,8 @@ struct MarkLigPosFormat1_2 return_trace (false); } - const LigatureArray& lig_array = this+ligatureArray; - const LigatureAttach& lig_attach = lig_array[lig_index]; + const LigatureArray& lig_array = this+ligatureArray; + const AnchorMatrix& lig_attach = lig_array[lig_index]; /* Find component to attach to */ unsigned int comp_count = lig_attach.rows; @@ -182,7 +178,7 @@ struct MarkLigPosFormat1_2 out->classCount = klass_mapping.get_population (); auto mark_iter = - + hb_zip (this+markCoverage, this+markArray) + + hb_zip (this+markCoverage, hb_range ((unsigned) (this+markArray).len)) | hb_filter (glyphset, hb_first) ; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh index c06f013cdce..08e9c930d06 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh @@ -25,9 +25,9 @@ struct MarkMarkPos if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh index c93dbbb3f06..158f74a7409 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -7,33 +7,28 @@ namespace OT { namespace Layout { namespace GPOS_impl { -typedef AnchorMatrix Mark2Array; /* mark2-major-- - * in order of Mark2Coverage Index--, - * mark1-minor-- - * ordered by class--zero-based. */ - template struct MarkMarkPosFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo mark1Coverage; /* Offset to Combining Mark1 Coverage * table--from beginning of MarkMarkPos * subtable */ - typename Types::template OffsetTo + typename Types::template LOffsetTo mark2Coverage; /* Offset to Combining Mark2 Coverage * table--from beginning of MarkMarkPos * subtable */ HBUINT16 classCount; /* Number of defined mark classes */ - typename Types::template OffsetTo + typename Types::template LOffsetTo> mark1Array; /* Offset to Mark1Array table--from * beginning of MarkMarkPos subtable */ - typename Types::template OffsetTo + typename Types::template LOffsetTo> mark2Array; /* Offset to Mark2Array table--from * beginning of MarkMarkPos subtable */ public: - DEFINE_SIZE_STATIC (4 + 4 * Types::size); + DEFINE_SIZE_STATIC (4 + 4 * Types::LOffset::static_size); bool sanitize (hb_sanitize_context_t *c) const { @@ -56,31 +51,15 @@ struct MarkMarkPosFormat1_2 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)); }) - ; + (this+mark1Array).collect_variation_indices (c, this+mark1Coverage); 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 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) - ; - } + collect_anchor_indexes (this+mark2Coverage, (this+mark2Array).rows, + classCount, *c->glyph_set, klass_mapping, + mark2_indexes); (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ()); } @@ -90,6 +69,9 @@ struct MarkMarkPosFormat1_2 if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { (this+mark2Coverage).collect_coverage (digest); } + const Coverage &get_coverage () const { return this+mark1Coverage; } bool apply (hb_ot_apply_context_t *c) const @@ -189,43 +171,20 @@ struct MarkMarkPosFormat1_2 &klass_mapping))) return_trace (false); - unsigned mark2count = (this+mark2Array).rows; - auto mark2_iter = - + hb_zip (this+mark2Coverage, hb_range (mark2count)) - | hb_filter (glyphset, hb_first) - ; - new_coverage.reset (); hb_sorted_vector_t mark2_indexes; - auto &mark2_array = (this+mark2Array); - for (const auto _ : + mark2_iter) - { - unsigned row = _.second; - - bool non_empty = + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return !mark2_array.offset_is_null (row, col, (unsigned) classCount); }) - | hb_any - ; - - if (!non_empty) continue; - - hb_codepoint_t new_g = glyph_map.get ( _.first); - new_coverage.push (new_g); - - + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) - | hb_sink (mark2_indexes) - ; - } + const auto &mark2_array = this+mark2Array; + collect_subset_anchor_indexes (this+mark2Coverage, mark2_array.rows, + classCount, mark2_array.matrixZ.arrayZ, + glyphset, glyph_map, klass_mapping, + new_coverage, mark2_indexes); if (!new_coverage) return_trace (false); if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) return_trace (false); return_trace (out->mark2Array.serialize_subset (c, mark2Array, this, - mark2_iter.len (), + new_coverage.length, mark2_indexes.iter ())); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh index 12300252675..0703bad44c7 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh @@ -5,27 +5,30 @@ namespace OT { namespace Layout { namespace GPOS_impl { +template struct MarkArray; + +template struct MarkRecord { - friend struct MarkArray; + friend struct MarkArray; public: HBUINT16 klass; /* Class defined for this mark */ - Offset16To + typename Types::template OffsetTo> markAnchor; /* Offset to Anchor table--from * beginning of MarkArray table */ public: - DEFINE_SIZE_STATIC (4); + DEFINE_SIZE_STATIC (2 + Types::size); unsigned get_class () const { return (unsigned) klass; } - bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const MarkArray *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); } bool subset (hb_subset_context_t *c, - const void *src_base, + const MarkArray *src_base, const hb_map_t *klass_mapping) const { TRACE_SUBSET (this); @@ -37,7 +40,7 @@ struct MarkRecord } void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const void *src_base) const + const MarkArray *src_base) const { (src_base+markAnchor).collect_variation_indices (c); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh index bf7fff7face..df0ca6ad08d 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh @@ -28,11 +28,11 @@ struct PairPos if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K - case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); - case 4: return_trace (c->dispatch (u.format4, std::forward (ds)...)); + case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); + case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh index 1c067bde86f..c2649d6927b 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh @@ -16,7 +16,7 @@ struct PairPosFormat1_3 protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat[2]; /* [0] Defines the types of data in @@ -25,11 +25,11 @@ struct PairPosFormat1_3 /* [1] Defines the types of data in * ValueRecord2--for the second glyph * in the pair--may be zero (0) */ - Array16Of> - pairSet; /* Array of PairSet tables - * ordered by Coverage Index */ + typename Types::template ArrayOf> + pairSet; /* Array of PairSet tables ordered by + * Coverage Index */ public: - DEFINE_SIZE_ARRAY (8 + Types::size, pairSet); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + 2 * ValueFormat::static_size + Types::HBUINT::static_size, pairSet); bool sanitize (hb_sanitize_context_t *c) const { @@ -56,7 +56,7 @@ struct PairPosFormat1_3 if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len)) { - for (hb_codepoint_t g : glyphs->iter()) + for (hb_codepoint_t g : glyphs->iter ()) { unsigned i = cov.get_coverage (g); if ((this+pairSet[i]).intersects (glyphs, valueFormat)) @@ -101,18 +101,35 @@ struct PairPosFormat1_3 (this+pairSet[i]).collect_glyphs (c, valueFormat); } + void collect_second_glyphs (hb_set_digest_t *digest) const + { + unsigned count = pairSet.len; + for (unsigned i = 0; i < count; i++) + (this+pairSet[i]).collect_second_glyphs (digest, valueFormat); + } + const Coverage &get_coverage () const { return this+coverage; } struct external_cache_t { hb_ot_layout_mapping_cache_t coverage; + hb_set_digest_t pair_sets[HB_VAR_ARRAY]; }; void *external_cache_create () const { - external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); + unsigned count = pairSet.len; + unsigned size = sizeof (external_cache_t) - + HB_VAR_ARRAY * sizeof (hb_set_digest_t) + + count * sizeof (hb_set_digest_t); + external_cache_t *cache = (external_cache_t *) hb_malloc (size); if (likely (cache)) { cache->coverage.clear (); + for (unsigned i = 0; i < count; i++) + { + cache->pair_sets[i].init (); + (this+pairSet[i]).collect_second_glyphs (&cache->pair_sets[i], valueFormat); + } } return cache; } @@ -140,6 +157,16 @@ struct PairPosFormat1_3 return_trace (false); } +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + if (cache && + index < pairSet.len && + !cache->pair_sets[index].may_have (buffer->info[skippy_iter.idx].codepoint)) + { + buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + return_trace (false); + } +#endif + return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); } @@ -214,8 +241,6 @@ struct PairPosFormat1_3 bool strip_hints, bool strip_empty, const hb_hashmap_t> *varidx_delta_map = nullptr) const { - unsigned record_size = PairSet::get_size (valueFormat); - unsigned format1 = 0; unsigned format2 = 0; for (const auto & _ : @@ -225,20 +250,13 @@ struct PairPosFormat1_3 ) { const PairSet& set = (this + _); - const PairValueRecord *record = &set.firstPairValueRecord; - - unsigned count = set.len; - for (unsigned i = 0; i < count; i++) - { - if (record->intersects (glyphset)) - { - format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map); - format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map); - } - record = &StructAtOffset (record, record_size); - } + auto formats = set.get_values_view (valueFormat).compute_effective_value_formats ( + glyphset, valueFormat, strip_hints, strip_empty, varidx_delta_map); + format1 |= formats.first; + format2 |= formats.second; - if (format1 == valueFormat[0] && format2 == valueFormat[1]) + if (!varidx_delta_map && + format1 == valueFormat[0] && format2 == valueFormat[1]) break; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh index ce731450f41..a99858d545f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh @@ -7,12 +7,137 @@ namespace OT { namespace Layout { namespace GPOS_impl { +HB_INTERNAL inline +void collect_pair_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueBase *base, + const Coverage &coverage, + const ClassDef &class_def1, + const ClassDef &class_def2, + const ValueFormat &valueFormat1, + const ValueFormat &valueFormat2, + unsigned class1_count, + unsigned class2_count, + const ValueRecord &values) +{ + if (!coverage.intersects (c->glyph_set) || + !class_def2.intersects (c->glyph_set)) return; + if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return; + + hb_set_t klass1_glyphs, klass2_glyphs; + if (!class_def1.collect_coverage (&klass1_glyphs)) return; + if (!class_def2.collect_coverage (&klass2_glyphs)) return; + + hb_set_t class1_set, class2_set; + for (const unsigned cp : + c->glyph_set->iter () | hb_filter (coverage)) + { + if (!klass1_glyphs.has (cp)) class1_set.add (0); + else + { + unsigned klass1 = class_def1.get (cp); + class1_set.add (klass1); + } + } + + class2_set.add (0); + for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs)) + { + unsigned klass2 = class_def2.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 values_array = values.as_array ((unsigned)class1_count * (unsigned) class2_count * (len1 + len2)); + for (const unsigned class1_idx : class1_set.iter ()) + { + for (const unsigned class2_idx : class2_set.iter ()) + { + unsigned start_offset = (class1_idx * (unsigned) class2_count + class2_idx) * (len1 + len2); + if (valueFormat1.has_device ()) + valueFormat1.collect_variation_indices (c, base, values_array.sub_array (start_offset, len1)); + + if (valueFormat2.has_device ()) + valueFormat2.collect_variation_indices (c, base, values_array.sub_array (start_offset+len1, len2)); + } + } +} + +/* Keep class-matrix traversal independent of the source table width. */ +struct pair_pos_class_values_t +{ + const ValueBase *base; + const ValueRecord &values; + const ValueFormat &valueFormat1; + const ValueFormat &valueFormat2; + unsigned class1_count; + unsigned class2_count; + + hb_pair_t compute_effective_value_formats (const hb_map_t &klass1_map, + const hb_map_t &klass2_map, + bool strip_hints, bool strip_empty, + const hb_hashmap_t> *varidx_delta_map = nullptr) const + { + unsigned len1 = valueFormat1.get_len (); + unsigned len2 = valueFormat2.get_len (); + unsigned record_size = len1 + len2; + + unsigned format1 = 0; + unsigned format2 = 0; + + for (unsigned class1_idx : + hb_range (class1_count) | hb_filter (klass1_map)) + { + for (unsigned class2_idx : + hb_range (class2_count) | hb_filter (klass2_map)) + { + unsigned idx = (class1_idx * class2_count + class2_idx) * record_size; + format1 = format1 | valueFormat1.get_effective_format (&values[idx], strip_hints, strip_empty, base, varidx_delta_map); + format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1], strip_hints, strip_empty, base, varidx_delta_map); + } + + if (!varidx_delta_map && + format1 == valueFormat1 && format2 == valueFormat2) + break; + } + + return hb_pair (format1, format2); + } + + bool serialize (hb_subset_context_t *c, + const hb_map_t &klass1_map, + const hb_map_t &klass2_map, + ValueFormat newFormat1, + ValueFormat newFormat2) const + { + unsigned len1 = valueFormat1.get_len (); + unsigned len2 = valueFormat2.get_len (); + unsigned total_len = len1 + len2; + hb_vector_t class2_idxs (+ hb_range (class2_count) | hb_filter (klass2_map)); + if (unlikely (!c->serializer->propagate_error (class2_idxs))) + return false; + for (unsigned class1_idx : + hb_range (class1_count) | hb_filter (klass1_map)) + { + for (unsigned class2_idx : class2_idxs) + { + unsigned idx = (class1_idx * class2_count + class2_idx) * total_len; + valueFormat1.copy_values (c->serializer, newFormat1, base, &values[idx], &c->plan->layout_variation_idx_delta_map); + valueFormat2.copy_values (c->serializer, newFormat2, base, &values[idx + len1], &c->plan->layout_variation_idx_delta_map); + } + } + + return true; + } +}; + template struct PairPosFormat2_4 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 2 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat1; /* ValueRecord definition--for the @@ -21,11 +146,11 @@ struct PairPosFormat2_4 : ValueBase ValueFormat valueFormat2; /* ValueRecord definition--for the * second glyph of the pair--may be * zero (0) */ - typename Types::template OffsetTo + typename Types::template LOffsetTo classDef1; /* Offset to ClassDef table--from * beginning of PairPos subtable--for * the first glyph of the pair */ - typename Types::template OffsetTo + typename Types::template LOffsetTo classDef2; /* Offset to ClassDef table--from * beginning of PairPos subtable--for * the second glyph of the pair */ @@ -37,7 +162,7 @@ struct PairPosFormat2_4 : ValueBase * class1-major, class2-minor, * Each entry has value1 and value2 */ public: - DEFINE_SIZE_ARRAY (10 + 3 * Types::size, values); + DEFINE_SIZE_ARRAY (10 + 3 * Types::LOffset::static_size, values); bool sanitize (hb_sanitize_context_t *c) const { @@ -68,51 +193,10 @@ struct PairPosFormat2_4 : ValueBase 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 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)); - } - } + collect_pair_variation_indices (c, this, this+coverage, + this+classDef1, this+classDef2, + valueFormat1, valueFormat2, + class1Count, class2Count, values); } void collect_glyphs (hb_collect_glyphs_context_t *c) const @@ -228,15 +312,15 @@ struct PairPosFormat2_4 : ValueBase if (!backward) { - dst1[i] += kern1; - dst2[i] += kern2; - dst2[i + 2] += kern2; + dst1[i] = hb_saturate_add (dst1[i], kern1); + dst2[i] = hb_saturate_add (dst2[i], kern2); + dst2[i + 2] = hb_saturate_add (dst2[i + 2], kern2); } else { - dst1[i] += kern1; - dst1[i + 2] += src[i + 2] - kern2; - dst2[i] += kern2; + dst1[i] = hb_saturate_add (dst1[i], kern1); + dst1[i + 2] = hb_clamp_to ((int64_t) dst1[i + 2] + src[i + 2] - kern2); + dst2[i] = hb_saturate_add (dst2[i], kern2); } applied_first = applied_second = kern != 0; @@ -307,8 +391,8 @@ struct PairPosFormat2_4 : ValueBase 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 (); + pair_pos_class_values_t class_values {this, values, valueFormat1, valueFormat2, + class1Count, class2Count}; hb_pair_t newFormats = hb_pair (valueFormat1, valueFormat2); @@ -316,7 +400,7 @@ struct PairPosFormat2_4 : ValueBase { /* in case of full instancing, all var device flags will be dropped so no * need to strip hints here */ - newFormats = compute_effective_value_formats (klass1_map, klass2_map, false, false, &c->plan->layout_variation_idx_delta_map); + newFormats = class_values.compute_effective_value_formats (klass1_map, klass2_map, false, false, &c->plan->layout_variation_idx_delta_map); } /* do not strip hints for VF */ else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) @@ -330,56 +414,19 @@ struct PairPosFormat2_4 : ValueBase * subsetting*/ if (has_fvar && !c->plan->has_gdef_varstore) strip = true; - newFormats = compute_effective_value_formats (klass1_map, klass2_map, strip, true); + newFormats = class_values.compute_effective_value_formats (klass1_map, klass2_map, strip, true); } out->valueFormat1 = newFormats.first; out->valueFormat2 = newFormats.second; - unsigned total_len = len1 + len2; - hb_vector_t class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map)); - for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) - { - for (unsigned class2_idx : class2_idxs) - { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len; - valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map); - valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map); - } - } + if (!class_values.serialize (c, klass1_map, klass2_map, + out->valueFormat1, out->valueFormat2)) + return_trace (false); bool ret = out->coverage.serialize_subset(c, coverage, this); return_trace (out->class1Count && out->class2Count && ret); } - - - hb_pair_t compute_effective_value_formats (const hb_map_t& klass1_map, - const hb_map_t& klass2_map, - bool strip_hints, bool strip_empty, - const hb_hashmap_t> *varidx_delta_map = nullptr) const - { - unsigned len1 = valueFormat1.get_len (); - unsigned len2 = valueFormat2.get_len (); - unsigned record_size = len1 + len2; - - 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) * record_size; - format1 = format1 | valueFormat1.get_effective_format (&values[idx], strip_hints, strip_empty, this, varidx_delta_map); - format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1], strip_hints, strip_empty, this, varidx_delta_map); - } - - if (format1 == valueFormat1 && format2 == valueFormat2) - break; - } - - return hb_pair (format1, format2); - } }; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh index d8428a12562..d8c84a30150 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh @@ -8,6 +8,60 @@ namespace Layout { namespace GPOS_impl { +/* Pair records vary in glyph width; their value traversal need not. */ +struct pair_set_values_t +{ + const ValueBase *base; + glyph_data_t glyphs; + const Value *values; + unsigned count; + unsigned record_size; + + unsigned get_glyph (unsigned i) const + { + glyph_data_t glyph = glyphs; + glyph.data = (const char *) glyph.data + i * record_size; + return glyph[0]; + } + + const Value *get_values (unsigned i) const + { return reinterpret_cast ((const char *) values + i * record_size); } + + hb_pair_t + compute_effective_value_formats (const hb_set_t &glyphset, + const ValueFormat valueFormats[2], + bool strip_hints, bool strip_empty, + const hb_hashmap_t> *varidx_delta_map) const + { + unsigned len1 = valueFormats[0].get_len (); + unsigned format1 = 0, format2 = 0; + for (unsigned i = 0; i < count; i++) + { + if (!glyphset.has (get_glyph (i))) continue; + const Value *v = get_values (i); + format1 |= valueFormats[0].get_effective_format (v, strip_hints, strip_empty, base, varidx_delta_map); + format2 |= valueFormats[1].get_effective_format (v + len1, strip_hints, strip_empty, base, varidx_delta_map); + } + return hb_pair (format1, format2); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat valueFormats[2]) const + { + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + for (unsigned i = 0; i < count; i++) + { + if (!c->glyph_set->has (get_glyph (i))) continue; + const hb_array_t v = hb_array (get_values (i), len1 + len2); + if (valueFormats[0].has_device ()) + valueFormats[0].collect_variation_indices (c, base, v.sub_array (0, len1)); + if (valueFormats[1].has_device ()) + valueFormats[1].collect_variation_indices (c, base, v.sub_array (len1, len2)); + } + } +}; + template struct PairSet : ValueBase { @@ -17,12 +71,13 @@ struct PairSet : ValueBase using PairValueRecord = GPOS_impl::PairValueRecord; protected: - HBUINT16 len; /* Number of PairValueRecords */ + typename Types::HBUINT + len; /* Number of PairValueRecords */ PairValueRecord firstPairValueRecord; /* Array of PairValueRecords--ordered * by GlyphID of the second glyph */ public: - DEFINE_SIZE_MIN (2); + DEFINE_SIZE_MIN (Types::HBUINT::static_size); static size_t get_size (unsigned len1, unsigned len2) { @@ -84,20 +139,25 @@ struct PairSet : ValueBase c->input->add_array (&record->secondGlyph, len, record_size); } - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const ValueFormat *valueFormats) const + template + void collect_second_glyphs (set_t *glyphs, + const ValueFormat *valueFormats) const { unsigned record_size = get_size (valueFormats); - 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); } + glyphs->add_array (&record->secondGlyph, len, record_size); + } - record = &StructAtOffset (record, record_size); - } + pair_set_values_t get_values_view (const ValueFormat valueFormats[2]) const + { + return {this, &firstPairValueRecord.secondGlyph, &firstPairValueRecord.values[0], + (unsigned) len, (unsigned) get_size (valueFormats)}; + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats) const + { + get_values_view (valueFormats).collect_variation_indices (c, valueFormats); } bool apply (hb_ot_apply_context_t *c, @@ -112,7 +172,7 @@ struct PairSet : ValueBase const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, &firstPairValueRecord, - len, + (unsigned) len, record_size); if (record) { @@ -143,6 +203,9 @@ struct PairSet : ValueBase if (applied_first || applied_second) buffer->unsafe_to_break (buffer->idx, pos + 1); + else + /* Even a zero-valued pair record is a concat hazard. */ + buffer->unsafe_to_concat (buffer->idx, pos + 1); if (len2) { @@ -177,7 +240,7 @@ struct PairSet : ValueBase unsigned len2 = valueFormats[1].get_len (); unsigned record_size = get_size (len1, len2); - typename PairValueRecord::context_t context = + pair_value_record_context_t context = { this, valueFormats, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh index fe9595f1266..1fb3dc46953 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh @@ -8,6 +8,24 @@ namespace Layout { namespace GPOS_impl { +struct pair_value_record_context_t +{ + const ValueBase *base; + const ValueFormat *valueFormats; + const ValueFormat *newFormats; + unsigned len1; /* valueFormats[0].get_len() */ + const hb_map_t *glyph_map; + const hb_hashmap_t> *layout_variation_idx_delta_map; + + void copy_values (hb_serialize_context_t *s, const Value *values) const + { + valueFormats[0].copy_values (s, newFormats[0], base, values, + layout_variation_idx_delta_map); + valueFormats[1].copy_values (s, newFormats[1], base, values + len1, + layout_variation_idx_delta_map); + } +}; + template struct PairValueRecord { @@ -27,18 +45,8 @@ struct PairValueRecord int cmp (hb_codepoint_t k) const { return secondGlyph.cmp (k); } - struct context_t - { - const ValueBase *base; - const ValueFormat *valueFormats; - const ValueFormat *newFormats; - unsigned len1; /* valueFormats[0].get_len() */ - const hb_map_t *glyph_map; - const hb_hashmap_t> *layout_variation_idx_delta_map; - }; - bool subset (hb_subset_context_t *c, - context_t *closure) const + pair_value_record_context_t *closure) const { TRACE_SERIALIZE (this); auto *s = c->serializer; @@ -47,15 +55,7 @@ struct PairValueRecord out->secondGlyph = (*closure->glyph_map)[secondGlyph]; - closure->valueFormats[0].copy_values (s, - closure->newFormats[0], - closure->base, &values[0], - closure->layout_variation_idx_delta_map); - closure->valueFormats[1].copy_values (s, - closure->newFormats[1], - closure->base, - &values[closure->len1], - closure->layout_variation_idx_delta_map); + closure->copy_values (s, values); return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PosLookupSubTable.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PosLookupSubTable.hh index c19fbc323ff..4238f98f4e1 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PosLookupSubTable.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PosLookupSubTable.hh @@ -37,15 +37,15 @@ struct PosLookupSubTable { TRACE_DISPATCH (this, lookup_type); switch (lookup_type) { - case Single: return_trace (u.single.dispatch (c, std::forward (ds)...)); - case Pair: return_trace (u.pair.dispatch (c, std::forward (ds)...)); - case Cursive: return_trace (u.cursive.dispatch (c, std::forward (ds)...)); - case MarkBase: return_trace (u.markBase.dispatch (c, std::forward (ds)...)); - case MarkLig: return_trace (u.markLig.dispatch (c, std::forward (ds)...)); - case MarkMark: return_trace (u.markMark.dispatch (c, std::forward (ds)...)); - case Context: return_trace (u.context.dispatch (c, std::forward (ds)...)); - case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward (ds)...)); - case Extension: return_trace (u.extension.dispatch (c, std::forward (ds)...)); + case Single: hb_barrier (); return_trace (u.single.dispatch (c, std::forward (ds)...)); + case Pair: hb_barrier (); return_trace (u.pair.dispatch (c, std::forward (ds)...)); + case Cursive: hb_barrier (); return_trace (u.cursive.dispatch (c, std::forward (ds)...)); + case MarkBase: hb_barrier (); return_trace (u.markBase.dispatch (c, std::forward (ds)...)); + case MarkLig: hb_barrier (); return_trace (u.markLig.dispatch (c, std::forward (ds)...)); + case MarkMark: hb_barrier (); return_trace (u.markMark.dispatch (c, std::forward (ds)...)); + case Context: hb_barrier (); return_trace (u.context.dispatch (c, std::forward (ds)...)); + case ChainContext: hb_barrier (); return_trace (u.chainContext.dispatch (c, std::forward (ds)...)); + case Extension: hb_barrier (); return_trace (u.extension.dispatch (c, std::forward (ds)...)); default: return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh index 30fc1aacda8..f49518ece8a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh @@ -13,8 +13,12 @@ struct SinglePos protected: union { struct { HBUINT16 v; } format; /* Format identifier */ - SinglePosFormat1 format1; - SinglePosFormat2 format2; + SinglePosFormat1_3 format1; + SinglePosFormat2_4 format2; +#ifndef HB_NO_BEYOND_64K + SinglePosFormat1_3 format3; + SinglePosFormat2_4 format4; +#endif } u; public: @@ -33,10 +37,10 @@ struct SinglePos } template void serialize (hb_serialize_context_t *c, - const SrcLookup* src, + const ValueBase* src, + ValueFormat src_format, Iterator glyph_val_iter_pairs, const hb_hashmap_t> *layout_variation_idx_delta_map, unsigned newFormat) @@ -49,20 +53,41 @@ struct SinglePos if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs); +#ifndef HB_NO_BEYOND_64K + if (+ glyph_val_iter_pairs + | hb_map_retains_sorting (hb_first) + | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; })) + format += 2; +#endif + u.format.v = format; switch (u.format.v) { - case 1: u.format1.serialize (c, - src, + case 1: hb_barrier (); u.format1.serialize (c, + src, src_format, + glyph_val_iter_pairs, + new_format, + layout_variation_idx_delta_map); + return; + case 2: hb_barrier (); u.format2.serialize (c, + src, src_format, + glyph_val_iter_pairs, + new_format, + layout_variation_idx_delta_map); + return; +#ifndef HB_NO_BEYOND_64K + case 3: u.format3.serialize (c, + src, src_format, glyph_val_iter_pairs, new_format, layout_variation_idx_delta_map); return; - case 2: u.format2.serialize (c, - src, + case 4: u.format4.serialize (c, + src, src_format, glyph_val_iter_pairs, new_format, layout_variation_idx_delta_map); return; +#endif default:return; } } @@ -73,22 +98,27 @@ struct SinglePos if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); + case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } }; -template +template static void SinglePos_serialize (hb_serialize_context_t *c, - const SrcLookup *src, + const ValueBase *src, + ValueFormat src_format, Iterator it, const hb_hashmap_t> *layout_variation_idx_delta_map, unsigned new_format) -{ c->start_embed ()->serialize (c, src, it, layout_variation_idx_delta_map, new_format); } +{ c->start_embed ()->serialize (c, src, src_format, it, layout_variation_idx_delta_map, new_format); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh index b33e761bac2..6625e8b3de4 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh @@ -8,11 +8,12 @@ namespace OT { namespace Layout { namespace GPOS_impl { -struct SinglePosFormat1 : ValueBase +template +struct SinglePosFormat1_3 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat; /* Defines the types of data in the @@ -21,7 +22,7 @@ struct SinglePosFormat1 : ValueBase * value(s)--applied to all glyphs in * the Coverage table */ public: - DEFINE_SIZE_ARRAY (6, values); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + ValueFormat::static_size, values); bool sanitize (hb_sanitize_context_t *c) const { @@ -99,20 +100,16 @@ struct SinglePosFormat1 : ValueBase unsigned int index = (this+coverage).get_coverage (gid); if (likely (index == NOT_COVERED)) return false; - /* This is ugly... */ - hb_buffer_t buffer {}; - buffer.props.direction = direction; - OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); - - valueFormat.apply_value (&c, this, values, pos); + valueFormat.position_single (font, table_blob, direction, this, + values, pos); return true; } template void serialize (hb_serialize_context_t *c, - const SrcLookup *src, + const ValueBase *src, + ValueFormat src_format, Iterator it, ValueFormat newFormat, const hb_hashmap_t> *layout_variation_idx_delta_map) @@ -124,7 +121,7 @@ struct SinglePosFormat1 : ValueBase for (const hb_array_t& _ : + it | hb_map (hb_second)) { - src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); + src_format.copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); // Only serialize the first entry in the iterator, the rest are assumed to // be the same. break; @@ -178,7 +175,7 @@ struct SinglePosFormat1 : ValueBase ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format); + SinglePos_serialize (c->serializer, this, valueFormat, it, &c->plan->layout_variation_idx_delta_map, new_format); return_trace (ret); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh index 686126c9f5e..9aecdb2d7f4 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh @@ -7,20 +7,38 @@ namespace OT { namespace Layout { namespace GPOS_impl { -struct SinglePosFormat2 : ValueBase +/* Keep the iterator type independent of the source table width so + * the output serializers can share their instantiations. */ +struct single_pos_value_mapper_t +{ + const hb_map_t &glyph_map; + const hb_array_t &values; + const unsigned &sub_length; + + hb_pair_t> + operator () (const hb_pair_t &_) const + { + return hb_pair (glyph_map[_.first], + values.sub_array (_.second * sub_length, sub_length)); + } +}; + +template +struct SinglePosFormat2_4 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 2 */ - Offset16To + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat; /* Defines the types of data in the * ValueRecord */ - HBUINT16 valueCount; /* Number of ValueRecords */ + typename Types::HBUINT + valueCount; /* Number of ValueRecords */ ValueRecord values; /* Array of ValueRecords--positioning * values applied to glyphs */ public: - DEFINE_SIZE_ARRAY (8, values); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + ValueFormat::static_size + Types::HBUINT::static_size, values); bool sanitize (hb_sanitize_context_t *c) const { @@ -103,23 +121,17 @@ struct SinglePosFormat2 : ValueBase if (likely (index == NOT_COVERED)) return false; if (unlikely (index >= valueCount)) return false; - /* This is ugly... */ - hb_buffer_t buffer {}; - buffer.props.direction = direction; - OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); - - valueFormat.apply_value (&c, this, - &values[index * valueFormat.get_len ()], - pos); + valueFormat.position_single (font, table_blob, direction, this, + &values[index * valueFormat.get_len ()], pos); return true; } template void serialize (hb_serialize_context_t *c, - const SrcLookup *src, + const ValueBase *src, + ValueFormat src_format, Iterator it, ValueFormat newFormat, const hb_hashmap_t> *layout_variation_idx_delta_map) @@ -132,7 +144,7 @@ struct SinglePosFormat2 : ValueBase + it | hb_map (hb_second) | hb_apply ([&] (hb_array_t _) - { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); }) + { src_format.copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); }) ; auto glyphs = @@ -181,17 +193,14 @@ struct SinglePosFormat2 : ValueBase 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 values_array = values.as_array ((unsigned) 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& _) - { - return hb_pair (glyph_map[_.first], - values_array.sub_array (_.second * sub_length, - sub_length)); - }) + | hb_map_retains_sorting (single_pos_value_mapper_t {glyph_map, + values_array, + sub_length}) ; unsigned new_format = compute_effective_format (c->plan->source, it, @@ -200,7 +209,7 @@ struct SinglePosFormat2 : ValueBase c->plan->has_gdef_varstore, &c->plan->layout_variation_idx_delta_map); bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format); + SinglePos_serialize (c->serializer, this, valueFormat, it, &c->plan->layout_variation_idx_delta_map, new_format); return_trace (ret); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh index 613de17bf6a..7591221185a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh @@ -102,15 +102,19 @@ struct ValueFormat : HBUINT16 #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 & xPlacement) + glyph_pos.x_offset = hb_saturate_add (glyph_pos.x_offset, font->em_scale_x (get_short (values++, &ret))); + if (format & yPlacement) + glyph_pos.y_offset = hb_saturate_add (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)); + if (likely (horizontal)) + glyph_pos.x_advance = hb_saturate_add (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)); + if (unlikely (!horizontal)) + glyph_pos.y_advance = hb_saturate_sub (glyph_pos.y_advance, font->em_scale_y (get_short (values, &ret))); values++; } @@ -127,28 +131,47 @@ struct ValueFormat : HBUINT16 /* pixel -> fractional pixel */ if (format & xPlaDevice) { - if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); + if (use_x_device) + glyph_pos.x_offset = hb_saturate_add (glyph_pos.x_offset, get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache)); values++; } if (format & yPlaDevice) { - if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); + if (use_y_device) + glyph_pos.y_offset = hb_saturate_add (glyph_pos.y_offset, get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache)); values++; } if (format & xAdvDevice) { - if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); + if (horizontal && use_x_device) + glyph_pos.x_advance = hb_saturate_add (glyph_pos.x_advance, get_device (values, &ret, base, c->sanitizer).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 -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); + if (!horizontal && use_y_device) + glyph_pos.y_advance = hb_saturate_sub (glyph_pos.y_advance, get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache)); values++; } return ret; } + void position_single (hb_font_t *font, + hb_blob_t *table_blob, + hb_direction_t direction, + const ValueBase *base, + const Value *values, + hb_glyph_position_t &pos) const + { + /* This is ugly... */ + hb_buffer_t buffer {}; + buffer.props.direction = direction; + hb_ot_apply_context_t c (1, font, &buffer, table_blob); + + apply_value (&c, base, values, pos); + } + unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base, const hb_hashmap_t> *varidx_delta_map) const { @@ -199,10 +222,14 @@ struct ValueFormat : HBUINT16 if (!format) return; HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr; - if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++); - if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++); - if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); - if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); + if ((format | new_format) & xPlacement) + x_placement = copy_value (c, new_format, xPlacement, format & xPlacement ? *values++ : Null (Value)); + if ((format | new_format) & yPlacement) + y_placement = copy_value (c, new_format, yPlacement, format & yPlacement ? *values++ : Null (Value)); + if ((format | new_format) & xAdvance) + x_adv = copy_value (c, new_format, xAdvance, format & xAdvance ? *values++ : Null (Value)); + if ((format | new_format) & yAdvance) + y_adv = copy_value (c, new_format, yAdvance, format & yAdvance ? *values++ : Null (Value)); if (!has_device ()) return; @@ -431,9 +458,14 @@ struct ValueFormat : HBUINT16 { unsigned varidx = (base + get_device (value)).get_variation_index (); hb_pair_t *varidx_delta; - if (varidx_delta_map->has (varidx, &varidx_delta) && - varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) - return; + if (varidx_delta_map->has (varidx, &varidx_delta)) + { + /* A device-only value needs a base field for its instanced delta. */ + if (varidx_delta->second) + *format |= flag >> 4; + if (varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + return; + } } *format = *format & ~flag; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh index f13c5e7e251..be9bab6c1b2 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh @@ -29,6 +29,13 @@ struct AlternateSet void closure (hb_closure_context_t *c) const { c->output->add_array (alternates.arrayZ, alternates.len); } + void depend (hb_depend_context_t *c, hb_codepoint_t source) const + { + + hb_iter (alternates) + | hb_apply ([&] (const hb_codepoint_t &target) { c->depend_data->add_gsub_lookup (source, c->lookup_index, target); }) + ; + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { c->output->add_array (alternates.arrayZ, alternates.len); } @@ -82,7 +89,7 @@ struct AlternateSet unsigned *alternate_count /* IN/OUT. May be NULL. */, hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const { - if (alternates.len && alternate_count) + if (alternates.len && alternate_count && alternate_glyphs) { + alternates.as_array ().sub_array (start_offset, alternate_count) | hb_sink (hb_array (alternate_glyphs, *alternate_count)) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh index a43c75c8f4e..6a86981699e 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh @@ -26,27 +26,28 @@ struct AlternateSubst if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } } - /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using - * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */ + /* TODO This function is unused and should be done using iterators. While + * at it perhaps using iterator of arrays of hb_codepoint_t instead. */ + template bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t alternate_len_list, - hb_array_t alternate_glyphs_list) + hb_array_t alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format.v))) return_trace (false); unsigned int format = 1; u.format.v = format; switch (u.format.v) { - case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list)); + case 1: hb_barrier (); return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list)); default:return_trace (false); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh index 7a3a2511b7f..e13fd11337b 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh @@ -13,14 +13,14 @@ struct AlternateSubstFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - Array16Of>> + typename Types::template ArrayOf>> alternateSet; /* Array of AlternateSet tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (2 + 2 * Types::size, alternateSet); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + Types::HBUINT::static_size, alternateSet); bool sanitize (hb_sanitize_context_t *c) const { @@ -34,6 +34,19 @@ struct AlternateSubstFormat1_2 bool may_have_non_1to1 () const { return false; } + void depend (hb_depend_context_t *c) const + { + // Filter by parent_active_glyphs like closure does + + hb_zip (this+coverage, alternateSet) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_apply ([&] (const hb_pair_t>&> &_) + { + const AlternateSet& as = this+_.second; + as.depend (c, _.first); + }) + ; + } + void closure (hb_closure_context_t *c) const { + hb_zip (this+coverage, alternateSet) @@ -92,10 +105,11 @@ struct AlternateSubstFormat1_2 return_trace ((this+alternateSet[index]).apply (c)); } + template bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t alternate_len_list, - hb_array_t alternate_glyphs_list) + hb_array_t alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/GSUB.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/GSUB.hh index 900cf603e45..3d221b828ef 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/GSUB.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/GSUB.hh @@ -53,6 +53,7 @@ struct GSUB : GSUBGPOS struct GSUB_accelerator_t : Layout::GSUB::accelerator_t { GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::accelerator_t (face) {} + HB_INTERNAL void depend (hb_depend_data_builder_t *builder, hb_face_t *face) const; }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh index 7bc98d31f32..91c8072d526 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh @@ -38,6 +38,40 @@ struct Ligature c->output->add (ligGlyph); } + void depend (hb_depend_context_t *c, hb_codepoint_t first) const + { + // Build the complete ligature set upfront before adding any edges + hb_set_t complete_ligset; + complete_ligset.add (first); + + hb_iter (component) | hb_sink (complete_ligset); + if (unlikely (complete_ligset.in_error ())) + { + c->depend_data->fail (); + return; + } + + bool ligset_created; + hb_codepoint_t ligset_idx = c->depend_data->find_or_create_set (complete_ligset, + &ligset_created); + if (unlikely (ligset_idx == HB_CODEPOINT_INVALID)) + return; + + // Track whether any edge using this ligset_idx was actually added + bool any_added = false; + + // Now add one edge for each glyph in the complete, immutable set + + hb_iter (complete_ligset) + | hb_apply ([&] (hb_codepoint_t gid) { + if (c->depend_data->add_gsub_lookup (gid, c->lookup_index, ligGlyph, ligset_idx)) + any_added = true; + }) + ; + + // If no edges were added, a newly allocated set is unused - free it for reuse + if (!any_added && ligset_created) + c->depend_data->discard_set (ligset_idx); + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { c->input->add_array (component.arrayZ, component.get_length ()); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh index 81c5c2bcfe4..d07246cd080 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh @@ -12,7 +12,7 @@ template struct LigatureSet { public: - Array16OfOffset16To> + Array16Of>> ligature; /* Array LigatureSet tables * ordered by preference */ @@ -54,6 +54,14 @@ struct LigatureSet ; } + void depend (hb_depend_context_t *c, hb_codepoint_t first) const + { + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_apply ([&] (const Ligature &_) { _.depend (c, first); }) + ; + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { + hb_iter (ligature) @@ -128,7 +136,10 @@ struct LigatureSet goto slow; if (seconds && !seconds->may_have (second)) + { + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); return_trace (false); + } bool unsafe_to_concat = false; for (unsigned int i = 0; i < num_ligs; i++) { @@ -152,10 +163,11 @@ struct LigatureSet return_trace (false); } + template bool serialize (hb_serialize_context_t *c, - hb_array_t ligatures, + hb_array_t ligatures, hb_array_t component_count_list, - hb_array_t &component_list /* Starting from second for each ligature */) + hb_array_t &component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh index 22ce9b79d7f..8d744096d1e 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh @@ -26,30 +26,30 @@ struct LigatureSubst if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } } - /* TODO This function is only used by small GIDs, and not updated to 24bit GIDs. Should - * be done by using iterators. While at it perhaps using iterator of arrays of hb_codepoint_t - * instead. */ + /* TODO This function should be done using iterators. While at it perhaps + * using iterator of arrays of hb_codepoint_t instead. */ + template bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t first_glyphs, + hb_sorted_array_t first_glyphs, hb_array_t ligature_per_first_glyph_count_list, - hb_array_t ligatures_list, + hb_array_t ligatures_list, hb_array_t component_count_list, - hb_array_t component_list /* Starting from second for each ligature */) + hb_array_t component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format.v))) return_trace (false); unsigned int format = 1; u.format.v = format; switch (u.format.v) { - case 1: return_trace (u.format1.serialize (c, + case 1: hb_barrier (); return_trace (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, ligatures_list, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh index 909ddca220f..7295bffd9fe 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -13,14 +13,14 @@ struct LigatureSubstFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - Array16Of>> + typename Types::template ArrayOf>> ligatureSet; /* Array LigatureSet tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (4 + Types::size, ligatureSet); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + Types::HBUINT::static_size, ligatureSet); bool sanitize (hb_sanitize_context_t *c) const { @@ -43,6 +43,18 @@ struct LigatureSubstFormat1_2 bool may_have_non_1to1 () const { return true; } + void depend (hb_depend_context_t *c) const + { + + hb_zip (this+coverage, ligatureSet) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_apply ([&] (const hb_pair_t>&> &_) + { + const LigatureSet& ls = this+_.second; + ls.depend (c, _.first); + }) + ; + } + void closure (hb_closure_context_t *c) const { + hb_zip (this+coverage, ligatureSet) @@ -67,6 +79,14 @@ struct LigatureSubstFormat1_2 ; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { + + hb_iter (ligatureSet) + | hb_map (hb_add (this)) + | hb_apply ([digest] (const LigatureSet &_) { _.collect_seconds (*digest); }) + ; + } + const Coverage &get_coverage () const { return this+coverage; } bool would_apply (hb_would_apply_context_t *c) const @@ -118,12 +138,13 @@ struct LigatureSubstFormat1_2 return_trace (lig_set.apply (c, seconds)); } + template bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t first_glyphs, + hb_sorted_array_t first_glyphs, hb_array_t ligature_per_first_glyph_count_list, - hb_array_t ligatures_list, + hb_array_t ligatures_list, hb_array_t component_count_list, - hb_array_t component_list /* Starting from second for each ligature */) + hb_array_t component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh index 8fb663825b5..d528f23d60b 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh @@ -27,9 +27,9 @@ struct MultipleSubst if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } @@ -45,7 +45,7 @@ struct MultipleSubst unsigned int format = 1; u.format.v = format; switch (u.format.v) { - case 1: return_trace (u.format1.serialize (c, it)); + case 1: hb_barrier (); return_trace (u.format1.serialize (c, it)); default:return_trace (false); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubstFormat1.hh index aec8d0f2c07..8db7b95e305 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubstFormat1.hh @@ -13,14 +13,14 @@ struct MultipleSubstFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - Array16Of>> + typename Types::template ArrayOf>> sequence; /* Array of Sequence tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (4 + Types::size, sequence); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + Types::HBUINT::static_size, sequence); bool sanitize (hb_sanitize_context_t *c) const { @@ -44,6 +44,19 @@ struct MultipleSubstFormat1_2 ; } + void depend (hb_depend_context_t *c) const + { + // Filter by parent_active_glyphs like closure does + + hb_zip (this+coverage, sequence) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_apply ([&] (const hb_pair_t>&> &_) + { + const Sequence& s = this+_.second; + s.depend (c, _.first); + }) + ; + } + void closure_lookups (hb_closure_lookups_context_t *c) const {} void collect_glyphs (hb_collect_glyphs_context_t *c) const diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh index e33148d770b..7ec5ba8bc37 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh @@ -13,7 +13,12 @@ struct ReverseChainSingleSubst protected: union { struct { HBUINT16 v; } format; /* Format identifier */ - ReverseChainSingleSubstFormat1 format1; + ReverseChainSingleSubstFormat1_2 + format1; +#ifndef HB_NO_BEYOND_64K + ReverseChainSingleSubstFormat1_2 + format2; +#endif } u; public: @@ -23,7 +28,10 @@ struct ReverseChainSingleSubst if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh index 400a9e73791..0947b67c6db 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -7,26 +7,29 @@ namespace OT { namespace Layout { namespace GSUB_impl { -struct ReverseChainSingleSubstFormat1 +template +struct ReverseChainSingleSubstFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of table */ - Array16OfOffset16To + Array16Of> backtrack; /* Array of coverage tables * in backtracking sequence, in glyph * sequence order */ - Array16OfOffset16To + /* Format 2 widens the backtrack and lookahead coverage offsets but + * keeps their counts 16-bit. */ + Array16Of> lookaheadX; /* Array of coverage tables * in lookahead sequence, in glyph * sequence order */ - Array16Of + typename Types::template ArrayOf substituteX; /* Array of substitute * GlyphIDs--ordered by Coverage Index */ public: - DEFINE_SIZE_MIN (10); + DEFINE_SIZE_MIN (6 + Types::LOffset::static_size + Types::HBUINT::static_size); bool sanitize (hb_sanitize_context_t *c) const { @@ -67,6 +70,76 @@ struct ReverseChainSingleSubstFormat1 bool may_have_non_1to1 () const { return false; } + void depend (hb_depend_context_t *c) const { + // Filter by intersects and parent_active_glyphs like closure does + if (!intersects (c->glyphs)) return; + + const auto &lookahead = StructAfter (backtrack); + const auto &substitute = StructAfter (lookahead); + + /* Build context set from backtrack and lookahead coverages. + * ReverseChainSingleSubst has contextual requirements - the substitution + * only fires when backtrack and lookahead glyphs are present. */ + hb_set_t context_glyphs; + + /* Add glyphs from backtrack coverages */ + unsigned int count = backtrack.len; + for (unsigned int i = 0; i < count; i++) + { + hb_set_t back_glyphs; + (this+backtrack[i]).intersect_set (*c->glyphs, back_glyphs); + if (back_glyphs.get_population () == 1) + context_glyphs.add (back_glyphs.get_min ()); + else if (back_glyphs.get_population () > 1) + { + hb_codepoint_t set_idx = c->depend_data->find_or_create_context_set (back_glyphs); + if (unlikely (set_idx == HB_CODEPOINT_INVALID)) + return; + context_glyphs.add (HB_DEPEND_CONTEXT_SET_FLAG | set_idx); + } + } + + /* Add glyphs from lookahead coverages */ + count = lookahead.len; + for (unsigned int i = 0; i < count; i++) + { + hb_set_t look_glyphs; + (this+lookahead[i]).intersect_set (*c->glyphs, look_glyphs); + if (look_glyphs.get_population () == 1) + context_glyphs.add (look_glyphs.get_min ()); + else if (look_glyphs.get_population () > 1) + { + hb_codepoint_t set_idx = c->depend_data->find_or_create_context_set (look_glyphs); + if (unlikely (set_idx == HB_CODEPOINT_INVALID)) + return; + context_glyphs.add (HB_DEPEND_CONTEXT_SET_FLAG | set_idx); + } + } + + /* Allocate context set and save/restore around edge creation */ + if (unlikely (context_glyphs.in_error ())) + { + c->depend_data->fail (); + return; + } + hb_codepoint_t context_set_idx = context_glyphs.is_empty () + ? HB_CODEPOINT_INVALID + : c->depend_data->find_or_create_context_set (context_glyphs); + if (unlikely (!context_glyphs.is_empty () && + context_set_idx == HB_CODEPOINT_INVALID)) + return; + + hb_codepoint_t saved_context = c->depend_data->current_context_set_index; + c->depend_data->current_context_set_index = context_set_idx; + + + hb_zip (this+coverage, substitute) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_apply ([&] (const hb_codepoint_pair_t &_) { c->depend_data->add_gsub_lookup (_.first, c->lookup_index, _.second); }) + ; + + c->depend_data->current_context_set_index = saved_context; + } + void closure (hb_closure_context_t *c) const { if (!intersects (c->glyphs)) return; @@ -124,11 +197,11 @@ struct ReverseChainSingleSubstFormat1 unsigned int start_index = 0, end_index = 0; if (match_backtrack (c, - backtrack.len, (HBUINT16 *) backtrack.arrayZ, + backtrack.len, backtrack.arrayZ, match_coverage, this, &start_index) && match_lookahead (c, - lookahead.len, (HBUINT16 *) lookahead.arrayZ, + lookahead.len, lookahead.arrayZ, match_coverage, this, c->buffer->idx + 1, &end_index)) { @@ -167,10 +240,8 @@ struct ReverseChainSingleSubstFormat1 bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const { TRACE_SERIALIZE (this); - auto *out = c->serializer->start_embed> (); - - if (unlikely (!c->serializer->allocate_size (HBUINT16::static_size))) - return_trace (false); + auto *out = c->serializer->start_embed>> (); + if (unlikely (!out->serialize (c->serializer, 0u))) return_trace (false); for (auto& offset : it) { auto *o = out->serialize_append (c->serializer); @@ -197,9 +268,9 @@ struct ReverseChainSingleSubstFormat1 if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false); if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false); - if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false); + if (!serialize_lookahead_coverage_offset_array (c, lookahead_iter)) return_trace (false); - auto *substitute_out = c->serializer->start_embed> (); + auto *substitute_out = c->serializer->start_embed> (); auto substitutes = + coverage_subst_iter | hb_map (hb_second) @@ -230,12 +301,29 @@ struct ReverseChainSingleSubstFormat1 + hb_zip (this+coverage, substitute) | hb_filter (glyphset, hb_first) | hb_filter (glyphset, hb_second) - | hb_map_retains_sorting ([&] (hb_pair_t p) -> hb_codepoint_pair_t + | hb_map_retains_sorting ([&] (hb_pair_t p) -> hb_codepoint_pair_t { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) ; return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ())); } + + template + bool serialize_lookahead_coverage_offset_array (hb_subset_context_t *c, Iterator it) const + { + TRACE_SERIALIZE (this); + auto *out = c->serializer->start_embed>> (); + if (unlikely (!out->serialize (c->serializer, 0u))) return_trace (false); + + for (auto& offset : it) { + auto *o = out->serialize_append (c->serializer); + if (unlikely (!o) || !o->serialize_subset (c, offset, this)) + return_trace (false); + } + + return_trace (true); + } }; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh index b3295bee16d..5d502ea99de 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh @@ -28,6 +28,13 @@ struct Sequence void closure (hb_closure_context_t *c) const { c->output->add_array (substitute.arrayZ, substitute.len); } + void depend (hb_depend_context_t *c, hb_codepoint_t source) const + { + + hb_iter (substitute) + | hb_apply ([&] (const hb_codepoint_t &target) { c->depend_data->add_gsub_lookup (source, c->lookup_index, target); }) + ; + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { c->output->add_array (substitute.arrayZ, substitute.len); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh index 323eb4d0f90..21c6ce98a0f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh @@ -30,11 +30,11 @@ struct SingleSubst if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format.v); switch (u.format.v) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K - case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); - case 4: return_trace (c->dispatch (u.format4, std::forward (ds)...)); + case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); + case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } @@ -73,17 +73,17 @@ struct SingleSubst u.format.v = format; switch (u.format.v) { - case 1: return_trace (u.format1.serialize (c, + case 1: hb_barrier (); return_trace (u.format1.serialize (c, + glyphs | hb_map_retains_sorting (hb_first), delta)); - case 2: return_trace (u.format2.serialize (c, glyphs)); + case 2: hb_barrier (); return_trace (u.format2.serialize (c, glyphs)); #ifndef HB_NO_BEYOND_64K - case 3: return_trace (u.format3.serialize (c, + case 3: hb_barrier (); return_trace (u.format3.serialize (c, + glyphs | hb_map_retains_sorting (hb_first), delta)); - case 4: return_trace (u.format4.serialize (c, glyphs)); + case 4: hb_barrier (); return_trace (u.format4.serialize (c, glyphs)); #endif default:return_trace (false); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh index 5ee2c1d1f46..c1dc1e6cdc8 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -7,12 +7,101 @@ namespace OT { namespace Layout { namespace GSUB_impl { +static inline bool +subset_single_subst (hb_subset_context_t *c, + const Coverage &coverage, + hb_codepoint_t d, + hb_codepoint_t mask) +{ + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + hb_set_t intersection; + coverage.intersect_set (glyphset, intersection); + + auto it = + + hb_iter (intersection) + | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) { + return hb_codepoint_pair_t (g, + (g + d) & mask); }) + | hb_filter (glyphset, hb_second) + | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t + { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) + ; + + bool ret = bool (it); + SingleSubst_serialize (c->serializer, it); + return ret; +} + +HB_INTERNAL inline +void single_subst_depend (hb_depend_context_t *c, + const Coverage &coverage, + hb_codepoint_t d, hb_codepoint_t mask) +{ + unsigned num_glyphs = c->face->get_num_glyphs (); + + // Filter coverage by active glyphs (like closure does) + hb_set_t intersection; + coverage.intersect_set (c->parent_active_glyphs (), intersection); + + + hb_iter (intersection) + | hb_map ([&] (hb_codepoint_t _) { return hb_codepoint_pair_t (_, (_ + d) & mask); }) + | hb_filter ([num_glyphs] (const hb_codepoint_pair_t &_) { return _.second < num_glyphs; }) + | hb_apply ([&] (const hb_codepoint_pair_t &_) { c->depend_data->add_gsub_lookup(_.first, c->lookup_index, _.second); }) + ; +} + +HB_INTERNAL inline +void single_subst_closure (hb_closure_context_t *c, + const Coverage &coverage, + hb_codepoint_t d, hb_codepoint_t mask) +{ + /* Help fuzzer avoid this function as much. */ + unsigned pop = coverage.get_population (); + if (pop >= mask) + return; + + hb_set_t intersection; + coverage.intersect_set (c->parent_active_glyphs (), intersection); + + /* In degenerate fuzzer-found fonts, but not real fonts, + * this table can keep adding new glyphs in each round of closure. + * Refuse to close-over, if it maps glyph range to overlapping range. */ + hb_codepoint_t min_before = intersection.get_min (); + hb_codepoint_t max_before = intersection.get_max (); + hb_codepoint_t min_after = (min_before + d) & mask; + hb_codepoint_t max_after = (max_before + d) & mask; + if (intersection.get_population () == max_before - min_before + 1 && + ((min_before <= min_after && min_after <= max_before) || + (min_before <= max_after && max_after <= max_before))) + return; + + + hb_iter (intersection) + | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; }) + | hb_sink (c->output) + ; +} + +HB_INTERNAL inline +void single_subst_collect_glyphs (hb_collect_glyphs_context_t *c, + const Coverage &coverage, + hb_codepoint_t d, hb_codepoint_t mask) +{ + if (unlikely (!coverage.collect_coverage (c->input))) return; + + + hb_iter (coverage) + | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; }) + | hb_sink (c->output) + ; +} + template struct SingleSubstFormat1_3 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ typename Types::HBUINT @@ -20,7 +109,7 @@ struct SingleSubstFormat1_3 * substitute GlyphID, modulo 0x10000 */ public: - DEFINE_SIZE_STATIC (2 + 2 * Types::size); + DEFINE_SIZE_STATIC (2 + Types::LOffset::static_size + Types::HBUINT::static_size); bool sanitize (hb_sanitize_context_t *c) const { @@ -45,49 +134,21 @@ struct SingleSubstFormat1_3 bool may_have_non_1to1 () const { return false; } - void closure (hb_closure_context_t *c) const + void depend (hb_depend_context_t *c) const { - hb_codepoint_t d = deltaGlyphID; - hb_codepoint_t mask = get_mask (); - - /* Help fuzzer avoid this function as much. */ - unsigned pop = (this+coverage).get_population (); - if (pop >= mask) - return; - - hb_set_t intersection; - (this+coverage).intersect_set (c->parent_active_glyphs (), intersection); - - /* In degenerate fuzzer-found fonts, but not real fonts, - * this table can keep adding new glyphs in each round of closure. - * Refuse to close-over, if it maps glyph range to overlapping range. */ - hb_codepoint_t min_before = intersection.get_min (); - hb_codepoint_t max_before = intersection.get_max (); - hb_codepoint_t min_after = (min_before + d) & mask; - hb_codepoint_t max_after = (max_before + d) & mask; - if (intersection.get_population () == max_before - min_before + 1 && - ((min_before <= min_after && min_after <= max_before) || - (min_before <= max_after && max_after <= max_before))) - return; + single_subst_depend (c, this+coverage, deltaGlyphID, get_mask ()); + } - + hb_iter (intersection) - | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; }) - | hb_sink (c->output) - ; + void closure (hb_closure_context_t *c) const + { + single_subst_closure (c, this+coverage, deltaGlyphID, get_mask ()); } void closure_lookups (hb_closure_lookups_context_t *c) const {} void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - hb_codepoint_t d = deltaGlyphID; - hb_codepoint_t mask = get_mask (); - - + hb_iter (this+coverage) - | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; }) - | hb_sink (c->output) - ; + single_subst_collect_glyphs (c, this+coverage, deltaGlyphID, get_mask ()); } const Coverage &get_coverage () const { return this+coverage; } @@ -109,7 +170,7 @@ struct SingleSubstFormat1_3 return 0; } - if (alternate_count && *alternate_count) + if (alternate_count && *alternate_count && alternate_glyphs) { hb_codepoint_t d = deltaGlyphID; hb_codepoint_t mask = get_mask (); @@ -186,28 +247,7 @@ struct SingleSubstFormat1_3 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; - - hb_codepoint_t d = deltaGlyphID; - hb_codepoint_t mask = get_mask (); - - hb_set_t intersection; - (this+coverage).intersect_set (glyphset, intersection); - - auto it = - + hb_iter (intersection) - | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) { - return hb_codepoint_pair_t (g, - (g + d) & mask); }) - | hb_filter (glyphset, hb_second) - | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t - { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) - ; - - bool ret = bool (it); - SingleSubst_serialize (c->serializer, it); - return_trace (ret); + return_trace (subset_single_subst (c, this+coverage, deltaGlyphID, get_mask ())); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh index 0d51d130fee..b1ba5ad7a63 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -12,15 +12,15 @@ struct SingleSubstFormat2_4 { protected: HBUINT16 format; /* Format identifier--format = 2 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - Array16Of + typename Types::template ArrayOf substitute; /* Array of substitute * GlyphIDs--ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (4 + Types::size, substitute); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + Types::HBUINT::static_size, substitute); bool sanitize (hb_sanitize_context_t *c) const { @@ -34,6 +34,31 @@ struct SingleSubstFormat2_4 bool may_have_non_1to1 () const { return false; } + void depend (hb_depend_context_t *c) const + { + auto &cov = this+coverage; + auto &glyph_set = c->parent_active_glyphs (); + + // Filter by active glyphs like closure does + if (substitute.len > glyph_set.get_population () * 4) + { + for (auto g : glyph_set) + { + unsigned i = cov.get_coverage (g); + if (i == NOT_COVERED || i >= substitute.len) + continue; + c->depend_data->add_gsub_lookup (g, c->lookup_index, substitute.arrayZ[i]); + } + + return; + } + + + hb_zip (cov, substitute) + | hb_filter (glyph_set, hb_first) + | hb_apply ([&] (const hb_codepoint_pair_t &_) { c->depend_data->add_gsub_lookup (_.first, c->lookup_index, _.second); }) + ; + } + void closure (hb_closure_context_t *c) const { auto &cov = this+coverage; @@ -89,7 +114,7 @@ struct SingleSubstFormat2_4 return 0; } - if (alternate_count && *alternate_count) + if (alternate_count && *alternate_count && alternate_glyphs) { glyph_id = substitute[index]; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookup.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookup.hh index 5796cc3be57..8f536ab21fe 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookup.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookup.hh @@ -24,7 +24,7 @@ struct SubstLookup : Lookup bool is_reverse () const { unsigned int type = get_type (); - if (unlikely (type == SubTable::Extension)) + if (unlikely (type == SubTable::Extension) && hb_barrier ()) return get_subtable (0).u.extension.is_reverse (); return lookup_type_is_reverse (type); } @@ -61,6 +61,12 @@ struct SubstLookup : Lookup return ret; } + void depend (hb_depend_context_t *c) const + { + c->set_recurse_func (dispatch_depend_recurse_func); + 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)) @@ -137,11 +143,12 @@ struct SubstLookup : Lookup return_trace (false); } + template bool serialize_alternate (hb_serialize_context_t *c, uint32_t lookup_props, - hb_sorted_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t alternate_len_list, - hb_array_t alternate_glyphs_list) + hb_array_t alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); @@ -159,13 +166,14 @@ struct SubstLookup : Lookup return_trace (false); } + template bool serialize_ligature (hb_serialize_context_t *c, uint32_t lookup_props, - hb_sorted_array_t first_glyphs, + hb_sorted_array_t first_glyphs, hb_array_t ligature_per_first_glyph_count_list, - hb_array_t ligatures_list, + hb_array_t ligatures_list, hb_array_t component_count_list, - hb_array_t component_list /* Starting from second for each ligature */) + hb_array_t component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false); @@ -189,6 +197,7 @@ struct SubstLookup : Lookup static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index); + static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index) { if (!c->should_visit_lookup (lookup_index)) @@ -204,6 +213,13 @@ struct SubstLookup : Lookup return ret; } + static inline hb_depend_context_t::return_t depend_glyphs_recurse_func (hb_depend_context_t *c, unsigned lookup_index, hb_bit_page_t *covered_seq_indices, unsigned seq_index, unsigned end_index); + + static inline hb_depend_context_t::return_t dispatch_depend_recurse_func (hb_depend_context_t *c, unsigned lookup_index, hb_bit_page_t *covered_seq_indices, unsigned seq_index, unsigned end_index) + { + return depend_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index); + } + template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { return Lookup::dispatch (c, std::forward (ds)...); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookupSubTable.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookupSubTable.hh index a525fba0399..c36f0d7bf15 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookupSubTable.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookupSubTable.hh @@ -50,14 +50,14 @@ struct SubstLookupSubTable { TRACE_DISPATCH (this, lookup_type); switch (lookup_type) { - case Single: return_trace (u.single.dispatch (c, std::forward (ds)...)); - case Multiple: return_trace (u.multiple.dispatch (c, std::forward (ds)...)); - case Alternate: return_trace (u.alternate.dispatch (c, std::forward (ds)...)); - case Ligature: return_trace (u.ligature.dispatch (c, std::forward (ds)...)); - case Context: return_trace (u.context.dispatch (c, std::forward (ds)...)); - case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward (ds)...)); - case Extension: return_trace (u.extension.dispatch (c, std::forward (ds)...)); - case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, std::forward (ds)...)); + case Single: hb_barrier (); return_trace (u.single.dispatch (c, std::forward (ds)...)); + case Multiple: hb_barrier (); return_trace (u.multiple.dispatch (c, std::forward (ds)...)); + case Alternate: hb_barrier (); return_trace (u.alternate.dispatch (c, std::forward (ds)...)); + case Ligature: hb_barrier (); return_trace (u.ligature.dispatch (c, std::forward (ds)...)); + case Context: hb_barrier (); return_trace (u.context.dispatch (c, std::forward (ds)...)); + case ChainContext: hb_barrier (); return_trace (u.chainContext.dispatch (c, std::forward (ds)...)); + case Extension: hb_barrier (); return_trace (u.extension.dispatch (c, std::forward (ds)...)); + case ReverseChainSingle: hb_barrier (); return_trace (u.reverseChainContextSingle.dispatch (c, std::forward (ds)...)); default: return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc index 792a7553d8f..da10b45a7ae 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc +++ b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc @@ -1,8 +1,13 @@ +#ifndef HB_OT_VAR_VARC_CC +#define HB_OT_VAR_VARC_CC +#ifdef HB_OT_VAR_VARC_CC /* Pacify -Wunused-macros. */ + #include "VARC.hh" #ifndef HB_NO_VAR_COMPOSITES #include "../../../hb-draw.hh" +#include "../../../hb-depend-data.hh" #include "../../../hb-ot-layout-common.hh" #include "../../../hb-ot-layout-gdef-table.hh" @@ -10,6 +15,200 @@ namespace OT { //namespace Var { +#define VARC_PROCESS_TRANSFORM_COMPONENTS \ + HB_STMT_START { \ + PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_X, translateX); \ + PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_Y, translateY); \ + PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_ROTATION, rotation); \ + PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_X, scaleX); \ + PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_Y, scaleY); \ + PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_X, skewX); \ + PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_Y, skewY); \ + PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_X, tCenterX); \ + PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_Y, tCenterY); \ + } HB_STMT_END + +bool +VarComponent::decompile_record (const VARC &varc, + hb_ubytes_t total_record, + hb_vector_t *axis_indices, + hb_vector_t *axis_values, + record_t *decoded, + int64_t *budget) +{ + const unsigned char *start = total_record.arrayZ; + const unsigned char *record = start; + const unsigned char *end = start + total_record.length; + + if (axis_indices) axis_indices->clear (); + if (axis_values) axis_values->clear (); + +#define READ_UINT32VAR(name) \ + HB_STMT_START { \ + if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return false; \ + hb_barrier (); \ + auto &varint = * (const HBUINT32VAR *) record; \ + unsigned size = varint.get_size (); \ + if (unlikely (unsigned (end - record) < size)) return false; \ + name = (uint32_t) varint; \ + record += size; \ + } HB_STMT_END +#define READ_UINT32VAR_FIELD(name, field) \ + HB_STMT_START { \ + decoded->field##_offset = record - start; \ + READ_UINT32VAR (name); \ + decoded->field##_size = record - start - decoded->field##_offset; \ + } HB_STMT_END + + READ_UINT32VAR (decoded->flags); + + decoded->gid_offset = record - start; + if (decoded->flags & (unsigned) flags_t::GID_IS_24BIT) + { + decoded->gid_size = HBGlyphID24::static_size; + if (unlikely (unsigned (end - record) < HBGlyphID24::static_size)) return false; + hb_barrier (); + decoded->gid = * (const HBGlyphID24 *) record; + record += HBGlyphID24::static_size; + } + else + { + decoded->gid_size = HBGlyphID16::static_size; + if (unlikely (unsigned (end - record) < HBGlyphID16::static_size)) return false; + hb_barrier (); + decoded->gid = * (const HBGlyphID16 *) record; + record += HBGlyphID16::static_size; + } + + if (decoded->flags & (unsigned) flags_t::HAVE_CONDITION) + READ_UINT32VAR_FIELD (decoded->condition_index, condition); + + if (decoded->flags & (unsigned) flags_t::HAVE_AXES) + { + READ_UINT32VAR_FIELD (decoded->axis_indices_index, axis_indices); + unsigned axis_count; + if (axis_indices) + { + axis_indices->extend ((&varc+varc.axisIndicesList)[decoded->axis_indices_index]); + if (unlikely (axis_indices->in_error ())) return false; + axis_count = axis_indices->length; + } + else + axis_count = hb_len ((&varc+varc.axisIndicesList)[decoded->axis_indices_index]); + if (unlikely (budget && axis_count && + !hb_budget_spend (*budget, HB_BUDGET_1, axis_count))) + return false; + if (axis_values) + { + if (unlikely (!axis_values->resize (axis_count))) return false; + const HBUINT8 *p = (const HBUINT8 *) record; + if (unlikely (!TupleValues::decompile (p, *axis_values, + (const HBUINT8 *) end))) + return false; + record = (const unsigned char *) p; + } + else if (unlikely (!TupleValues::skip (record, end, axis_count))) + return false; + } + + decoded->axis_values_var_idx = VarIdx::NO_VARIATION; + if (decoded->flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) + READ_UINT32VAR_FIELD (decoded->axis_values_var_idx, axis_values_var); + + decoded->transform_var_idx = VarIdx::NO_VARIATION; + if (decoded->flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION) + READ_UINT32VAR_FIELD (decoded->transform_var_idx, transform_var); + +#define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ + if (decoded->flags & (unsigned) flags_t::flag) \ + { \ + static_assert (type::static_size == HBINT16::static_size, ""); \ + if (unlikely (unsigned (end - record) < HBINT16::static_size)) return false; \ + hb_barrier (); \ + decoded->transform.name = * (const HBINT16 *) record; \ + record += HBINT16::static_size; \ + } + VARC_PROCESS_TRANSFORM_COMPONENTS; +#undef PROCESS_TRANSFORM_COMPONENT + + unsigned reserved = decoded->flags & (unsigned) flags_t::RESERVED_MASK; + while (reserved) + { + uint32_t discard HB_UNUSED; + READ_UINT32VAR (discard); + reserved &= reserved - 1; + } + + decoded->size = record - start; +#undef READ_UINT32VAR_FIELD +#undef READ_UINT32VAR + return true; +} + +bool +VARC::closure_glyphs (hb_set_t *glyphset) const +{ + if (unlikely (glyphset->in_error ())) + return false; + + hb_set_t pending = *glyphset; + if (unlikely (pending.in_error ())) + return false; + + while (pending) + { + hb_codepoint_t gid = pending.get_min (); + pending.del (gid); + + unsigned index = (this+coverage).get_coverage (gid); + if (index == NOT_COVERED) continue; + + hb_ubytes_t record = (this+glyphRecords)[index]; + while (record) + { + VarComponent::record_t component; + if (unlikely (!VarComponent::decompile_record (*this, record, + nullptr, nullptr, &component))) + return false; + if (!glyphset->has (component.gid)) + { + glyphset->add (component.gid); + if (unlikely (glyphset->in_error ())) + return false; + pending.add (component.gid); + if (unlikely (pending.in_error ())) + return false; + } + record = record.sub_array (component.size); + } + } + return true; +} + +void +VARC::depend (hb_depend_data_builder_t *depend_data) const +{ + const CFF2Index &records = this+glyphRecords; + for (auto _ : + hb_zip (this+coverage, + hb_range ((unsigned) records.count))) + { + hb_codepoint_t gid = _.first; + hb_ubytes_t record = records[_.second]; + while (record) + { + VarComponent::record_t component; + if (unlikely (!VarComponent::decompile_record (*this, record, + nullptr, nullptr, &component))) + { + depend_data->fail (); + return; + } + depend_data->add_depend (gid, tableTag, component.gid); + record = record.sub_array (component.size); + } + } +} + #ifndef HB_NO_DRAW @@ -19,6 +218,7 @@ struct hb_transforming_pen_context_t hb_draw_funcs_t *dfuncs; void *data; hb_draw_state_t *st; + int64_t *budget_remaining; }; static void @@ -94,6 +294,12 @@ hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, c->dfuncs->close_path (c->data, *c->st); } +static int64_t * +hb_transforming_pen_get_budget_remaining (hb_draw_funcs_t *, void *draw_data, void *) +{ + return ((hb_transforming_pen_context_t *) draw_data)->budget_remaining; +} + static inline void free_static_transforming_pen_funcs (); static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t @@ -107,6 +313,7 @@ static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loade hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr); hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr); hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr); + hb_draw_funcs_set_get_budget_remaining_func (funcs, hb_transforming_pen_get_budget_remaining, nullptr, nullptr); hb_draw_funcs_make_immutable (funcs); @@ -136,81 +343,45 @@ VarComponent::get_path_at (const hb_varc_context_t &c, hb_ubytes_t total_record, hb_scalar_cache_t *cache) const { - const unsigned char *end = total_record.arrayZ + total_record.length; - const unsigned char *record = total_record.arrayZ; + if (unlikely (!hb_budget_spend (c.budget, HB_BUDGET_4))) + return hb_ubytes_t (); + const unsigned char *end = total_record.arrayZ + total_record.length; auto &VARC = *c.font->face->table.VARC->table; auto &varStore = &VARC+VARC.varStore; -#define READ_UINT32VAR(name) \ - HB_STMT_START { \ - if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \ - hb_barrier (); \ - auto &varint = * (const HBUINT32VAR *) record; \ - unsigned size = varint.get_size (); \ - if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \ - name = (uint32_t) varint; \ - record += size; \ - } HB_STMT_END - - uint32_t flags; - READ_UINT32VAR (flags); + auto &axisIndices = c.scratch.axisIndices; + auto &axisValues = c.scratch.axisValues; + record_t component; + if (unlikely (!decompile_record (VARC, total_record, + &axisIndices, &axisValues, &component, + &c.budget))) + return hb_ubytes_t (); - // gid - - hb_codepoint_t gid = 0; - if (flags & (unsigned) flags_t::GID_IS_24BIT) - { - if (unlikely (unsigned (end - record) < HBGlyphID24::static_size)) - return hb_ubytes_t (); - hb_barrier (); - gid = * (const HBGlyphID24 *) record; - record += HBGlyphID24::static_size; - } - else - { - if (unlikely (unsigned (end - record) < HBGlyphID16::static_size)) - return hb_ubytes_t (); - hb_barrier (); - gid = * (const HBGlyphID16 *) record; - record += HBGlyphID16::static_size; - } + uint32_t flags = component.flags; + hb_codepoint_t gid = component.gid; + const unsigned char *record = total_record.arrayZ + component.size; // Condition bool show = true; if (flags & (unsigned) flags_t::HAVE_CONDITION) { - unsigned conditionIndex; - READ_UINT32VAR (conditionIndex); - const auto &condition = (&VARC+VARC.conditionList)[conditionIndex]; + const auto &condition = (&VARC+VARC.conditionList)[component.condition_index]; auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache); show = condition.evaluate (coords.arrayZ, coords.length, &instancer); } // Axis values - auto &axisIndices = c.scratch.axisIndices; - axisIndices.clear (); - auto &axisValues = c.scratch.axisValues; - axisValues.clear (); - if (flags & (unsigned) flags_t::HAVE_AXES) - { - unsigned axisIndicesIndex; - READ_UINT32VAR (axisIndicesIndex); - axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]); - axisValues.resize (axisIndices.length); - const HBUINT8 *p = (const HBUINT8 *) record; - TupleValues::decompile (p, axisValues, (const HBUINT8 *) end); - record = (const unsigned char *) p; - } - // Apply variations if any - if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) + if ((flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) && + show && !axisValues.in_error ()) { - uint32_t axisValuesVarIdx; - READ_UINT32VAR (axisValuesVarIdx); - if (show && coords && !axisValues.in_error ()) - varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache); + if (unlikely (!hb_budget_spend (c.budget, axisValues.length, + coords.length))) + return hb_ubytes_t (); + varStore.get_delta (component.axis_values_var_idx, coords, + axisValues.as_array (), cache); } auto component_coords = coords; @@ -220,77 +391,41 @@ VarComponent::get_path_at (const hb_varc_context_t &c, coords.length > HB_VAR_COMPOSITE_MAX_AXES) component_coords = hb_array (c.font->coords, c.font->num_coords); - // Transform - - uint32_t transformVarIdx = VarIdx::NO_VARIATION; - if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION) - READ_UINT32VAR (transformVarIdx); - -#define PROCESS_TRANSFORM_COMPONENTS \ - HB_STMT_START { \ - PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_X, translateX); \ - PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_Y, translateY); \ - PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_ROTATION, rotation); \ - PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_X, scaleX); \ - PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_Y, scaleY); \ - PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_X, skewX); \ - PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_Y, skewY); \ - PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_X, tCenterX); \ - PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_Y, tCenterY); \ - } HB_STMT_END - - hb_transform_decomposed_t<> transform; - - // Read transform components -#define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ - if (flags & (unsigned) flags_t::flag) \ - { \ - static_assert (type::static_size == HBINT16::static_size, ""); \ - if (unlikely (unsigned (end - record) < HBINT16::static_size)) \ - return hb_ubytes_t (); \ - hb_barrier (); \ - transform.name = * (const HBINT16 *) record; \ - record += HBINT16::static_size; \ - } - PROCESS_TRANSFORM_COMPONENTS; -#undef PROCESS_TRANSFORM_COMPONENT - - // Read reserved records - unsigned i = flags & (unsigned) flags_t::RESERVED_MASK; - while (i) - { - HB_UNUSED uint32_t discard; - READ_UINT32VAR (discard); - i &= i - 1; - } - - /* Parsing is over now. */ + uint32_t transformVarIdx = component.transform_var_idx; + hb_transform_decomposed_t<> transform = component.transform; if (show) { // Only use coord_setter if there's actually any axis overrides. + if (unlikely (axisIndices && + !hb_budget_spend (c.budget, HB_BUDGET_1, + component_coords.length))) + return hb_ubytes_t (); coord_setter_t coord_setter (axisIndices ? component_coords : hb_array ()); for (unsigned i = 0; i < axisIndices.length; i++) - coord_setter[axisIndices[i]] = roundf (axisValues[i]); + coord_setter[axisIndices[i]] = hb_clamp_to (round (axisValues[i])); if (axisIndices) component_coords = coord_setter.get_coords (); // Apply transform variations if any - if (transformVarIdx != VarIdx::NO_VARIATION && coords) + if (transformVarIdx != VarIdx::NO_VARIATION) { - float transformValues[9]; + double transformValues[9]; unsigned numTransformValues = 0; #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ if (flags & (unsigned) flags_t::flag) \ - transformValues[numTransformValues++] = transform.name; - PROCESS_TRANSFORM_COMPONENTS; + transformValues[numTransformValues++] = (double) transform.name; + VARC_PROCESS_TRANSFORM_COMPONENTS; #undef PROCESS_TRANSFORM_COMPONENT + if (unlikely (!hb_budget_spend (c.budget, numTransformValues, + coords.length))) + return hb_ubytes_t (); varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache); numTransformValues = 0; #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ if (flags & (unsigned) flags_t::flag) \ - transform.name = transformValues[numTransformValues++]; - PROCESS_TRANSFORM_COMPONENTS; + transform.name = (float) transformValues[numTransformValues++]; + VARC_PROCESS_TRANSFORM_COMPONENTS; #undef PROCESS_TRANSFORM_COMPONENT } @@ -298,7 +433,7 @@ VarComponent::get_path_at (const hb_varc_context_t &c, #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ if (shift && (flags & (unsigned) flags_t::flag)) \ transform.name *= 1.f / (1 << shift); - PROCESS_TRANSFORM_COMPONENTS; + VARC_PROCESS_TRANSFORM_COMPONENTS; #undef PROCESS_TRANSFORM_COMPONENT if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y)) @@ -321,9 +456,6 @@ VarComponent::get_path_at (const hb_varc_context_t &c, c.depth_left++; } -#undef PROCESS_TRANSFORM_COMPONENTS -#undef READ_UINT32VAR - return hb_ubytes_t (record, end - record); } @@ -343,6 +475,10 @@ VARC::get_path_at (const hb_varc_context_t &c, { if (c.draw_session) { + /* Out of budget: draw nothing, but signal success so remaining + * leaves are skipped instead of falling back per-glyph. */ + if (unlikely (!hb_budget_spend (c.budget, HB_BUDGET_1))) return true; + hb_transform_t<> leaf_transform = transform; leaf_transform.x0 *= c.font->x_multf; leaf_transform.y0 *= c.font->y_multf; @@ -352,24 +488,27 @@ VARC::get_path_at (const hb_varc_context_t &c, hb_transforming_pen_context_t context {leaf_transform, c.draw_session->funcs, c.draw_session->draw_data, - &c.draw_session->st}; + &c.draw_session->st, + &c.budget}; hb_draw_session_t transformer_session {transformer_funcs, &context}; hb_draw_session_t &shape_draw_session = leaf_transform.is_identity () ? *c.draw_session : transformer_session; - if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true; + if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch, nullptr, &shape_draw_session.get_budget ())) return true; #ifndef HB_NO_CFF - if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true; - if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) return true; // Doesn't have variations + if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords, &shape_draw_session.get_budget ())) return true; + if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session, &shape_draw_session.get_budget ())) return true; // Doesn't have variations #endif return false; } else if (c.extents) { + if (unlikely (!hb_budget_spend (c.budget, HB_BUDGET_1))) return true; + hb_glyph_extents_t glyph_extents; - if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords)) + if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords, &c.budget)) #ifndef HB_NO_CFF - if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords)) - if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations + if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords, &c.budget)) + if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents, &c.budget)) // Doesn't have variations #endif return false; @@ -415,7 +554,12 @@ VARC::get_path_at (const hb_varc_context_t &c, #endif +#undef VARC_PROCESS_TRANSFORM_COMPONENTS + //} // namespace Var } // namespace OT #endif + +#endif /* HB_OT_VAR_VARC_CC (pacify clang) */ +#endif /* HB_OT_VAR_VARC_CC */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh index 6b40f044556..ad8cf473ef3 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh @@ -10,6 +10,8 @@ #include "coord-setter.hh" +struct hb_depend_data_builder_t; + namespace OT { //namespace Var { @@ -24,7 +26,7 @@ namespace OT { struct hb_varc_scratch_t { hb_vector_t axisIndices; - hb_vector_t axisValues; + hb_vector_t axisValues; hb_glyf_scratch_t glyf_scratch; }; @@ -36,9 +38,14 @@ struct hb_varc_context_t mutable hb_decycler_t decycler; mutable signed edges_left; mutable signed depth_left; + /* Renderer-owned live budget, shared by VARC record processing and + * every leaf loaded from glyf/CFF/CFF2. */ + int64_t &budget; hb_varc_scratch_t &scratch; }; +struct VARC; + struct VarComponent { enum class flags_t : uint32_t @@ -61,6 +68,28 @@ struct VarComponent RESERVED_MASK = ~((1u << 15) - 1), }; + struct record_t + { + uint32_t flags; + hb_codepoint_t gid; + unsigned gid_offset; + unsigned gid_size; + unsigned condition_index; + unsigned condition_offset; + unsigned condition_size; + unsigned axis_indices_index; + unsigned axis_indices_offset; + unsigned axis_indices_size; + uint32_t axis_values_var_idx; + unsigned axis_values_var_offset; + unsigned axis_values_var_size; + uint32_t transform_var_idx; + unsigned transform_var_offset; + unsigned transform_var_size; + hb_transform_decomposed_t<> transform; + unsigned size; + }; + HB_INTERNAL hb_ubytes_t get_path_at (const hb_varc_context_t &c, hb_codepoint_t parent_gid, @@ -68,6 +97,13 @@ struct VarComponent hb_transform_t<> transform, hb_ubytes_t record, hb_scalar_cache_t *cache = nullptr) const; + + HB_INTERNAL static bool decompile_record (const VARC &varc, + hb_ubytes_t record, + hb_vector_t *axis_indices, + hb_vector_t *axis_values, + record_t *decoded /* OUT */, + int64_t *budget = nullptr); }; struct VarCompositeGlyph @@ -108,18 +144,24 @@ struct VARC hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID, hb_scalar_cache_t *parent_cache = nullptr) const; + HB_INTERNAL bool closure_glyphs (hb_set_t *glyphset) const; + HB_INTERNAL void depend (hb_depend_data_builder_t *depend_data) const; + HB_INTERNAL bool subset (hb_subset_context_t *c) const; + bool get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_varc_scratch_t &scratch) const { + int64_t &budget = draw_session.get_budget (); hb_varc_context_t c {font, &draw_session, nullptr, hb_decycler_t {}, HB_MAX_GRAPH_EDGE_COUNT, HB_MAX_NESTING_LEVEL, + budget, scratch}; return get_path_at (c, gid, @@ -132,12 +174,14 @@ struct VARC hb_extents_t<> *extents, hb_varc_scratch_t &scratch) const { + int64_t budget = HB_BUDGET_GLYPH; hb_varc_context_t c {font, nullptr, extents, hb_decycler_t {}, HB_MAX_GRAPH_EDGE_COUNT, HB_MAX_NESTING_LEVEL, + budget, scratch}; return get_path_at (c, gid, @@ -177,6 +221,8 @@ struct VARC table.destroy (); } + bool has_data () const { return table->has_data (); } + bool get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const { @@ -189,6 +235,19 @@ struct VARC return ret; } + bool closure_glyphs (hb_set_t *glyphset) const + { + if (table->has_data ()) + return table->closure_glyphs (glyphset); + return true; + } + + void depend (hb_depend_data_builder_t *depend_data) const + { + if (table->has_data ()) + table->depend (depend_data); + } + bool get_extents (hb_font_t *font, hb_codepoint_t gid, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh index 7243e180101..89dbc35a498 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh @@ -33,12 +33,12 @@ struct CompositeGlyphRecord }; public: - size_t get_size () const + size_t get_size (bool extended) const { unsigned int size = min_size; /* glyphIndex is 24bit instead of 16bit */ #ifndef HB_NO_BEYOND_64K - if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size; + if (extended && (flags & GID_IS_24BIT)) size += HBGlyphID24::static_size - HBGlyphID16::static_size; #endif /* arg1 and 2 are int16 */ if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; @@ -66,11 +66,11 @@ struct CompositeGlyphRecord 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 + void get_anchor_points (unsigned int &point1, unsigned int &point2, bool extended) const { const auto *p = &StructAfter (flags); #ifndef HB_NO_BEYOND_64K - if (flags & GID_IS_24BIT) + if (extended && (flags & GID_IS_24BIT)) p += HBGlyphID24::static_size; else #endif @@ -138,28 +138,29 @@ struct CompositeGlyphRecord } } - bool get_points (contour_point_vector_t &points) const + bool get_points (contour_point_vector_t &points, bool extended) const { float matrix[4]; contour_point_t trans; - get_transformation (matrix, trans); + get_transformation (matrix, trans, extended); if (unlikely (!points.alloc (points.length + 1 + 4))) return false; // For phantom points points.push (trans); return true; } unsigned compile_with_point (const contour_point_t &point, - char *out) const + char *out, + bool extended) const { const HBINT8 *p = &StructAfter (flags); #ifndef HB_NO_BEYOND_64K - if (flags & GID_IS_24BIT) + if (extended && (flags & GID_IS_24BIT)) p += HBGlyphID24::static_size; else #endif p += HBGlyphID16::static_size; - unsigned len = get_size (); + unsigned len = get_size (extended); unsigned len_before_val = (const char *)p - (const char *)this; if (flags & ARG_1_AND_2_ARE_WORDS) { @@ -213,14 +214,14 @@ struct CompositeGlyphRecord { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } public: - bool get_transformation (float (&matrix)[4], contour_point_t &trans) const + bool get_transformation (float (&matrix)[4], contour_point_t &trans, bool extended) const { matrix[0] = matrix[3] = 1.f; matrix[1] = matrix[2] = 0.f; const auto *p = &StructAfter (flags); #ifndef HB_NO_BEYOND_64K - if (flags & GID_IS_24BIT) + if (extended && (flags & GID_IS_24BIT)) p += HBGlyphID24::static_size; else #endif @@ -268,19 +269,19 @@ struct CompositeGlyphRecord return tx || ty; } - hb_codepoint_t get_gid () const + hb_codepoint_t get_gid (bool extended) const { #ifndef HB_NO_BEYOND_64K - if (flags & GID_IS_24BIT) + if (extended && (flags & GID_IS_24BIT)) return StructAfter (flags); else #endif return StructAfter (flags); } - void set_gid (hb_codepoint_t gid) + void set_gid (hb_codepoint_t gid, bool extended) { #ifndef HB_NO_BEYOND_64K - if (flags & GID_IS_24BIT) + if (extended && (flags & GID_IS_24BIT)) StructAfter (flags) = gid; else #endif @@ -291,19 +292,19 @@ struct CompositeGlyphRecord #ifndef HB_NO_BEYOND_64K void lower_gid_24_to_16 () { - hb_codepoint_t gid = get_gid (); + hb_codepoint_t gid = get_gid (true); if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu) return; /* Lower the flag and move the rest of the struct down. */ - unsigned size = get_size (); + unsigned size = get_size (true); char *end = (char *) this + size; char *p = &StructAfter (flags); p += HBGlyphID24::static_size; flags = flags & ~GID_IS_24BIT; - set_gid (gid); + set_gid (gid, true); memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p); } @@ -322,11 +323,12 @@ struct CompositeGlyph { const GlyphHeader &header; hb_bytes_t bytes; - CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : - header (header_), bytes (bytes_) {} + bool extended; + CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_, bool extended_) : + header (header_), bytes (bytes_), extended (extended_) {} composite_iter_t iter () const - { return composite_iter_t (bytes, &StructAfter (header)); } + { return composite_iter_t (bytes, &StructAfter (header), extended); } unsigned int instructions_length (hb_bytes_t bytes) const { @@ -338,7 +340,7 @@ struct CompositeGlyph if (unlikely (!last)) return 0; if (last->has_instructions ()) - start = (char *) last - &bytes + last->get_size (); + start = (char *) last - &bytes + last->get_size (extended); if (unlikely (start > end)) return 0; return end - start; } @@ -386,7 +388,7 @@ struct CompositeGlyph if (unlikely (!o)) return false; const CompositeGlyphRecord *c = reinterpret_cast (source_bytes.arrayZ + GlyphHeader::static_size); - auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c); + auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c, extended); char *p = o; unsigned i = 0, source_comp_len = 0; @@ -398,7 +400,7 @@ struct CompositeGlyph return false; } - unsigned comp_len = component.get_size (); + unsigned comp_len = component.get_size (extended); if (component.is_anchored ()) { hb_memcpy (p, &component, comp_len); @@ -406,7 +408,7 @@ struct CompositeGlyph } else { - unsigned new_len = component.compile_with_point (points_with_deltas[i], p); + unsigned new_len = component.compile_with_point (points_with_deltas[i], p, extended); p += new_len; } i++; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh index 432b4dfe464..f6c34bb1bfb 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh @@ -37,13 +37,13 @@ struct Glyph composite_iter_t get_composite_iterator () const { if (type != COMPOSITE) return composite_iter_t (); - return CompositeGlyph (*header, bytes).iter (); + return CompositeGlyph (*header, bytes, extended).iter (); } const hb_bytes_t trim_padding () const { switch (type) { - case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); + case COMPOSITE: return CompositeGlyph (*header, bytes, extended).trim_padding (); case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); case EMPTY: return bytes; default: return bytes; @@ -53,16 +53,19 @@ struct Glyph void drop_hints () { switch (type) { - case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; + case COMPOSITE: CompositeGlyph (*header, bytes, extended).drop_hints (); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; - case EMPTY: return; + case EMPTY: + if (bytes.length >= GlyphHeader::static_size) + SimpleGlyph (*header, bytes).drop_hints (); + return; } } void set_overlaps_flag () { switch (type) { - case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; + case COMPOSITE: CompositeGlyph (*header, bytes, extended).set_overlaps_flag (); return; case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; case EMPTY: return; } @@ -71,9 +74,15 @@ struct Glyph 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 COMPOSITE: CompositeGlyph (*header, bytes, extended).drop_hints_bytes (dest_start); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; - case EMPTY: return; + case EMPTY: + dest_start = bytes; + dest_end = hb_bytes_t (); + if (bytes.length >= GlyphHeader::static_size && + SimpleGlyph (*header, bytes).has_instructions_length ()) + SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); + return; } } @@ -85,13 +94,13 @@ struct Glyph { switch (type) { case SIMPLE: - if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points))) + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, extended))) return false; break; case COMPOSITE: { for (auto &item : get_composite_iterator ()) - if (unlikely (!item.get_points (points))) return false; + if (unlikely (!item.get_points (points, extended))) return false; break; } case EMPTY: @@ -269,9 +278,9 @@ struct Glyph switch (type) { case COMPOSITE: - if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, - points_with_deltas, - dest_end)) + if (!CompositeGlyph (*header, bytes, extended).compile_bytes_with_deltas (dest_start, + points_with_deltas, + dest_end)) return false; break; case SIMPLE: @@ -281,10 +290,25 @@ struct Glyph return false; break; case EMPTY: - /* set empty bytes for empty glyph - * do not use source glyph's pointers */ dest_start = hb_bytes_t (); dest_end = hb_bytes_t (); + /* Zero-contour glyphs may carry instructions for phantom points. + * Copy them into owned memory like the other compiled glyphs. */ + if (!(plan->flags & HB_SUBSET_FLAGS_NO_HINTING) && + bytes.length >= GlyphHeader::static_size && + header->numberOfContours == 0) + { + SimpleGlyph simple (*header, bytes); + unsigned length = simple.instructions_length (); + if (length) + { + length = simple.length (length); + char *p = (char *) hb_malloc (length); + if (unlikely (!p)) return false; + hb_memcpy (p, bytes.arrayZ, length); + dest_start = hb_bytes_t (p, length); + } + } break; } } @@ -314,7 +338,8 @@ struct Glyph hb_array_t coords = hb_array_t (), hb_scalar_cache_t *gvar_cache = nullptr, unsigned int depth = 0, - unsigned *edge_count = nullptr) const + unsigned *edge_count = nullptr, + int64_t *budget = nullptr) const { if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; unsigned stack_edge_count = 0; @@ -322,6 +347,10 @@ struct Glyph if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false; (*edge_count)++; + int64_t stack_budget = HB_BUDGET_GLYPH; + if (!budget) budget = &stack_budget; + if (unlikely (!hb_budget_spend (*budget, HB_BUDGET_16))) return false; + if (head_maxp_info) { head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); @@ -339,13 +368,22 @@ struct Glyph head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours); if (depth > 0 && composite_contours) *composite_contours += (unsigned) header->numberOfContours; - if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only))) + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, extended, phantom_only, budget))) return false; break; case COMPOSITE: { for (auto &item : get_composite_iterator ()) - if (unlikely (!item.get_points (points))) return false; + { + /* Preparing a component is a traversal step, even if cycle + * detection later skips its child glyph. */ + if (unlikely (!hb_budget_spend (*budget, HB_BUDGET_16) || + !item.get_points (points, extended))) + { + points.resize (old_length); + return false; + } + } break; } case EMPTY: @@ -382,25 +420,13 @@ struct Glyph #ifndef HB_NO_VAR if (hb_any (coords)) { -#ifndef HB_NO_BEYOND_64K - if (glyf_accelerator.GVAR->has_data ()) - { - if (!glyf_accelerator.GVAR->apply_deltas_to_points (gid, - coords, - points.as_array ().sub_array (old_length), - scratch, - gvar_cache, - phantom_only && type == SIMPLE)) - return false; - } - else -#endif if (!glyf_accelerator.gvar->apply_deltas_to_points (gid, coords, points.as_array ().sub_array (old_length), scratch, gvar_cache, - phantom_only && type == SIMPLE)) + phantom_only && type == SIMPLE, + budget)) return false; } #endif @@ -427,7 +453,7 @@ struct Glyph unsigned int comp_index = 0; for (auto &item : get_composite_iterator ()) { - hb_codepoint_t item_gid = item.get_gid (); + hb_codepoint_t item_gid = item.get_gid (extended); if (unlikely (!decycler_node.visit (item_gid))) { @@ -452,7 +478,8 @@ struct Glyph coords, gvar_cache, depth + 1, - edge_count))) + edge_count, + budget))) { points.resize (old_length); return false; @@ -468,11 +495,20 @@ struct Glyph for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; + /* Each composite level transforms the whole subtree below it; + * charge that work here so deep nesting is bounded by the budget + * rather than by the per-draw point cap alone. */ + if (unlikely (!hb_budget_spend (*budget, HB_BUDGET_1, comp_points.length))) + { + points.resize (old_length); + return false; + } + if (comp_points) // Empty in case of phantom_only { float matrix[4]; contour_point_t default_trans; - item.get_transformation (matrix, default_trans); + item.get_transformation (matrix, default_trans, extended); /* Apply component transformation & translation (with deltas applied) */ item.transform_points (comp_points, matrix, points[old_length + comp_index]); @@ -481,7 +517,7 @@ struct Glyph if (item.is_anchored () && !phantom_only) { unsigned int p1, p2; - item.get_anchor_points (p1, p2); + item.get_anchor_points (p1, p2, extended); if (likely (p1 < all_points.length && p2 < comp_points.length)) { contour_point_t delta; @@ -548,17 +584,21 @@ struct Glyph hb_bytes_t get_bytes () const { return bytes; } glyph_type_t get_type () const { return type; } const GlyphHeader *get_header () const { return header; } + bool is_extended () const { return extended; } Glyph () : bytes (), header (bytes.as ()), gid (-1), - type(EMPTY) + type(EMPTY), + extended (false) {} Glyph (hb_bytes_t bytes_, - hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_), - header (bytes.as ()), - gid (gid_) + hb_codepoint_t gid_, + bool extended_) : bytes (bytes_), + header (bytes.as ()), + gid (gid_), + extended (extended_) { int num_contours = header->numberOfContours; if (unlikely (num_contours == 0)) type = EMPTY; @@ -572,6 +612,7 @@ struct Glyph const GlyphHeader *header; hb_codepoint_t gid; glyph_type_t type; + bool extended; }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh index d94a2f3ddfe..cdb3136e097 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh @@ -125,7 +125,8 @@ struct SimpleGlyph static bool read_flags (const HBUINT8 *&p /* IN/OUT */, hb_array_t points_ /* IN/OUT */, - const HBUINT8 *end) + const HBUINT8 *end, + bool extended) { auto *points = points_.arrayZ; unsigned count = points_.length; @@ -133,6 +134,8 @@ struct SimpleGlyph { if (unlikely (p + 1 > end)) return false; uint8_t flag = *p++; + if (!extended) + flag &= ~FLAG_CUBIC; points[i++].flag = flag; if (flag & FLAG_REPEAT) { @@ -178,7 +181,9 @@ struct SimpleGlyph } bool get_contour_points (contour_point_vector_t &points /* OUT */, - bool phantom_only = false) const + bool extended, + bool phantom_only = false, + int64_t *budget = nullptr) const { const HBUINT16 *endPtsOfContours = &StructAfter (header); int num_contours = header.numberOfContours; @@ -188,6 +193,10 @@ struct SimpleGlyph unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; if (unlikely (num_points < (unsigned) num_contours)) return false; + /* Charge before allocating and reading, so that glyphs that fail + * later (truncated data, composite caps) still pay for this work. */ + if (budget && unlikely (!hb_budget_spend (*budget, HB_BUDGET_1, num_points))) return false; + unsigned old_length = points.length; points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy if (unlikely (!points.resize_dirty (points.length + num_points))) return false; @@ -208,7 +217,7 @@ struct SimpleGlyph if (unlikely (p >= end)) return false; /* Read x & y coordinates */ - return read_flags (p, points_, end) + return read_flags (p, points_, end, extended) && read_points (p, points_, end, &contour_point_t::x, FLAG_X_SHORT, FLAG_X_SAME) && read_points (p, points_, end, &contour_point_t::y, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh index 643b0226492..2f3368f8375 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh @@ -46,63 +46,68 @@ struct SubsetGlyph if (unlikely (!dest_glyph.length)) return_trace (true); + bool extended = source_glyph.is_extended (); + /* update components gids. */ - for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) + for (auto &_ : Glyph (dest_glyph, old_gid, extended).get_composite_iterator ()) { hb_codepoint_t new_gid; - if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) - const_cast (_).set_gid (new_gid); + if (plan->new_gid_for_old_gid (_.get_gid (extended), &new_gid)) + const_cast (_).set_gid (new_gid, extended); } #ifndef HB_NO_BEYOND_64K - auto it = Glyph (dest_glyph).get_composite_iterator (); - if (it) + if (extended) { - /* lower GID24 to GID16 in components if possible. */ - char *p = it ? (char *) &*it : nullptr; - char *q = p; - const char *end = dest_glyph.arrayZ + dest_glyph.length; - while (it) + auto it = Glyph (dest_glyph, old_gid, extended).get_composite_iterator (); + if (it) { - auto &rec = const_cast (*it); - ++it; - - q += rec.get_size (); - - rec.lower_gid_24_to_16 (); - - unsigned size = rec.get_size (); - - memmove (p, &rec, size); - - p += size; + /* lower GID24 to GID16 in components if possible. */ + char *p = it ? (char *) &*it : nullptr; + char *q = p; + const char *end = dest_glyph.arrayZ + dest_glyph.length; + while (it) + { + auto &rec = const_cast (*it); + ++it; + + q += rec.get_size (extended); + + rec.lower_gid_24_to_16 (); + + unsigned size = rec.get_size (extended); + + memmove (p, &rec, size); + + p += size; + } + memmove (p, q, end - q); + p += end - q; + + /* We want to shorten the glyph, but we can't do that without + * updating the length in the loca table, which is already + * written out :-(. So we just fill the rest of the glyph with + * harmless instructions, since that's what they will be + * interpreted as. + * + * Should move the lowering to _populate_subset_glyphs() to + * fix this issue. */ + + hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p); + p += end - p; + dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ); + + // TODO: Padding; & trim serialized bytes. + // TODO: Update length in loca. Ugh. } - memmove (p, q, end - q); - p += end - q; - - /* We want to shorten the glyph, but we can't do that without - * updating the length in the loca table, which is already - * written out :-(. So we just fill the rest of the glyph with - * harmless instructions, since that's what they will be - * interpreted as. - * - * Should move the lowering to _populate_subset_glyphs() to - * fix this issue. */ - - hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p); - p += end - p; - dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ); - - // TODO: Padding; & trim serialized bytes. - // TODO: Update length in loca. Ugh. } #endif if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - Glyph (dest_glyph).drop_hints (); + Glyph (dest_glyph, old_gid, extended).drop_hints (); if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG) - Glyph (dest_glyph).set_overlaps_flag (); + Glyph (dest_glyph, old_gid, extended).set_overlaps_flag (); return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/composite-iter.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/composite-iter.hh index 21e6b4ee962..e6e74630b8d 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/composite-iter.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/composite-iter.hh @@ -14,13 +14,13 @@ struct composite_iter_tmpl : hb_iter_with_fallback_t { typedef const CompositeGlyphRecord *__item_t__; - composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_) : - glyph (glyph_), current (nullptr), current_size (0) + composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_, bool extended_) : + glyph (glyph_), current (nullptr), current_size (0), extended (extended_) { set_current (current_); } - composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} + composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0), extended (false) {} const CompositeGlyphRecord & __item__ () const { return *current; } bool __more__ () const { return current; } @@ -43,7 +43,7 @@ struct composite_iter_tmpl : hb_iter_with_fallback_tget_size (); + unsigned size = current_->get_size (extended); if (!glyph.check_range (current_, size)) { current = nullptr; @@ -59,6 +59,7 @@ struct composite_iter_tmpl : hb_iter_with_fallback_tplan->num_output_glyphs () + 1; unsigned entry_size = use_short_loca ? 2 : 4; - char *loca_prime_data = (char *) hb_malloc (entry_size * num_offsets); + char *loca_prime_data = (char *) hb_malloc2 (num_offsets, entry_size); if (unlikely (!loca_prime_data)) return false; @@ -112,7 +113,7 @@ _add_loca_and_head (hb_subset_context_t *c, loca_prime_data, hb_free); - bool result = c->plan->add_table (HB_OT_TAG_loca, loca_blob) + bool result = c->plan->add_table (extended ? HB_OT_TAG_LOCA : HB_OT_TAG_loca, loca_blob) && _add_head_and_set_loca_version (c->plan, use_short_loca); hb_blob_destroy (loca_blob); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh index 9f5f267f96a..0957f30a260 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh @@ -3,6 +3,7 @@ #include "../../hb-open-type.hh" +#include "../../hb-depend-data.hh" #include "../../hb-ot-head-table.hh" #include "../../hb-ot-hmtx-table.hh" #include "../../hb-ot-var-gvar-table.hh" @@ -24,6 +25,7 @@ namespace OT { * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf */ #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') +#define HB_OT_TAG_GLYF HB_TAG('G','L','Y','F') struct glyf { @@ -37,6 +39,20 @@ struct glyf return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1; } + static bool has_extended_glyf (hb_face_t *face) + { +#ifndef HB_NO_BEYOND_64K + hb_blob_ptr_t GLYF_table = hb_sanitize_context_t ().reference_table (face, HB_OT_TAG_GLYF); + hb_blob_ptr_t LOCA_table = hb_sanitize_context_t ().reference_table (face, HB_OT_TAG_LOCA); + bool ret = GLYF_table.get_length () && LOCA_table.get_length (); + GLYF_table.destroy (); + LOCA_table.destroy (); + return ret; +#else + return false; +#endif + } + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); @@ -78,6 +94,12 @@ struct glyf { TRACE_SUBSET (this); + bool extended = has_extended_glyf (c->plan->source); +#ifndef HB_NO_BEYOND_64K + if (extended != (c->table_tag == HB_OT_TAG_GLYF)) + return_trace (false); +#endif + if (!has_valid_glyf_format (c->plan->source)) { // glyf format is unknown don't attempt to subset it. DEBUG_MSG (SUBSET, nullptr, @@ -95,11 +117,17 @@ struct glyf hb_vector_t padded_offsets; if (unlikely (!padded_offsets.alloc_exact (c->plan->new_to_old_gid_list.length))) + { + hb_font_destroy (font); return_trace (false); + } hb_vector_t glyphs; - if (!_populate_subset_glyphs (c->plan, font, glyphs)) + /* SubsetGlyphs borrow bytes from this blob until they are serialized. */ + hb_blob_t *source_glyf = nullptr; + if (!_populate_subset_glyphs (c->plan, font, glyphs, &source_glyf)) { + hb_blob_destroy (source_glyf); hb_font_destroy (font); return_trace (false); } @@ -130,10 +158,12 @@ struct glyf bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); if (c->plan->normalized_coords && !c->plan->pinned_at_default) _free_compiled_subset_glyphs (glyphs); + hb_blob_destroy (source_glyf); if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c, padded_offsets.iter (), - use_short_loca)))) + use_short_loca, + extended)))) return_trace (false); return result; @@ -142,7 +172,8 @@ struct glyf bool _populate_subset_glyphs (const hb_subset_plan_t *plan, hb_font_t *font, - hb_vector_t& glyphs /* OUT */) const; + hb_vector_t& glyphs /* OUT */, + hb_blob_t **source_glyf /* OUT */) const; hb_font_t * _create_font_for_instancing (const hb_subset_plan_t *plan) const; @@ -162,19 +193,24 @@ struct glyf * defining it _MIN instead. */ }; +#ifndef HB_NO_BEYOND_64K +struct GLYF : glyf +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_GLYF; +}; +#endif + struct glyf_accelerator_t { glyf_accelerator_t (hb_face_t *face) { + extended = false; short_offset = false; num_glyphs = 0; loca_table = nullptr; glyf_table = nullptr; #ifndef HB_NO_VAR gvar = nullptr; -#ifndef HB_NO_BEYOND_64K - GVAR = nullptr; -#endif #endif hmtx = nullptr; #ifndef HB_NO_VERTICAL @@ -186,13 +222,28 @@ struct glyf_accelerator_t return; short_offset = 0 == head.indexToLocFormat; - loca_table = face->table.loca.get_blob (); // Needs no destruct! - glyf_table = hb_sanitize_context_t ().reference_table (face); -#ifndef HB_NO_VAR - gvar = face->table.gvar; #ifndef HB_NO_BEYOND_64K - GVAR = face->table.GVAR; + hb_blob_ptr_t GLYF_table = hb_sanitize_context_t ().reference_table (face, HB_OT_TAG_GLYF); + hb_blob_ptr_t LOCA_table = hb_sanitize_context_t ().reference_table (face, HB_OT_TAG_LOCA); + extended = GLYF_table.get_length () && LOCA_table.get_length (); + if (extended) + { + glyf_table = std::move (GLYF_table); + loca_table = std::move (LOCA_table); + } + else + { + GLYF_table.destroy (); + LOCA_table.destroy (); + } #endif + if (!extended) + { + glyf_table = hb_sanitize_context_t ().reference_table (face); + loca_table = hb_sanitize_context_t ().reference_table (face); + } +#ifndef HB_NO_VAR + gvar = face->table.gvar; #endif hmtx = face->table.hmtx; #ifndef HB_NO_VERTICAL @@ -212,24 +263,46 @@ struct glyf_accelerator_t } glyf_table.destroy (); + loca_table.destroy (); } bool has_data () const { return num_glyphs; } + bool is_extended () const { return extended; } + + void depend (hb_depend_data_builder_t *builder) const + { + if (!has_data ()) return; + for (hb_codepoint_t gid = 0; gid < get_num_glyphs (); gid++) + { + auto glyph = glyph_for_gid (gid); + for (auto &item : glyph.get_composite_iterator ()) + builder->add_depend (gid, + extended ? HB_OT_TAG_GLYF : HB_OT_TAG_glyf, + item.get_gid (extended)); + } + } protected: template bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer, hb_array_t coords, hb_glyf_scratch_t &scratch, - hb_scalar_cache_t *gvar_cache = nullptr) const + hb_scalar_cache_t *gvar_cache = nullptr, + int64_t *budget = nullptr) const { if (gid >= num_glyphs) return false; + int64_t stack_budget = HB_BUDGET_GLYPH; + if (!budget) budget = &stack_budget; + auto &all_points = scratch.all_points; all_points.clear (); bool phantom_only = !consumer.is_consuming_contour_points (); - if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache))) + if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache, 0, nullptr, budget))) + return false; + + if (unlikely (!hb_budget_spend (*budget, HB_BUDGET_1, all_points.length))) return false; unsigned count = all_points.length; @@ -281,12 +354,25 @@ struct glyf_accelerator_t unsigned end = i; - // Enough to start from the end. Our path-builder takes care of the rest. - if (likely (end < count)) // Can only fail in case of alloc failure *maybe*. + unsigned limit = end; +#ifndef HB_NO_CUBIC_GLYF + /* Rotating by one control point changes cubic pairing. Preserve + * the original order when the contour starts and ends off-curve + * with cubic controls, including all-off-curve contours. */ + if (likely (end < count) && + (points[start].flag & glyf_impl::SimpleGlyph::FLAG_CUBIC) && + (points[end].flag & (glyf_impl::SimpleGlyph::FLAG_ON_CURVE | + glyf_impl::SimpleGlyph::FLAG_CUBIC)) == + glyf_impl::SimpleGlyph::FLAG_CUBIC) + limit++; + else +#endif + if (likely (end < count)) consumer.consume_point (points[end]); - for (i = start; i < end; i++) + for (i = start; i < limit; i++) consumer.consume_point (points[i]); + i = end; consumer.contour_end (); } @@ -307,7 +393,6 @@ struct glyf_accelerator_t public: -#ifndef HB_NO_VAR struct points_aggregator_t { hb_font_t *font; @@ -340,10 +425,12 @@ struct glyf_accelerator_t return; } { - extents->x_bearing = roundf (min_x); - extents->width = roundf (max_x - extents->x_bearing); - extents->y_bearing = roundf (max_y); - extents->height = roundf (min_y - extents->y_bearing); + double x_bearing = (double) roundf (min_x); + double y_bearing = (double) roundf (max_y); + extents->x_bearing = hb_clamp_to (x_bearing); + extents->width = hb_clamp_to ((double) roundf (max_x) - x_bearing); + extents->y_bearing = hb_clamp_to (y_bearing); + extents->height = hb_clamp_to ((double) roundf (min_y) - y_bearing); if (scaled) font->scale_glyph_extents (extents); @@ -400,6 +487,7 @@ struct glyf_accelerator_t : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x; return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); } +#endif float get_v_origin_with_var_unscaled (hb_codepoint_t gid, @@ -423,8 +511,6 @@ struct glyf_accelerator_t return phantoms[glyf_impl::PHANTOM_TOP].y; } -#endif -#endif public: @@ -437,7 +523,8 @@ struct glyf_accelerator_t bool get_extents_at (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents, - hb_array_t coords) const + hb_array_t coords, + int64_t *budget = nullptr) const { if (unlikely (gid >= num_glyphs)) return false; @@ -450,7 +537,9 @@ struct glyf_accelerator_t gid, points_aggregator_t (font, extents, nullptr, true), coords, - *scratch); + *scratch, + nullptr, + budget); release_scratch (scratch); return ret; } @@ -482,12 +571,14 @@ struct glyf_accelerator_t 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; + end_offset - start_offset), gid, extended); + return needs_padding_removal ? glyf_impl::Glyph (glyph.trim_padding (), gid, extended) : glyph; } bool - get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_scalar_cache_t *gvar_cache = nullptr) const + get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, + hb_scalar_cache_t *gvar_cache = nullptr, + int64_t *budget = nullptr) const { if (!has_data ()) return false; @@ -498,7 +589,8 @@ struct glyf_accelerator_t hb_array (font->coords, font->has_nonzero_coords ? font->num_coords : 0), *scratch, - gvar_cache); + gvar_cache, + budget); release_scratch (scratch); @@ -509,13 +601,16 @@ struct glyf_accelerator_t get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_array_t coords, hb_glyf_scratch_t &scratch, - hb_scalar_cache_t *gvar_cache = nullptr) const + hb_scalar_cache_t *gvar_cache = nullptr, + int64_t *budget = nullptr) const { if (!has_data ()) return false; - return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), - coords, - scratch, - gvar_cache); + bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), + coords, + scratch, + gvar_cache, + budget); + return ret; } @@ -542,11 +637,12 @@ struct glyf_accelerator_t } } + unsigned int get_num_glyphs () const { return num_glyphs; } + hb_blob_t *reference_glyf_table () const + { return hb_blob_reference (glyf_table.get_blob ()); } + #ifndef HB_NO_VAR const gvar_accelerator_t *gvar; -#ifndef HB_NO_BEYOND_64K - const GVAR_accelerator_t *GVAR; -#endif #endif const hmtx_accelerator_t *hmtx; #ifndef HB_NO_VERTICAL @@ -554,6 +650,7 @@ struct glyf_accelerator_t #endif private: + bool extended; bool short_offset; unsigned int num_glyphs; hb_blob_ptr_t loca_table; @@ -565,10 +662,12 @@ struct glyf_accelerator_t inline bool glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, hb_font_t *font, - hb_vector_t& glyphs /* OUT */) const + hb_vector_t& glyphs /* OUT */, + hb_blob_t **source_glyf /* OUT */) const { OT::glyf_accelerator_t glyf (plan->source); if (!glyphs.alloc_exact (plan->new_to_old_gid_list.length)) return false; + *source_glyf = glyf.reference_glyf_table (); for (const auto &pair : plan->new_to_old_gid_list) { @@ -605,6 +704,13 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, } } } + /* All retained glyphs can be empty. Do not write the untouched bounds + * accumulator's inverted sentinels into the instance's head table. */ + if (font && plan->head_maxp_info.xMin > plan->head_maxp_info.xMax) + { + plan->head_maxp_info.xMin = plan->head_maxp_info.xMax = 0; + plan->head_maxp_info.yMin = plan->head_maxp_info.yMax = 0; + } return true; } @@ -614,6 +720,19 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const hb_font_t *font = hb_font_create (plan->source); if (unlikely (font == hb_font_get_empty ())) return nullptr; +#ifndef HB_NO_VAR + if (plan->has_avar2) + { + /* Under avar2, instancing applies only to the self-contained pins, + * whose constant final coordinates the plan holds in normalized_coords. + * Setting user-space variations would run the full avar2 mapping and + * bake contributions that remain live in the instance's variations. */ + hb_font_set_var_coords_normalized (font, plan->normalized_coords.arrayZ, + plan->normalized_coords.length); + return font; + } +#endif + hb_vector_t vars; if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true))) { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/loca.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/loca.hh index 07966ea5919..ee20aae52ef 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/loca.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/loca.hh @@ -13,6 +13,7 @@ namespace OT { * https://docs.microsoft.com/en-us/typography/opentype/spec/loca */ #define HB_OT_TAG_loca HB_TAG('l','o','c','a') +#define HB_OT_TAG_LOCA HB_TAG('L','O','C','A') struct loca { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh index f5495f92332..3414621fb03 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh @@ -166,6 +166,15 @@ struct path_builder_t } else if (first_oncurve) draw_session->line_to (first_oncurve.x, first_oncurve.y); + else if (first_offcurve2) + { + /* A contour with just two cubic controls closes at their midpoint. */ + optional_point_t mid = first_offcurve2.mid (first_offcurve); + draw_session->move_to (mid.x, mid.y); + draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, + first_offcurve.x, first_offcurve.y, + mid.x, mid.y); + } else if (first_offcurve) { float x = first_offcurve.x, y = first_offcurve.y; @@ -174,7 +183,7 @@ struct path_builder_t } /* Getting ready for the next contour */ - first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); + first_oncurve = first_offcurve = first_offcurve2 = last_offcurve = last_offcurve2 = optional_point_t (); draw_session->close_path (); } diff --git a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh index df06e00e725..19826ce4430 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh @@ -26,107 +26,120 @@ #include "graph.hh" #include "../hb-ot-layout-common.hh" +#include "graph-result.hh" #ifndef GRAPH_CLASSDEF_GRAPH_HH #define GRAPH_CLASSDEF_GRAPH_HH namespace graph { -struct ClassDefFormat1 : public OT::ClassDefFormat1_3 +template +struct ClassDefFormat1_3 : public OT::ClassDefFormat1_3 { - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - constexpr unsigned min_size = OT::ClassDefFormat1_3::min_size; - if (vertex_len < min_size) return false; + size_t vertex_len = vertex.table_size(); + constexpr unsigned min_size = OT::ClassDefFormat1_3::min_size; + if (unlikely (vertex_len < min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size (); + if (unlikely (vertex_len < min_size + this->classValue.get_size () - this->classValue.len.get_size ())) + return Err(SANITIZE_FAILURE); + return Ok(); } }; -struct ClassDefFormat2 : public OT::ClassDefFormat2_4 +template +struct ClassDefFormat2_4 : public OT::ClassDefFormat2_4 { - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - constexpr unsigned min_size = OT::ClassDefFormat2_4::min_size; - if (vertex_len < min_size) return false; + size_t vertex_len = vertex.table_size(); + constexpr unsigned min_size = OT::ClassDefFormat2_4::min_size; + if (unlikely (vertex_len < min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); + if (unlikely (vertex_len < min_size + this->rangeRecord.get_size () - this->rangeRecord.len.get_size ())) + return Err(SANITIZE_FAILURE); + return Ok(); } }; struct ClassDef : public OT::ClassDef { template - static bool add_class_def (gsubgpos_graph_context_t& c, - unsigned parent_id, - unsigned link_position, - It glyph_and_class, - unsigned max_size) + static graph_result_t add_class_def (gsubgpos_graph_context_t& c, + unsigned parent_id, + unsigned link_position, + It glyph_and_class, + unsigned max_size) { - unsigned class_def_prime_id = c.graph.new_node (nullptr, nullptr); + TRY_ASSIGN (unsigned class_def_prime_id, c.graph.new_node (nullptr, nullptr)); auto& class_def_prime_vertex = c.graph.vertices_[class_def_prime_id]; - if (!make_class_def (c, glyph_and_class, class_def_prime_id, max_size)) - return false; + TRY (make_class_def (c, glyph_and_class, class_def_prime_id, max_size)); - auto* class_def_link = c.graph.vertices_[parent_id].obj.real_links.push (); - class_def_link->width = SmallTypes::size; - class_def_link->objidx = class_def_prime_id; - class_def_link->position = link_position; - class_def_prime_vertex.add_parent (parent_id, false); + TRY(c.graph.vertices_[parent_id].add_real_link (SmallTypes::size, class_def_prime_id, link_position)); + TRY(class_def_prime_vertex.add_parent (parent_id, false)); - return true; + return Ok(); } template - static bool make_class_def (gsubgpos_graph_context_t& c, - It glyph_and_class, - unsigned dest_obj, - unsigned max_size) + static graph_result_t make_class_def (gsubgpos_graph_context_t& c, + It glyph_and_class, + unsigned dest_obj, + unsigned max_size) { char* buffer = (char*) hb_calloc (1, max_size); + if (unlikely (!buffer)) + return Err(ALLOCATION_FAILURE); + hb_serialize_context_t serializer (buffer, max_size); OT::ClassDef_serialize (&serializer, glyph_and_class); serializer.end_serialize (); - if (serializer.in_error ()) + if (unlikely (serializer.in_error ())) { hb_free (buffer); - return false; + return Err(ALLOCATION_FAILURE); } hb_bytes_t class_def_copy = serializer.copy_bytes (); - if (!class_def_copy.arrayZ) return false; + if (unlikely (!class_def_copy.arrayZ)) + { + hb_free (buffer); + return Err(ALLOCATION_FAILURE); + } + // Give ownership to the context, it will cleanup the buffer. - if (!c.add_buffer ((char *) class_def_copy.arrayZ)) + auto res = c.add_buffer ((char *) class_def_copy.arrayZ); + if (unlikely (!res.is_ok ())) { + hb_free (buffer); hb_free ((char *) class_def_copy.arrayZ); - return false; + return res; } - auto& obj = c.graph.vertices_[dest_obj].obj; - obj.head = (char *) class_def_copy.arrayZ; - obj.tail = obj.head + class_def_copy.length; + + auto& v = c.graph.vertices_[dest_obj]; + char* head = (char *) class_def_copy.arrayZ; + v.set_buffer (head, head + class_def_copy.length); hb_free (buffer); - return true; + return Ok(); } - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < OT::ClassDef::min_size) return false; + size_t vertex_len = vertex.table_size(); + if (unlikely (vertex_len < OT::ClassDef::min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); switch (u.format.v) { - case 1: return ((ClassDefFormat1*)this)->sanitize (vertex); - case 2: return ((ClassDefFormat2*)this)->sanitize (vertex); + case 1: return ((ClassDefFormat1_3*)this)->sanitize (vertex); + case 2: return ((ClassDefFormat2_4*)this)->sanitize (vertex); #ifndef HB_NO_BEYOND_64K - // Not currently supported - case 3: - case 4: + case 3: return ((ClassDefFormat1_3*)this)->sanitize (vertex); + case 4: return ((ClassDefFormat2_4*)this)->sanitize (vertex); #endif - default: return false; + default: return Err(SANITIZE_FAILURE); } } }; @@ -134,41 +147,34 @@ struct ClassDef : public OT::ClassDef struct class_def_size_estimator_t { - // TODO(garretrieger): update to support beyond64k coverage/classdef tables. - constexpr static unsigned class_def_format1_base_size = 6; - constexpr static unsigned class_def_format2_base_size = 4; - constexpr static unsigned coverage_base_size = 4; - constexpr static unsigned bytes_per_range = 6; - constexpr static unsigned bytes_per_glyph = 2; - template - class_def_size_estimator_t (It glyph_and_class) - : num_ranges_per_class (), glyphs_per_class () + static graph_result_t create (It glyph_and_class) { - reset(); + class_def_size_estimator_t estimator; + estimator.reset(); for (auto p : + glyph_and_class) { unsigned gid = p.first; unsigned klass = p.second; hb_set_t* glyphs; - if (glyphs_per_class.has (klass, &glyphs) && glyphs) { + if (estimator.glyphs_per_class.has (klass, &glyphs) && glyphs) { glyphs->add (gid); continue; } hb_set_t new_glyphs; new_glyphs.add (gid); - glyphs_per_class.set (klass, std::move (new_glyphs)); + estimator.glyphs_per_class.set (klass, std::move (new_glyphs)); } - if (in_error ()) return; + TRY(estimator.to_result ()); - for (unsigned klass : glyphs_per_class.keys ()) + for (unsigned klass : estimator.glyphs_per_class.keys ()) { if (!klass) continue; // class 0 doesn't get encoded. - const hb_set_t& glyphs = glyphs_per_class.get (klass); + const hb_set_t& glyphs = estimator.glyphs_per_class.get (klass); hb_codepoint_t start = HB_SET_VALUE_INVALID; hb_codepoint_t end = HB_SET_VALUE_INVALID; @@ -176,23 +182,26 @@ struct class_def_size_estimator_t while (glyphs.next_range (&start, &end)) count++; - num_ranges_per_class.set (klass, count); + estimator.num_ranges_per_class.set (klass, count); } + + TRY(estimator.to_result ()); + return estimator; } void reset() { - class_def_1_size = class_def_format1_base_size; - class_def_2_size = class_def_format2_base_size; included_glyphs.clear(); + included_class_def_glyphs.clear(); included_classes.clear(); + class_def_range_count = 0; + class_max = 0; + coverage_size_val = compute_coverage_size (); } - // Compute the size of coverage for all glyphs added via 'add_class_def_size'. + // Size of coverage for all glyphs added via 'add_class_def_size'. unsigned coverage_size () const { - unsigned format1_size = coverage_base_size + bytes_per_glyph * included_glyphs.get_population(); - unsigned format2_size = coverage_base_size + bytes_per_range * num_glyph_ranges(); - return hb_min(format1_size, format2_size); + return coverage_size_val; } // Compute the new size of the ClassDef table if all glyphs associated with 'klass' were added. @@ -201,54 +210,105 @@ struct class_def_size_estimator_t if (!included_classes.has(klass)) { hb_set_t* glyphs = nullptr; if (glyphs_per_class.has(klass, &glyphs)) { + unsigned num_glyphs = included_glyphs.get_population(); included_glyphs.union_(*glyphs); + if (klass) + included_class_def_glyphs.union_(*glyphs); + if (num_glyphs != included_glyphs.get_population()) + coverage_size_val = compute_coverage_size (); } - class_def_1_size = class_def_format1_base_size; - if (!included_glyphs.is_empty()) { - unsigned min_glyph = included_glyphs.get_min(); - unsigned max_glyph = included_glyphs.get_max(); - class_def_1_size += bytes_per_glyph * (max_glyph - min_glyph + 1); + if (klass) + { + class_def_range_count += num_ranges_per_class.get (klass); + if (glyphs && klass > class_max) + class_max = klass; } - - class_def_2_size += bytes_per_range * num_ranges_per_class.get (klass); - included_classes.add(klass); } - return hb_min (class_def_1_size, class_def_2_size); + return class_def_size (); } - unsigned num_glyph_ranges() const { + unsigned num_glyph_ranges (const hb_set_t &glyphs) const { hb_codepoint_t start = HB_SET_VALUE_INVALID; hb_codepoint_t end = HB_SET_VALUE_INVALID; unsigned count = 0; - while (included_glyphs.next_range (&start, &end)) { + while (glyphs.next_range (&start, &end)) { count++; } return count; } - bool in_error () + private: + graph_result_t to_result() const { - if (num_ranges_per_class.in_error ()) return true; - if (glyphs_per_class.in_error ()) return true; + TRY (graph_result_t::from (num_ranges_per_class, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (glyphs_per_class, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (included_classes, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (included_glyphs, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (included_class_def_glyphs, ALLOCATION_FAILURE)); for (const hb_set_t& s : glyphs_per_class.values ()) { - if (s.in_error ()) return true; + TRY (graph_result_t::from (s, ALLOCATION_FAILURE)); } - return false; + return Ok(); + } + + class_def_size_estimator_t () + : num_ranges_per_class (), glyphs_per_class () {} + + unsigned compute_coverage_size () const + { + unsigned glyph_size = glyph_id_size (included_glyphs); + unsigned coverage_base_size = OT::HBUINT16::static_size + glyph_size; + unsigned range_size = 3 * glyph_size; + unsigned format1_size = coverage_base_size + glyph_size * included_glyphs.get_population(); + unsigned format2_size = coverage_base_size + range_size * num_glyph_ranges (included_glyphs); + return hb_min(format1_size, format2_size); + } + + unsigned glyph_id_size (const hb_set_t &glyphs) const + { +#ifndef HB_NO_BEYOND_64K + if (!glyphs.is_empty () && glyphs.get_max () > 0xFFFFu) + return OT::Layout::MediumTypes::size; +#endif + return OT::Layout::SmallTypes::size; + } + + unsigned class_def_size () const + { + if (included_class_def_glyphs.is_empty ()) + return OT::HBUINT16::static_size + OT::Layout::SmallTypes::size; + + unsigned best_size = UINT_MAX; + hb_codepoint_t glyph_max = included_class_def_glyphs.get_max (); + unsigned glyph_span = glyph_max - included_class_def_glyphs.get_min () + 1; + + if (glyph_max <= 0xFFFFu && glyph_span <= 0xFFFFu && class_max <= 0xFFFFu) + best_size = hb_min (best_size, 6 + 2 * glyph_span); + if (glyph_max <= 0xFFFFu && class_def_range_count <= 0xFFFFu && class_max <= 0xFFFFu) + best_size = hb_min (best_size, 4 + 6 * class_def_range_count); +#ifndef HB_NO_BEYOND_64K + if (glyph_max <= 0xFFFFFFu && glyph_span <= 0xFFFFFFu && class_max <= 0xFFFFFFu) + best_size = hb_min (best_size, 8 + 3 * glyph_span); + if (glyph_max <= 0xFFFFFFu && class_def_range_count <= 0xFFFFFFu && class_max <= 0xFFFFu) + best_size = hb_min (best_size, 5 + 8 * class_def_range_count); +#endif + return best_size; } - private: hb_hashmap_t num_ranges_per_class; hb_hashmap_t glyphs_per_class; hb_set_t included_classes; hb_set_t included_glyphs; - unsigned class_def_1_size; - unsigned class_def_2_size; + hb_set_t included_class_def_glyphs; + unsigned class_def_range_count; + unsigned class_max; + unsigned coverage_size_val; }; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh index 5778ee9e1d3..aad4af707c3 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh @@ -32,42 +32,49 @@ namespace graph { -static bool sanitize ( - const OT::Layout::Common::CoverageFormat1_3* thiz, - graph_t::vertex_t& vertex +template +static graph_result_t sanitize ( + const OT::Layout::Common::CoverageFormat1_3* thiz, + const graph_t::vertex_t& vertex ) { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size; - if (vertex_len < min_size) return false; + size_t vertex_len = vertex.table_size(); + constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size; + if (unlikely (vertex_len < min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= min_size + thiz->glyphArray.get_size () - thiz->glyphArray.len.get_size (); + if (unlikely (vertex_len < min_size + thiz->glyphArray.get_size () - thiz->glyphArray.len.get_size ())) + return Err(SANITIZE_FAILURE); + return Ok(); } -static bool sanitize ( - const OT::Layout::Common::CoverageFormat2_4* thiz, - graph_t::vertex_t& vertex +template +static graph_result_t sanitize ( + const OT::Layout::Common::CoverageFormat2_4* thiz, + const graph_t::vertex_t& vertex ) { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size; - if (vertex_len < min_size) return false; + size_t vertex_len = vertex.table_size(); + constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size; + if (unlikely (vertex_len < min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= min_size + thiz->rangeRecord.get_size () - thiz->rangeRecord.len.get_size (); + if (unlikely (vertex_len < min_size + thiz->rangeRecord.get_size () - thiz->rangeRecord.len.get_size ())) + return Err(SANITIZE_FAILURE); + return Ok(); } struct Coverage : public OT::Layout::Common::Coverage { - static Coverage* clone_coverage (gsubgpos_graph_context_t& c, - unsigned coverage_id, - unsigned new_parent_id, - unsigned link_position, - unsigned start, unsigned end) + static graph_result_t clone_coverage (gsubgpos_graph_context_t& c, + unsigned coverage_id, + unsigned new_parent_id, + unsigned link_position, + unsigned start, unsigned end) { unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); auto& coverage_v = c.graph.vertices_[coverage_id]; - Coverage* coverage_table = (Coverage*) coverage_v.obj.head; - if (!coverage_table || !coverage_table->sanitize (coverage_v)) - return nullptr; + const Coverage* coverage_table = (const Coverage*) coverage_v.obj().head; + if (unlikely (!coverage_table)) + return Err(INVALID_ARGUMENT); + TRY (coverage_table->sanitize (coverage_v)); auto new_coverage = + hb_zip (coverage_table->iter (), hb_range ()) @@ -81,35 +88,32 @@ struct Coverage : public OT::Layout::Common::Coverage } template - static Coverage* add_coverage (gsubgpos_graph_context_t& c, - unsigned parent_id, - unsigned link_position, - It glyphs, - unsigned max_size) + static graph_result_t add_coverage (gsubgpos_graph_context_t& c, + unsigned parent_id, + unsigned link_position, + It glyphs, + unsigned max_size) { - unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr); + TRY_ASSIGN (unsigned coverage_prime_id, c.graph.new_node (nullptr, nullptr)); auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id]; - if (!make_coverage (c, glyphs, coverage_prime_id, max_size)) - return nullptr; + TRY (make_coverage (c, glyphs, coverage_prime_id, max_size)); - auto* coverage_link = c.graph.vertices_[parent_id].obj.real_links.push (); - coverage_link->width = SmallTypes::size; - coverage_link->objidx = coverage_prime_id; - coverage_link->position = link_position; - coverage_prime_vertex.add_parent (parent_id, false); + TRY(c.graph.vertices_[parent_id].add_real_link (SmallTypes::size, coverage_prime_id, link_position)); + TRY(coverage_prime_vertex.add_parent (parent_id, false)); - return (Coverage*) coverage_prime_vertex.obj.head; + return Ok(); } // Filter an existing coverage table to glyphs at indices [start, end) and replace it with the filtered version. - static bool filter_coverage (gsubgpos_graph_context_t& c, - unsigned existing_coverage, - unsigned start, unsigned end) { + static graph_result_t filter_coverage (gsubgpos_graph_context_t& c, + unsigned existing_coverage, + unsigned start, unsigned end) { unsigned coverage_size = c.graph.vertices_[existing_coverage].table_size (); auto& coverage_v = c.graph.vertices_[existing_coverage]; - Coverage* coverage_table = (Coverage*) coverage_v.obj.head; - if (!coverage_table || !coverage_table->sanitize (coverage_v)) - return false; + const Coverage* coverage_table = (const Coverage*) coverage_v.obj().head; + if (unlikely (!coverage_table)) + return Err(INVALID_ARGUMENT); + TRY (coverage_table->sanitize (coverage_v)); auto new_coverage = + hb_zip (coverage_table->iter (), hb_range ()) @@ -124,53 +128,61 @@ struct Coverage : public OT::Layout::Common::Coverage // Replace the coverage table at dest obj with one covering 'glyphs'. template - static bool make_coverage (gsubgpos_graph_context_t& c, - It glyphs, - unsigned dest_obj, - unsigned max_size) + static graph_result_t make_coverage (gsubgpos_graph_context_t& c, + It glyphs, + unsigned dest_obj, + unsigned max_size) { char* buffer = (char*) hb_calloc (1, max_size); + if (unlikely (!buffer)) + return Err(ALLOCATION_FAILURE); + hb_serialize_context_t serializer (buffer, max_size); OT::Layout::Common::Coverage_serialize (&serializer, glyphs); serializer.end_serialize (); - if (serializer.in_error ()) + if (unlikely (serializer.in_error ())) { hb_free (buffer); - return false; + return Err(ALLOCATION_FAILURE); } hb_bytes_t coverage_copy = serializer.copy_bytes (); - if (!coverage_copy.arrayZ) return false; + if (unlikely (!coverage_copy.arrayZ)) { + hb_free (buffer); + return Err(ALLOCATION_FAILURE); + } + // Give ownership to the context, it will cleanup the buffer. - if (!c.add_buffer ((char *) coverage_copy.arrayZ)) + auto res = c.add_buffer ((char *) coverage_copy.arrayZ); + if (unlikely (!res.is_ok ())) { + hb_free (buffer); hb_free ((char *) coverage_copy.arrayZ); - return false; + return res; } - auto& obj = c.graph.vertices_[dest_obj].obj; - obj.head = (char *) coverage_copy.arrayZ; - obj.tail = obj.head + coverage_copy.length; + auto& v = c.graph.vertices_[dest_obj]; + char* head = (char *) coverage_copy.arrayZ; + v.set_buffer (head, head + coverage_copy.length); hb_free (buffer); - return true; + return Ok(); } - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < OT::Layout::Common::Coverage::min_size) return false; + size_t vertex_len = vertex.table_size (); + if (unlikely (vertex_len < OT::Layout::Common::Coverage::min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); switch (u.format.v) { case 1: return graph::sanitize ((const OT::Layout::Common::CoverageFormat1_3*) this, vertex); case 2: return graph::sanitize ((const OT::Layout::Common::CoverageFormat2_4*) this, vertex); #ifndef HB_NO_BEYOND_64K - // Not currently supported - case 3: - case 4: + case 3: return graph::sanitize ((const OT::Layout::Common::CoverageFormat1_3*) this, vertex); + case 4: return graph::sanitize ((const OT::Layout::Common::CoverageFormat2_4*) this, vertex); #endif - default: return false; + default: return Err(SANITIZE_FAILURE); } } }; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh index 9ca7434ca19..94e74ec5270 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh @@ -27,10 +27,13 @@ #include "../hb-set.hh" #include "../hb-priority-queue.hh" #include "../hb-serialize.hh" +#include "graph-result.hh" #ifndef GRAPH_GRAPH_HH #define GRAPH_GRAPH_HH +#define HB_GRAPH_INVALID ((unsigned) -1) + namespace graph { /** @@ -39,32 +42,119 @@ namespace graph { */ struct graph_t { + // TODO(garretrieger): experiment with using scratch vector for visited sets instead of allocating + // a new hb_set_t each time. + struct vertex_t { - hb_serialize_context_t::object_t obj; + // TODO(garretrieger): have vertex_t gaurantee that head/tail are non null and head < tail + // so downstream users don't need to constantly check that. + + // TODO(garretrieger): have vertex_t gaurantee that all link indexes are valid (ie < vertices_.length) + // so downstream users don't need to constantly check that. + + // TODO(garretrieger): track where the real links are currently sorted, and automatically sort + // prior to accessing iterator for real links. Avoids needing to manually trigger sorting by + // downstream users. + int64_t distance = 0 ; unsigned space = 0 ; unsigned start = 0; unsigned end = 0; unsigned priority = 0; + private: + hb_serialize_context_t::object_t obj_; unsigned incoming_edges_ = 0; - unsigned single_parent = (unsigned) -1; + unsigned single_parent = HB_GRAPH_INVALID; bool has_incoming_virtual_edges_ = false; hb_hashmap_t parents; + hb_set_t virtual_parents; public: + vertex_t () + {} + + explicit vertex_t(const hb_serialize_context_t::object_t& obj) : obj_(obj) + {} + auto parents_iter () const HB_AUTO_RETURN ( hb_concat ( - hb_iter (&single_parent, single_parent != (unsigned) -1), + hb_iter (&single_parent, single_parent != HB_GRAPH_INVALID), parents.keys_ref () ) ) - bool in_error () const + void set_buffer (char* head, char* tail) { + obj_.head = head; + obj_.tail = tail; + } + + void shrink_buffer (size_t count) + { + obj_.tail -= count; + } + + auto all_links_writer () HB_AUTO_RETURN (( obj_.all_links_writer() )); + auto real_links_writer () HB_AUTO_RETURN (( obj_.real_links.writer() )); + auto virtual_links_writer () HB_AUTO_RETURN (( obj_.virtual_links.writer() )); + + void sort_real_links () { + obj_.real_links.qsort (); + } + + graph_result_t add_real_link (unsigned width, unsigned obj_idx, unsigned position) { + auto* link = obj_.real_links.push (); + TRY (graph_result_t::from (obj_.real_links, ALLOCATION_FAILURE)); + link->width = width; + link->objidx = obj_idx; + link->position = position; + return Ok(); + } + + graph_result_t add_virtual_link (unsigned obj_idx) { + auto* link = obj_.virtual_links.push (); + TRY (graph_result_t::from (obj_.virtual_links, ALLOCATION_FAILURE)); + link->objidx = obj_idx; + return Ok(); + } + + graph_result_t add_real_link (const hb_serialize_context_t::object_t::link_t& link) + { + obj_.real_links.push (link); + return graph_result_t::from (obj_.real_links, ALLOCATION_FAILURE); + } + + graph_result_t set_real_links (hb_vector_t&& links) + { + TRY(graph_result_t::from (links, ALLOCATION_FAILURE)); + obj_.real_links = links; + return Ok(); + } + + void clear_real_links () + { + obj_.real_links.reset(); + } + + void clear_virtual_links () + { + obj_.virtual_links.reset(); + } + + graph_result_t add_virtual_link (const hb_serialize_context_t::object_t::link_t& link) + { + obj_.virtual_links.push (link); + return graph_result_t::from (obj_.virtual_links, ALLOCATION_FAILURE); + } + + const hb_serialize_context_t::object_t& obj() const { return obj_; } + + template + T as () const { - return parents.in_error (); + return reinterpret_cast (obj_.head); } bool has_incoming_virtual_edges () const @@ -72,17 +162,17 @@ struct graph_t return has_incoming_virtual_edges_; } - bool link_positions_valid (unsigned num_objects, bool removed_nil) + graph_result_t link_positions_valid (unsigned num_objects, bool removed_nil) { hb_set_t assigned_bytes; - for (const auto& l : obj.real_links) + for (const auto& l : obj_.real_links) { - if (l.objidx >= num_objects - || (removed_nil && !l.objidx)) + if (unlikely (l.objidx >= num_objects + || (removed_nil && !l.objidx))) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Invalid object index."); - return false; + return Err(INVALID_ARGUMENT); } unsigned start = l.position; @@ -92,37 +182,37 @@ struct graph_t { DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Invalid link width."); - return false; + return Err(INVALID_ARGUMENT); } if (unlikely (end >= table_size ())) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Link position is out of bounds."); - return false; + return Err(OUT_OF_BOUNDS); } if (unlikely (assigned_bytes.intersects (start, end))) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Found offsets whose positions overlap."); - return false; + return Err(INVALID_ARGUMENT); } assigned_bytes.add_range (start, end); } - return !assigned_bytes.in_error (); + return graph_result_t::from (assigned_bytes, ALLOCATION_FAILURE); } void normalize () { - obj.real_links.qsort (); - for (auto& l : obj.real_links) + obj_.real_links.qsort (); + for (const auto& l : obj_.real_links) { for (unsigned i = 0; i < l.width; i++) { - obj.head[l.position + i] = 0; + obj_.head[l.position + i] = 0; } } } @@ -156,21 +246,22 @@ struct graph_t return false; } - return links_equal (obj.real_links, other.obj.real_links, graph, other_graph, depth); + return links_equal (obj_.real_links, other.obj_.real_links, graph, other_graph, depth); } hb_bytes_t as_bytes () const { - return hb_bytes_t (obj.head, table_size ()); + return hb_bytes_t (obj_.head, table_size ()); } friend void swap (vertex_t& a, vertex_t& b) { - hb_swap (a.obj, b.obj); + hb_swap (a.obj_, b.obj_); hb_swap (a.distance, b.distance); hb_swap (a.space, b.space); hb_swap (a.single_parent, b.single_parent); hb_swap (a.parents, b.parents); + hb_swap (a.virtual_parents, b.virtual_parents); hb_swap (a.incoming_edges_, b.incoming_edges_); hb_swap (a.has_incoming_virtual_edges_, b.has_incoming_virtual_edges_); hb_swap (a.start, b.start); @@ -178,36 +269,36 @@ struct graph_t hb_swap (a.priority, b.priority); } - hb_hashmap_t + graph_result_t> position_to_index_map () const { hb_hashmap_t result; - result.alloc (obj.real_links.length); - for (const auto& l : obj.real_links) { + result.alloc (obj_.real_links.length); + for (const auto& l : obj_.real_links) { result.set (l.position, l.objidx); } - return result; + return graph_result_t>::from (std::move(result), ALLOCATION_FAILURE); } bool is_shared () const { - return parents.get_population () > 1; + return parents.get_population () > virtual_parents.get_population () + 1; } unsigned incoming_edges () const { if (HB_DEBUG_SUBSET_REPACK) { - assert (incoming_edges_ == (single_parent != (unsigned) -1) + + assert (incoming_edges_ == (single_parent != HB_GRAPH_INVALID) + (parents.values_ref () | hb_reduce (hb_add, 0))); } return incoming_edges_; } unsigned incoming_edges_from_parent (unsigned parent_index) const { - if (single_parent != (unsigned) -1) { + if (single_parent != HB_GRAPH_INVALID) { return single_parent == parent_index ? 1 : 0; } @@ -219,27 +310,30 @@ struct graph_t { incoming_edges_ = 0; has_incoming_virtual_edges_ = false; - single_parent = (unsigned) -1; + single_parent = HB_GRAPH_INVALID; parents.reset (); + virtual_parents.reset (); } - void add_parent (unsigned parent_index, bool is_virtual) + graph_result_t add_parent (unsigned parent_index, bool is_virtual) { - assert (parent_index != (unsigned) -1); + assert (parent_index != HB_GRAPH_INVALID); has_incoming_virtual_edges_ |= is_virtual; + if (is_virtual) + virtual_parents.add (parent_index); if (incoming_edges_ == 0) { single_parent = parent_index; incoming_edges_ = 1; - return; + return to_result(); } - else if (single_parent != (unsigned) -1) + else if (single_parent != HB_GRAPH_INVALID) { assert (incoming_edges_ == 1); if (!parents.set (single_parent, 1)) - return; - single_parent = (unsigned) -1; + return to_result (); + single_parent = HB_GRAPH_INVALID; } unsigned *v; @@ -250,14 +344,17 @@ struct graph_t } else if (parents.set (parent_index, 1)) incoming_edges_++; + + return to_result(); } void remove_parent (unsigned parent_index) { if (parent_index == single_parent) { - single_parent = (unsigned) -1; + single_parent = HB_GRAPH_INVALID; incoming_edges_--; + virtual_parents.reset (); return; } @@ -268,7 +365,10 @@ struct graph_t if (*v > 1) (*v)--; else + { parents.del (parent_index); + virtual_parents.del (parent_index); + } if (incoming_edges_ == 1) { @@ -278,55 +378,41 @@ struct graph_t } } - void remove_real_link (unsigned child_index, const void* offset) + void remove_real_link_unordered (unsigned link_array_index) { + obj_.real_links.remove_unordered (link_array_index); + } + + void remove_real_link_unordered (unsigned child_index, const void* offset) { - unsigned count = obj.real_links.length; + unsigned count = obj_.real_links.length; for (unsigned i = 0; i < count; i++) { - auto& link = obj.real_links.arrayZ[i]; + auto& link = obj_.real_links.arrayZ[i]; if (link.objidx != child_index) continue; - if ((obj.head + link.position) != offset) + if ((obj_.head + link.position) != offset) continue; - obj.real_links.remove_unordered (i); + obj_.real_links.remove_unordered (i); return; } } - bool remap_parents (const hb_vector_t& id_map) - { - if (single_parent != (unsigned) -1) - { - assert (single_parent < id_map.length); - single_parent = id_map[single_parent]; - return true; - } - - hb_hashmap_t new_parents; - new_parents.alloc (parents.get_population ()); - for (auto _ : parents) - { - assert (_.first < id_map.length); - assert (!new_parents.has (id_map[_.first])); - new_parents.set (id_map[_.first], _.second); - } - - if (parents.in_error() || new_parents.in_error ()) - return false; - - parents = std::move (new_parents); - return true; - } - - void remap_parent (unsigned old_index, unsigned new_index) + graph_result_t remap_parent (unsigned old_index, unsigned new_index) { - if (single_parent != (unsigned) -1) + if (single_parent != HB_GRAPH_INVALID) { if (single_parent == old_index) + { single_parent = new_index; - return; + if (virtual_parents.has (old_index)) + { + virtual_parents.del (old_index); + virtual_parents.add (new_index); + } + } + return graph_result_t::from(virtual_parents, ALLOCATION_FAILURE); } const unsigned *pv; @@ -343,11 +429,19 @@ struct graph_t parents.reset (); } } + + if (virtual_parents.has (old_index)) + { + virtual_parents.del (old_index); + virtual_parents.add (new_index); + } + + return graph_result_t::from(virtual_parents, ALLOCATION_FAILURE); } bool is_leaf () const { - return !obj.real_links.length && !obj.virtual_links.length; + return !obj_.real_links.length && !obj_.virtual_links.length; } bool raise_priority () @@ -372,7 +466,7 @@ struct graph_t } size_t table_size () const { - return obj.tail - obj.head; + return obj_.tail - obj_.head; } int64_t modified_distance (unsigned order) const @@ -382,7 +476,8 @@ struct graph_t // it's parent where possible. int64_t modified_distance = - hb_clamp (distance + distance_modifier (), (int64_t) 0, 0x7FFFFFFFFFF); + hb_clamp (distance + distance_modifier (), (int64_t) 0, + hb_int_max (int64_t) >> 18); if (has_max_priority ()) { modified_distance = 0; } @@ -392,7 +487,7 @@ struct graph_t int64_t distance_modifier () const { if (!priority) return 0; - int64_t table_size = obj.tail - obj.head; + int64_t table_size = obj_.tail - obj_.head; if (priority == 1) return -table_size / 2; @@ -401,6 +496,14 @@ struct graph_t } private: + graph_result_t to_result() const { + if (unlikely ( + parents.in_error() || virtual_parents.in_error() || + obj_.real_links.in_error() || obj_.virtual_links.in_error())) + return Err(ALLOCATION_FAILURE); + return Ok(); + } + bool links_equal (const hb_vector_t& this_links, const hb_vector_t& other_links, const graph_t& graph, @@ -437,19 +540,27 @@ struct graph_t } }; - template + enum vertex_mutability_t + { + Immutable, + Mutable + }; + + template struct vertex_and_table_t { vertex_and_table_t () : index (0), vertex (nullptr), table (nullptr) {} + template + vertex_and_table_t (const vertex_and_table_t& o) + : index (o.index), vertex (o.vertex), table (o.table) + {} + unsigned index; - vertex_t* vertex; - T* table; + typename std::conditional::type vertex; + typename std::conditional::type table; - operator bool () { - return table && vertex; - } }; /* @@ -460,20 +571,29 @@ struct graph_t * serializer */ template - graph_t (const T& objects) - : parents_invalid (true), - distance_invalid (true), - positions_invalid (true), - successful (true), - buffers () + static graph_result_t create (const T& objects) { - num_roots_for_space_.push (1); + if (unlikely (objects.length > HB_REPACKER_MAX_VERTICES)) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "constructing graph: num of objects %u exceeds HB_REPACKER_MAX_VERTICES.", + objects.length); + return Err(LIMIT_EXCEEDED); + } + + graph_t g; + g.num_roots_for_space_.push (1); + TRY (graph_result_t::from (g.num_roots_for_space_, ALLOCATION_FAILURE)); + bool removed_nil = false; - vertices_.alloc (objects.length); - ordering_.resize (objects.length); - ordering_scratch_.alloc (objects.length); + const unsigned count = objects.length; + g.vertices_.alloc (count); + g.ordering_.resize (count); + g.ordering_scratch_.alloc (count); + TRY (graph_result_t::from (g.vertices_, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (g.ordering_, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (g.ordering_scratch_, ALLOCATION_FAILURE)); - unsigned count = objects.length; unsigned order = objects.length; unsigned skip = 0; for (unsigned i = 0; i < count; i++) @@ -484,37 +604,57 @@ struct graph_t { removed_nil = true; order--; - ordering_.resize(objects.length - 1); + g.ordering_.resize (count - 1); skip++; continue; } - vertex_t* v = vertices_.push (); - if (check_success (!vertices_.in_error ())) - v->obj = *objects.arrayZ[i]; + hb_serialize_context_t::object_t obj (*objects.arrayZ[i]); + if (unlikely (obj.in_error ())) { + return Err(ALLOCATION_FAILURE); + } + vertex_t* v = g.vertices_.push (std::move (obj)); - check_success (v->link_positions_valid (count, removed_nil)); + TRY (v->link_positions_valid (count, removed_nil)); // To start we set the ordering to match the provided objects // list. Note: objects are provided to us in reverse order (ie. // the last object is the root). unsigned obj_idx = i - skip; - ordering_[--order] = obj_idx; + g.ordering_[--order] = obj_idx; if (!removed_nil) continue; // Fix indices to account for removed nil object. - for (auto& l : v->obj.all_links_writer ()) { + for (auto& l : v->all_links_writer ()) { l.objidx--; } } + + auto r = g.is_fully_connected(); + if (r.is_err() && r.error() == ORPHANED_NODES) { + g.print_orphaned_nodes (); + } + TRY(r); + + return Ok (std::move (g)); } + graph_t (const graph_t&) = delete; + graph_t& operator = (const graph_t&) = delete; + graph_t (graph_t&&) = default; + graph_t& operator = (graph_t&&) = default; + ~graph_t () { for (char* b : buffers) hb_free (b); } +private: + graph_t () = default; + +public: + bool operator== (const graph_t& other) const { return root ().equals (root_idx(), other.root_idx(), other.root (), *this, other, 0); @@ -525,10 +665,10 @@ struct graph_t { const auto& v = vertices_[id]; printf("%u: %u [", id, (unsigned int)v.table_size()); - for (const auto &l : v.obj.real_links) { + for (const auto &l : v.obj().real_links) { printf("%u, ", l.objidx); } - for (const auto &l : v.obj.virtual_links) { + for (const auto &l : v.obj().virtual_links) { printf("v%u, ", l.objidx); } printf("]\n"); @@ -542,14 +682,6 @@ struct graph_t v.normalize (); } - bool in_error () const - { - return !successful || - vertices_.in_error () || - ordering_.in_error() || - num_roots_for_space_.in_error (); - } - const vertex_t& root () const { return vertices_[root_idx ()]; @@ -565,39 +697,38 @@ struct graph_t const hb_serialize_context_t::object_t& object (unsigned i) const { - return vertices_[i].obj; + return vertices_[i].obj(); } - bool add_buffer (char* buffer) + graph_result_t add_buffer (char* buffer) { buffers.push (buffer); - return !buffers.in_error (); + return graph_result_t::from (buffers, ALLOCATION_FAILURE); } /* * Adds a 16 bit link from parent_id to child_id */ template - void add_link (T* offset, - unsigned parent_id, - unsigned child_id) + graph_result_t add_link (T* offset, + unsigned parent_id, + unsigned child_id) { + if (unlikely (parent_id >= vertices_.length || child_id >= vertices_.length)) + return Err(OUT_OF_BOUNDS); auto& v = vertices_[parent_id]; - auto* link = v.obj.real_links.push (); - link->width = 2; - link->objidx = child_id; - link->position = (char*) offset - (char*) v.obj.head; - vertices_[child_id].add_parent (parent_id, false); + TRY(v.add_real_link(2, child_id, (char*) offset - (char*) v.obj().head)); + return vertices_[child_id].add_parent (parent_id, false); } /* * Generates a new topological sorting of graph ordered by the shortest * distance to each node if positions are marked as invalid. */ - void sort_shortest_distance_if_needed () + graph_result_t sort_shortest_distance_if_needed () { - if (!positions_invalid) return; - sort_shortest_distance (); + if (!positions_invalid) return Ok(); + return sort_shortest_distance (); } @@ -605,25 +736,30 @@ struct graph_t * Generates a new topological sorting of graph ordered by the shortest * distance to each node. */ - void sort_shortest_distance () + graph_result_t sort_shortest_distance () { positions_invalid = true; if (vertices_.length <= 1) { // Graph of 1 or less doesn't need sorting. - return; + return Ok(); } - update_distances (); + TRY (update_distances ()); hb_priority_queue_t queue; queue.alloc (vertices_.length); + TRY (graph_result_t::from (queue, ALLOCATION_FAILURE)); + hb_vector_t &new_ordering = ordering_scratch_; - if (unlikely (!check_success (new_ordering.resize (vertices_.length)))) return; + new_ordering.resize (vertices_.length); + TRY (graph_result_t::from (new_ordering, ALLOCATION_FAILURE)); hb_vector_t removed_edges; - if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; - update_parents (); + removed_edges.resize (vertices_.length); + TRY (graph_result_t::from (removed_edges, ALLOCATION_FAILURE)); + + TRY (update_parents ()); queue.insert (root ().modified_distance (0), root_idx ()); unsigned order = 1; @@ -632,16 +768,18 @@ struct graph_t { unsigned next_id = queue.pop_minimum().second; - if (unlikely (!check_success(pos < new_ordering.length))) { + if (unlikely (pos >= new_ordering.length)) { // We are out of ids. Which means we've visited a node more than once. // This graph contains a cycle which is not allowed. DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle."); - return; + return Err(CYCLE_DETECTED); } new_ordering[pos++] = next_id; const vertex_t& next = vertices_[next_id]; - for (const auto& link : next.obj.all_links ()) { + for (const auto& link : next.obj().all_links ()) { + if (unlikely (link.objidx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); removed_edges[link.objidx]++; const auto& v = vertices_[link.objidx]; if (!(v.incoming_edges () - removed_edges[link.objidx])) @@ -655,14 +793,17 @@ struct graph_t } } - check_success (!queue.in_error ()); - check_success (!new_ordering.in_error ()); + TRY (graph_result_t::from (queue, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (new_ordering, ALLOCATION_FAILURE)); hb_swap (ordering_, new_ordering); - if (!check_success (pos == vertices_.length)) { + if (unlikely (pos != vertices_.length)) { print_orphaned_nodes (); + return Err(ORPHANED_NODES); } + + return Ok(); } /* @@ -670,7 +811,7 @@ struct graph_t * More specifically this looks for the top most 24 bit or 32 bit links in the graph. * Some special casing is done that is specific to the layout of GSUB/GPOS tables. */ - void find_space_roots (hb_set_t& visited, hb_set_t& roots) + graph_result_t find_space_roots (hb_set_t& visited, hb_set_t& roots) { unsigned root_index = root_idx (); for (unsigned i : ordering_) @@ -678,7 +819,7 @@ struct graph_t if (visited.has (i)) continue; // Only real links can form 32 bit spaces - for (auto& l : vertices_[i].obj.real_links) + for (const auto& l : vertices_[i].obj().real_links) { if (l.is_signed || l.width < 3) continue; @@ -688,66 +829,71 @@ struct graph_t // pointer to the lookup list. continue; - if (l.width == 3) + if (l.width >= 3) { - // A 24bit offset forms a root, unless there is 32bit offsets somewhere - // in it's subgraph, then those become the roots instead. This is to make sure - // that extension subtables beneath a 24bit lookup become the spaces instead - // of the offset to the lookup. + // A wide offset forms a root, unless there are 32-bit offsets somewhere + // in its subgraph, then those become the roots instead. This is to make sure + // that extension subtables beneath a 24-bit lookup and lookups beneath a + // 32-bit lookup list become the spaces instead of their enclosing lists. hb_set_t sub_roots; - find_32bit_roots (l.objidx, sub_roots); + TRY (find_32bit_roots (l.objidx, sub_roots)); if (sub_roots) { for (unsigned sub_root_idx : sub_roots) { roots.add (sub_root_idx); - find_subgraph (sub_root_idx, visited); + TRY (find_subgraph (sub_root_idx, visited)); } continue; } } roots.add (l.objidx); - find_subgraph (l.objidx, visited); + TRY (find_subgraph (l.objidx, visited)); } } + + TRY(graph_result_t::from (visited, ALLOCATION_FAILURE)); + TRY(graph_result_t::from (roots, ALLOCATION_FAILURE)); + return Ok(); } template - vertex_and_table_t as_table (unsigned parent, const void* offset, Ts... ds) + graph_result_t> as_table (unsigned parent, const void* offset, Ts... ds) { - return as_table_from_index (index_for_offset (parent, offset), std::forward(ds)...); + TRY_ASSIGN (unsigned idx, index_for_offset (parent, offset)); + return as_table_from_index (idx, std::forward(ds)...); } template - vertex_and_table_t as_mutable_table (unsigned parent, const void* offset, Ts... ds) + graph_result_t> as_mutable_table (unsigned parent, const void* offset, Ts... ds) { - return as_table_from_index (mutable_index_for_offset (parent, offset), std::forward(ds)...); + TRY_ASSIGN (auto idx, mutable_index_for_offset (parent, offset)); + return as_table_from_index (idx, std::forward(ds)...); } - template - vertex_and_table_t as_table_from_index (unsigned index, Ts... ds) + template + graph_result_t> as_table_from_index (unsigned index, Ts... ds) { - if (index >= vertices_.length) - return vertex_and_table_t (); + if (unlikely (index >= vertices_.length)) + return Err(OUT_OF_BOUNDS); - vertex_and_table_t r; - r.vertex = &vertices_[index]; - r.table = (T*) r.vertex->obj.head; + vertex_and_table_t r; + r.vertex = (typename std::conditional::type) &vertices_[index]; + r.table = r.vertex->template as::type> (); r.index = index; - if (!r.table) - return vertex_and_table_t (); - - if (!r.table->sanitize (*(r.vertex), std::forward(ds)...)) - return vertex_and_table_t (); + if (unlikely (!r.table)) + return Err(INVALID_ARGUMENT); + TRY(r.table->sanitize (*(r.vertex), std::forward(ds)...)); return r; } // Finds the object id of the object pointed to by the offset at 'offset' // within object[node_idx]. - unsigned index_for_offset (unsigned node_idx, const void* offset) const + graph_result_t index_for_offset (unsigned node_idx, const void* offset) const { + if (unlikely (node_idx >= vertices_.length)) return Err(OUT_OF_BOUNDS); const auto& node = object (node_idx); - if (offset < node.head || offset >= node.tail) return -1; + if (unlikely (offset < node.head || offset >= node.tail)) return Err(OUT_OF_BOUNDS); unsigned count = node.real_links.length; for (unsigned i = 0; i < count; i++) @@ -756,28 +902,31 @@ struct graph_t const auto& link = node.real_links.arrayZ[i]; if (offset != node.head + link.position) continue; - return link.objidx; + return Ok(link.objidx); } - return -1; + return Err(INVALID_ARGUMENT); } // Finds the object id of the object pointed to by the offset at 'offset' // within object[node_idx]. Ensures that the returned object is safe to mutate. // That is, if the original child object is shared by parents other than node_idx // it will be duplicated and the duplicate will be returned instead. - unsigned mutable_index_for_offset (unsigned node_idx, const void* offset) + graph_result_t mutable_index_for_offset (unsigned node_idx, const void* offset) { - unsigned child_idx = index_for_offset (node_idx, offset); + TRY_ASSIGN (unsigned child_idx, index_for_offset (node_idx, offset)); + if (unlikely (child_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + auto& child = vertices_[child_idx]; for (unsigned p : child.parents_iter ()) { if (p != node_idx) { - return duplicate (node_idx, child_idx); + return duplicate (node_idx, child_idx, true); } } - return child_idx; + return Ok(child_idx); } @@ -786,40 +935,55 @@ struct graph_t * Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB * (including with 24bit offsets) table. */ - bool assign_spaces () + graph_result_t assign_spaces () { - update_parents (); + TRY (update_parents ()); + + for (auto& vertex : vertices_.writer ()) + { + vertex.space = 0; + vertex.priority = 0; + } + num_roots_for_space_.resize (1); + TRY (graph_result_t::from (num_roots_for_space_, ALLOCATION_FAILURE)); + num_roots_for_space_[0] = 1; + distance_invalid = true; + positions_invalid = true; hb_set_t visited; hb_set_t roots; - find_space_roots (visited, roots); + TRY (find_space_roots (visited, roots)); // Mark everything not in the subgraphs of the roots as visited. This prevents // subgraphs from being connected via nodes not in those subgraphs. visited.invert (); - if (!roots) return false; + if (!roots) return Ok(false); while (roots) { uint32_t next = HB_SET_VALUE_INVALID; - if (unlikely (!check_success (!roots.in_error ()))) break; + TRY (graph_result_t::from (roots, ALLOCATION_FAILURE)); 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; + TRY (find_connected_nodes (next, roots, visited, connected_roots)); + TRY (graph_result_t::from (connected_roots, ALLOCATION_FAILURE)); - isolate_subgraph (connected_roots); - if (unlikely (!check_success (!connected_roots.in_error ()))) break; + TRY (isolate_subgraph (connected_roots)); + TRY (graph_result_t::from (connected_roots, ALLOCATION_FAILURE)); unsigned next_space = this->next_space (); - if (next_space >= HB_REPACKER_MAX_SPACES) + if (unlikely (next_space >= HB_REPACKER_MAX_SPACES)) { - check_success (false); - break; + DEBUG_MSG (SUBSET_REPACK, nullptr, + "num of spaces %u exceeds HB_REPACKER_MAX_SPACES.", + next_space); + return Err(LIMIT_EXCEEDED); } num_roots_for_space_.push (0); + TRY(graph_result_t::from (num_roots_for_space_, ALLOCATION_FAILURE)); + for (unsigned root : connected_roots) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space); @@ -833,9 +997,7 @@ struct graph_t // into the 32 bit space as needed, instead of using isolation. } - - - return true; + return Ok(true); } /* @@ -845,9 +1007,9 @@ struct graph_t * * Indices stored in roots will be updated if any of the roots are duplicated to new indices. */ - bool isolate_subgraph (hb_set_t& roots) + graph_result_t isolate_subgraph (hb_set_t& roots) { - update_parents (); + TRY(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 @@ -855,11 +1017,15 @@ struct graph_t hb_set_t parents; for (unsigned root_idx : roots) { + if (unlikely (root_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); subgraph.set (root_idx, wide_parents (root_idx, parents)); - find_subgraph (root_idx, subgraph); } - if (subgraph.in_error ()) - return false; + for (unsigned root_idx : roots) + { + TRY (find_subgraph (root_idx, subgraph)); + } + TRY (graph_result_t::from (subgraph, ALLOCATION_FAILURE)); hb_map_t index_map; bool made_changes = false; @@ -873,15 +1039,14 @@ struct graph_t { // Only de-dup objects with incoming links from outside the subgraph. made_changes = true; - duplicate_subgraph (entry.first, index_map); + TRY (duplicate_subgraph (entry.first, index_map)); } } - if (in_error ()) - return false; + TRY (graph_result_t::from (index_map, ALLOCATION_FAILURE)); if (!made_changes) - return false; + return Ok(false); auto new_subgraph = + subgraph.keys () @@ -892,8 +1057,8 @@ struct graph_t }) ; - remap_obj_indices (index_map, new_subgraph); - remap_obj_indices (index_map, parents.iter (), true); + TRY(remap_obj_indices (index_map, new_subgraph)); + TRY(remap_obj_indices (index_map, parents.iter (), true)); // Update roots set with new indices as needed. for (auto next : roots) @@ -906,61 +1071,160 @@ struct graph_t } } - return true; + return Ok(true); } - void find_subgraph (unsigned node_idx, hb_map_t& subgraph) + // BFS graph traversal starting at start_idx. + // + // The visit_edge function will be called once for the root node and then for each traversed edge + // with the following signature: + // + // bool VisitEdgeFunc(unsigned parent, const link_t* link, unsigned child, unsigned depth) + // + // Where a return value of false signals that traversal should not continue into child's outgoing + // edges. parent/child are the vertex indices. depth starts at 0 for the root node. + // link will be null when called for entering the root node at the start of the traversal. + // + // This traversal does not use a visited set internally, it is the responsibility of visit_edge + // to track and filter visited nodes if required for the particular traversal. + template + graph_result_t traverse_directed_bfs (unsigned start_idx, VisitEdgeFunc&& visit_edge) { - for (const auto& link : vertices_[node_idx].obj.all_links ()) + if (unlikely (start_idx >= vertices_.length)) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "traverse_directed_bfs: unexpected start_idx out of bounds."); + return Err(OUT_OF_BOUNDS); + } + + // For performance we want to avoid allocating extra memory. So use the ordering_scratch_ + // buffer to implement a queue for BFS. + ordering_scratch_.resize (vertices_.length); + TRY (graph_result_t::from (ordering_scratch_, ALLOCATION_FAILURE)); + + if (!visit_edge (HB_CODEPOINT_INVALID, nullptr, start_idx, 0)) + return Ok(); + + unsigned head = 0; + unsigned tail = 0; + auto& queue = ordering_scratch_; + queue[tail++] = start_idx; + + unsigned depth = 0; + while (head < tail) { - hb_codepoint_t *v; - if (subgraph.has (link.objidx, &v)) + unsigned level_end = tail; + while (head < level_end) { - (*v)++; - continue; + unsigned node_idx = queue[head++]; + const auto& v = vertices_[node_idx]; + + unsigned num_real = v.obj().real_links.length; + unsigned total_links = num_real + v.obj().virtual_links.length; + + for (unsigned i = 0; i < total_links; i++) + { + // vertices_ may have re-alloc'd inside an op() call, so reassign the v ref. + const auto& v = vertices_[node_idx]; + const auto& link = (i < num_real) + ? v.obj().real_links[i] + : v.obj().virtual_links[i - num_real]; + unsigned child_idx = link.objidx; + + if (!visit_edge (node_idx, &link, child_idx, depth + 1)) + continue; + + if (unlikely (tail >= queue.length)) + return Err(CYCLE_DETECTED); + + queue[tail++] = child_idx; + } } - subgraph.set (link.objidx, 1); - find_subgraph (link.objidx, subgraph); + depth++; } + return Ok(); } - void find_subgraph (unsigned node_idx, hb_set_t& subgraph) + graph_result_t find_subgraph (unsigned node_idx, hb_map_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); + return traverse_directed_bfs (node_idx, [&] ( + unsigned parent, + const hb_serialize_context_t::object_t::link_t* link, + unsigned child, + unsigned depth) { + if (depth == 0) return true; + hb_codepoint_t *count; + if (subgraph.has (child, &count)) + { + (*count)++; + return false; + } + subgraph.set (child, 1); + return true; + }); } - size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = -1) + graph_result_t find_subgraph (unsigned node_idx, hb_set_t& subgraph) { - if (subgraph.has (node_idx)) return 0; - subgraph.add (node_idx); - - const auto& o = vertices_[node_idx].obj; - size_t size = o.tail - o.head; - if (max_depth == 0) - return size; + return traverse_directed_bfs (node_idx, [&] ( + unsigned parent, + const hb_serialize_context_t::object_t::link_t* link, + unsigned child, + unsigned depth) { + if (subgraph.has (child)) return false; + subgraph.add (child); + return true; + }); + } - for (const auto& link : o.all_links ()) - size += find_subgraph_size (link.objidx, subgraph, max_depth - 1); - return size; + graph_result_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = HB_GRAPH_INVALID) + { + size_t size = 0; + TRY (traverse_directed_bfs (node_idx, [&] ( + unsigned parent, + const hb_serialize_context_t::object_t::link_t* link, + unsigned child, + unsigned depth) { + if (subgraph.has (child)) return false; + subgraph.add (child); + + const auto& o = vertices_[child].obj(); + size += o.tail - o.head; + return depth < max_depth; + })); + return Ok(size); } /* * Finds the topmost children of 32bit offsets in the subgraph starting * at node_idx. Found indices are placed into 'found'. */ - void find_32bit_roots (unsigned node_idx, hb_set_t& found) + graph_result_t find_32bit_roots (unsigned node_idx, hb_set_t& found) { - for (const auto& link : vertices_[node_idx].obj.all_links ()) - { - if (!link.is_signed && link.width == 4) { - found.add (link.objidx); - continue; + // Note: this specifically requires a BFS based traversal to ensure we don't recurse through + // a node that is accessible via both 32bit and non-32 bit links. + hb_set_t visited; + return traverse_directed_bfs (node_idx, [&] ( + unsigned parent, + const hb_serialize_context_t::object_t::link_t* link, + unsigned child, + unsigned _) { + + if (link && found.has(parent)) + // Don't traverse from something that's already marked as a root. + return false; + + if (link && !link->is_signed && link->width == 4) + { + found.add (link->objidx); + visited.add (link->objidx); + return false; } - find_32bit_roots (link.objidx, found); - } + + if (visited.has (child)) return false; + visited.add (child); + return true; + }); } /* @@ -970,32 +1234,35 @@ struct graph_t * Returns the id of the child node that was moved. */ template - unsigned move_child (unsigned old_parent_idx, - const O* old_offset, - unsigned new_parent_idx, - const O* new_offset) + graph_result_t move_child (unsigned old_parent_idx, + const O* old_offset, + unsigned new_parent_idx, + const O* new_offset) { distance_invalid = true; positions_invalid = true; + if (unlikely (old_parent_idx >= vertices_.length || + new_parent_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + auto& old_v = vertices_[old_parent_idx]; auto& new_v = vertices_[new_parent_idx]; - unsigned child_id = index_for_offset (old_parent_idx, - old_offset); + TRY_ASSIGN (unsigned child_id, index_for_offset (old_parent_idx, + old_offset)); + if (unlikely (child_id >= vertices_.length)) + return Err(OUT_OF_BOUNDS); - auto* new_link = new_v.obj.real_links.push (); - new_link->width = O::static_size; - new_link->objidx = child_id; - new_link->position = (const char*) new_offset - (const char*) new_v.obj.head; + TRY(new_v.add_real_link(O::static_size, child_id, (const char*) new_offset - (const char*) new_v.obj().head)); auto& child = vertices_[child_id]; - child.add_parent (new_parent_idx, false); + TRY(child.add_parent (new_parent_idx, false)); - old_v.remove_real_link (child_id, old_offset); + old_v.remove_real_link_unordered (child_id, old_offset); child.remove_parent (old_parent_idx); - return child_id; + return Ok(child_id); } /* @@ -1005,12 +1272,16 @@ struct graph_t * parent starting at new_pos_start. */ template - void move_children (unsigned old_parent_idx, - unsigned old_pos_start, - unsigned old_pos_end, - unsigned new_parent_idx, - unsigned new_pos_start) + graph_result_t move_children (unsigned old_parent_idx, + unsigned old_pos_start, + unsigned old_pos_end, + unsigned new_parent_idx, + unsigned new_pos_start) { + if (unlikely (old_parent_idx >= vertices_.length || + new_parent_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + distance_invalid = true; positions_invalid = true; @@ -1018,28 +1289,29 @@ struct graph_t auto& new_v = vertices_[new_parent_idx]; hb_vector_t old_links; - for (const auto& l : old_v.obj.real_links) + for (const auto& l : old_v.obj().real_links) { if (l.position < old_pos_start || l.position >= old_pos_end) { - old_links.push(l); + old_links.push (l); continue; } unsigned array_pos = l.position - old_pos_start; unsigned child_id = l.objidx; - auto* new_link = new_v.obj.real_links.push (); - new_link->width = O::static_size; - new_link->objidx = child_id; - new_link->position = new_pos_start + array_pos; + if (unlikely (child_id >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + + TRY(new_v.add_real_link(O::static_size, child_id, new_pos_start + array_pos)); auto& child = vertices_[child_id]; - child.add_parent (new_parent_idx, false); + TRY(child.add_parent (new_parent_idx, false)); child.remove_parent (old_parent_idx); } - old_v.obj.real_links = std::move (old_links); + TRY (graph_result_t::from (old_links, ALLOCATION_FAILURE)); + return old_v.set_real_links(std::move (old_links)); } /* @@ -1047,65 +1319,92 @@ struct graph_t * 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) + graph_result_t duplicate_subgraph (unsigned node_idx, hb_map_t& index_map) { - if (index_map.has (node_idx)) - return; - - unsigned clone_idx = duplicate (node_idx); - if (!check_success (clone_idx != (unsigned) -1)) - return; + graph_result_t result = Ok(); + TRY (traverse_directed_bfs (node_idx, [&] ( + unsigned parent, + const hb_serialize_context_t::object_t::link_t* link, + unsigned child, + unsigned _) { + if (result.is_err () || index_map.has (child)) return false; + auto r = duplicate (child); + if (unlikely (r.is_err ())) + { + result = Err(r.error ()); + return false; + } + index_map.set (child, *r); + return true; + })); - index_map.set (node_idx, clone_idx); - for (const auto& l : object (node_idx).all_links ()) { - duplicate_subgraph (l.objidx, index_map); - } + return graph_result_t::from(index_map, ALLOCATION_FAILURE); } /* * Creates a copy of node_idx and returns it's new index. */ - unsigned duplicate (unsigned node_idx) + graph_result_t duplicate (unsigned node_idx, bool copy_table = false) { - if (vertices_.length >= HB_REPACKER_MAX_VERTICES) + if (unlikely (node_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + + if (unlikely (vertices_.length >= HB_REPACKER_MAX_VERTICES)) { - check_success (false); - return -1; + DEBUG_MSG (SUBSET_REPACK, nullptr, + "duplicating node: num of vertices %u exceeds HB_REPACKER_MAX_VERTICES.", + vertices_.length); + return Err(LIMIT_EXCEEDED); } positions_invalid = true; distance_invalid = true; auto* clone = vertices_.push (); + TRY (graph_result_t::from (vertices_, ALLOCATION_FAILURE)); + unsigned clone_idx = vertices_.length - 1; - ordering_.push(clone_idx); + ordering_.push (clone_idx); + TRY (graph_result_t::from (ordering_, ALLOCATION_FAILURE)); auto& child = vertices_[node_idx]; - if (vertices_.in_error () || ordering_.in_error()) { - return -1; - } - clone->obj.head = child.obj.head; - clone->obj.tail = child.obj.tail; + unsigned table_size = child.obj().tail - child.obj().head; + if (copy_table && table_size) + { + char* buffer = (char*) hb_malloc (table_size); + if (unlikely (!buffer)) + return Err(ALLOCATION_FAILURE); + auto res = add_buffer (buffer); + if (unlikely (res.is_err ())) + { + hb_free (buffer); + return Err(res.error ()); + } + hb_memcpy (buffer, child.obj().head, table_size); + clone->set_buffer(buffer, buffer + table_size); + } + else + { + clone->set_buffer(child.obj().head, child.obj().tail); + } clone->distance = child.distance; clone->space = child.space; clone->reset_parents (); - for (const auto& l : child.obj.real_links) + for (const auto& l : child.obj().real_links) { - clone->obj.real_links.push (l); - vertices_[l.objidx].add_parent (clone_idx, false); + TRY(clone->add_real_link (l)); + TRY(vertices_[l.objidx].add_parent (clone_idx, false)); } - for (const auto& l : child.obj.virtual_links) + + for (const auto& l : child.obj().virtual_links) { - clone->obj.virtual_links.push (l); - vertices_[l.objidx].add_parent (clone_idx, true); + TRY(clone->add_virtual_link (l)); + TRY(vertices_[l.objidx].add_parent (clone_idx, true)); } - check_success (!clone->obj.real_links.in_error ()); - check_success (!clone->obj.virtual_links.in_error ()); - - return clone_idx; + return Ok(clone_idx); } /* @@ -1116,16 +1415,19 @@ struct graph_t * Returns the index of the newly created duplicate. * * If the child_idx only has incoming edges from parent_idx, - * duplication isn't possible and this will return -1. + * duplication isn't possible and this will return an error. */ - unsigned duplicate (unsigned parent_idx, unsigned child_idx) + graph_result_t duplicate (unsigned parent_idx, unsigned child_idx, bool copy_table = false) { - update_parents (); + if (unlikely (parent_idx >= vertices_.length || child_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + + TRY (update_parents ()); const auto& child = vertices_[child_idx]; - unsigned links_to_child = child.incoming_edges_from_parent(parent_idx); + unsigned links_to_child = child.incoming_edges_from_parent (parent_idx); - if (child.incoming_edges () <= links_to_child || child.has_incoming_virtual_edges()) + if (unlikely (child.incoming_edges () <= links_to_child || child.has_incoming_virtual_edges ())) { // Can't duplicate this node, doing so would orphan the original one as all remaining links // to child are from parent. @@ -1136,30 +1438,29 @@ struct graph_t // to by virtual edges). DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u => %u", parent_idx, child_idx); - return -1; + return Err(INVALID_ARGUMENT); } DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u => %u", parent_idx, child_idx); - unsigned clone_idx = duplicate (child_idx); - if (clone_idx == (unsigned) -1) return -1; + TRY_ASSIGN (unsigned clone_idx, duplicate (child_idx, copy_table)); // 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]; unsigned count = 0; - unsigned num_real = parent.obj.real_links.length; - for (auto& l : parent.obj.all_links_writer ()) + unsigned num_real = parent.obj().real_links.length; + for (auto& l : parent.all_links_writer ()) { count++; if (l.objidx != child_idx) continue; - reassign_link (l, parent_idx, clone_idx, count > num_real); + TRY(reassign_link (l, parent_idx, clone_idx, count > num_real)); } - return clone_idx; + return Ok(clone_idx); } /* @@ -1171,25 +1472,29 @@ struct graph_t * * If the child_idx only has incoming edges from parents, * duplication isn't possible or duplication fails and this will - * return -1. + * return an error. */ - unsigned duplicate (const hb_set_t* parents, unsigned child_idx) + graph_result_t duplicate (const hb_set_t* parents, unsigned child_idx) { - if (parents->is_empty()) { - return -1; - } + if (unlikely (!parents || parents->is_empty ())) + return Err(INVALID_ARGUMENT); - update_parents (); + if (unlikely (child_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + + TRY (update_parents ()); const auto& child = vertices_[child_idx]; unsigned links_to_child = 0; - unsigned last_parent = parents->get_max(); - unsigned first_parent = parents->get_min(); + unsigned last_parent = parents->get_max (); + unsigned first_parent = parents->get_min (); for (unsigned parent_idx : *parents) { - links_to_child += child.incoming_edges_from_parent(parent_idx); + if (unlikely (parent_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + links_to_child += child.incoming_edges_from_parent (parent_idx); } - if (child.incoming_edges () <= links_to_child || child.has_incoming_virtual_edges()) + if (unlikely (child.incoming_edges () <= links_to_child || child.has_incoming_virtual_edges ())) { // Can't duplicate this node, doing so would orphan the original one as all remaining links // to child are from parent. @@ -1199,62 +1504,61 @@ struct graph_t // with virtual edges may end up orphaned by duplication (ie. where one copy is only pointed // to by virtual edges). DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx); - return -1; + return Err(INVALID_ARGUMENT); } DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx); - unsigned clone_idx = duplicate (child_idx); - if (clone_idx == (unsigned) -1) return false; + TRY_ASSIGN (unsigned clone_idx, duplicate (child_idx)); for (unsigned parent_idx : *parents) { // 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]; unsigned count = 0; - unsigned num_real = parent.obj.real_links.length; - for (auto& l : parent.obj.all_links_writer ()) + unsigned num_real = parent.obj().real_links.length; + for (auto& l : parent.all_links_writer ()) { count++; if (l.objidx != child_idx) continue; - reassign_link (l, parent_idx, clone_idx, count > num_real); + TRY(reassign_link (l, parent_idx, clone_idx, count > num_real)); } } - return clone_idx; + return Ok(clone_idx); } /* * Adds a new node to the graph, not connected to anything. */ - unsigned new_node (char* head, char* tail) + graph_result_t new_node (char* head, char* tail) { - if (vertices_.length >= HB_REPACKER_MAX_VERTICES) + if (unlikely (vertices_.length >= HB_REPACKER_MAX_VERTICES)) { - check_success (false); - return -1; + DEBUG_MSG (SUBSET_REPACK, nullptr, + "creating new node: num of vertices %u exceeds HB_REPACKER_MAX_VERTICES.", + vertices_.length); + return Err(LIMIT_EXCEEDED); } positions_invalid = true; distance_invalid = true; auto* clone = vertices_.push (); - unsigned clone_idx = vertices_.length - 1; - ordering_.push(clone_idx); + TRY (graph_result_t::from (vertices_, ALLOCATION_FAILURE)); - if (vertices_.in_error () || ordering_.in_error()) { - return -1; - } + unsigned clone_idx = vertices_.length - 1; + ordering_.push (clone_idx); + TRY (graph_result_t::from (ordering_, ALLOCATION_FAILURE)); - clone->obj.head = head; - clone->obj.tail = tail; + clone->set_buffer (head, tail); clone->distance = 0; clone->space = 0; - return clone_idx; + return Ok(clone_idx); } /* @@ -1263,59 +1567,61 @@ struct graph_t * Returns the index of the newly created child. * */ - unsigned remap_child (unsigned parent_idx, unsigned old_child_idx) + graph_result_t remap_child (unsigned parent_idx, unsigned old_child_idx) { - unsigned new_child_idx = duplicate (old_child_idx); - if (new_child_idx == (unsigned) -1) return -1; + if (unlikely (parent_idx >= vertices_.length || old_child_idx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + + TRY_ASSIGN (unsigned new_child_idx, duplicate (old_child_idx)); auto& parent = vertices_[parent_idx]; - for (auto& l : parent.obj.real_links) + for (auto& l : parent.real_links_writer ()) { if (l.objidx != old_child_idx) continue; - reassign_link (l, parent_idx, new_child_idx, false); + TRY(reassign_link (l, parent_idx, new_child_idx, false)); } - for (auto& l : parent.obj.virtual_links) + for (auto& l : parent.virtual_links_writer ()) { if (l.objidx != old_child_idx) continue; - reassign_link (l, parent_idx, new_child_idx, true); + TRY(reassign_link (l, parent_idx, new_child_idx, true)); } - return new_child_idx; + return Ok(new_child_idx); } /* * Raises the sorting priority of all children. */ - bool raise_childrens_priority (unsigned parent_idx) + graph_result_t raise_childrens_priority (unsigned parent_idx) { DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %u", 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; + if (unlikely (parent_idx >= vertices_.length)) return Err(OUT_OF_BOUNDS); bool made_change = false; - for (auto& l : parent.all_links_writer ()) + for (auto& l : vertices_[parent_idx].all_links_writer ()) made_change |= vertices_[l.objidx].raise_priority (); - return made_change; + return Ok(made_change); } - bool is_fully_connected () + graph_result_t is_fully_connected () { - update_parents(); + TRY(update_parents()); - if (root().incoming_edges ()) + if (unlikely (root().incoming_edges ())) // Root cannot have parents. - return false; + return Err(ORPHANED_NODES); for (unsigned i = 0; i < root_idx (); i++) { - if (!vertices_[i].incoming_edges ()) - return false; + if (unlikely (!vertices_[i].incoming_edges ())) + return Err(ORPHANED_NODES); } - return true; + return Ok(); } #if 0 @@ -1368,27 +1674,6 @@ struct graph_t } #endif - 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(); - - if (root().incoming_edges ()) { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges."); - } - - for (unsigned i = 0; i < root_idx (); i++) - { - const auto& v = vertices_[i]; - if (!v.incoming_edges ()) - DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i); - } - } - unsigned num_roots_for_space (unsigned space) const { return num_roots_for_space_[space]; @@ -1399,17 +1684,22 @@ struct graph_t return num_roots_for_space_.length; } - void move_to_new_space (const hb_set_t& indices) + graph_result_t move_to_new_space (const hb_set_t& indices) { - if (num_roots_for_space_.length >= HB_REPACKER_MAX_SPACES) + if (unlikely (num_roots_for_space_.length >= HB_REPACKER_MAX_SPACES)) { - check_success (false); - return; + DEBUG_MSG (SUBSET_REPACK, nullptr, + "move_to_new_space: num of spaces %u exceeds HB_REPACKER_MAX_SPACES.", + num_roots_for_space_.length); + return Err(LIMIT_EXCEEDED); } num_roots_for_space_.push (0); + TRY (graph_result_t::from (num_roots_for_space_, ALLOCATION_FAILURE)); unsigned new_space = num_roots_for_space_.length - 1; for (unsigned index : indices) { + if (unlikely (index >= vertices_.length)) + return Err(OUT_OF_BOUNDS); 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; @@ -1417,39 +1707,38 @@ struct graph_t distance_invalid = true; positions_invalid = true; } + return Ok(); } unsigned space_for (unsigned index, unsigned* root = nullptr) const { - loop: - assert (index < vertices_.length); - const auto& node = vertices_[index]; - if (node.space) + while (true) { - if (root != nullptr) - *root = index; - return node.space; - } + assert (index < vertices_.length); + const auto& node = vertices_[index]; + if (node.space) + { + if (root != nullptr) + *root = index; + return node.space; + } - if (!node.incoming_edges ()) - { - if (root) - *root = index; - return 0; - } + if (!node.incoming_edges ()) + { + if (root) + *root = index; + return 0; + } - index = *node.parents_iter (); - goto loop; + index = *node.parents_iter (); + } } - void err_other_error () { this->successful = false; } - size_t total_size_in_bytes () const { size_t total_size = 0; unsigned count = vertices_.length; for (unsigned i = 0; i < count; i++) { - const auto& obj = vertices_.arrayZ[i].obj; - size_t size = obj.tail - obj.head; + size_t size = vertices_.arrayZ[i].table_size (); total_size += size; } return total_size; @@ -1458,6 +1747,27 @@ struct graph_t private: + void print_orphaned_nodes () + { + if (!DEBUG_ENABLED(SUBSET_REPACK)) return; + + DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); + + parents_invalid = true; + (void) update_parents(); + + if (root().incoming_edges ()) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges."); + } + + for (unsigned i = 0; i < vertices_.length; i++) + { + const auto& v = vertices_[i]; + if (!v.incoming_edges ()) + DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i); + } + } + /* * Returns the numbers of incoming edges that are 24 or 32 bits wide. */ @@ -1467,7 +1777,7 @@ struct graph_t for (unsigned p : vertices_[node_idx].parents_iter ()) { // Only real links can be wide - for (const auto& l : vertices_[p].obj.real_links) + for (const auto& l : vertices_[p].obj().real_links) { if (l.objidx == node_idx && (l.width == 3 || l.width == 4) @@ -1481,16 +1791,13 @@ struct graph_t 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 () + graph_result_t update_parents () { - if (!parents_invalid) return; + if (!parents_invalid) return Ok(); unsigned count = vertices_.length; @@ -1499,19 +1806,21 @@ struct graph_t for (unsigned p = 0; p < count; p++) { - for (auto& l : vertices_.arrayZ[p].obj.real_links) - vertices_[l.objidx].add_parent (p, false); + for (const auto& l : vertices_.arrayZ[p].obj().real_links) + { + if (unlikely (l.objidx >= count)) return Err(INVALID_ARGUMENT); + TRY(vertices_[l.objidx].add_parent (p, false)); + } - for (auto& l : vertices_.arrayZ[p].obj.virtual_links) - vertices_[l.objidx].add_parent (p, true); + for (const auto& l : vertices_.arrayZ[p].obj().virtual_links) + { + if (unlikely (l.objidx >= count)) return Err(INVALID_ARGUMENT); + TRY(vertices_[l.objidx].add_parent (p, true)); + } } - for (unsigned i = 0; i < count; i++) - // parents arrays must be accurate or downstream operations like cycle detection - // and sorting won't work correctly. - check_success (!vertices_.arrayZ[i].in_error ()); - parents_invalid = false; + return Ok(); } /* @@ -1526,7 +1835,7 @@ struct graph_t { auto& v = vertices_[i]; v.start = current_pos; - current_pos += v.obj.tail - v.obj.head; + current_pos += v.obj().tail - v.obj().head; v.end = current_pos; } @@ -1537,9 +1846,9 @@ struct graph_t * Finds the distance to each object in the graph * from the initial node. */ - void update_distances () + graph_result_t update_distances () { - if (!distance_invalid) return; + if (!distance_invalid) return Ok(); // Uses Dijkstra's algorithm to find all of the shortest distances. // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm @@ -1559,9 +1868,11 @@ struct graph_t hb_priority_queue_t queue; queue.alloc (count); queue.insert (0, root_idx ()); + TRY (graph_result_t::from (queue, ALLOCATION_FAILURE)); hb_vector_t visited; visited.resize (vertices_.length); + TRY (graph_result_t::from (visited, ALLOCATION_FAILURE)); while (!queue.in_error () && !queue.is_empty ()) { @@ -1571,12 +1882,15 @@ struct graph_t int64_t next_distance = next.distance; visited[next_idx] = true; - for (const auto& link : next.obj.all_links ()) + for (const auto& link : next.obj().all_links ()) { + if (unlikely (link.objidx >= vertices_.length)) + return Err(OUT_OF_BOUNDS); + if (visited[link.objidx]) continue; auto& child_v = vertices_.arrayZ[link.objidx]; - const auto& child = child_v.obj; + const auto& child = child_v.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)) * (child_v.space + 1); @@ -1590,14 +1904,15 @@ struct graph_t } } - check_success (!queue.in_error ()); - if (!check_success (queue.is_empty ())) + TRY (graph_result_t::from (queue, ALLOCATION_FAILURE)); + if (unlikely (!queue.is_empty ())) { print_orphaned_nodes (); - return; + return Err(ORPHANED_NODES); } distance_invalid = false; + return Ok(); } private: @@ -1605,7 +1920,7 @@ struct graph_t * 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, + graph_result_t reassign_link (hb_serialize_context_t::object_t::link_t& link, unsigned parent_idx, unsigned new_idx, bool is_virtual) @@ -1613,33 +1928,34 @@ struct graph_t unsigned old_idx = link.objidx; link.objidx = new_idx; vertices_[old_idx].remove_parent (parent_idx); - vertices_[new_idx].add_parent (parent_idx, is_virtual); + return vertices_[new_idx].add_parent (parent_idx, is_virtual); } /* * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts. */ template - void remap_obj_indices (const hb_map_t& id_map, - Iterator subgraph, - bool only_wide = false) + graph_result_t remap_obj_indices (const hb_map_t& id_map, + Iterator subgraph, + bool only_wide = false) { - if (!id_map) return; + if (!id_map) return Ok(); for (unsigned i : subgraph) { - auto& obj = vertices_[i].obj; - unsigned num_real = obj.real_links.length; + auto& vertex = vertices_[i]; + unsigned num_real = vertex.obj().real_links.length; unsigned count = 0; - for (auto& link : obj.all_links_writer ()) + for (auto& link : vertex.all_links_writer ()) { count++; const uint32_t *v; if (!id_map.has (link.objidx, &v)) continue; if (only_wide && (link.is_signed || (link.width != 4 && link.width != 3))) continue; - reassign_link (link, i, *v, count > num_real); + TRY(reassign_link (link, i, *v, count > num_real)); } } + return Ok(); } /* @@ -1649,29 +1965,71 @@ struct graph_t * 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) + graph_result_t 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)) + TRY (graph_result_t::from (visited, ALLOCATION_FAILURE)); + if (visited.has (start_idx)) return Ok(); + if (unlikely (start_idx >= vertices_.length)) { - targets.del (start_idx); - connected.add (start_idx); + DEBUG_MSG (SUBSET_REPACK, nullptr, + "find_connected_nodes: unexpected start_idx out of bounds."); + return Err(OUT_OF_BOUNDS); } - const auto& v = vertices_[start_idx]; + // For performance we want to avoid allocating extra memory. So use the ordering_scratch_ + // buffer to implement a stack for DFS. + ordering_scratch_.resize (vertices_.length); + TRY (graph_result_t::from (ordering_scratch_, ALLOCATION_FAILURE)); + + auto& stack = ordering_scratch_; + unsigned stack_len = 0; + + graph_result_t res = Ok(); + auto handle_node = [&] (unsigned node_idx) { + visited.add (node_idx); + if (targets.has (node_idx)) { + targets.del (node_idx); + connected.add (node_idx); + } + + if (unlikely (stack_len >= stack.length)) + { + res = Err(CYCLE_DETECTED); + return false; + } + stack[stack_len++] = node_idx; + return true; + }; + + if (!handle_node (start_idx)) return res; + + while (stack_len > 0) + { + unsigned node_idx = stack[--stack_len]; + const auto& v = vertices_[node_idx]; + + // Graph is treated as undirected so search children and parents of node_idx + for (const auto& l : v.obj().all_links ()) + { + unsigned child_idx = l.objidx; + if (visited.has (child_idx)) continue; + if (!handle_node (child_idx)) return res; + } + + for (unsigned parent_idx : v.parents_iter ()) + { + if (visited.has (parent_idx)) continue; + if (!handle_node (parent_idx)) return res; + } + } - // 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); + TRY (graph_result_t::from (visited, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (connected, ALLOCATION_FAILURE)); - for (unsigned p : v.parents_iter ()) - find_connected_nodes (p, targets, visited, connected); + return Ok(); } public: @@ -1688,10 +2046,9 @@ struct graph_t hb_vector_t ordering_scratch_; private: - bool parents_invalid; - bool distance_invalid; - bool positions_invalid; - bool successful; + bool parents_invalid = true; + bool distance_invalid = true; + bool positions_invalid = true; hb_vector_t num_roots_for_space_; hb_vector_t buffers; }; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc index d66eb49cfd2..02c5e8742ce 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc @@ -28,34 +28,41 @@ namespace graph { +graph_result_t gsubgpos_graph_context_t::create (hb_tag_t table_tag_, + graph_t& graph_) +{ + gsubgpos_graph_context_t context (table_tag_, graph_); + + if (unlikely (table_tag_ != HB_OT_TAG_GPOS + && table_tag_ != HB_OT_TAG_GSUB)) + return Err(INVALID_ARGUMENT); + + TRY_ASSIGN (const GSTAR* gstar, graph::GSTAR::graph_to_gstar (context.graph)); + TRY(gstar->find_lookups (context.graph, context.lookups)); + TRY_ASSIGN (context.lookup_list_index, gstar->get_lookup_list_index (context.graph)); + + return context; +} + gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_, graph_t& graph_) : table_tag (table_tag_), graph (graph_), lookup_list_index (0), lookups () -{ - if (table_tag_ != HB_OT_TAG_GPOS - && table_tag_ != HB_OT_TAG_GSUB) - return; - - GSTAR* gstar = graph::GSTAR::graph_to_gstar (graph_); - if (gstar) { - gstar->find_lookups (graph, lookups); - lookup_list_index = gstar->get_lookup_list_index (graph_); - } -} +{} -unsigned gsubgpos_graph_context_t::create_node (unsigned size) +graph_result_t gsubgpos_graph_context_t::create_node (unsigned size) { char* buffer = (char*) hb_calloc (1, size); - if (!buffer) - return -1; + if (unlikely (!buffer)) + return Err(ALLOCATION_FAILURE); - if (!add_buffer (buffer)) { + auto res = add_buffer (buffer); + if (unlikely (!res.is_ok ())) { // Allocation did not get stored for freeing later. hb_free (buffer); - return -1; + return Err(res.error ()); } return graph.new_node (buffer, buffer + size); diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh index 8969d007879..947669f8700 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh @@ -36,6 +36,9 @@ struct Lookup; struct gsubgpos_graph_context_t { + HB_INTERNAL static graph_result_t create (hb_tag_t table_tag_, + graph_t& graph_); + hb_tag_t table_tag; graph_t& graph; unsigned lookup_list_index; @@ -43,17 +46,18 @@ struct gsubgpos_graph_context_t hb_hashmap_t subtable_to_extension; hb_hashmap_t> split_subtables; - HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_, - graph_t& graph_); - HB_INTERNAL unsigned create_node (unsigned size); + HB_INTERNAL graph_result_t create_node (unsigned size); - bool add_buffer (char* buffer) + graph_result_t add_buffer (char* buffer) { return graph.add_buffer (buffer); } private: + HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_, + graph_t& graph_); + HB_INTERNAL unsigned num_non_ext_subtables (); }; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh index 73f4b15660f..044ddf3317c 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh @@ -50,10 +50,12 @@ struct ExtensionFormat1 : public OT::ExtensionFormat1 this->extensionOffset = 0; } - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - return vertex_len >= OT::ExtensionFormat1::static_size; + size_t vertex_len = vertex.table_size (); + if (unlikely (vertex_len < OT::ExtensionFormat1::static_size)) + return Err(SANITIZE_FAILURE); + return Ok(); } unsigned get_lookup_type () const @@ -61,7 +63,7 @@ struct ExtensionFormat1 : public OT::ExtensionFormat1 return this->extensionLookupType; } - unsigned get_subtable_index (graph_t& graph, unsigned this_index) const + graph_result_t get_subtable_index (graph_t& graph, unsigned this_index) const { return graph.index_for_offset (this_index, &this->extensionOffset); } @@ -74,12 +76,13 @@ struct Lookup : public OT::Lookup return subTable.len; } - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < OT::Lookup::min_size) return false; + size_t vertex_len = vertex.table_size (); + if (unlikely (vertex_len < OT::Lookup::min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= this->get_size (); + if (unlikely (vertex_len < this->get_size ())) return Err(SANITIZE_FAILURE); + return Ok(); } bool is_extension (hb_tag_t table_tag) const @@ -93,15 +96,15 @@ struct Lookup : public OT::Lookup return flag & 0x0010u; } - bool make_extension (gsubgpos_graph_context_t& c, - unsigned this_index) + graph_result_t make_extension (gsubgpos_graph_context_t& c, + unsigned this_index) { unsigned type = lookupType; unsigned ext_type = extension_type (c.table_tag); if (!ext_type || is_extension (c.table_tag)) { // NOOP - return true; + return Ok(); } DEBUG_MSG (SUBSET_REPACK, nullptr, @@ -109,44 +112,55 @@ struct Lookup : public OT::Lookup type, this_index); + hb_set_t seen; + hb_vector_t subtables; for (unsigned i = 0; i < subTable.len; i++) { - unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); - if (!make_subtable_extension (c, - this_index, - subtable_index)) - return false; + TRY_ASSIGN (unsigned subtable_index, c.graph.index_for_offset (this_index, &subTable[i])); + if (seen.has (subtable_index)) + continue; + seen.add (subtable_index); + subtables.push (subtable_index); } + TRY (graph_result_t::from (seen, ALLOCATION_FAILURE)); + TRY (graph_result_t::from (subtables, ALLOCATION_FAILURE)); + + for (unsigned subtable_index : subtables) + TRY (make_subtable_extension (c, this_index, subtable_index)); lookupType = ext_type; - return true; + return Ok(); } - bool split_subtables_if_needed (gsubgpos_graph_context_t& c, - unsigned this_index) + graph_result_t split_subtables_if_needed (gsubgpos_graph_context_t& c, + unsigned this_index) { unsigned type = lookupType; bool is_ext = is_extension (c.table_tag); if (c.table_tag != HB_OT_TAG_GPOS && c.table_tag != HB_OT_TAG_GSUB) - return true; + return Ok(); if (!is_ext && !is_supported_gpos_type(type, c) && !is_supported_gsub_type(type, c)) - return true; + return Ok(); hb_vector_t>> all_new_subtables; for (unsigned i = 0; i < subTable.len; i++) { - unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); + // This assumes we are working with something like a GSUB/GPOS table, if + // sanitization fails we ignore and skip splitting for the particular sub table. + auto idx_res = c.graph.index_for_offset (this_index, &subTable[i]); + if (!idx_res.is_ok ()) continue; + unsigned subtable_index = *idx_res; if (is_ext) { unsigned ext_subtable_index = subtable_index; ExtensionFormat1* extension = (ExtensionFormat1*) c.graph.object (ext_subtable_index).head; - if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index])) + if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index]).is_ok ()) continue; - subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index); + TRY_ASSIGN (subtable_index, extension->get_subtable_index (c.graph, ext_subtable_index)); type = extension->get_lookup_type (); if (!is_supported_gpos_type(type, c) && !is_supported_gsub_type(type, c)) continue; @@ -158,6 +172,7 @@ struct Lookup : public OT::Lookup if (split_result->length == 0) continue; all_new_subtables.push (hb_pair(i, *split_result)); + TRY (graph_result_t::from (all_new_subtables, ALLOCATION_FAILURE)); } else { @@ -167,9 +182,15 @@ struct Lookup : public OT::Lookup switch (type) { case 2: - new_sub_tables = split_subtable (c, subtable_index); break; + { + TRY_ASSIGN (new_sub_tables, split_subtable (c, subtable_index)); + break; + } case 4: - new_sub_tables = split_subtable (c, subtable_index); break; + { + TRY_ASSIGN (new_sub_tables, split_subtable (c, subtable_index)); + break; + } default: break; } @@ -177,42 +198,46 @@ struct Lookup : public OT::Lookup switch (type) { case 4: - new_sub_tables = split_subtable (c, subtable_index); break; + { + TRY_ASSIGN (new_sub_tables, split_subtable (c, subtable_index)); + break; + } default: break; } } - if (new_sub_tables.in_error ()) return false; - c.split_subtables.set (subtable_index, new_sub_tables); - if (new_sub_tables) + TRY (graph_result_t::from (c.split_subtables, ALLOCATION_FAILURE)); + if (new_sub_tables) { all_new_subtables.push (hb_pair (i, std::move (new_sub_tables))); + TRY (graph_result_t::from (all_new_subtables, ALLOCATION_FAILURE)); + } } } if (all_new_subtables) { - return add_sub_tables (c, this_index, type, all_new_subtables); + TRY (add_sub_tables (c, this_index, type, all_new_subtables)); } - return true; + return Ok(); } template - hb_vector_t split_subtable (gsubgpos_graph_context_t& c, - unsigned objidx) + graph_result_t> split_subtable (gsubgpos_graph_context_t& c, + unsigned objidx) { T* sub_table = (T*) c.graph.object (objidx).head; - if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx])) - return hb_vector_t (); + if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]).is_ok ()) + return Ok(hb_vector_t ()); return sub_table->split_subtables (c, objidx); } - bool add_sub_tables (gsubgpos_graph_context_t& c, - unsigned this_index, - unsigned type, - const hb_vector_t>>& subtable_ids) + graph_result_t add_sub_tables (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned type, + const hb_vector_t>>& subtable_ids) { bool is_ext = is_extension (c.table_tag); auto* v = &c.graph.vertices_[this_index]; @@ -225,19 +250,19 @@ struct Lookup : public OT::Lookup size_t new_size = v->table_size () + new_subtable_count * OT::Offset16::static_size; char* buffer = (char*) hb_calloc (1, new_size); - if (!buffer) return false; - if (!c.add_buffer (buffer)) + if (unlikely (!buffer)) return Err(ALLOCATION_FAILURE); + auto res = c.add_buffer (buffer); + if (unlikely (!res.is_ok ())) { hb_free (buffer); - return false; + return res; } - hb_memcpy (buffer, v->obj.head, v->table_size()); + hb_memcpy (buffer, v->obj ().head, v->table_size()); if (use_mark_filtering_set ()) - hb_memcpy (buffer + new_size - 2, v->obj.tail - 2, 2); + hb_memcpy (buffer + new_size - 2, v->obj ().tail - 2, 2); - v->obj.head = buffer; - v->obj.tail = buffer + new_size; + v->set_buffer (buffer, buffer + new_size); Lookup* new_lookup = (Lookup*) buffer; @@ -252,29 +277,27 @@ struct Lookup : public OT::Lookup { if (is_ext) { - unsigned ext_id = create_extension_subtable (c, subtable_id, type); - c.graph.vertices_[subtable_id].add_parent (ext_id, false); + TRY_ASSIGN (unsigned ext_id, create_extension_subtable (c, subtable_id, type)); + TRY(c.graph.vertices_[subtable_id].add_parent (ext_id, false)); subtable_id = ext_id; // the reference to v may have changed on adding a node, so reassign it. v = &c.graph.vertices_[this_index]; } - auto* link = v->obj.real_links.push (); - link->width = 2; - link->objidx = subtable_id; - link->position = (char*) &new_lookup->subTable[offset_index++] - - (char*) new_lookup; - c.graph.vertices_[subtable_id].add_parent (this_index, false); + TRY(v->add_real_link(2, subtable_id, + (char*) &new_lookup->subTable[offset_index++] - (char*) new_lookup)); + TRY(c.graph.vertices_[subtable_id].add_parent (this_index, false)); } } // Repacker sort order depends on link order, which we've messed up so resort it. - v->obj.real_links.qsort (); + v->sort_real_links (); // The head location of the lookup has changed, invalidating the lookups map entry // in the context. Update the map. c.lookups.set (this_index, new_lookup); - return true; + TRY (graph_result_t::from (c.lookups, ALLOCATION_FAILURE)); + return Ok(); } void fix_existing_subtable_links (gsubgpos_graph_context_t& c, @@ -290,74 +313,70 @@ struct Lookup : public OT::Lookup unsigned insert_offset = Lookup::min_size + insert_index * OT::Offset16::static_size; shift += p.second.length; - for (auto& l : v.obj.all_links_writer ()) + for (auto& l : v.all_links_writer ()) { if (l.position > insert_offset) l.position += pos_offset; } } } - unsigned create_extension_subtable (gsubgpos_graph_context_t& c, - unsigned subtable_index, - unsigned type) + graph_result_t create_extension_subtable (gsubgpos_graph_context_t& c, + unsigned subtable_index, + unsigned type) { unsigned extension_size = OT::ExtensionFormat1::static_size; - unsigned ext_index = c.create_node (extension_size); - if (ext_index == (unsigned) -1) - return -1; + TRY_ASSIGN (unsigned ext_index, c.create_node (extension_size)); auto& ext_vertex = c.graph.vertices_[ext_index]; ExtensionFormat1* extension = - (ExtensionFormat1*) ext_vertex.obj.head; + ext_vertex.as*> (); extension->reset (type); // Make extension point at the subtable. - auto* l = ext_vertex.obj.real_links.push (); + TRY(ext_vertex.add_real_link (4, subtable_index, 4)); - l->width = 4; - l->objidx = subtable_index; - l->position = 4; - - return ext_index; + return Ok(ext_index); } - bool make_subtable_extension (gsubgpos_graph_context_t& c, - unsigned lookup_index, - unsigned subtable_index) + graph_result_t make_subtable_extension (gsubgpos_graph_context_t& c, + unsigned lookup_index, + unsigned subtable_index) { unsigned type = lookupType; - unsigned ext_index = -1; + unsigned ext_index = HB_GRAPH_INVALID; unsigned* existing_ext_index = nullptr; if (c.subtable_to_extension.has(subtable_index, &existing_ext_index)) { ext_index = *existing_ext_index; } else { - ext_index = create_extension_subtable(c, subtable_index, type); + TRY_ASSIGN (ext_index, create_extension_subtable(c, subtable_index, type)); c.subtable_to_extension.set(subtable_index, ext_index); + TRY (graph_result_t::from (c.subtable_to_extension, ALLOCATION_FAILURE)); } - if (ext_index == (unsigned) -1) - return false; - auto& subtable_vertex = c.graph.vertices_[subtable_index]; auto& lookup_vertex = c.graph.vertices_[lookup_index]; - for (auto& l : lookup_vertex.obj.real_links.writer ()) + unsigned replaced = 0; + for (auto& l : lookup_vertex.real_links_writer ()) { if (l.objidx == subtable_index) { // Change lookup to point at the extension. l.objidx = ext_index; - if (existing_ext_index) - subtable_vertex.remove_parent(lookup_index); + replaced++; } } // Make extension point at the subtable. auto& ext_vertex = c.graph.vertices_[ext_index]; - ext_vertex.add_parent (lookup_index, false); + for (unsigned i = 0; i < replaced; i++) + { + subtable_vertex.remove_parent (lookup_index); + TRY(ext_vertex.add_parent (lookup_index, false)); + } if (!existing_ext_index) - subtable_vertex.remap_parent (lookup_index, ext_index); + TRY(subtable_vertex.add_parent (ext_index, false)); - return true; + return Ok(); } private: @@ -388,24 +407,25 @@ struct Lookup : public OT::Lookup template struct LookupList : public OT::LookupList { - bool sanitize (const graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < OT::LookupList::min_size) return false; + size_t vertex_len = vertex.table_size (); + if (unlikely (vertex_len < OT::LookupList::min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= OT::LookupList::item_size * this->len; + if (unlikely (vertex_len < OT::LookupList::item_size * this->len)) return Err(SANITIZE_FAILURE); + return Ok(); } }; struct GSTAR : public OT::GSUBGPOS { - static GSTAR* graph_to_gstar (graph_t& graph) + static graph_result_t graph_to_gstar (graph_t& graph) { const auto& r = graph.root (); - GSTAR* gstar = (GSTAR*) r.obj.head; - if (!gstar || !gstar->sanitize (r)) - return nullptr; + const GSTAR* gstar = (GSTAR*) r.obj ().head; + if (unlikely (!gstar)) return Err(INVALID_ARGUMENT); + TRY (gstar->sanitize (r)); hb_barrier (); return gstar; @@ -413,57 +433,55 @@ struct GSTAR : public OT::GSUBGPOS const void* get_lookup_list_field_offset () const { - switch (u.version.major) { - case 1: return u.version1.get_lookup_list_offset (); -#ifndef HB_NO_BEYOND_64K - case 2: return u.version2.get_lookup_list_offset (); -#endif - default: return 0; - } + return OT::GSUBGPOS::get_lookup_list_field_offset (); } - bool sanitize (const graph_t::vertex_t& vertex) + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t len = vertex.obj.tail - vertex.obj.head; - if (len < OT::GSUBGPOS::min_size) return false; + size_t len = vertex.table_size (); + if (unlikely (len < OT::GSUBGPOS::min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return len >= get_size (); + if (unlikely (version.major != 1)) return Err(SANITIZE_FAILURE); + if (unlikely (len < get_size ())) return Err(SANITIZE_FAILURE); + return Ok(); } - void find_lookups (graph_t& graph, - hb_hashmap_t& lookups /* OUT */) + graph_result_t find_lookups (graph_t& graph, + hb_hashmap_t& lookups /* OUT */) const { - switch (u.version.major) { - case 1: find_lookups (graph, lookups); break; #ifndef HB_NO_BEYOND_64K - case 2: find_lookups (graph, lookups); break; + if (version.to_int () >= 0x00010002u && lookupList2) + return find_lookups (graph, lookups); #endif - } + TRY(find_lookups (graph, lookups)); + return Ok(); } - unsigned get_lookup_list_index (graph_t& graph) + graph_result_t get_lookup_list_index (graph_t& graph) const { - return graph.index_for_offset (graph.root_idx (), - get_lookup_list_field_offset()); + const void* offset = get_lookup_list_field_offset (); + if (unlikely (!offset)) return Err(INVALID_ARGUMENT); + return graph.index_for_offset (graph.root_idx (), offset); } template - void find_lookups (graph_t& graph, - hb_hashmap_t& lookups /* OUT */) + graph_result_t find_lookups (graph_t& graph, + hb_hashmap_t& lookups /* OUT */) const { - unsigned lookup_list_idx = get_lookup_list_index (graph); + TRY_ASSIGN (unsigned lookup_list_idx, get_lookup_list_index (graph)); const LookupList* lookupList = (const LookupList*) graph.object (lookup_list_idx).head; - if (!lookupList || !lookupList->sanitize (graph.vertices_[lookup_list_idx])) - return; + if (unlikely (!lookupList)) return Err(INVALID_ARGUMENT); + TRY(lookupList->sanitize (graph.vertices_[lookup_list_idx])); for (unsigned i = 0; i < lookupList->len; i++) { - unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i])); + TRY_ASSIGN (unsigned lookup_idx, graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i]))); Lookup* lookup = (Lookup*) graph.object (lookup_idx).head; - if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx])) continue; + if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx]).is_ok ()) continue; lookups.set (lookup_idx, lookup); } + return Ok(); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh index a653f402ab1..c0e38e00998 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh @@ -34,64 +34,69 @@ namespace graph { -struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix +struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix { - bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const + graph_result_t sanitize (const graph_t::vertex_t& vertex, unsigned class_count) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < AnchorMatrix::min_size) return false; + size_t vertex_len = vertex.table_size(); + if (unlikely (vertex_len < AnchorMatrix::min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= AnchorMatrix::min_size + - OT::Offset16::static_size * class_count * this->rows; + if (unlikely (vertex_len < AnchorMatrix::min_size + + OT::Offset16::static_size * class_count * this->rows)) + return Err(SANITIZE_FAILURE); + return Ok(); } - bool shrink (gsubgpos_graph_context_t& c, - unsigned this_index, - unsigned old_class_count, - unsigned new_class_count) + graph_result_t shrink (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned old_class_count, + unsigned new_class_count) { - if (new_class_count >= old_class_count) return false; - auto& o = c.graph.vertices_[this_index].obj; + if (unlikely (new_class_count >= old_class_count)) return Err(INVALID_ARGUMENT); + auto& v = c.graph.vertices_[this_index]; + const auto& o = v.obj (); unsigned base_count = rows; - o.tail = o.head + - AnchorMatrix::min_size + - OT::Offset16::static_size * base_count * new_class_count; + v.set_buffer (o.head, + o.head + + AnchorMatrix::min_size + + OT::Offset16::static_size * base_count * new_class_count); // Reposition links into the new indexing scheme. - for (auto& link : o.real_links.writer ()) + for (auto& link : v.real_links_writer ()) { unsigned index = (link.position - 2) / 2; unsigned base = index / old_class_count; unsigned klass = index % old_class_count; - if (klass >= new_class_count) + if (unlikely (klass >= new_class_count)) // should have already been removed - return false; + return Err(INVALID_ARGUMENT); unsigned new_index = base * new_class_count + klass; link.position = (char*) &(this->matrixZ[new_index]) - (char*) this; } - return true; + return Ok(); } - unsigned clone (gsubgpos_graph_context_t& c, - unsigned this_index, - unsigned start, - unsigned end, - unsigned class_count) + graph_result_t clone (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned start, + unsigned end, + unsigned class_count) { unsigned base_count = rows; unsigned new_class_count = end - start; unsigned size = AnchorMatrix::min_size + OT::Offset16::static_size * new_class_count * rows; - unsigned prime_id = c.create_node (size); - if (prime_id == (unsigned) -1) return -1; + TRY_ASSIGN (unsigned prime_id, c.create_node (size)); AnchorMatrix* prime = (AnchorMatrix*) c.graph.object (prime_id).head; prime->rows = base_count; - auto& o = c.graph.vertices_[this_index].obj; + auto& v = c.graph.vertices_[this_index]; + const auto& o = v.obj (); + int num_links = o.real_links.length; for (int i = 0; i < num_links; i++) { @@ -106,43 +111,48 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix unsigned child_idx = link.objidx; - c.graph.add_link (&(prime->matrixZ[new_index]), - prime_id, - child_idx); + TRY (c.graph.add_link (&(prime->matrixZ[new_index]), + prime_id, + child_idx)); auto& child = c.graph.vertices_[child_idx]; child.remove_parent (this_index); - o.real_links.remove_unordered (i); + v.remove_real_link_unordered (i); num_links--; i--; } - return prime_id; + // Restore correct ordering after the above removes, which mess up link ordering. + v.sort_real_links (); + + return Ok(prime_id); } }; -struct MarkArray : public OT::Layout::GPOS_impl::MarkArray +struct MarkArray : public OT::Layout::GPOS_impl::MarkArray { - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.table_size(); unsigned min_size = MarkArray::min_size; - if (vertex_len < min_size) return false; + if (unlikely (vertex_len < min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= get_size (); + if (unlikely (vertex_len < get_size ())) return Err(SANITIZE_FAILURE); + return Ok(); } - bool shrink (gsubgpos_graph_context_t& c, - const hb_hashmap_t& mark_array_links, - unsigned this_index, - unsigned new_class_count) + graph_result_t shrink (gsubgpos_graph_context_t& c, + const hb_hashmap_t& mark_array_links, + unsigned this_index, + unsigned new_class_count) { - auto& o = c.graph.vertices_[this_index].obj; + auto& v = c.graph.vertices_[this_index]; + const auto& o = v.obj (); for (const auto& link : o.real_links) c.graph.vertices_[link.objidx].remove_parent (this_index); - o.real_links.reset (); + v.clear_real_links (); unsigned new_index = 0; for (const auto& record : this->iter ()) @@ -159,27 +169,27 @@ struct MarkArray : public OT::Layout::GPOS_impl::MarkArray continue; } - c.graph.add_link (&(*this)[new_index].markAnchor, this_index, *objidx); + TRY (c.graph.add_link (&(*this)[new_index].markAnchor, this_index, *objidx)); new_index++; } this->len = new_index; - o.tail = o.head + MarkArray::min_size + - OT::Layout::GPOS_impl::MarkRecord::static_size * new_index; - return true; + v.set_buffer (o.head, o.head + MarkArray::min_size + + OT::Layout::GPOS_impl::MarkRecord::static_size * new_index); + + return Ok(); } - unsigned clone (gsubgpos_graph_context_t& c, - unsigned this_index, - const hb_hashmap_t& pos_to_index, - hb_set_t& marks, - unsigned start_class) + graph_result_t clone (gsubgpos_graph_context_t& c, + unsigned this_index, + const hb_hashmap_t& pos_to_index, + hb_set_t& marks, + unsigned start_class) { unsigned size = MarkArray::min_size + - OT::Layout::GPOS_impl::MarkRecord::static_size * + OT::Layout::GPOS_impl::MarkRecord::static_size * marks.get_population (); - unsigned prime_id = c.create_node (size); - if (prime_id == (unsigned) -1) return -1; + TRY_ASSIGN (unsigned prime_id, c.create_node (size)); MarkArray* prime = (MarkArray*) c.graph.object (prime_id).head; prime->len = marks.get_population (); @@ -191,45 +201,50 @@ struct MarkArray : public OT::Layout::GPOS_impl::MarkArray unsigned offset_pos = (char*) &((*this)[mark].markAnchor) - (char*) this; unsigned* anchor_index; if (pos_to_index.has (offset_pos, &anchor_index)) - c.graph.move_child (this_index, - &((*this)[mark].markAnchor), - prime_id, - &((*prime)[i].markAnchor)); + TRY (c.graph.move_child (this_index, + &((*this)[mark].markAnchor), + prime_id, + &((*prime)[i].markAnchor))); i++; } - return prime_id; + // Restore correct ordering of the vertex links which are disturbed by move_child. + c.graph.vertices_[this_index].sort_real_links (); + + return Ok(prime_id); } }; struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 { - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - return vertex_len >= MarkBasePosFormat1::static_size; + size_t vertex_len = vertex.table_size (); + if (unlikely (vertex_len < MarkBasePosFormat1::static_size)) + return Err(SANITIZE_FAILURE); + return Ok(); } - hb_vector_t split_subtables (gsubgpos_graph_context_t& c, - unsigned this_index) + graph_result_t> split_subtables (gsubgpos_graph_context_t& c, + unsigned this_index) { hb_set_t visited; - const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage); + TRY_ASSIGN (const unsigned base_coverage_id, c.graph.index_for_offset (this_index, &baseCoverage)); + const unsigned base_size = OT::Layout::GPOS_impl::MarkBasePosFormat1_2::min_size + MarkArray::min_size + AnchorMatrix::min_size + c.graph.vertices_[base_coverage_id].table_size (); - hb_vector_t class_to_info = get_class_info (c, this_index); + TRY_ASSIGN (hb_vector_t class_to_info, get_class_info (c, this_index)); unsigned class_count = classCount; - auto base_array = c.graph.as_table (this_index, - &baseArray, - class_count); - if (!base_array) return hb_vector_t (); + TRY_ASSIGN (auto base_array, c.graph.as_table (this_index, + &baseArray, + class_count)); unsigned base_count = base_array.table->rows; unsigned partial_coverage_size = 4; @@ -241,11 +256,11 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2::static_size * info.marks.get_population () + OT::Offset16::static_size * base_count; for (unsigned objidx : info.child_indices) - accumulated_delta += c.graph.find_subgraph_size (objidx, visited); + accumulated_delta += c.graph.find_subgraph_size (objidx, visited).value_or (0); accumulated += accumulated_delta; unsigned total = accumulated + partial_coverage_size; @@ -253,6 +268,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= (1 << 16)) { split_points.push (klass); + TRY (graph_result_t::from (split_points, ALLOCATION_FAILURE)); accumulated = base_size + accumulated_delta; partial_coverage_size = 4 + OT::HBUINT16::static_size * info.marks.get_population (); visited.clear (); // node sharing isn't allowed between splits. @@ -260,13 +276,15 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 (split_context, split_points); @@ -303,30 +321,30 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2classCount; } - unsigned clone_range (unsigned start, unsigned end) + graph_result_t clone_range (unsigned start, unsigned end) { return thiz->clone_range (*this, this->this_index, start, end); } - bool shrink (unsigned count) + graph_result_t shrink (unsigned count) { return thiz->shrink (*this, this->this_index, count); } }; - hb_vector_t get_class_info (gsubgpos_graph_context_t& c, - unsigned this_index) + graph_result_t> get_class_info (gsubgpos_graph_context_t& c, + unsigned this_index) { hb_vector_t class_to_info; unsigned class_count = classCount; if (!class_count) return class_to_info; - if (!class_to_info.resize (class_count)) - return hb_vector_t(); + if (unlikely (!class_to_info.resize (class_count))) + return Err(ALLOCATION_FAILURE); + + TRY_ASSIGN (auto mark_array, c.graph.as_table (this_index, &markArray)); - auto mark_array = c.graph.as_table (this_index, &markArray); - if (!mark_array) return hb_vector_t (); unsigned mark_count = mark_array.table->len; for (unsigned mark = 0; mark < mark_count; mark++) { @@ -335,20 +353,21 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2obj.real_links) + for (const auto& link : mark_array.vertex->obj ().real_links) { unsigned mark = (link.position - 2) / - OT::Layout::GPOS_impl::MarkRecord::static_size; + OT::Layout::GPOS_impl::MarkRecord::static_size; unsigned klass = (*mark_array.table)[mark].get_class (); if (klass >= class_count) continue; class_to_info[klass].child_indices.push (link.objidx); } - unsigned base_array_id = - c.graph.index_for_offset (this_index, &baseArray); + TRY_ASSIGN (unsigned base_array_id, + c.graph.index_for_offset (this_index, &baseArray)); + auto& base_array_v = c.graph.vertices_[base_array_id]; - for (const auto& link : base_array_v.obj.real_links) + for (const auto& link : base_array_v.obj ().real_links) { unsigned index = (link.position - 2) / OT::Offset16::static_size; unsigned klass = index % class_count; @@ -358,9 +377,9 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 shrink (split_context_t& sc, + unsigned this_index, + unsigned count) { DEBUG_MSG (SUBSET_REPACK, nullptr, " Shrinking MarkBasePosFormat1 (%u) to [0, %u).", @@ -369,49 +388,48 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= old_count) - return true; + return Ok(); classCount = count; - auto mark_coverage = sc.c.graph.as_mutable_table (this_index, - &markCoverage); - if (!mark_coverage) return false; + TRY_ASSIGN (auto mark_coverage, sc.c.graph.as_mutable_table (this_index, + &markCoverage)); + hb_set_t marks = sc.marks_for (0, count); auto new_coverage = + hb_enumerate (mark_coverage.table->iter ()) | hb_filter (marks, hb_first) | hb_map_retains_sorting (hb_second) ; - if (!Coverage::make_coverage (sc.c, + new_coverage, + TRY (Coverage::make_coverage (sc.c, + new_coverage, mark_coverage.index, - 4 + 2 * marks.get_population ())) - return false; - - - auto base_array = sc.c.graph.as_mutable_table (this_index, - &baseArray, - old_count); - if (!base_array || !base_array.table->shrink (sc.c, - base_array.index, - old_count, - count)) - return false; - - auto mark_array = sc.c.graph.as_mutable_table (this_index, - &markArray); - if (!mark_array || !mark_array.table->shrink (sc.c, - sc.mark_array_links, - mark_array.index, - count)) - return false; - - return true; + 4 + 2 * marks.get_population ())); + + + TRY_ASSIGN (auto base_array, sc.c.graph.as_mutable_table (this_index, + &baseArray, + old_count)); + + TRY (base_array.table->shrink (sc.c, + base_array.index, + old_count, + count)); + + TRY_ASSIGN (auto mark_array, sc.c.graph.as_mutable_table (this_index, + &markArray)); + + TRY (mark_array.table->shrink (sc.c, + sc.mark_array_links, + mark_array.index, + count)); + + return Ok(); } // Create a new MarkBasePos that has all of the data for classes from [start, end). - unsigned clone_range (split_context_t& sc, - unsigned this_index, - unsigned start, unsigned end) const + graph_result_t clone_range (split_context_t& sc, + unsigned this_index, + unsigned start, unsigned end) const { DEBUG_MSG (SUBSET_REPACK, nullptr, " Cloning MarkBasePosFormat1 (%u) range [%u, %u).", this_index, start, end); @@ -419,92 +437,93 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2::static_size; - unsigned prime_id = sc.c.create_node (prime_size); - if (prime_id == (unsigned) -1) return -1; + TRY_ASSIGN (unsigned prime_id, sc.c.create_node (prime_size)); MarkBasePosFormat1* prime = (MarkBasePosFormat1*) graph.object (prime_id).head; prime->format = this->format; unsigned new_class_count = end - start; prime->classCount = new_class_count; - unsigned base_coverage_id = - graph.index_for_offset (sc.this_index, &baseCoverage); - graph.add_link (&(prime->baseCoverage), prime_id, base_coverage_id); + TRY_ASSIGN (unsigned base_coverage_id, + graph.index_for_offset (sc.this_index, &baseCoverage)); + + TRY (graph.add_link (&(prime->baseCoverage), prime_id, base_coverage_id)); + + TRY_ASSIGN (auto mark_coverage, sc.c.graph.as_table (this_index, + &markCoverage)); - auto mark_coverage = sc.c.graph.as_table (this_index, - &markCoverage); - if (!mark_coverage) return false; hb_set_t marks = sc.marks_for (start, end); auto new_coverage = + hb_enumerate (mark_coverage.table->iter ()) | hb_filter (marks, hb_first) | hb_map_retains_sorting (hb_second) ; - if (!Coverage::add_coverage (sc.c, + TRY (Coverage::add_coverage (sc.c, prime_id, 2, + new_coverage, - marks.get_population () * 2 + 4)) - return -1; - - auto mark_array = - graph.as_table (sc.this_index, &markArray); - if (!mark_array) return -1; - unsigned new_mark_array = - mark_array.table->clone (sc.c, - mark_array.index, - sc.mark_array_links, - marks, - start); - graph.add_link (&(prime->markArray), prime_id, new_mark_array); + marks.get_population () * 2 + 4)); + + TRY_ASSIGN (auto mark_array, + graph.as_mutable_table (sc.this_index, &markArray)); + + TRY_ASSIGN (unsigned new_mark_array, + mark_array.table->clone (sc.c, + mark_array.index, + sc.mark_array_links, + marks, + start)); + TRY (graph.add_link (&(prime->markArray), prime_id, new_mark_array)); unsigned class_count = classCount; - auto base_array = - graph.as_table (sc.this_index, &baseArray, class_count); - if (!base_array) return -1; - unsigned new_base_array = - base_array.table->clone (sc.c, - base_array.index, - start, end, this->classCount); - graph.add_link (&(prime->baseArray), prime_id, new_base_array); - - return prime_id; + TRY_ASSIGN (auto base_array, + graph.as_mutable_table (sc.this_index, &baseArray, class_count)); + + TRY_ASSIGN (unsigned new_base_array, + base_array.table->clone (sc.c, + base_array.index, + start, end, this->classCount)); + TRY (graph.add_link (&(prime->baseArray), prime_id, new_base_array)); + + return Ok(prime_id); } }; struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos { - hb_vector_t split_subtables (gsubgpos_graph_context_t& c, - unsigned this_index) + graph_result_t> split_subtables (gsubgpos_graph_context_t& c, + unsigned this_index) { switch (u.format.v) { case 1: + hb_barrier (); return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index); #ifndef HB_NO_BEYOND_64K case 2: HB_FALLTHROUGH; - // Don't split 24bit MarkBasePos's. + // 24-bit MarkBasePos already has widened offsets; leave it unsplit. #endif default: - return hb_vector_t (); + return Ok(hb_vector_t ()); } } - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < u.format.v.get_size ()) return false; + size_t vertex_len = vertex.table_size (); + if (unlikely (vertex_len < u.format.v.get_size ())) return Err(SANITIZE_FAILURE); hb_barrier (); switch (u.format.v) { case 1: + hb_barrier (); return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex); #ifndef HB_NO_BEYOND_64K case 2: HB_FALLTHROUGH; #endif default: // We don't handle format 3 and 4 here. - return false; + return Err(SANITIZE_FAILURE); } } }; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh index 7c3b048195d..2c1d76d492c 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh @@ -37,23 +37,24 @@ namespace graph { struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 { - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.table_size (); unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3::min_size; - if (vertex_len < min_size) return false; + if (unlikely (vertex_len < min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); - return vertex_len >= - min_size + pairSet.get_size () - pairSet.len.get_size(); + if (unlikely (vertex_len < min_size + pairSet.get_size () - pairSet.len.get_size())) + return Err(SANITIZE_FAILURE); + return Ok(); } - hb_vector_t split_subtables (gsubgpos_graph_context_t& c, - unsigned this_index) + graph_result_t> split_subtables (gsubgpos_graph_context_t& c, + unsigned this_index) { hb_set_t visited; - const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); + TRY_ASSIGN (const unsigned coverage_id, c.graph.index_for_offset (this_index, &coverage)); const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3::min_size; @@ -62,9 +63,9 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 split_points; for (unsigned i = 0; i < pairSet.len; i++) { - unsigned pair_set_index = pair_set_graph_index (c, this_index, i); + TRY_ASSIGN (unsigned pair_set_index, pair_set_graph_index (c, this_index, i)); unsigned accumulated_delta = - c.graph.find_subgraph_size (pair_set_index, visited) + + c.graph.find_subgraph_size (pair_set_index, visited).value_or (0) + SmallTypes::size; // for PairSet offset. partial_coverage_size += OT::HBUINT16::static_size; @@ -74,6 +75,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3= (1 << 16)) { split_points.push (i); + TRY (graph_result_t::from (split_points, ALLOCATION_FAILURE)); accumulated = base_size + accumulated_delta; partial_coverage_size = 6; visited.clear (); // node sharing isn't allowed between splits. @@ -101,20 +103,20 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3pairSet.len; } - unsigned clone_range (unsigned start, unsigned end) + graph_result_t clone_range (unsigned start, unsigned end) { return thiz->clone_range (this->c, this->this_index, start, end); } - bool shrink (unsigned count) + graph_result_t shrink (unsigned count) { return thiz->shrink (this->c, this->this_index, count); } }; - bool shrink (gsubgpos_graph_context_t& c, - unsigned this_index, - unsigned count) + graph_result_t shrink (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned count) { DEBUG_MSG (SUBSET_REPACK, nullptr, " Shrinking PairPosFormat1 (%u) to [0, %u).", @@ -122,13 +124,12 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3= old_count) - return true; + return Ok(); pairSet.len = count; - c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size; + c.graph.vertices_[this_index].shrink_buffer ((old_count - count) * SmallTypes::size); - auto coverage = c.graph.as_mutable_table (this_index, &this->coverage); - if (!coverage) return false; + TRY_ASSIGN (auto coverage, c.graph.as_mutable_table (this_index, &this->coverage)); unsigned coverage_size = coverage.vertex->table_size (); auto new_coverage = @@ -144,9 +145,9 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 clone_range (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned start, unsigned end) const { DEBUG_MSG (SUBSET_REPACK, nullptr, " Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end); @@ -155,8 +156,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3::min_size + num_pair_sets * SmallTypes::size; - unsigned pair_pos_prime_id = c.create_node (prime_size); - if (pair_pos_prime_id == (unsigned) -1) return -1; + TRY_ASSIGN (unsigned pair_pos_prime_id, c.create_node (prime_size)); PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head; pair_pos_prime->format = this->format; @@ -166,26 +166,28 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 (this_index, - &pairSet[i], - pair_pos_prime_id, - &pair_pos_prime->pairSet[i - start]); + TRY (c.graph.move_child<> (this_index, + &pairSet[i], + pair_pos_prime_id, + &pair_pos_prime->pairSet[i - start])); } - unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); - if (!Coverage::clone_coverage (c, + // Restore correct ordering of the vertex links which are disturbed by move_child. + c.graph.vertices_[this_index].sort_real_links (); + + TRY_ASSIGN (unsigned coverage_id, c.graph.index_for_offset (this_index, &coverage)); + TRY (Coverage::clone_coverage (c, coverage_id, pair_pos_prime_id, 2, - start, end)) - return -1; + start, end)); - return pair_pos_prime_id; + return Ok(pair_pos_prime_id); } - unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const + graph_result_t pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const { return c.graph.index_for_offset (this_index, &pairSet[i]); } @@ -193,32 +195,33 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 { - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { size_t vertex_len = vertex.table_size (); unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4::min_size; - if (vertex_len < min_size) return false; + if (unlikely (vertex_len < min_size)) return Err(SANITIZE_FAILURE); hb_barrier (); const unsigned class1_count = class1Count; - return vertex_len >= - min_size + class1_count * get_class1_record_size (); + if (unlikely (vertex_len < min_size + class1_count * get_class1_record_size ())) + return Err(SANITIZE_FAILURE); + return Ok(); } - hb_vector_t split_subtables (gsubgpos_graph_context_t& c, - unsigned this_index) + graph_result_t> split_subtables (gsubgpos_graph_context_t& c, + unsigned this_index) { const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4::min_size; - const unsigned class_def_2_size = size_of (c, this_index, &classDef2); - const Coverage* coverage = get_coverage (c, this_index); - const ClassDef* class_def_1 = get_class_def_1 (c, this_index); + TRY_ASSIGN (const unsigned class_def_2_size, size_of (c, this_index, &classDef2)); + TRY_ASSIGN (const Coverage* coverage, get_coverage (c, this_index)); + TRY_ASSIGN (const ClassDef* class_def_1, get_class_def_1 (c, this_index)); auto gid_and_class = + coverage->iter () | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { return hb_codepoint_pair_t (gid, class_def_1->get_class (gid)); }) ; - class_def_size_estimator_t estimator (gid_and_class); + TRY_ASSIGN (class_def_size_estimator_t estimator, class_def_size_estimator_t::create (gid_and_class)); const unsigned class1_count = class1Count; const unsigned class2_count = class2Count; @@ -236,7 +239,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 split_points; - hb_hashmap_t device_tables = get_all_device_tables (c, this_index); + TRY_ASSIGN (auto device_tables, get_all_device_tables (c, this_index)); hb_vector_t format1_device_table_indices = valueFormat1.get_device_table_indices (); hb_vector_t format2_device_table_indices = valueFormat2.get_device_table_indices (); bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices); @@ -276,6 +279,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4= (1 << 16)) { split_points.push (i); + TRY (graph_result_t::from (split_points, ALLOCATION_FAILURE)); // split does not include i, so add the size for i when we reset the size counters. accumulated = base_size + accumulated_delta; @@ -326,12 +330,12 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4class1Count; } - unsigned clone_range (unsigned start, unsigned end) + graph_result_t clone_range (unsigned start, unsigned end) { return thiz->clone_range (*this, start, end); } - bool shrink (unsigned count) + graph_result_t shrink (unsigned count) { return thiz->shrink (*this, count); } @@ -344,8 +348,8 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 clone_range (split_context_t& split_context, + unsigned start, unsigned end) const { DEBUG_MSG (SUBSET_REPACK, nullptr, " Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end); @@ -356,8 +360,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4::min_size + num_records * split_context.class1_record_size; - unsigned pair_pos_prime_id = split_context.c.create_node (prime_size); - if (pair_pos_prime_id == (unsigned) -1) return -1; + TRY_ASSIGN (unsigned pair_pos_prime_id, split_context.c.create_node (prime_size)); PairPosFormat2* pair_pos_prime = (PairPosFormat2*) graph.object (pair_pos_prime_id).head; @@ -366,24 +369,24 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4valueFormat2 = this->valueFormat2; pair_pos_prime->class1Count = num_records; pair_pos_prime->class2Count = this->class2Count; - clone_class1_records (split_context, - pair_pos_prime_id, - start, - end); - - unsigned coverage_id = - graph.index_for_offset (split_context.this_index, &coverage); - unsigned class_def_1_id = - graph.index_for_offset (split_context.this_index, &classDef1); + TRY (clone_class1_records (split_context, + pair_pos_prime_id, + start, + end)); + + TRY_ASSIGN (unsigned coverage_id, + graph.index_for_offset (split_context.this_index, &coverage)); + TRY_ASSIGN (unsigned class_def_1_id, + graph.index_for_offset (split_context.this_index, &classDef1)); + auto& coverage_v = graph.vertices_[coverage_id]; auto& class_def_1_v = graph.vertices_[class_def_1_id]; - Coverage* coverage_table = (Coverage*) coverage_v.obj.head; - ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; - if (!coverage_table - || !coverage_table->sanitize (coverage_v) - || !class_def_1_table - || !class_def_1_table->sanitize (class_def_1_v)) - return -1; + const Coverage* coverage_table = (const Coverage*) coverage_v.obj().head; + const ClassDef* class_def_1_table = (const ClassDef*) class_def_1_v.obj().head; + if (unlikely (!coverage_table || !class_def_1_table)) + return Err(INVALID_ARGUMENT); + TRY (coverage_table->sanitize (coverage_v)); + TRY (class_def_1_table->sanitize (class_def_1_v)); auto klass_map = + coverage_table->iter () @@ -399,36 +402,32 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4width = SmallTypes::size; - class_def_link->objidx = class_def_2_id; - class_def_link->position = 10; - graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id, false); - - return pair_pos_prime_id; + TRY_ASSIGN (unsigned class_def_2_id, + graph.index_for_offset (split_context.this_index, &classDef2)); + + TRY(graph.vertices_[pair_pos_prime_id].add_real_link (SmallTypes::size, class_def_2_id, 10)); + TRY(graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id, false)); + + return Ok(pair_pos_prime_id); } - void clone_class1_records (split_context_t& split_context, - unsigned pair_pos_prime_id, - unsigned start, unsigned end) const + graph_result_t clone_class1_records (split_context_t& split_context, + unsigned pair_pos_prime_id, + unsigned start, unsigned end) const { PairPosFormat2* pair_pos_prime = (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head; @@ -442,7 +441,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4& device_table_indices, - unsigned old_value_record_index, - unsigned new_value_record_index) const + graph_result_t transfer_device_tables (split_context_t& split_context, + unsigned pair_pos_prime_id, + const hb_vector_t& device_table_indices, + unsigned old_value_record_index, + unsigned new_value_record_index) const { PairPosFormat2* pair_pos_prime = (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head; @@ -485,16 +485,21 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4values[new_value_record_index + i]); + (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i])); } + + // Restore correct ordering of the vertex links which are disturbed by move_child. + split_context.c.graph.vertices_[split_context.this_index].sort_real_links (); + + return Ok(); } - bool shrink (split_context_t& split_context, - unsigned count) + graph_result_t shrink (split_context_t& split_context, + unsigned count) { DEBUG_MSG (SUBSET_REPACK, nullptr, " Shrinking PairPosFormat2 (%u) to [0, %u).", @@ -502,20 +507,18 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4= old_count) - return true; + return Ok(); graph_t& graph = split_context.c.graph; class1Count = count; - graph.vertices_[split_context.this_index].obj.tail -= - (old_count - count) * split_context.class1_record_size; + graph.vertices_[split_context.this_index].shrink_buffer( + (old_count - count) * split_context.class1_record_size); - auto coverage = - graph.as_mutable_table (split_context.this_index, &this->coverage); - if (!coverage) return false; + TRY_ASSIGN (auto coverage, + graph.as_mutable_table (split_context.this_index, &this->coverage)); - auto class_def_1 = - graph.as_mutable_table (split_context.this_index, &classDef1); - if (!class_def_1) return false; + TRY_ASSIGN (auto class_def_1, + graph.as_mutable_table (split_context.this_index, &classDef1)); auto klass_map = + coverage.table->iter () @@ -528,13 +531,12 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4table_size ()); } - hb_hashmap_t + graph_result_t> get_all_device_tables (gsubgpos_graph_context_t& c, unsigned this_index) const { @@ -550,27 +552,28 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 get_coverage (gsubgpos_graph_context_t& c, + unsigned this_index) const { - unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); + TRY_ASSIGN (unsigned coverage_id, c.graph.index_for_offset (this_index, &coverage)); auto& coverage_v = c.graph.vertices_[coverage_id]; - Coverage* coverage_table = (Coverage*) coverage_v.obj.head; - if (!coverage_table || !coverage_table->sanitize (coverage_v)) - return &Null(Coverage); + const Coverage* coverage_table = (const Coverage*) coverage_v.obj().head; + if (unlikely (!coverage_table)) return Err(INVALID_ARGUMENT); + TRY(coverage_table->sanitize (coverage_v)); + return coverage_table; } - const ClassDef* get_class_def_1 (gsubgpos_graph_context_t& c, - unsigned this_index) const + graph_result_t get_class_def_1 (gsubgpos_graph_context_t& c, + unsigned this_index) const { - unsigned class_def_1_id = c.graph.index_for_offset (this_index, &classDef1); + TRY_ASSIGN (unsigned class_def_1_id, c.graph.index_for_offset (this_index, &classDef1)); auto& class_def_1_v = c.graph.vertices_[class_def_1_id]; - ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; - if (!class_def_1_table || !class_def_1_table->sanitize (class_def_1_v)) - return &Null(ClassDef); + const ClassDef* class_def_1_table = (const ClassDef*) class_def_1_v.obj().head; + if (unlikely (!class_def_1_table)) return Err(INVALID_ARGUMENT); + TRY(class_def_1_table->sanitize (class_def_1_v)); return class_def_1_table; } @@ -587,50 +590,54 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 size_of (gsubgpos_graph_context_t& c, + unsigned this_index, + const void* offset) const { - const unsigned id = c.graph.index_for_offset (this_index, offset); - return c.graph.vertices_[id].table_size (); + TRY_ASSIGN (const unsigned id, c.graph.index_for_offset (this_index, offset)); + return Ok(c.graph.vertices_[id].table_size ()); } }; struct PairPos : public OT::Layout::GPOS_impl::PairPos { - hb_vector_t split_subtables (gsubgpos_graph_context_t& c, - unsigned this_index) + graph_result_t> split_subtables (gsubgpos_graph_context_t& c, + unsigned this_index) { switch (u.format.v) { case 1: + hb_barrier (); return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index); case 2: + hb_barrier (); return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index); #ifndef HB_NO_BEYOND_64K case 3: HB_FALLTHROUGH; case 4: HB_FALLTHROUGH; - // Don't split 24bit PairPos's. + // 24-bit PairPos formats already have widened offsets; leave them unsplit. #endif default: - return hb_vector_t (); + return Ok(hb_vector_t ()); } } - bool sanitize (graph_t::vertex_t& vertex) const + graph_result_t sanitize (const graph_t::vertex_t& vertex) const { - size_t vertex_len = vertex.obj.tail - vertex.obj.head; - if (vertex_len < u.format.v.get_size ()) return false; + size_t vertex_len = vertex.table_size(); + if (unlikely (vertex_len < u.format.v.get_size ())) return Err(SANITIZE_FAILURE); hb_barrier (); switch (u.format.v) { case 1: + hb_barrier (); return ((PairPosFormat1*)(&u.format1))->sanitize (vertex); case 2: + hb_barrier (); return ((PairPosFormat2*)(&u.format2))->sanitize (vertex); #ifndef HB_NO_BEYOND_64K case 3: HB_FALLTHROUGH; @@ -638,7 +645,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos #endif default: // We don't handle format 3 and 4 here. - return false; + return Err(SANITIZE_FAILURE); } } }; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh index 4f89f1011d8..d33b736adc6 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh @@ -27,6 +27,8 @@ #ifndef GRAPH_SERIALIZE_HH #define GRAPH_SERIALIZE_HH +#include "graph-result.hh" + namespace graph { struct overflow_record_t @@ -104,38 +106,41 @@ bool is_valid_offset (int64_t offset, /* * Will any offsets overflow on graph when it's serialized? */ -inline bool +inline graph_result_t will_overflow (graph_t& graph, hb_vector_t* overflows = nullptr) { if (overflows) overflows->clear (); graph.update_positions (); - hb_hashmap_t record_set; + hb_hashmap_t record_set; const auto& vertices = graph.vertices_; for (unsigned parent_idx : graph.ordering_) { // Don't need to check virtual links for overflow - for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links) + for (const auto& link : vertices.arrayZ[parent_idx].obj ().real_links) { int64_t offset = compute_offset (graph, parent_idx, link); if (likely (is_valid_offset (offset, link))) continue; - if (!overflows) return true; + if (!overflows) return Ok(true); overflow_record_t r; r.parent = parent_idx; r.child = link.objidx; - if (record_set.has(&r)) continue; // don't keep duplicate overflows. + if (record_set.has(r)) continue; // don't keep duplicate overflows. overflows->push (r); - record_set.set(&r, true); + record_set.set (r, true); } } - if (!overflows) return false; - return overflows->length; + TRY (graph_result_t::from (record_set, ALLOCATION_FAILURE)); + if (overflows) + TRY (graph_result_t::from (*overflows, ALLOCATION_FAILURE)); + + return Ok((bool) (overflows && overflows->length)); } inline @@ -144,7 +149,13 @@ void print_overflows (graph_t& graph, { if (!DEBUG_ENABLED(SUBSET_REPACK)) return; - graph.update_parents (); + auto r = graph.update_parents (); + if (r.is_err()) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to print overflows due to error updating parent links: %s", + to_string(r.error())); + return; + } + int limit = 10; for (const auto& o : overflows) { @@ -157,11 +168,11 @@ void print_overflows (graph_t& graph, "%4u (%4u in, %4u out, space %2u)", o.parent, parent.incoming_edges (), - parent.obj.real_links.length + parent.obj.virtual_links.length, + 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, + child.obj ().real_links.length + child.obj ().virtual_links.length, graph.space_for (o.child)); } if (overflows.length > 10) { @@ -176,7 +187,12 @@ serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link, const hb_vector_t& id_map, hb_serialize_context_t* c) { - assert(link.position + link.width <= size); + // A link must never write outside the bounds of its parent object. + if (unlikely (link.position + link.width > size)) + { + c->err (HB_SERIALIZE_ERROR_OTHER); + return; + } OT::Offset* offset = reinterpret_cast*> (head + link.position); *offset = 0; @@ -226,16 +242,16 @@ void serialize_link (const hb_serialize_context_t::object_t::link_t& link, /* * serialize graph into the provided serialization buffer. */ -inline hb_blob_t* serialize (const graph_t& graph) +inline graph_result_t serialize (const graph_t& graph) { hb_vector_t buffer; size_t size = graph.total_size_in_bytes (); - if (!size) return hb_blob_get_empty (); + if (!size) return Ok(hb_blob_get_empty ()); - if (!buffer.alloc (size)) { + if (unlikely (!buffer.alloc (size))) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer."); - return nullptr; + return Err(ALLOCATION_FAILURE); } hb_serialize_context_t c((void *) buffer, size); @@ -247,25 +263,29 @@ inline hb_blob_t* serialize (const graph_t& graph) // Maps from our obj id's to the id's used during this serialization. hb_vector_t id_map; - id_map.resize(graph.ordering_.length); + if (unlikely (!id_map.resize(graph.ordering_.length))) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate id_map buffer."); + return Err(ALLOCATION_FAILURE); + } + for (int pos = graph.ordering_.length - 1; pos >= 0; pos--) { unsigned i = graph.ordering_[pos]; c.push (); auto& v = vertices[i]; - size_t size = v.obj.tail - v.obj.head; + size_t size = v.table_size (); char* start = c.allocate_size (size); - if (!start) { + if (unlikely (!start)) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space."); - return nullptr; + return Err(ALLOCATION_FAILURE); } - hb_memcpy (start, v.obj.head, size); + hb_memcpy (start, v.obj ().head, size); // Only real links needs to be serialized. - for (const auto& link : v.obj.real_links) + for (const auto& link : v.obj ().real_links) serialize_link (link, start, size, id_map, &c); // All duplications are already encoded in the graph, so don't @@ -274,13 +294,17 @@ inline hb_blob_t* serialize (const graph_t& graph) } c.end_serialize (); - if (c.in_error ()) { + if (unlikely (c.in_error ())) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d", c.errors); - return nullptr; + if (c.errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW) + return Err(OVERFLOW_RESOLUTION_FAILED); + return Err(ALLOCATION_FAILURE); } - return c.copy_blob (); + auto* blob = c.copy_blob (); + if (unlikely (!blob)) return Err(ALLOCATION_FAILURE); + return Ok(blob); } } // namespace graph diff --git a/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh b/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh index f1f86e332db..b10e9d3a848 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh @@ -27,16 +27,18 @@ #ifndef GRAPH_SPLIT_HELPERS_HH #define GRAPH_SPLIT_HELPERS_HH +#include "graph-result.hh" + namespace graph { template HB_INTERNAL -hb_vector_t actuate_subtable_split (Context& split_context, - const hb_vector_t& split_points) +graph_result_t> actuate_subtable_split (Context& split_context, + const hb_vector_t& split_points) { hb_vector_t new_objects; if (!split_points) - return new_objects; + return Ok(new_objects); for (unsigned i = 0; i < split_points.length; i++) { @@ -44,24 +46,14 @@ hb_vector_t actuate_subtable_split (Context& split_context, unsigned end = (i < split_points.length - 1) ? split_points[i + 1] : split_context.original_count (); - unsigned id = split_context.clone_range (start, end); - - if (id == (unsigned) -1) - { - new_objects.reset (); - new_objects.ensure_error (); - return new_objects; - } + TRY_ASSIGN (unsigned id, split_context.clone_range (start, end)); new_objects.push (id); + TRY (graph_result_t::from (new_objects, ALLOCATION_FAILURE)); } - if (!split_context.shrink (split_points[0])) - { - new_objects.reset (); - new_objects.ensure_error (); - } + TRY (split_context.shrink (split_points[0])); - return new_objects; + return Ok(new_objects); } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh index b14540f3a71..10aafea4bb3 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh @@ -127,10 +127,10 @@ struct bsln switch (format) { - case 0: return_trace (parts.format0.sanitize (c)); - case 1: return_trace (parts.format1.sanitize (c)); - case 2: return_trace (parts.format2.sanitize (c)); - case 3: return_trace (parts.format3.sanitize (c)); + case 0: hb_barrier (); return_trace (parts.format0.sanitize (c)); + case 1: hb_barrier (); return_trace (parts.format1.sanitize (c)); + case 2: hb_barrier (); return_trace (parts.format2.sanitize (c)); + case 3: hb_barrier (); return_trace (parts.format3.sanitize (c)); default:return_trace (true); } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh index d2ce32616be..8a90d4de0b4 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh @@ -49,6 +49,17 @@ struct ankr; using hb_aat_class_cache_t = hb_ot_layout_mapping_cache_t; +/* The state-machine subtables' transition functions are called once per + * transition from the drive loop, but are big enough that the compiler + * declines to inline them, leaving a call in the hottest loop of AAT + * shaping. Forcing them inline is worth 3-10% instructions on + * morx/kerx-heavy fonts, for about 16KB of code. */ +#ifndef HB_OPTIMIZE_SIZE +#define HB_AAT_TRANSITION_INLINE HB_ALWAYS_INLINE +#else +#define HB_AAT_TRANSITION_INLINE +#endif + struct hb_aat_scratch_t { hb_aat_scratch_t () = default; @@ -182,20 +193,26 @@ struct hb_aat_apply_context_t : buffer_glyph_set->add_array (glyphs, count); for (unsigned int i = 0; i < count; i++) { + bool at_end_of_text = buffer->idx == buffer->len; + if (at_end_of_text) + if (unlikely (!buffer->output_glyph (glyphs[i]))) return false; + + hb_glyph_info_t &info = at_end_of_text ? buffer->prev () : buffer->cur (); if (glyphs[i] == DELETED_GLYPH) { buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED; - _hb_glyph_info_set_aat_deleted (&buffer->cur()); + _hb_glyph_info_set_aat_deleted (&info); } else { #ifndef HB_NO_OT_LAYOUT if (has_glyph_classes) - _hb_glyph_info_set_glyph_props (&buffer->cur(), + _hb_glyph_info_set_glyph_props (&info, gdef.get_glyph_props (glyphs[i])); #endif } - if (unlikely (!buffer->output_glyph (glyphs[i]))) return false; + if (!at_end_of_text) + if (unlikely (!buffer->output_glyph (glyphs[i]))) return false; } return true; } @@ -222,12 +239,19 @@ struct hb_aat_apply_context_t : { buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED; _hb_glyph_info_set_aat_deleted (&buffer->cur()); + if (likely (using_buffer_glyph_set)) + buffer_glyph_set->add (DELETED_GLYPH); return buffer->replace_glyph (DELETED_GLYPH); } void replace_glyph_inplace (unsigned i, hb_codepoint_t glyph) { buffer->info[i].codepoint = glyph; + if (glyph == DELETED_GLYPH) + { + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED; + _hb_glyph_info_set_aat_deleted (&buffer->info[i]); + } if (likely (using_buffer_glyph_set)) buffer_glyph_set->add (glyph); #ifndef HB_NO_OT_LAYOUT @@ -792,7 +816,7 @@ struct Lookup public: DEFINE_SIZE_UNION (2, format.v); }; -DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); +DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 13); /* * (Extended) State Table @@ -1134,31 +1158,37 @@ struct ObsoleteTypes typedef ClassTable ClassTypeWide; template - static unsigned int offsetToIndex (unsigned int offset, - const void *base, - const T *array) + static int offsetToIndex (int64_t offset, + const void *base, + const T *array) { + int64_t array_offset = (const char *) array - (const char *) base; + int bad_index = INT_MAX / T::static_size; + /* https://github.com/harfbuzz/harfbuzz/issues/3483 */ /* If offset is less than base, return an offset that would * result in an address half a 32bit address-space away, * to make sure sanitize fails even on 32bit builds. */ - if (unlikely (offset < unsigned ((const char *) array - (const char *) base))) - return INT_MAX / T::static_size; + if (unlikely (offset < array_offset)) + return bad_index; /* https://github.com/harfbuzz/harfbuzz/issues/2816 */ - return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size; + int64_t index = (offset - array_offset) / T::static_size; + if (unlikely (index > bad_index)) + return bad_index; + return index; } template - static unsigned int byteOffsetToIndex (unsigned int offset, - const void *base, - const T *array) + static int byteOffsetToIndex (int64_t offset, + const void *base, + const T *array) { return offsetToIndex (offset, base, array); } template - static unsigned int wordOffsetToIndex (unsigned int offset, - const void *base, - const T *array) + static int wordOffsetToIndex (int64_t offset, + const void *base, + const T *array) { return offsetToIndex (2 * offset, base, array); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh index 7b68a932c3f..4f7ce989b34 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh @@ -114,7 +114,7 @@ struct FeatureName if (pdefault_index) *pdefault_index = default_index; - if (selectors_count) + if (selectors_count && selectors) { + settings_table.sub_array (start_offset, selectors_count) | hb_map ([=] (const SettingName& setting) { return setting.get_info (default_selector); }) @@ -168,7 +168,7 @@ struct feat unsigned int *count, hb_aat_layout_feature_type_t *features) const { - if (count) + if (count && features) { + namesZ.as_array (featureNameCount).sub_array (start_offset, count) | hb_map (&FeatureName::get_feature_type) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh index 1186cad41f8..a56729f1a08 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh @@ -258,6 +258,7 @@ struct KerxSubTableFormat1 depth (0), crossStream (table->header.coverage & table->header.CrossStream) {} + HB_AAT_TRANSITION_INLINE void transition (hb_buffer_t *buffer, StateTableDriver *driver, const Entry &entry) @@ -322,15 +323,15 @@ struct KerxSubTableFormat1 } else if (o.attach_type()) { - o.y_offset += c->font->em_scale_y (v); + o.y_offset = hb_saturate_add (o.y_offset, c->font->em_scale_y (v)); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; } } else if (buffer->info[idx].mask & kern_mask) { auto scaled = c->font->em_scale_x (v); - o.x_advance += scaled; - o.x_offset += scaled; + o.x_advance = hb_saturate_add (o.x_advance, scaled); + o.x_offset = hb_saturate_add (o.x_offset, scaled); } } else @@ -346,14 +347,15 @@ struct KerxSubTableFormat1 } else if (o.attach_type()) { - o.x_offset += c->font->em_scale_x (v); + o.x_offset = hb_saturate_add (o.x_offset, c->font->em_scale_x (v)); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; } } else if (buffer->info[idx].mask & kern_mask) { - o.y_advance += c->font->em_scale_y (v); - o.y_offset += c->font->em_scale_y (v); + auto scaled = c->font->em_scale_y (v); + o.y_advance = hb_saturate_add (o.y_advance, scaled); + o.y_offset = hb_saturate_add (o.y_offset, scaled); } } } @@ -550,6 +552,7 @@ struct KerxSubTableFormat4 mark_set (false), mark (0) {} + HB_AAT_TRANSITION_INLINE void transition (hb_buffer_t *buffer, StateTableDriver *driver, const Entry &entry) @@ -583,8 +586,8 @@ struct KerxSubTableFormat4 &currX, &currY)) return; - o.x_offset = markX - currX; - o.y_offset = markY - currY; + o.x_offset = hb_saturate_sub (markX, currX); + o.y_offset = hb_saturate_sub (markY, currY); } break; @@ -605,8 +608,10 @@ struct KerxSubTableFormat4 currAnchorPoint, c->sanitizer.get_num_glyphs ()); - o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate); - o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate); + o.x_offset = hb_saturate_sub (c->font->em_scale_x (markAnchor.xCoordinate), + c->font->em_scale_x (currAnchor.xCoordinate)); + o.y_offset = hb_saturate_sub (c->font->em_scale_y (markAnchor.yCoordinate), + c->font->em_scale_y (currAnchor.yCoordinate)); } break; @@ -622,8 +627,8 @@ struct KerxSubTableFormat4 int currX = *data++; int currY = *data++; - o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX); - o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY); + o.x_offset = hb_saturate_sub (c->font->em_scale_x (markX), c->font->em_scale_x (currX)); + o.y_offset = hb_saturate_sub (c->font->em_scale_y (markY), c->font->em_scale_y (currY)); } break; } @@ -870,11 +875,11 @@ struct KerxSubTable unsigned int subtable_type = get_type (); TRACE_DISPATCH (this, subtable_type); switch (subtable_type) { - case 0: return_trace (c->dispatch (u.format0, std::forward (ds)...)); - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); - case 4: return_trace (c->dispatch (u.format4, std::forward (ds)...)); - case 6: return_trace (c->dispatch (u.format6, std::forward (ds)...)); + case 0: hb_barrier (); return_trace (c->dispatch (u.format0, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward (ds)...)); + case 6: hb_barrier (); return_trace (c->dispatch (u.format6, std::forward (ds)...)); default: return_trace (c->default_return_value ()); } } @@ -884,11 +889,11 @@ struct KerxSubTable { unsigned int subtable_type = get_type (); switch (subtable_type) { - case 0: u.format0.collect_glyphs (first_set, second_set, num_glyphs); return; - case 1: u.format1.collect_glyphs (first_set, second_set, num_glyphs); return; - case 2: u.format2.collect_glyphs (first_set, second_set, num_glyphs); return; - case 4: u.format4.collect_glyphs (first_set, second_set, num_glyphs); return; - case 6: u.format6.collect_glyphs (first_set, second_set, num_glyphs); return; + case 0: hb_barrier (); u.format0.collect_glyphs (first_set, second_set, num_glyphs); return; + case 1: hb_barrier (); u.format1.collect_glyphs (first_set, second_set, num_glyphs); return; + case 2: hb_barrier (); u.format2.collect_glyphs (first_set, second_set, num_glyphs); return; + case 4: hb_barrier (); u.format4.collect_glyphs (first_set, second_set, num_glyphs); return; + case 6: hb_barrier (); u.format6.collect_glyphs (first_set, second_set, num_glyphs); return; default: return; } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh index fef21450b27..4eeb86914b1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh @@ -84,6 +84,7 @@ struct RearrangementSubtable table (table_), start (0), end (0) {} + HB_AAT_TRANSITION_INLINE void transition (hb_buffer_t *buffer, StateTableDriver *driver, const Entry &entry) @@ -200,10 +201,12 @@ struct ContextualSubtable struct EntryData { - HBUINT16 markIndex; /* Index of the substitution table for the - * marked glyph (use 0xFFFF for none). */ - HBUINT16 currentIndex; /* Index of the substitution table for the - * current glyph (use 0xFFFF for none). */ + typedef typename std::conditional::type OffsetType; + + OffsetType markIndex; /* Index/offset of the substitution table for the + * marked glyph. */ + OffsetType currentIndex; /* Index/offset of the substitution table for the + * current glyph. */ public: DEFINE_SIZE_STATIC (4); }; @@ -222,7 +225,10 @@ struct ContextualSubtable } bool is_actionable (const Entry &entry) const { - return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; + if (Types::extended) + return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; + else + return entry.data.markIndex || entry.data.currentIndex; } struct driver_context_t @@ -238,6 +244,7 @@ struct ContextualSubtable mark (0), subs (table+table->substitutionTables) {} + HB_AAT_TRANSITION_INLINE void transition (hb_buffer_t *buffer, StateTableDriver *driver, const Entry &entry) @@ -260,13 +267,16 @@ struct ContextualSubtable } else { - unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint; - const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; - replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; - if (!(replacement->sanitize (&c->sanitizer) && - hb_barrier () && - *replacement)) - replacement = nullptr; + if (entry.data.markIndex) + { + int offset = (int) entry.data.markIndex + buffer->info[mark].codepoint; + const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; + replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; + if (!(replacement->sanitize (&c->sanitizer) && + hb_barrier () && + *replacement)) + replacement = nullptr; + } } if (replacement) { @@ -287,13 +297,16 @@ struct ContextualSubtable } else { - unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint; - const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; - replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; - if (!(replacement->sanitize (&c->sanitizer) && - hb_barrier () && - *replacement)) - replacement = nullptr; + if (entry.data.currentIndex) + { + int offset = (int) entry.data.currentIndex + buffer->info[idx].codepoint; + const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; + replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; + if (!(replacement->sanitize (&c->sanitizer) && + hb_barrier () && + *replacement)) + replacement = nullptr; + } } if (replacement) { @@ -479,6 +492,7 @@ struct LigatureSubtable ligature (table+table->ligature), match_length (0) {} + HB_AAT_TRANSITION_INLINE void transition (hb_buffer_t *buffer, StateTableDriver *driver, const Entry &entry) @@ -776,6 +790,7 @@ struct InsertionSubtable mark (0), insertionAction (table+table->insertionAction) {} + HB_AAT_TRANSITION_INLINE void transition (hb_buffer_t *buffer, StateTableDriver *driver, const Entry &entry) @@ -1067,11 +1082,11 @@ struct ChainSubtable unsigned int subtable_type = get_type (); TRACE_DISPATCH (this, subtable_type); switch (subtable_type) { - case Rearrangement: return_trace (c->dispatch (u.rearrangement, std::forward (ds)...)); - case Contextual: return_trace (c->dispatch (u.contextual, std::forward (ds)...)); - case Ligature: return_trace (c->dispatch (u.ligature, std::forward (ds)...)); - case Noncontextual: return_trace (c->dispatch (u.noncontextual, std::forward (ds)...)); - case Insertion: return_trace (c->dispatch (u.insertion, std::forward (ds)...)); + case Rearrangement: hb_barrier (); return_trace (c->dispatch (u.rearrangement, std::forward (ds)...)); + case Contextual: hb_barrier (); return_trace (c->dispatch (u.contextual, std::forward (ds)...)); + case Ligature: hb_barrier (); return_trace (c->dispatch (u.ligature, std::forward (ds)...)); + case Noncontextual: hb_barrier (); return_trace (c->dispatch (u.noncontextual, std::forward (ds)...)); + case Insertion: hb_barrier (); return_trace (c->dispatch (u.insertion, std::forward (ds)...)); default: return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh index 4ee73ecee69..a28aba0aa73 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh @@ -230,13 +230,13 @@ struct trak { hb_position_t advance_to_add = get_h_tracking (c->font, track); foreach_grapheme (buffer, start, end) - buffer->pos[start].x_advance += advance_to_add; + buffer->pos[start].x_advance = hb_saturate_add (buffer->pos[start].x_advance, advance_to_add); } else { hb_position_t advance_to_add = get_v_tracking (c->font, track); foreach_grapheme (buffer, start, end) - buffer->pos[start].y_advance += advance_to_add; + buffer->pos[start].y_advance = hb_saturate_add (buffer->pos[start].y_advance, advance_to_add); } return_trace (true); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc index b349c3026b6..1fd24b13602 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc @@ -411,7 +411,7 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan, * @start_offset: offset of the first feature type to retrieve * @feature_count: (inout) (optional): Input = the maximum number of feature types to return; * Output = the actual number of feature types returned (may be zero) - * @features: (out caller-allocates) (array length=feature_count): Array of feature types found + * @features: (out caller-allocates) (array length=feature_count) (nullable): Array of feature types found * * Fetches a list of the AAT feature types included in the specified face. * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh index 05053b1f858..71173a31795 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh @@ -39,6 +39,19 @@ #include #include +static HB_ALWAYS_INLINE void * +hb_malloc2 (size_t nmemb, size_t size) +{ + if (size && nmemb > SIZE_MAX / size) return nullptr; + return hb_malloc (nmemb * size); +} +static HB_ALWAYS_INLINE void * +hb_realloc2 (void *ptr, size_t nmemb, size_t size) +{ + if (size && nmemb > SIZE_MAX / size) return nullptr; + return hb_realloc (ptr, nmemb * size); +} + /* * Flags */ @@ -214,10 +227,10 @@ struct HBInt __builtin_bswap32 ((uint32_t) *((const hb_packed_t *) v)) ; #else - return (BE ? (v[0] << 24) : (v[0] )) - + (BE ? (v[1] << 16) : (v[1] << 8)) - + (BE ? (v[2] << 8) : (v[2] << 16)) - + (BE ? (v[3] ) : (v[3] << 24)); + return (BE ? (uint32_t (v[0]) << 24) : (uint32_t (v[0]) )) + + (BE ? (uint32_t (v[1]) << 16) : (uint32_t (v[1]) << 8)) + + (BE ? (uint32_t (v[2]) << 8) : (uint32_t (v[2]) << 16)) + + (BE ? (uint32_t (v[3]) ) : (uint32_t (v[3]) << 24)); #endif } private: uint8_t v[4]; @@ -332,7 +345,7 @@ static inline double _hb_roundf (double x) { return floor (x + .5); } static inline float -_hb_roundf (float x) { return floorf (x + .5f); } +_hb_roundf (float x) { return floor ((double) x + .5); } #define roundf(x) _hb_roundf(x) @@ -877,6 +890,94 @@ struct } HB_FUNCOBJ (hb_clamp); +/* Signed saturating arithmetic. */ +template +static HB_ALWAYS_INLINE T +hb_saturate_add (T a, T b) +{ + static_assert (std::is_integral::value && std::is_signed::value, ""); + +#if hb_has_builtin(__builtin_add_overflow) + T result; + if (likely (!__builtin_add_overflow (a, b, &result))) + return result; +#else + if (b > 0) + { + if (likely (a <= hb_int_max (T) - b)) + return a + b; + } + else if (likely (a >= hb_int_min (T) - b)) + return a + b; +#endif + + return a < 0 ? hb_int_min (T) : hb_int_max (T); +} + +template +static HB_ALWAYS_INLINE T +hb_saturate_sub (T a, T b) +{ + static_assert (std::is_integral::value && std::is_signed::value, ""); + +#if hb_has_builtin(__builtin_sub_overflow) + T result; + if (likely (!__builtin_sub_overflow (a, b, &result))) + return result; +#else + if (b > 0) + { + if (likely (a >= hb_int_min (T) + b)) + return a - b; + } + else if (likely (a <= hb_int_max (T) + b)) + return a - b; +#endif + + return b < 0 ? hb_int_max (T) : hb_int_min (T); +} + +template +static HB_ALWAYS_INLINE T +hb_saturate_neg (T a) +{ + static_assert (std::is_integral::value && std::is_signed::value, ""); + + return hb_saturate_sub ((T) 0, a); +} + +/* Convert a floating-point value to integer type T, saturating to T's + * range instead of relying on the undefined behavior of an out-of-range + * float-to-int conversion. NaN saturates to the minimum of T. */ +template +static HB_ALWAYS_INLINE T +hb_clamp_to (double v) +{ + return (T) hb_clamp (v, + (double) hb_int_min (T), + (double) hb_int_max (T)); +} + +template +static HB_ALWAYS_INLINE T +hb_clamp_to (float v) +{ + /* Widen explicitly: float cannot represent all integer bounds exactly, + * so the clamp itself is done in double. */ + return hb_clamp_to ((double) v); +} + +template +static HB_ALWAYS_INLINE T +hb_clamp_to (int64_t v) +{ + static_assert (std::is_integral::value && std::is_signed::value, ""); + + return (T) hb_clamp (v, + (int64_t) hb_int_min (T), + (int64_t) hb_int_max (T)); +} + /* * Bithacks. */ @@ -1215,6 +1316,62 @@ hb_unsigned_add_overflows (unsigned int a, unsigned int b, unsigned *result = nu return b > (unsigned int) -1 - a; } +/* Saturating arithmetic on size_t. On platforms where size_t is wider than + * unsigned int (i.e. 64-bit), the inputs to get_size()-style computations + * (counts and static_sizes which are at most 32-bit) cannot overflow size_t, + * so these reduce to plain arithmetic. On 32-bit platforms (size_t is + * unsigned int), they saturate to SIZE_MAX so sanitize/serialize callers + * naturally reject the resulting size as out-of-range. */ + +static inline size_t +hb_unsigned_mul_saturate (size_t a, size_t b) +{ + if (sizeof (size_t) > sizeof (unsigned int)) + return a * b; +#if hb_has_builtin(__builtin_mul_overflow) + size_t result; + if (__builtin_mul_overflow (a, b, &result)) + return (size_t) -1; + return result; +#else + if (b > 0 && a > ((size_t) -1) / b) return (size_t) -1; + return a * b; +#endif +} + +static inline size_t +hb_unsigned_add_saturate (size_t a, size_t b) +{ + if (sizeof (size_t) > sizeof (unsigned int)) + return a + b; +#if hb_has_builtin(__builtin_add_overflow) + size_t result; + if (__builtin_add_overflow (a, b, &result)) + return (size_t) -1; + return result; +#else + if (b > ((size_t) -1) - a) return (size_t) -1; + return a + b; +#endif +} + +/* Variadic forms: fold left across all arguments. */ +template +static inline size_t +hb_unsigned_mul_saturate (size_t a, size_t b, size_t c, Ts... rest) +{ return hb_unsigned_mul_saturate (hb_unsigned_mul_saturate (a, b), c, rest...); } + +template +static inline size_t +hb_unsigned_add_saturate (size_t a, size_t b, size_t c, Ts... rest) +{ return hb_unsigned_add_saturate (hb_unsigned_add_saturate (a, b), c, rest...); } + +/* Saturating mul-add: a * b + c. Covers the dominant get_size() pattern + * `count * static_size + min_size`. */ +static inline size_t +hb_unsigned_mul_add_saturate (size_t a, size_t b, size_t c) +{ return hb_unsigned_add_saturate (hb_unsigned_mul_saturate (a, b), c); } + /* * Sort and search. @@ -1305,143 +1462,87 @@ hb_bsearch (const K& key, V* base, } -/* From https://github.com/noporpoise/sort_r - Feb 5, 2019 (c8c65c1e) - Modified to support optional argument using templates */ - -/* Isaac Turner 29 April 2014 Public Domain */ - -/* -hb_qsort function to be exported. -Parameters: - base is the array to be sorted - nel is the number of elements in the array - width is the size in bytes of each element of the array - compar is the comparison function - arg (optional) is a pointer to be passed to the comparison function - -void hb_qsort(void *base, size_t nel, size_t width, - int (*compar)(const void *_a, const void *_b, [void *_arg]), - [void *arg]); -*/ - -#define SORT_R_SWAP(a,b,tmp) ((void) ((tmp) = (a)), (void) ((a) = (b)), (b) = (tmp)) - -/* swap a and b */ -/* a and b must not be equal! */ -static inline void sort_r_swap(char *__restrict a, char *__restrict b, - size_t w) -{ - char tmp, *end = a+w; - for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); } -} - -/* swap a, b iff a>b */ -/* a and b must not be equal! */ -/* __restrict is same as restrict but better support on old machines */ -template -static inline int sort_r_cmpswap(char *__restrict a, - char *__restrict b, size_t w, - Compar compar) -{ - if(compar(a, b) > 0) { - sort_r_swap(a, b, w); - return 1; - } - return 0; -} - -/* -Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr, -with the smallest swap so that the blocks are in the opposite order. Blocks may -be internally re-ordered e.g. - 12345ab -> ab34512 - 123abc -> abc123 - 12abcde -> deabc12 -*/ -static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb) -{ - if(na > 0 && nb > 0) { - if(na > nb) { sort_r_swap(ptr, ptr+na, nb); } - else { sort_r_swap(ptr, ptr+nb, na); } - } -} - -/* Implement recursive quicksort ourselves */ -/* Note: quicksort is not stable, equivalent values may be swapped */ -template -static inline void sort_r_simple(void *base, size_t nel, size_t w, - Compar compar) +/* Quicksort partitioning loop: median-of-three pivot, two-way + * Hoare partition, tail-call elimination on the larger side. + * Stops partitioning when subranges shrink below the threshold; + * a single insertion-sort pass over the whole array (run by the + * caller) finishes the job. Same structure libstdc++ uses for + * std::sort. + * + * Not stable; equivalent values may be swapped. */ +/* Quicksort partitioning loop: median-of-three pivot, two-way + * Hoare partition, tail-call elimination on the larger side. + * Stops partitioning when subranges shrink below the threshold; + * a single insertion-sort pass over the whole array (run by + * hb_qsort_inline below) finishes the job. Same shape libstdc++ + * uses for std::sort. + * + * Not stable; equivalent values may be swapped. */ +template +static inline void +hb_qsort_loop (T *base, size_t nel, Compar compar) { - char *b = (char *)base, *end = b + nel*w; - - if(nel < 10) { - /* Insertion sort for arbitrarily small inputs */ - char *pi, *pj; - for(pi = b+w; pi < end; pi += w) { - for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar); pj -= w) {} - } - } - else + while (nel > 24) { - /* nel > 9; Quicksort */ + T *last = base + nel - 1; + T *mid = base + nel / 2; - int cmp; - char *pl, *ple, *pr, *pre, *pivot; - char *last = b+w*(nel-1), *tmp; - - char *l[3]; - l[0] = b + w; - l[1] = b+w*(nel/2); - l[2] = last - w; - - if(compar(l[0],l[1]) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } - if(compar(l[1],l[2]) > 0) { - SORT_R_SWAP(l[1], l[2], tmp); - if(compar(l[0],l[1]) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } + /* Median-of-three pivot, parked at last-1. */ + if (compar (*base, *mid) > 0) hb_swap (*base, *mid); + if (compar (*mid, *last) > 0) + { + hb_swap (*mid, *last); + if (compar (*base, *mid) > 0) hb_swap (*base, *mid); } - - if(l[1] != last) { sort_r_swap(l[1], last, w); } - - pivot = last; - ple = pl = b; - pre = pr = last; - - while(pl < pr) { - for(; pl < pr; pl += w) { - cmp = compar(pl, pivot); - if(cmp > 0) { break; } - else if(cmp == 0) { - if(ple < pl) { sort_r_swap(ple, pl, w); } - ple += w; - } - } - if(pl >= pr) { break; } - for(; pl < pr; ) { - pr -= w; - cmp = compar(pr, pivot); - if(cmp == 0) { - pre -= w; - if(pr < pre) { sort_r_swap(pr, pre, w); } - } - else if(cmp < 0) { - if(pl < pr) { sort_r_swap(pl, pr, w); } - pl += w; - break; - } - } + hb_swap (*mid, *(last - 1)); + T &pivot = *(last - 1); + + /* Two-way Hoare partition. Inner loops are unguarded: + * median-of-three left *base <= pivot and *last >= pivot, + * which act as sentinels. */ + T *i = base, *j = last - 1; + while (true) + { + while (compar (*++i, pivot) < 0) {} + while (compar (*--j, pivot) > 0) {} + if (i >= j) break; + hb_swap (*i, *j); } + hb_swap (*i, *(last - 1)); - pl = pr; - - sort_r_swap_blocks(b, ple-b, pl-ple); - sort_r_swap_blocks(pr, pre-pr, end-pre); - - sort_r_simple(b, (pl-ple)/w, w, compar); - sort_r_simple(end-(pre-pr), (pre-pr)/w, w, compar); + /* Recurse on smaller side, loop on larger — bounds stack + * depth at O(log n). */ + size_t left = (size_t) (i - base); + size_t right = nel - left - 1; + if (left < right) + { + hb_qsort_loop (base, left, compar); + base = i + 1; + nel = right; + } + else + { + hb_qsort_loop (i + 1, right, compar); + nel = left; + } } } +template +static inline void +hb_qsort_inline (T *base, size_t nel, Compar compar) +{ + hb_qsort_loop (base, nel, compar); + + /* Single final insertion sort over the whole array. After + * the partitioning loop, every element is within the threshold + * of its sorted position, so this pass is O(n * threshold). */ + T *end = base + nel; + for (T *pi = base + 1; pi < end; pi++) + for (T *pj = pi; pj > base && compar (pj[-1], pj[0]) > 0; pj--) + hb_swap (pj[-1], pj[0]); +} + static inline void hb_qsort (void *base, size_t nel, size_t width, int (*compar)(const void *_a, const void *_b)) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-array.hh index dd3369307ef..8eadc4ab8c6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-array.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-array.hh @@ -32,8 +32,6 @@ #include "hb-iter.hh" #include "hb-null.hh" -#include - template struct hb_sorted_array_t; @@ -227,22 +225,14 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> hb_qsort (arrayZ, length, this->get_item_size (), cmp); return hb_sorted_array_t (*this); } - /* std::sort wants a strict-weak `a < b` boolean, but our other - * qsort overload (and most existing call sites) follow the C - * qsort convention of returning negative / zero / positive ints. - * Adapt to either via overload resolution: bool passes through; - * any other arithmetic return type is treated as the int signed - * comparator. */ - template static bool _qsort_lt (T v) { return v < 0; } - static bool _qsort_lt (bool v) { return v; } + /* Comparator follows the C qsort convention: returns + * negative / zero / positive int. */ template hb_sorted_array_t qsort (Compar compar) { if (likely (length)) - std::sort (arrayZ, arrayZ + length, - [&] (const Type &a, const Type &b) - { return _qsort_lt (compar (a, b)); }); + hb_qsort_inline (arrayZ, length, compar); return hb_sorted_array_t (*this); } @@ -251,7 +241,7 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> hb_enable_if (std::is_move_assignable::value)> hb_sorted_array_t _qsort (hb_priority<1>) { - return qsort ([] (const Type &a, const Type &b) { return Type::cmp (&a, &b) < 0; }); + return qsort ([] (const Type &a, const Type &b) { return Type::cmp (&a, &b); }); } hb_sorted_array_t _qsort (hb_priority<0>) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh index f95a3079475..de37c4b423a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh @@ -36,60 +36,8 @@ #include "hb-meta.hh" -/* - * Atomic integers and pointers. - */ - -/* We need external help for these */ - -#if defined(hb_atomic_int_impl_add) \ - && defined(hb_atomic_ptr_impl_get) \ - && defined(hb_atomic_ptr_impl_cmpexch) - -/* Defined externally, i.e. in config.h. */ - - -#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE) - -/* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */ - -#define _hb_memory_barrier() __sync_synchronize () - -#define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL) -#define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED) -#define hb_atomic_int_impl_set(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELEASE) -#define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED) -#define hb_atomic_int_impl_get(AI) __atomic_load_n ((AI), __ATOMIC_ACQUIRE) - -#define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n ((P), (V), __ATOMIC_RELAXED) -#define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n ((P), __ATOMIC_RELAXED) -#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_ACQUIRE) -static inline bool -_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) -{ - const void *O = O_; // Need lvalue - return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED); -} -#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N)) - - -#elif !defined(HB_NO_MT) - -/* C++11 atomics. */ - +#ifndef HB_NO_MT #include - -#define HB_STL_ATOMIC_IMPL - -#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire) -#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release) - -#else /* defined(HB_NO_MT) */ - -#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V)) -#define _hb_memory_barrier() do {} while (0) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) - #endif @@ -110,46 +58,15 @@ static inline void _hb_compiler_memory_r_barrier () {} #endif +#ifndef HB_NO_MT -#ifndef _hb_memory_r_barrier -#define _hb_memory_r_barrier() _hb_memory_barrier () -#endif -#ifndef _hb_memory_w_barrier -#define _hb_memory_w_barrier() _hb_memory_barrier () -#endif -#ifndef hb_atomic_int_impl_set_relaxed -#define hb_atomic_int_impl_set_relaxed(AI, V) (*(AI) = (V)) -#endif -#ifndef hb_atomic_int_impl_get_relaxed -#define hb_atomic_int_impl_get_relaxed(AI) (*(AI)) -#endif - -#ifndef hb_atomic_ptr_impl_set_relaxed -#define hb_atomic_ptr_impl_set_relaxed(P, V) (*(P) = (V)) -#endif -#ifndef hb_atomic_ptr_impl_get_relaxed -#define hb_atomic_ptr_impl_get_relaxed(P) (*(P)) -#endif -#ifndef hb_atomic_int_impl_set -template -inline void hb_atomic_int_impl_set (T *AI, T v) { _hb_memory_w_barrier (); *AI = v; } -#endif -#ifndef hb_atomic_int_impl_get -template -inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrier (); return v; } -#endif -#ifndef hb_atomic_ptr_impl_get -inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; } -#endif - -#ifdef HB_STL_ATOMIC_IMPL template struct hb_atomic_t { hb_atomic_t () = default; constexpr hb_atomic_t (T v) : v (v) {} constexpr hb_atomic_t (const hb_atomic_t& o) : v (o.get_relaxed ()) {} - constexpr hb_atomic_t (hb_atomic_t&& o) : v (o.get_relaxed ()) { o.set_relaxed ({}); } + hb_atomic_t (hb_atomic_t&& o) : v (o.get_relaxed ()) { o.set_relaxed ({}); } hb_atomic_t &operator= (const hb_atomic_t& o) { set_relaxed (o.get_relaxed ()); return *this; } hb_atomic_t &operator= (hb_atomic_t&& o){ set_relaxed (o.get_relaxed ()); o.set_relaxed ({}); return *this; } @@ -177,7 +94,7 @@ struct hb_atomic_t b.set_relaxed (v); } - std::atomic v = 0; + std::atomic v {0}; }; template @@ -211,10 +128,10 @@ struct hb_atomic_t b.set_relaxed (p); } - std::atomic v = nullptr; + std::atomic v {nullptr}; }; -#else +#else /* defined(HB_NO_MT) */ template struct hb_atomic_t @@ -225,12 +142,12 @@ struct hb_atomic_t hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; } operator T () const { return get_relaxed (); } - void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } - void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); } - T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } - T get_acquire () const { return hb_atomic_int_impl_get (&v); } - T inc () { return hb_atomic_int_impl_add (&v, 1); } - T dec () { return hb_atomic_int_impl_add (&v, -1); } + void set_relaxed (T v_) { v = v_; } + void set_release (T v_) { v = v_; } + T get_relaxed () const { return v; } + T get_acquire () const { return v; } + T inc () { return v++; } + T dec () { return v--; } int operator ++ (int) { return inc (); } int operator -- (int) { return dec (); } @@ -246,10 +163,15 @@ struct hb_atomic_t hb_atomic_t (const hb_atomic_t &other) = delete; void init (T* v_ = nullptr) { set_relaxed (v_); } - void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } - T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } - T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } - bool cmpexch (T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } + void set_relaxed (T* v_) { v = v_; } + T *get_relaxed () const { return v; } + T *get_acquire () const { return v; } + bool cmpexch (T *old, T *new_) + { + if (v != old) return false; + v = new_; + return true; + } operator bool () const { return get_acquire () != nullptr; } T * operator -> () const { return get_acquire (); } @@ -260,6 +182,7 @@ struct hb_atomic_t #endif + static inline bool hb_barrier () { _hb_compiler_memory_r_barrier (); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh index 902db195507..216e653a252 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh @@ -135,7 +135,9 @@ struct hb_bit_page_t } void add (hb_codepoint_t g) { elt (g) |= mask (g); dirty (); } + void add_bits (hb_codepoint_t g, uint64_t bits) { elt (g) |= bits; dirty (); } void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); } + void del_bits (hb_codepoint_t g, uint64_t bits) { elt (g) &= ~bits; dirty (); } void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); } bool get (hb_codepoint_t g) const { return elt (g) & mask (g); } bool may_have (hb_codepoint_t g) const { return get (g); } @@ -150,7 +152,7 @@ struct hb_bit_page_t elt_t *lb = &elt (b); if (la == lb) *la |= (mask (b) << 1) - mask(a); - else + else if (likely (la < lb)) { *la |= ~(mask (a) - 1llu); la++; @@ -159,6 +161,8 @@ struct hb_bit_page_t *lb |= ((mask (b) << 1) - 1llu); } + else + return; dirty (); } void del_range (hb_codepoint_t a, hb_codepoint_t b) @@ -167,7 +171,7 @@ struct hb_bit_page_t elt_t *lb = &elt (b); if (la == lb) *la &= ~((mask (b) << 1llu) - mask(a)); - else + else if (likely (la < lb)) { *la &= mask (a) - 1; la++; @@ -176,6 +180,8 @@ struct hb_bit_page_t *lb &= ~((mask (b) << 1) - 1llu); } + else + return; dirty (); } void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v) @@ -344,7 +350,7 @@ struct hb_bit_page_t for (int i = len () - 1; i >= 0; i--) if (v[i]) return i * ELT_BITS + elt_get_max (v[i]); - return 0; + return INVALID; } /* diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh index 2c97f416fe6..f79d4342653 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh @@ -101,9 +101,20 @@ struct hb_bit_set_invertible_t } unsigned int get_population () const { return inverted ? INVALID - s.get_population () : s.get_population (); } + bool get_singleton (hb_codepoint_t *codepoint) const + { + if (likely (!inverted)) + return s.get_singleton (codepoint); + if (s.get_population () != INVALID - 1) + return false; + *codepoint = get_min (); + return *codepoint != INVALID; + } void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); } + void add_bits (hb_codepoint_t g, uint64_t bits) + { unlikely (inverted) ? s.del_bits (g, bits) : s.add_bits (g, bits); } bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return unlikely (inverted) ? ((void) s.del_range (a, b), true) : s.add_range (a, b); } @@ -143,6 +154,24 @@ struct hb_bit_set_invertible_t bool may_intersect (const hb_bit_set_invertible_t &other) const { return inverted || other.inverted || s.intersects (other.s); } + bool intersects (const hb_bit_set_invertible_t &other) const + { + if (likely (!inverted)) + return unlikely (other.inverted) ? !s.is_subset (other.s) + : s.intersects (other.s); + if (likely (!other.inverted)) + return !other.s.is_subset (s); + + unsigned population = s.get_population (); + unsigned other_population = other.s.get_population (); + if ((uint64_t) population + other_population < INVALID) + return true; + + return population >= other_population + ? !hb_all (iter (), other.s) + : !hb_all (other.iter (), s); + } + bool intersects (hb_codepoint_t first, hb_codepoint_t last) const { hb_codepoint_t c = first - 1; @@ -162,6 +191,9 @@ struct hb_bit_set_invertible_t return s.is_equal (other.s); else { + if (get_population () != other.get_population ()) + return false; + /* TODO Add iter_ranges() and use here. */ auto it1 = iter (); auto it2 = other.iter (); @@ -187,8 +219,10 @@ struct hb_bit_set_invertible_t protected: template - void process (const Op& op, const hb_bit_set_invertible_t &other) - { s.process (op, other.s); } + void process (const Op& op, + const hb_bit_set_invertible_t &other, + hb_vector_t *workspace = nullptr) + { s.process (op, other.s, workspace); } public: void union_ (const hb_bit_set_invertible_t &other) { @@ -209,21 +243,22 @@ struct hb_bit_set_invertible_t if (likely (s.successful)) inverted = inverted || other.inverted; } - void intersect (const hb_bit_set_invertible_t &other) + void intersect (const hb_bit_set_invertible_t &other, + hb_vector_t *workspace = nullptr) { if (likely (inverted == other.inverted)) { if (unlikely (inverted)) - process (hb_bitwise_or, other); + process (hb_bitwise_or, other, workspace); else - process (hb_bitwise_and, other); /* Main branch. */ + process (hb_bitwise_and, other, workspace); /* Main branch. */ } else { if (unlikely (inverted)) - process (hb_bitwise_lt, other); + process (hb_bitwise_lt, other, workspace); else - process (hb_bitwise_gt, other); + process (hb_bitwise_gt, other, workspace); } if (likely (s.successful)) inverted = inverted && other.inverted; @@ -280,6 +315,47 @@ struct hb_bit_set_invertible_t *codepoint = v + 1; return *codepoint != INVALID; } + bool next_bits (hb_codepoint_t *codepoint, uint64_t *bits) const + { + if (likely (!inverted)) + return s.next_bits (codepoint, bits); + + hb_codepoint_t base; + if (unlikely (*codepoint == INVALID)) + base = 0; + else + { + base = *codepoint & ~hb_bit_page_t::ELT_MASK; + if (unlikely (base >= INVALID - hb_bit_page_t::ELT_BITS + 1)) + goto done; + base += hb_bit_page_t::ELT_BITS; + } + + while (true) + { + hb_codepoint_t cursor = base ? base - hb_bit_page_t::ELT_BITS : INVALID; + uint64_t excluded = 0; + if (!s.next_bits (&cursor, &excluded) || cursor != base) + excluded = 0; + *bits = ~excluded; + bool last = unlikely (base >= INVALID - hb_bit_page_t::ELT_BITS + 1); + if (last) + *bits &= UINT64_MAX >> 1; + if (*bits) + { + *codepoint = base; + return true; + } + if (unlikely (last)) + break; + base += hb_bit_page_t::ELT_BITS; + } + + done: + *codepoint = INVALID; + *bits = 0; + return false; + } bool previous (hb_codepoint_t *codepoint) const { if (likely (!inverted)) @@ -352,27 +428,50 @@ struct hb_bit_set_invertible_t /* * Iterator implementation. + * Mutating the set invalidates its iterators. */ struct iter_t : hb_iter_with_fallback_t { static constexpr bool is_sorted_iterator = true; static constexpr bool has_fast_len = true; iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t), - bool init = true) : s (&s_), v (INVALID), l(0) + bool init = true) : s (&s_), v (INVALID), remaining (0), + have_len (!init), base (INVALID), bits (0) { if (init) - { - l = s->get_population () + 1; - __next__ (); - } + advance (); } typedef hb_codepoint_t __item_t__; hb_codepoint_t __item__ () const { return v; } bool __more__ () const { return v != INVALID; } - void __next__ () { s->next (&v); if (likely (l)) l--; } - void __prev__ () { s->previous (&v); l++; } - unsigned __len__ () const { return l; } + void __next__ () + { + remaining--; + advance (); + } + void __prev__ () + { + if (s->previous (&v)) + { + sync (); + remaining++; + } + else + { + base = INVALID; + bits = 0; + } + } + unsigned __len__ () const + { + if (unlikely (!have_len)) + { + remaining += s->get_population (); + have_len = true; + } + return remaining; + } iter_t end () const { return iter_t (*s, false); } bool operator != (const iter_t& o) const { return v != o.v; } @@ -380,7 +479,35 @@ struct hb_bit_set_invertible_t protected: const hb_bit_set_invertible_t *s; hb_codepoint_t v; - unsigned l; + mutable unsigned remaining; + mutable bool have_len; + hb_codepoint_t base; + uint64_t bits; + + void advance () + { + if (likely (bits)) + { + v = base + hb_ctz (bits); + bits &= bits - 1; + } + else if (s->next_bits (&base, &bits)) + { + v = base + hb_ctz (bits); + bits &= bits - 1; + } + else + v = INVALID; + } + + void sync () + { + base = v & ~hb_bit_page_t::ELT_MASK; + hb_codepoint_t cursor = base ? base - hb_bit_page_t::ELT_BITS : INVALID; + s->next_bits (&cursor, &bits); + unsigned int bit = v & (hb_bit_page_t::ELT_BITS - 1); + bits = bit == hb_bit_page_t::ELT_BITS - 1 ? 0 : bits >> (bit + 1) << (bit + 1); + } }; iter_t iter () const { return iter_t (*this); } operator iter_t () const { return iter (); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh index 9e29d2af323..62d1aad9142 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh @@ -31,7 +31,6 @@ #include "hb.hh" #include "hb-bit-page.hh" - struct hb_bit_set_t { hb_bit_set_t () = default; @@ -161,6 +160,14 @@ struct hb_bit_set_t page_t *page = page_for (g, true); if (unlikely (!page)) return; page->add (g); } + void add_bits (hb_codepoint_t g, uint64_t bits) + { + if (unlikely (!successful) || unlikely (!bits)) return; + assert (!(g & (page_t::ELT_BITS - 1))); + dirty (); + page_t *page = page_for (g, true); if (unlikely (!page)) return; + page->add_bits (g, bits); + } bool add_range (hb_codepoint_t a, hb_codepoint_t b) { if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */ @@ -260,7 +267,7 @@ struct hb_bit_set_t last_g = g; if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ - page->add (g); + page->set (g, v); array = &StructAtOffsetUnaligned (array, stride); count--; @@ -291,6 +298,16 @@ struct hb_bit_set_t dirty (); page->del (g); } + void del_bits (hb_codepoint_t g, uint64_t bits) + { + if (unlikely (!successful) || unlikely (!bits)) return; + assert (!(g & (page_t::ELT_BITS - 1))); + page_t *page = page_for (g); + if (!page) + return; + dirty (); + page->del_bits (g, bits); + } private: void del_pages (int ds, int de) @@ -524,7 +541,8 @@ struct hb_bit_set_t void process_ (hb_bit_page_t::vector_t (*op) (const hb_bit_page_t::vector_t &, const hb_bit_page_t::vector_t &), bool passthru_left, bool passthru_right, - const hb_bit_set_t &other) + const hb_bit_set_t &other, + hb_vector_t *workspace = nullptr) { if (unlikely (!successful)) return; @@ -540,8 +558,18 @@ struct hb_bit_set_t // Pre-allocate the workspace that compact() will need so we can bail on allocation failure // before attempting to rewrite the page map. - hb_vector_t compact_workspace; - if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return; + hb_vector_t local_workspace; + hb_vector_t &compact_workspace = workspace ? *workspace : local_workspace; + if (!passthru_left) + { + bool allocated = workspace ? compact_workspace.resize (pages.length) + : allocate_compact_workspace (compact_workspace); + if (unlikely (!allocated)) + { + successful = false; + return; + } + } for (; a < na && b < nb; ) { @@ -651,13 +679,17 @@ struct hb_bit_set_t op_ (const hb_bit_page_t::vector_t &a, const hb_bit_page_t::vector_t &b) { return Op{} (a, b); } template - void process (const Op& op, const hb_bit_set_t &other) + void process (const Op& op, + const hb_bit_set_t &other, + hb_vector_t *workspace = nullptr) { - process_ (op_, op (1, 0), op (0, 1), other); + process_ (op_, op (1, 0), op (0, 1), other, workspace); } void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); } - void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); } + void intersect (const hb_bit_set_t &other, + hb_vector_t *workspace = nullptr) + { process (hb_bitwise_and, other, workspace); } void subtract (const hb_bit_set_t &other) { process (hb_bitwise_gt, other); } void symmetric_difference (const hb_bit_set_t &other) { process (hb_bitwise_xor, other); } @@ -708,6 +740,50 @@ struct hb_bit_set_t *codepoint = INVALID; return false; } + bool next_bits (hb_codepoint_t *codepoint, uint64_t *bits) const + { + static_assert (page_t::ELT_BITS == 64, ""); + + unsigned int i = 0; + unsigned int elt = 0; + if (likely (*codepoint != INVALID)) + { + hb_codepoint_t base = *codepoint & ~page_t::ELT_MASK; + if (unlikely (base >= INVALID - page_t::ELT_BITS + 1)) + goto done; + base += page_t::ELT_BITS; + + unsigned int major = get_major (base); + i = last_page_lookup; + if (unlikely (i >= page_map.length || page_map.arrayZ[i].major != major)) + { + page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST); + if (i >= page_map.length) + goto done; + } + if (page_map.arrayZ[i].major == major) + elt = page_remainder (base) / page_t::ELT_BITS; + } + + for (; i < page_map.length; i++, elt = 0) + { + const page_map_t &map = page_map.arrayZ[i]; + const page_t &page = pages.arrayZ[map.index]; + for (; elt < page_t::len (); elt++) + if (page.v[elt]) + { + *codepoint = major_start (map.major) + elt * page_t::ELT_BITS; + *bits = page.v[elt]; + last_page_lookup = i; + return true; + } + } + + done: + *codepoint = INVALID; + *bits = 0; + return false; + } bool previous (hb_codepoint_t *codepoint) const { if (unlikely (*codepoint == INVALID)) { @@ -750,13 +826,62 @@ struct hb_bit_set_t return false; } - /* TODO Speed up. */ *last = *first = i; - while (next (&i) && i == *last + 1) - (*last)++; - return true; + const auto* page_map_array = page_map.arrayZ; + const auto* pages_array = pages.arrayZ; + unsigned int major = get_major (*last); + unsigned int p_index = last_page_lookup; + + if (unlikely (p_index >= page_map.length || page_map_array[p_index].major != major)) + { + page_map.bfind (major, &p_index, HB_NOT_FOUND_STORE_CLOSEST); + // The above next() call gaurantees the page we're looking for exists. + assert(p_index < page_map.length && page_map_array[p_index].major == major); + last_page_lookup = p_index; + } + + unsigned int rem = page_remainder (*last); + unsigned int elt = rem / page_t::ELT_BITS; + unsigned int bit = rem & page_t::ELT_MASK; + + const page_t *page = &pages_array[page_map_array[p_index].index]; + unsigned int run = hb_ctz (~(page->v[elt] >> bit)); + *last += run - 1; + if (run < page_t::ELT_BITS - bit) + return true; + + elt++; + + while (true) + { + for (; elt < page_t::len (); elt++) + { + uint64_t w = page->v[elt]; + if (w == (uint64_t) -1) + { + *last += page_t::ELT_BITS; + continue; + } + uint64_t inv = ~w; + *last += hb_ctz (inv); + return true; + } + + p_index++; + + + if (p_index >= page_map.length || page_map_array[p_index].major != major + 1) + return true; + + const auto& entry = page_map_array[p_index]; + major = entry.major; + last_page_lookup = p_index; + page = &pages_array[entry.index]; + elt = 0; + } } + bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const { hb_codepoint_t i; @@ -768,12 +893,62 @@ struct hb_bit_set_t return false; } - /* TODO Speed up. */ *last = *first = i; - while (previous (&i) && i == *first - 1) - (*first)--; - return true; + const auto* page_map_array = page_map.arrayZ; + const auto* pages_array = pages.arrayZ; + unsigned int major = get_major (*first); + unsigned int p_index = last_page_lookup; + + if (unlikely (p_index >= page_map.length || page_map_array[p_index].major != major)) + { + page_map.bfind (major, &p_index, HB_NOT_FOUND_STORE_CLOSEST); + // The above previous() call gaurantees the page we're looking for exists. + assert(p_index < page_map.length && page_map_array[p_index].major == major); + last_page_lookup = p_index; + } + + unsigned int rem = page_remainder (*first); + int elt = rem / page_t::ELT_BITS; + unsigned int bit = rem & page_t::ELT_MASK; + + const page_t *page = &pages_array[page_map_array[p_index].index]; + uint64_t inv = ~(page->v[elt] << (63 - bit)); + unsigned int run = hb_bit_storage (inv) ? (page_t::ELT_BITS - hb_bit_storage (inv)) : page_t::ELT_BITS; + *first -= run - 1; + if (run < bit + 1) + return true; + + elt--; + + while (true) + { + for (; elt >= 0; elt--) + { + uint64_t w = page->v[elt]; + if (w == (uint64_t) -1) + { + *first -= page_t::ELT_BITS; + continue; + } + uint64_t inv = ~w; + unsigned int zeros = hb_bit_storage (inv) ? (page_t::ELT_BITS - hb_bit_storage (inv)) : page_t::ELT_BITS; + *first -= zeros; + return true; + } + + + if (p_index == 0 || page_map_array[p_index - 1].major != major - 1) + return true; + + p_index--; + const auto& entry = page_map_array[p_index]; + + major = entry.major; + last_page_lookup = p_index; + page = &pages_array[entry.index]; + elt = page_t::len () - 1; + } } unsigned int next_many (hb_codepoint_t codepoint, @@ -795,12 +970,15 @@ struct hb_bit_set_t return 0; // codepoint is greater than our max element. } start_page = i; - start_page_value = page_remainder (codepoint + 1); - if (unlikely (start_page_value == 0)) + if (page_map_array[i].major == major) { - // The export-after value was last in the page. Start on next page. - start_page++; - start_page_value = 0; + start_page_value = page_remainder (codepoint + 1); + if (unlikely (start_page_value == 0)) + { + // The export-after value was last in the page. Start on next page. + start_page++; + start_page_value = 0; + } } } @@ -844,12 +1022,15 @@ struct hb_bit_set_t } } start_page = i; - start_page_value = page_remainder (codepoint + 1); - if (unlikely (start_page_value == 0)) + if (page_map_array[i].major == major) { - // The export-after value was last in the page. Start on next page. - start_page++; - start_page_value = 0; + start_page_value = page_remainder (codepoint + 1); + if (unlikely (start_page_value == 0)) + { + // The export-after value was last in the page. Start on next page. + start_page++; + start_page_value = 0; + } } } @@ -883,6 +1064,39 @@ struct hb_bit_set_t population = pop; return pop; } + bool get_singleton (hb_codepoint_t *codepoint) const + { + if (has_population ()) + { + if (population != 1) return false; + *codepoint = get_min (); + return true; + } + + hb_codepoint_t singleton = INVALID; + for (const auto &map : page_map) + { + const auto &page = pages.arrayZ[map.index]; + for (unsigned i = 0; i < page_t::len (); i++) + { + page_t::elt_t bits = page.v[i]; + if (!bits) continue; + if (singleton != INVALID || (bits & (bits - 1))) + return false; + singleton = map.major * page_t::PAGE_BITS + + i * page_t::ELT_BITS + hb_ctz (bits); + } + } + + if (singleton == INVALID) + { + population = 0; + return false; + } + population = 1; + *codepoint = singleton; + return true; + } hb_codepoint_t get_min () const { unsigned count = pages.length; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc index e60259f52da..fcb4e6e1b5f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc @@ -662,7 +662,7 @@ _hb_blob_try_mmap (const char *file_name) if (unlikely (!file)) return nullptr; auto file_guard = hb_make_scope_guard ([&]() { hb_free (file); }); - unsigned int size = strlen (file_name) + 1; + size_t size = strlen (file_name) + 1; wchar_t *wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); if (unlikely (!wchar_file_name)) return nullptr; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc index b3190ffc8ef..502bd7326cb 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc @@ -120,8 +120,8 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, { for (unsigned int i = 0; i < start; i++) { - x += pos[i].x_advance; - y += pos[i].y_advance; + x = hb_saturate_add (x, pos[i].x_advance); + y = hb_saturate_add (y, pos[i].y_advance); } } @@ -164,8 +164,10 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, if (pos && !(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) { + hb_position_t dx = hb_saturate_add (x, pos[i].x_offset); + hb_position_t dy = hb_saturate_add (y, pos[i].y_offset); p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", - x+pos[i].x_offset, y+pos[i].y_offset)); + dx, dy)); if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", pos[i].x_advance, pos[i].y_advance)); @@ -206,8 +208,8 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) { - x += pos[i].x_advance; - y += pos[i].y_advance; + x = hb_saturate_add (x, pos[i].x_advance); + y = hb_saturate_add (y, pos[i].y_advance); } } @@ -289,8 +291,8 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, { for (unsigned int i = 0; i < start; i++) { - x += pos[i].x_advance; - y += pos[i].y_advance; + x = hb_saturate_add (x, pos[i].x_advance); + y = hb_saturate_add (y, pos[i].y_advance); } } @@ -321,8 +323,10 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, if (pos && !(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) { - if (x+pos[i].x_offset || y+pos[i].y_offset) - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset)); + hb_position_t dx = hb_saturate_add (x, pos[i].x_offset); + hb_position_t dy = hb_saturate_add (y, pos[i].y_offset); + if (dx || dy) + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", dx, dy)); if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) { @@ -363,8 +367,8 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) { - x += pos[i].x_advance; - y += pos[i].y_advance; + x = hb_saturate_add (x, pos[i].x_advance); + y = hb_saturate_add (y, pos[i].y_advance); } } @@ -796,19 +800,19 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, return false; } - hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); - if (!font) font = hb_font_get_empty (); switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); return _hb_buffer_deserialize_text_glyphs (buffer, buf, buf_len, end_ptr, font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); return _hb_buffer_deserialize_json (buffer, buf, buf_len, end_ptr, font); @@ -867,18 +871,18 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer, return false; } - hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE); - hb_font_t* font = hb_font_get_empty (); switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE); return _hb_buffer_deserialize_text_unicode (buffer, buf, buf_len, end_ptr, font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE); return _hb_buffer_deserialize_json (buffer, buf, buf_len, end_ptr, font); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc index 647c270c02a..e09a2c3f027 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc @@ -147,7 +147,11 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, text_start--; } } - assert (text_start < text_end); + if (unlikely (text_start >= text_end)) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break text range is invalid."); + return false; + } if (false) printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); @@ -163,7 +167,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, hb_buffer_append (fragment, text_buffer, text_start, text_end); if (!hb_shape_full (font, fragment, features, num_features, shapers) || - fragment->successful) + !fragment->successful) return true; hb_buffer_append (reconstruction, fragment, 0, -1); @@ -380,11 +384,14 @@ hb_buffer_t::verify (hb_buffer_t *text_buffer, const char * const *shapers) { bool ret = true; - if (!buffer_verify_monotone (this, font)) + bool monotone = buffer_verify_monotone (this, font); + if (!monotone) ret = false; - if (!buffer_verify_unsafe_to_break (this, text_buffer, font, features, num_features, shapers)) + if (monotone && + !buffer_verify_unsafe_to_break (this, text_buffer, font, features, num_features, shapers)) ret = false; - if ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) != 0 && + if (monotone && + (flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) != 0 && !buffer_verify_unsafe_to_concat (this, text_buffer, font, features, num_features, shapers)) ret = false; if (!ret) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc index f4eb6040de7..f1088ccaa5b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc @@ -484,6 +484,13 @@ hb_buffer_t::move_to (unsigned int i) unsigned int count = i - out_len; if (unlikely (!make_room_for (count, count))) return false; + max_ops -= count; + if (unlikely (max_ops < 0)) + { + successful = false; + return false; + } + memmove (out_info + out_len, info + idx, count * sizeof (out_info[0])); idx += count; out_len += count; @@ -504,6 +511,13 @@ hb_buffer_t::move_to (unsigned int i) assert (idx >= count); + max_ops -= count; + if (unlikely (max_ops < 0)) + { + successful = false; + return false; + } + idx -= count; out_len -= count; memmove (info + idx, out_info + out_len, count * sizeof (out_info[0])); @@ -802,8 +816,12 @@ hb_buffer_create_similar (const hb_buffer_t *src) * hb_buffer_reset: * @buffer: An #hb_buffer_t * - * Resets the buffer to its initial status, as if it was just newly created - * with hb_buffer_create(). + * Clears the buffer contents and segment properties, and restores the + * default Unicode functions and buffer settings. + * + * The message callback, its associated data, and any attached user data are + * preserved. To remove the message callback, call + * hb_buffer_set_message_func() with a `NULL` function. * * Since: 0.9.2 **/ @@ -1478,8 +1496,12 @@ hb_buffer_get_random_state (const hb_buffer_t *buffer) * hb_buffer_clear_contents: * @buffer: An #hb_buffer_t * - * Similar to hb_buffer_reset(), but does not clear the Unicode functions and - * the replacement code point. + * Clears the buffer contents and segment properties (direction, script, + * language), and resets the random state to its default value of 1. + * + * Unlike hb_buffer_reset(), this function preserves the Unicode functions, + * flags, cluster level, replacement code point, and invisible and not-found + * glyphs. The message callback and attached user data are also preserved. * * Since: 0.9.11 **/ @@ -2103,18 +2125,18 @@ normalize_glyphs_cluster (hb_buffer_t *buffer, hb_position_t total_x_advance = 0, total_y_advance = 0; for (unsigned int i = start; i < end; i++) { - total_x_advance += pos[i].x_advance; - total_y_advance += pos[i].y_advance; + total_x_advance = hb_saturate_add (total_x_advance, pos[i].x_advance); + total_y_advance = hb_saturate_add (total_y_advance, pos[i].y_advance); } hb_position_t x_advance = 0, y_advance = 0; for (unsigned int i = start; i < end; i++) { - pos[i].x_offset += x_advance; - pos[i].y_offset += y_advance; + pos[i].x_offset = hb_saturate_add (pos[i].x_offset, x_advance); + pos[i].y_offset = hb_saturate_add (pos[i].y_offset, y_advance); - x_advance += pos[i].x_advance; - y_advance += pos[i].y_advance; + x_advance = hb_saturate_add (x_advance, pos[i].x_advance); + y_advance = hb_saturate_add (y_advance, pos[i].y_advance); pos[i].x_advance = 0; pos[i].y_advance = 0; @@ -2129,11 +2151,11 @@ normalize_glyphs_cluster (hb_buffer_t *buffer, hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start); } else { /* Transfer all cluster advance to the first glyph. */ - pos[start].x_advance += total_x_advance; - pos[start].y_advance += total_y_advance; + pos[start].x_advance = hb_saturate_add (pos[start].x_advance, total_x_advance); + pos[start].y_advance = hb_saturate_add (pos[start].y_advance, total_y_advance); for (unsigned int i = start + 1; i < end; i++) { - pos[i].x_offset -= total_x_advance; - pos[i].y_offset -= total_y_advance; + pos[i].x_offset = hb_saturate_sub (pos[i].x_offset, total_x_advance); + pos[i].y_offset = hb_saturate_sub (pos[i].y_offset, total_y_advance); } hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1); } @@ -2258,15 +2280,20 @@ hb_buffer_diff (hb_buffer_t *buffer, if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) { + auto position_diff = [] (hb_position_t a, hb_position_t b) -> uint64_t + { + int64_t diff = (int64_t) a - b; + return diff < 0 ? -diff : diff; + }; assert (buffer->have_positions); const hb_glyph_position_t *buf_pos = buffer->pos; const hb_glyph_position_t *ref_pos = reference->pos; for (unsigned int i = 0; i < count; i++) { - if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz || - (unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz || - (unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz || - (unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz) + if (position_diff (buf_pos->x_advance, ref_pos->x_advance) > position_fuzz || + position_diff (buf_pos->y_advance, ref_pos->y_advance) > position_fuzz || + position_diff (buf_pos->x_offset, ref_pos->x_offset) > position_fuzz || + position_diff (buf_pos->y_offset, ref_pos->y_offset) > position_fuzz) { result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH; break; @@ -2309,6 +2336,9 @@ hb_buffer_t::changed () * @destroy: (nullable): The function to call when @user_data is not needed anymore * * Sets the implementation function for #hb_buffer_message_func_t. + * The callback and its associated data are preserved by hb_buffer_reset() + * and hb_buffer_clear_contents(). The @destroy function is called when the + * callback is replaced or removed, or when @buffer is destroyed. * * Since: 1.1.3 **/ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh index 32eca7021f8..107ddb1f902 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh @@ -385,11 +385,6 @@ struct hb_buffer_t } /* Advance idx without copying to output. */ void skip_glyph () { idx++; } - void reset_masks (hb_mask_t mask) - { - for (unsigned int j = 0; j < len; j++) - info[j].mask = mask; - } void add_masks (hb_mask_t mask) { for (unsigned int j = 0; j < len; j++) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh index 3609ccecc71..b7a915591bf 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh @@ -94,8 +94,11 @@ struct hb_cache_t { unsigned int k = key & ((1u<> value_bits) != (key >> cache_bits)) + constexpr unsigned int empty = (1ULL << (8 * sizeof (item_t))) - 1; + /* Combine overflow, tag mismatch, and empty checks into one branch. */ + if ((key >> key_bits) | + ((v >> value_bits) ^ (key >> cache_bits)) | + ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t)) && (v == empty))) return false; *value = v & ((1u<> key_bits) || (value >> value_bits))) return; /* Overflows */ - set_unchecked (key, value); - } - - HB_HOT - void set_unchecked (unsigned int key, unsigned int value) - { unsigned int k = key & ((1u<>cache_bits)<= INT_MIN && value <= INT_MAX))) + { + *v = 0; + return false; + } + *v = (int) value; + return true; + } + int to_int () const + { + int v; + if (likely (to_int (&v))) return v; + return value < 0 ? INT_MIN : value > 0 ? INT_MAX : 0; + } void set_fixed (int32_t v) { value = v / 65536.0; } - int32_t to_fixed () const { return value * 65536.0; } + int32_t to_fixed () const + { return (int32_t) hb_clamp (value * 65536.0, (double) INT32_MIN, (double) INT32_MAX); } void set_real (double v) { value = v; } double to_real () const { return value; } bool in_int_range () const - { return ((double) (int16_t) to_int () == value); } + { return value >= INT16_MIN && value <= INT16_MAX && (double) (int16_t) value == value; } bool operator > (const number_t &n) const { return value > n.to_real (); } bool operator < (const number_t &n) const { return n > *this; } @@ -446,7 +462,13 @@ struct arg_stack_t : cff_stack_t ARG& pop_num () { return this->pop (); } - int pop_int () { return this->pop ().to_int (); } + int pop_int () + { + int v; + if (unlikely (!this->pop ().to_int (&v))) + S::set_error (); + return v; + } unsigned int pop_uint () { @@ -461,7 +483,7 @@ struct arg_stack_t : cff_stack_t void push_longint_from_substr (byte_str_ref_t& str_ref) { - push_int ((str_ref[0] << 24) | (str_ref[1] << 16) | (str_ref[2] << 8) | (str_ref[3])); + push_int ((int) ((uint32_t (str_ref[0]) << 24) | (str_ref[1] << 16) | (str_ref[2] << 8) | (str_ref[3]))); str_ref.inc (4); } @@ -481,15 +503,15 @@ struct arg_stack_t : cff_stack_t /* an operator prefixed by its operands in a byte string */ struct op_str_t { - /* This used to have a hb_ubytes_t. Using a pointer and length - * in a particular order, saves 8 bytes in this struct and more - * in our parsed_cs_op_t subclass. */ + /* Borrow the encoded bytes. DICT entries with accumulated blends can + * exceed the length of an individual charstring token. */ const unsigned char *ptr = nullptr; op_code_t op = OpCode_Invalid; - uint8_t length = 0; + /* DICT entries can contain many blends before their final operator. */ + unsigned length = 0; }; /* base of OP_SERIALIZER */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh index 2628effa5cc..a1f705c59b4 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh @@ -121,6 +121,7 @@ struct cs_interp_env_t : interp_env_t hstem_count = 0; vstem_count = 0; hintmask_size = 0; + budget = nullptr; pt.set_int (0, 0); globalSubrs.init (globalSubrs_); localSubrs.init (localSubrs_); @@ -186,6 +187,11 @@ struct cs_interp_env_t : interp_env_t void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; } bool is_endchar () const { return endchar_flag; } + void set_budget (int64_t *budget_) { budget = budget_; } + int64_t *get_budget () const { return budget; } + bool spend_budget (unsigned int cost, unsigned int mult = 1) + { return !budget || hb_budget_spend (*budget, cost, mult); } + const number_t &get_x () const { return pt.x; } const number_t &get_y () const { return pt.y; } const point_t &get_pt () const { return pt; } @@ -201,6 +207,7 @@ struct cs_interp_env_t : interp_env_t unsigned int hstem_count; unsigned int vstem_count; unsigned int hintmask_size; + int64_t *budget; call_stack_t callStack; biased_subrs_t globalSubrs; biased_subrs_t localSubrs; @@ -877,23 +884,43 @@ struct cs_interpreter_t : interpreter_t { cs_interpreter_t (ENV& env_) : interpreter_t (env_) {} - bool interpret (PARAM& param) + bool interpret (PARAM& param, int64_t *budget = nullptr) { SUPER::env.set_endchar (false); - - unsigned max_ops = HB_CFF_MAX_OPS; - for (;;) { - OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); - if (unlikely (SUPER::env.in_error () || !--max_ops)) - { - SUPER::env.set_error (); - return false; + SUPER::env.set_budget (budget); + + /* Cap the operator count by the caller's remaining budget so the single + * max_ops counter enforces both the structural limit and the live work + * budget, with no budget check in the hot loop. The consumed operators + * are charged back after the loop, and since the cap never exceeds the + * remaining budget the charstring cannot overshoot it. CFF2 blend + * charges its proportional work separately, in place. */ + int64_t remaining = budget ? *budget : (int64_t) HB_CFF_MAX_OPS; + unsigned max_ops = (unsigned) hb_clamp (remaining, (int64_t) 0, (int64_t) HB_CFF_MAX_OPS); + unsigned start_ops = max_ops; + + bool ret = true; + if (likely (max_ops)) + for (;;) { + OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); + if (unlikely (SUPER::env.in_error () || !--max_ops)) + { + SUPER::env.set_error (); + ret = false; + break; + } + if (SUPER::env.is_endchar ()) + break; } - if (SUPER::env.is_endchar ()) - break; + else + { + SUPER::env.set_error (); + ret = false; } - return true; + if (budget) *budget -= (int64_t) (start_ops - max_ops); + + return ret; } private: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh index a4aa005d82c..c2664de9462 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh @@ -78,7 +78,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t num_coords = num_coords_; varStore = acc.varStore; do_blend = num_coords && varStore->size; - set_ivs (acc.privateDicts[fd].ivs); + orig_ivs = acc.privateDicts[fd].ivs; + set_ivs (orig_ivs); } ~cff2_cs_interp_env_t () @@ -179,6 +180,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t void set_region_count (unsigned int region_count_) { region_count = region_count_; } unsigned int get_ivs () const { return ivs; } void set_ivs (unsigned int ivs_) { ivs = ivs_; } + /* The FD's private-dict ivs, before any vsindex op in the charstring. */ + unsigned int get_orig_ivs () const { return orig_ivs; } bool seen_vsindex () const { return seen_vsindex_; } double blend_deltas (hb_array_t deltas) const @@ -198,12 +201,16 @@ struct cff2_cs_interp_env_t : cs_interp_env_t bool have_coords () const { return num_coords; } + /* Subsetter instancing can defer rounding until absolute points are known. */ + bool round_blends = true; + protected: const int *coords; unsigned int num_coords; const CFF2ItemVariationStore *varStore; unsigned int region_count; unsigned int ivs; + unsigned int orig_ivs; hb_vector_t *scalars = nullptr; hb_atomic_t *> *cached_scalars_vector = nullptr; bool do_blend; @@ -259,7 +266,23 @@ struct cff2_cs_opset_t : cs_opset_t, PAR unsigned n, unsigned i) { if (env.have_coords ()) - arg.set_int (round (arg.to_real () + env.blend_deltas (blends))); + { + double v = arg.to_real () + env.blend_deltas (blends); + arg.set_real (env.round_blends ? round (v) : v); + } + else if (unlikely (arg.blending ())) + { + /* A blend result used as an operand of a later blend: the value is + * default + inner deltas + outer deltas, so accumulate the deltas. */ + hb_vector_t inner = std::move (arg.deltas); + arg.set_blends (n, i, blends); + if (likely (inner.length == arg.deltas.length)) + for (unsigned j = 0; j < inner.length; j++) + arg.deltas.arrayZ[j].set_real (arg.deltas.arrayZ[j].to_real () + + inner.arrayZ[j].to_real ()); + else + env.set_error (); + } else arg.set_blends (n, i, blends); } @@ -288,6 +311,11 @@ struct cff2_cs_opset_t : cs_opset_t, PAR env.set_error (); return; } + if (unlikely (!env.spend_budget (HB_BUDGET_1, total - n))) + { + env.set_error (); + return; + } unsigned int start = count - total; for (unsigned int i = 0; i < n; i++) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-common.cc index 9eeae358a75..962d8990d37 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-common.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-common.cc @@ -433,14 +433,8 @@ hb_script_from_iso15924_tag (hb_tag_t tag) /* Be lenient, adjust case (one capital letter followed by three small letters) */ tag = (tag & 0xDFDFDFDFu) | 0x00202020u; - switch (tag) { - - /* These graduated from the 'Q' private-area codes, but - * the old code is still aliased by Unicode, and the Qaai - * one in use by ICU. */ - case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED; - case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC; - + switch (tag) + { /* Script variants from https://unicode.org/iso15924/ */ case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC; case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.h b/src/java.desktop/share/native/libharfbuzz/hb-common.h index 5a0ef65392d..a36ad13e25a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-common.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-common.h @@ -94,6 +94,25 @@ HB_BEGIN_DECLS **/ typedef int hb_bool_t; +/** + * HB_BUDGET_DEFAULT: + * + * Use the implementation's finite default work budget. + * + * Since: 14.5.0 + **/ +#define HB_BUDGET_DEFAULT ((int64_t) (-0x7FFFFFFFFFFFFFFF - 1)) + +/** + * HB_BUDGET_UNLIMITED: + * + * Use an effectively unlimited work budget. Structural safety limits remain + * active. + * + * Since: 14.5.0 + **/ +#define HB_BUDGET_UNLIMITED ((int64_t) 0x7FFFFFFFFFFFFFFF) + /** * hb_codepoint_t: * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-config.hh b/src/java.desktop/share/native/libharfbuzz/hb-config.hh index 62e0d2022e3..8f81ee8c11c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-config.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-config.hh @@ -36,8 +36,7 @@ #endif #ifndef HB_EXPERIMENTAL_API -#define HB_NO_BEYOND_64K -#define HB_NO_CUBIC_GLYF +#define HB_NO_SUBSET_DEPEND #endif #ifdef HB_TINY @@ -75,9 +74,11 @@ #define HB_NO_MMAP #define HB_NO_NAME #define HB_NO_OPEN +#define HB_NO_OT_FETCH #define HB_NO_OT_FONT_GLYPH_NAMES #define HB_NO_SETLOCALE #define HB_NO_STYLE +#define HB_NO_SUBSET_DEPEND #define HB_NO_VERTICAL #define HB_NO_VAR @@ -136,7 +137,7 @@ #endif #ifdef HB_NO_DRAW -#define HB_NO_CFF +#define HB_NO_OT_FONT_CFF #define HB_NO_OUTLINE #define HB_NO_PAINT #endif @@ -188,6 +189,13 @@ #define HB_NO_OT_FONT_CMAP_CACHE #endif +#if defined(HAVE_CONFIG_OVERRIDE_LAST_H) || defined(HB_CONFIG_OVERRIDE_LAST_H) +#ifndef HB_CONFIG_OVERRIDE_LAST_H +#define HB_CONFIG_OVERRIDE_LAST_H "config-override-last.h" +#endif +#include HB_CONFIG_OVERRIDE_LAST_H +#endif + #ifdef HB_OPTIMIZE_SIZE #define HB_OPTIMIZE_SIZE_VAL 1 #else diff --git a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh index 87d30d9ded1..563690a3901 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh @@ -356,6 +356,10 @@ struct hb_no_trace_t { #define HB_DEBUG_KBTS (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_DEPEND +#define HB_DEBUG_DEPEND (HB_DEBUG+0) +#endif + /* * With tracing. */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-depend-data.hh b/src/java.desktop/share/native/libharfbuzz/hb-depend-data.hh new file mode 100644 index 00000000000..a83893d2658 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-depend-data.hh @@ -0,0 +1,668 @@ +/* + * Copyright © 2024 Adobe, 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. + * + * Adobe Author(s): Skef Iterum + */ + +#ifndef HB_DEPEND_DATA_HH +#define HB_DEPEND_DATA_HH + +/* This file exists to break include cycles: hb-ot-layout-gsubgpos.hh needs + * hb_depend_data_builder_t for hb_depend_context_t, but hb-depend.hh pulls + * in table headers that include hb-ot-layout-gsubgpos.hh. */ + +#include "hb.hh" + +#include "hb-multimap.hh" + +/* hb_subset_depend_edge_flags_t is defined in hb-depend.h (public header). + * We redeclare it here under the same include-guard so internal code that + * includes hb-depend-data.hh without going through hb-depend.h still gets + * the type. The definitions must stay in sync. */ +#ifndef HB_SUBSET_DEPEND_EDGE_FLAGS_T_DEFINED +#define HB_SUBSET_DEPEND_EDGE_FLAGS_T_DEFINED +typedef enum { + HB_SUBSET_DEPEND_EDGE_FLAG_NONE = 0x00u, + HB_SUBSET_DEPEND_EDGE_FLAG_FROM_CONTEXT_POSITION = 0x01u, + HB_SUBSET_DEPEND_EDGE_FLAG_FROM_NESTED_CONTEXT = 0x02u, +} hb_subset_depend_edge_flags_t; +#endif +/* Apply operator overloads now that hb.hh (and thus hb-algs.hh) is available. */ +HB_MARK_AS_FLAG_T (hb_subset_depend_edge_flags_t); + +/* High bit of a context-set element marks it as an index into the sets array + * rather than a raw glyph ID. */ +#define HB_DEPEND_CONTEXT_SET_FLAG 0x80000000u + +/** + * hb_depend_edge_t: + * + * Internal structure representing a single dependency edge in the graph. + * Records that glyph A depends on glyph B through a specific OpenType + * mechanism (table_tag), with additional metadata: + * + * - table_tag: Source table (GSUB, glyf, CFF, COLR, MATH, VARC) + * - dependent: Target glyph ID + * - layout_tag: Feature tag (for GSUB), else 0 + * - ligature_set: Index into sets array for ligature components, else INVALID + * - context_set: Index into sets array for context requirements, else INVALID + * - flags: Edge flags (FROM_CONTEXT_POSITION, FROM_NESTED_CONTEXT) + */ +struct hb_depend_edge_t { + hb_depend_edge_t() = delete; + hb_depend_edge_t(hb_tag_t table_tag, + hb_codepoint_t dependent, + hb_tag_t layout_tag, + hb_codepoint_t ligature_set, + hb_codepoint_t context_set, + hb_subset_depend_edge_flags_t flags = HB_SUBSET_DEPEND_EDGE_FLAG_NONE) : table_tag(table_tag), + dependent(dependent), layout_tag(layout_tag), + ligature_set(ligature_set), context_set(context_set), + flags(flags) + {} + + bool operator == (const hb_depend_edge_t &o) const + { + /* NOTE: flags intentionally excluded from equality comparison. + * Flags are metadata about how an edge was discovered (e.g., + * FROM_CONTEXT_POSITION, FROM_NESTED_CONTEXT), not part of the + * edge's identity. Multiple discoveries of the same edge via + * different paths should be treated as duplicates. */ + return table_tag == o.table_tag && + dependent == o.dependent && + layout_tag == o.layout_tag && + ligature_set == o.ligature_set && + context_set == o.context_set; + } + + uint32_t hash () const + { + /* FNV-1a hash of all identity fields (excludes flags) */ + uint32_t current = 0x84222325; /* FNV-1a offset basis */ + current = current ^ hb_hash (table_tag); + current = current * 16777619; /* FNV-1a prime */ + current = current ^ hb_hash (dependent); + current = current * 16777619; + current = current ^ hb_hash (layout_tag); + current = current * 16777619; + current = current ^ hb_hash (ligature_set); + current = current * 16777619; + current = current ^ hb_hash (context_set); + current = current * 16777619; + return current; + } + + hb_tag_t table_tag; + hb_codepoint_t dependent; + hb_tag_t layout_tag; + hb_codepoint_t ligature_set; + hb_codepoint_t context_set; + hb_subset_depend_edge_flags_t flags; +}; + +/** + * hb_depend_edge_key_t: + * + * Key structure for edge deduplication. Combines source glyph with edge record. + * Uses the record's equality and hash operators for comparison. + */ +struct hb_depend_edge_key_t { + hb_codepoint_t source; + hb_depend_edge_t record; + + hb_depend_edge_key_t () : source (0), record (0, 0, 0, HB_CODEPOINT_INVALID, HB_CODEPOINT_INVALID, HB_SUBSET_DEPEND_EDGE_FLAG_NONE) {} + + hb_depend_edge_key_t (hb_codepoint_t source, + hb_tag_t table_tag, + hb_tag_t layout_tag, + hb_codepoint_t dependent, + hb_codepoint_t ligature_set, + hb_codepoint_t context_set) + : source (source), + record (table_tag, dependent, layout_tag, ligature_set, context_set, HB_SUBSET_DEPEND_EDGE_FLAG_NONE) {} + + bool operator == (const hb_depend_edge_key_t &o) const + { + return source == o.source && record == o.record; + } + + uint32_t hash () const + { + /* Combine source hash with record hash */ + uint32_t current = 0x84222325; /* FNV-1a offset basis */ + current = current ^ hb_hash (source); + current = current * 16777619; /* FNV-1a prime */ + current = current ^ record.hash (); + current = current * 16777619; + return current; + } +}; + +/** + * hb_depend_glyph_record_t: + * + * Internal structure holding all dependency edges for a single glyph. + */ +struct hb_depend_glyph_record_t { + hb_vector_t dependencies; +}; + +/** + * hb_depend_lookup_revmap_t: + * + * Internal structure tracking which features are associated with a lookup. + * Used during GSUB dependency analysis to record the feature tags that + * activate each lookup. + */ +struct hb_depend_lookup_revmap_t +{ + hb_depend_lookup_revmap_t () = default; + explicit hb_depend_lookup_revmap_t (bool full) : full (full) {} + hb_depend_lookup_revmap_t (const hb_depend_lookup_revmap_t &o) : full(o.full), + fv_indexes(o.fv_indexes) {} + hb_depend_lookup_revmap_t (hb_depend_lookup_revmap_t &&o) : full(o.full), + fv_indexes(std::move(o.fv_indexes)) {} + hb_depend_lookup_revmap_t& operator = (const hb_depend_lookup_revmap_t &o) + { + full = o.full; + fv_indexes = o.fv_indexes; + return *this; + } + + bool full = true; + hb_set_t fv_indexes; +}; + +/** + * hb_depend_data_t: + * + * Persistent dependency graph data, retained for the lifetime of hb_subset_depend_t. + * Contains only what is needed at query time: + * - glyph_dependencies: Per-glyph edge lists + * - sets: Ligature and context sets indexed by set ID + * + * Constructed via hb_depend_data_builder_t; immutable thereafter. + */ +struct hb_depend_data_t +{ + /* Set storage: vector of heap-allocated sets (both ligature and context sets). + * Using unique_ptr follows HarfBuzz pattern and provides stable pointers. */ + hb_vector_t> sets; + + hb_vector_t glyph_dependencies; + + const hb_set_t *get_set_from_index (hb_codepoint_t index) + { + if (index < sets.length) + return sets[index].get (); + return nullptr; + } + + unsigned int get_glyph_entry_count (hb_codepoint_t gid) const + { + if (gid < glyph_dependencies.length) + return glyph_dependencies[gid].dependencies.length; + return 0; + } + + bool get_glyph_entry (hb_codepoint_t gid, unsigned int index, + hb_tag_t *table_tag, hb_codepoint_t *dependent, + hb_tag_t *layout_tag, hb_codepoint_t *ligature_set, + hb_codepoint_t *context_set, uint8_t *flags) + { + if (gid < glyph_dependencies.length && + index < glyph_dependencies[gid].dependencies.length) { + auto &d = glyph_dependencies[gid].dependencies[index]; + *table_tag = d.table_tag; + *dependent = d.dependent; + *layout_tag = d.layout_tag; + *ligature_set = d.ligature_set; + *context_set = d.context_set; + if (flags) *flags = d.flags; + return true; + } + return false; + } + + void print () + { + for (unsigned i = 0; i < glyph_dependencies.length; i++) { + auto &gd = glyph_dependencies[i]; + if (!gd.dependencies.length) + continue; + printf ("GID %u:\n", i); + for (auto &d : gd.dependencies) { + if (d.table_tag == HB_OT_TAG_GSUB) { + printf (" layout %c%c%c%c -> %u", HB_UNTAG(d.layout_tag), d.dependent); + if (d.ligature_set != HB_CODEPOINT_INVALID) + printf (" (ligature)"); + } else { + printf (" %c%c%c%c -> %u", HB_UNTAG(d.table_tag), d.dependent); + } + printf ("\n"); + } + } + } +}; + +/** + * hb_depend_data_builder_t: + * + * Temporary builder for constructing hb_depend_data_t. Holds all state + * needed during graph extraction; goes out of scope (and is freed) when + * construction is complete, leaving only hb_depend_data_t. + * + * Temporary state (freed on destruction): + * - lookup_features: Packed lookup index to feature tag mapping + * - lookup_feature_offsets: Per-lookup offsets into lookup_features + * - edge_slots: Compact edge deduplication table + * - set_to_index: Content-based dependency set deduplication map + * - free_set_list: Indices of freed sets available for reuse + * - current_context_set_index: Context requirements for current rule + * - current_edge_flags: Flags to apply to edges being recorded + */ +struct hb_depend_data_builder_t +{ + hb_depend_data_builder_t (hb_depend_data_t &data_) + : current_context_set_index (HB_CODEPOINT_INVALID), + current_edge_flags (HB_SUBSET_DEPEND_EDGE_FLAG_NONE), + data (data_) {} + + /* Forward to data for use during construction (e.g. from hb_depend_context_t) */ + const hb_set_t *get_set_from_index (hb_codepoint_t index) + { return data.get_set_from_index (index); } + + /* Discard an unused set that was allocated but had no edges added. */ + void discard_set (hb_codepoint_t set_index) + { + if (set_index >= data.sets.length) + { + DEBUG_MSG (SUBSET, nullptr, "Attempting to discard invalid set %u (max is %u)", + set_index, data.sets.length - 1); + return; + } + set_to_index.del (data.sets[set_index].get ()); + data.sets[set_index]->clear (); + check_success (free_set_list.push_or_fail (set_index)); + } + + hb_codepoint_t new_set (const hb_set_t &set) + { + hb_codepoint_t set_index; + + if (free_set_list.length > 0) + { + set_index = free_set_list.pop (); + data.sets[set_index]->set (set); + if (unlikely (data.sets[set_index]->in_error ())) + return fail_invalid (); + } + else + { + set_index = data.sets.length; + hb_set_t *new_set = hb_set_create (); + if (unlikely (!new_set)) + return fail_invalid (); + new_set->set (set); + if (unlikely (new_set->in_error ())) + { + hb_set_destroy (new_set); + return fail_invalid (); + } + if (unlikely (!data.sets.push_or_fail (hb::unique_ptr {new_set}))) + return fail_invalid (); + } + + return set_index; + } + + /* Find an existing dependency set with the same contents, or create one. */ + hb_codepoint_t find_or_create_set (const hb_set_t &set, bool *created = nullptr) + { + hb_codepoint_t *existing_idx = nullptr; + if (set_to_index.has (&set, &existing_idx)) + { + if (created) *created = false; + return *existing_idx; + } + + hb_codepoint_t new_idx = new_set (set); + if (unlikely (new_idx == HB_CODEPOINT_INVALID)) + return HB_CODEPOINT_INVALID; + + if (unlikely (!set_to_index.set (data.sets[new_idx].get (), new_idx))) + return fail_invalid (); + if (created) *created = true; + return new_idx; + } + + hb_codepoint_t find_or_create_context_set (const hb_set_t &set) + { return find_or_create_set (set); } + + /* Build a context set from context information. + * Encodes backtrack and lookahead requirements as a flattened set. + * Returns HB_CODEPOINT_INVALID if no context. + * + * To ensure canonical encoding and avoid redundancy: + * 1. First pass: collect all direct (single-glyph) requirements + * 2. Second pass: create disjunction sets, subtracting direct requirements + * 3. Combine: add direct requirements and filtered disjunction references + */ + hb_codepoint_t build_context_set (const hb_vector_t *backtrack_sets, + const hb_vector_t *lookahead_sets) + { + if ((!backtrack_sets || backtrack_sets->length == 0) && + (!lookahead_sets || lookahead_sets->length == 0)) + return HB_CODEPOINT_INVALID; + + /* First pass: collect all direct (single-glyph) requirements */ + hb_set_t direct_requirements; + + if (backtrack_sets) + { + for (const auto &back_set : *backtrack_sets) + { + if (back_set.get_population () == 1) + direct_requirements.add (back_set.get_min ()); + } + } + + if (lookahead_sets) + { + for (const auto &look_set : *lookahead_sets) + { + if (look_set.get_population () == 1) + direct_requirements.add (look_set.get_min ()); + } + } + + /* Second pass: create disjunction sets, filtering out direct requirements */ + hb_set_t context_elements; + + if (backtrack_sets) + { + for (const auto &back_set : *backtrack_sets) + { + if (back_set.get_population () > 1) + { + hb_set_t filtered_set; + filtered_set.set (back_set); + filtered_set.subtract (direct_requirements); + if (unlikely (filtered_set.in_error ())) + return fail_invalid (); + + if (!filtered_set.is_empty ()) + { + hb_codepoint_t set_idx = find_or_create_context_set (filtered_set); + if (unlikely (set_idx == HB_CODEPOINT_INVALID)) + return HB_CODEPOINT_INVALID; + context_elements.add (HB_DEPEND_CONTEXT_SET_FLAG | set_idx); + } + } + } + } + + if (lookahead_sets) + { + for (const auto &look_set : *lookahead_sets) + { + if (look_set.get_population () > 1) + { + hb_set_t filtered_set; + filtered_set.set (look_set); + filtered_set.subtract (direct_requirements); + if (unlikely (filtered_set.in_error ())) + return fail_invalid (); + + if (!filtered_set.is_empty ()) + { + hb_codepoint_t set_idx = find_or_create_context_set (filtered_set); + if (unlikely (set_idx == HB_CODEPOINT_INVALID)) + return HB_CODEPOINT_INVALID; + context_elements.add (HB_DEPEND_CONTEXT_SET_FLAG | set_idx); + } + } + } + } + + context_elements.union_ (direct_requirements); + if (unlikely (direct_requirements.in_error () || + context_elements.in_error ())) + return fail_invalid (); + + if (context_elements.is_empty ()) + return HB_CODEPOINT_INVALID; + + return find_or_create_context_set (context_elements); + } + + static uint64_t encode_edge_ref (hb_codepoint_t source, unsigned int index) + { return (uint64_t (source) + 1) << 32 | index; } + + static void decode_edge_ref (uint64_t ref, + hb_codepoint_t *source, + unsigned int *index) + { + *source = (ref >> 32) - 1; + *index = ref; + } + + uint32_t edge_hash (hb_codepoint_t source, const hb_depend_edge_t &record) const + { + hb_depend_edge_key_t key (source, record.table_tag, record.layout_tag, + record.dependent, record.ligature_set, + record.context_set); + return key.hash (); + } + + bool resize_edge_slots () + { + unsigned int new_size = edge_slots.length ? edge_slots.length * 2 : 8; + if (unlikely (new_size < edge_slots.length)) + return fail (); + + hb_vector_t new_slots; + if (unlikely (!new_slots.resize_exact (new_size))) + return fail (); + + for (uint64_t ref : edge_slots) + { + if (!ref) + continue; + + hb_codepoint_t source; + unsigned int index; + decode_edge_ref (ref, &source, &index); + const hb_depend_edge_t &record = data.glyph_dependencies[source].dependencies[index]; + unsigned int slot = edge_hash (source, record) & (new_size - 1); + unsigned int step = 0; + while (new_slots[slot]) + slot = (slot + ++step) & (new_size - 1); + new_slots[slot] = ref; + } + + edge_slots = std::move (new_slots); + return true; + } + + bool add_edge (hb_codepoint_t source, const hb_depend_edge_t &record) + { + /* Store only a source and per-glyph edge index in each bucket. The edge + * itself already lives in the output vector, where it can be compared to + * resolve hash collisions exactly. Adding one to the encoded source + * reserves zero as the empty-bucket value. */ + if (unlikely (!edge_slots.length || + uint64_t (edge_population) * 3 / 2 >= edge_slots.length - 1)) + if (unlikely (!resize_edge_slots ())) + return false; + + unsigned int slot = edge_hash (source, record) & (edge_slots.length - 1); + unsigned int step = 0; + while (uint64_t ref = edge_slots[slot]) + { + hb_codepoint_t existing_source; + unsigned int existing_index; + decode_edge_ref (ref, &existing_source, &existing_index); + if (existing_source == source && + data.glyph_dependencies[source].dependencies[existing_index] == record) + return false; + slot = (slot + ++step) & (edge_slots.length - 1); + } + + auto &dependencies = data.glyph_dependencies[source].dependencies; + unsigned int index = dependencies.length; + if (unlikely (!dependencies.push_or_fail (record))) + return fail (); + + edge_slots[slot] = encode_edge_ref (source, index); + edge_population++; + return true; + } + + bool add_depend_layout (hb_codepoint_t target, hb_tag_t table_tag, + hb_tag_t layout_tag, + hb_codepoint_t dependent, + hb_codepoint_t lig_set = HB_CODEPOINT_INVALID, + hb_codepoint_t context_set = HB_CODEPOINT_INVALID, + hb_subset_depend_edge_flags_t flags = HB_SUBSET_DEPEND_EDGE_FLAG_NONE) + { + if (target >= data.glyph_dependencies.length) { + DEBUG_MSG (SUBSET, nullptr, "Dependency glyph %u for %c%c%c%c too large", + target, HB_UNTAG(table_tag)); + return false; + } + + return add_edge (target, hb_depend_edge_t (table_tag, dependent, layout_tag, + lig_set, context_set, flags)); + } + + bool add_gsub_lookup (hb_codepoint_t target, hb_codepoint_t lookup_index, + hb_codepoint_t dependent, + hb_codepoint_t lig_set = HB_CODEPOINT_INVALID, + hb_codepoint_t context_set = HB_CODEPOINT_INVALID) + { + if (context_set == HB_CODEPOINT_INVALID) + context_set = current_context_set_index; + hb_subset_depend_edge_flags_t flags = current_edge_flags; + + bool any_added = false; + for (uint64_t entry : get_lookup_features (lookup_index)) { + hb_tag_t t = (hb_tag_t) entry; + if (add_depend_layout (target, HB_OT_TAG_GSUB, t, dependent, lig_set, context_set, flags)) + any_added = true; + } + return any_added; + } + + bool init_lookup_features (unsigned lookup_count) + { + return check_success (lookup_feature_offsets.resize (lookup_count + 1)); + } + + bool add_lookup_feature (hb_codepoint_t lookup_index, hb_tag_t feature_tag) + { + if (feature_tag == HB_SET_VALUE_INVALID) + return true; + + if (unlikely (!lookup_feature_offsets.length || + lookup_index >= lookup_feature_offsets.length - 1)) + return fail (); + + uint64_t entry = ((uint64_t) lookup_index << 32) | feature_tag; + return check_success (lookup_features.push_or_fail (entry)); + } + + bool finish_lookup_features () + { + lookup_features.qsort ([] (uint64_t a, uint64_t b) { + return a < b ? -1 : a > b ? 1 : 0; + }); + + unsigned write = 0; + for (uint64_t entry : lookup_features) + if (!write || entry != lookup_features[write - 1]) + lookup_features[write++] = entry; + lookup_features.shrink (write, false); + + unsigned feature_index = 0; + unsigned lookup_count = lookup_feature_offsets.length - 1; + for (unsigned lookup_index = 0; lookup_index < lookup_count; lookup_index++) + { + lookup_feature_offsets[lookup_index] = feature_index; + while (feature_index < lookup_features.length && + lookup_features[feature_index] >> 32 == lookup_index) + feature_index++; + } + lookup_feature_offsets[lookup_count] = feature_index; + return true; + } + + hb_array_t get_lookup_features (hb_codepoint_t lookup_index) const + { + if (unlikely (!lookup_feature_offsets.length || + lookup_index >= lookup_feature_offsets.length - 1)) + return {}; + + unsigned start = lookup_feature_offsets[lookup_index]; + unsigned end = lookup_feature_offsets[lookup_index + 1]; + return lookup_features.as_array ().sub_array (start, end - start); + } + + void add_depend (hb_codepoint_t target, hb_tag_t table_tag, + hb_codepoint_t dependent, + hb_codepoint_t lig_set = HB_CODEPOINT_INVALID, + hb_codepoint_t context_set = HB_CODEPOINT_INVALID, + hb_subset_depend_edge_flags_t flags = HB_SUBSET_DEPEND_EDGE_FLAG_NONE) + { + add_depend_layout (target, table_tag, HB_CODEPOINT_INVALID, dependent, lig_set, + context_set, flags); + } + + hb_codepoint_t get_nominal_glyph (hb_codepoint_t cp) + { return hb_map_get (&nominal_glyphs, cp); } + + HB_INTERNAL bool compile (hb_face_t *face); + + bool fail () { successful = false; return false; } + hb_codepoint_t fail_invalid () { fail (); return HB_CODEPOINT_INVALID; } + bool check_success (bool s) { successful = (successful && s); return successful; } + + HB_INTERNAL void get_gsub_dependencies (hb_face_t *face); + + bool successful = true; + hb_set_t unicodes; + hb_map_t nominal_glyphs; + hb_vector_t lookup_features; + hb_vector_t lookup_feature_offsets; + hb_vector_t edge_slots; + unsigned int edge_population = 0; + hb_hashmap_t set_to_index; + hb_vector_t free_set_list; + hb_codepoint_t current_context_set_index; + hb_subset_depend_edge_flags_t current_edge_flags; + + hb_depend_data_t &data; +}; + + +#endif /* HB_DEPEND_DATA_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h index a87a53d0e30..794b82a6323 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h @@ -388,6 +388,11 @@ hb_font_get_glyph_shape (hb_font_t *font, */ #define HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION +HB_DEPRECATED_FOR (hb_font_create) +HB_EXTERN void +hb_font_set_face (hb_font_t *font, + hb_face_t *face); + #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc index a9d00f695ce..5f1b33f9e65 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc @@ -65,12 +65,20 @@ 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_TWO_THIRD 0.66666666666666666666666667f + /* Compute in double precision, so that the result does not depend + * on how the compiler evaluates float expressions. */ +#define HB_TWO_THIRD 0.66666666666666666666666667 + double current_x = (double) st->current_x; + double current_y = (double) st->current_y; + double cx = (double) control_x; + double cy = (double) control_y; + double tx = (double) to_x; + double ty = (double) to_y; dfuncs->emit_cubic_to (draw_data, *st, - st->current_x + (control_x - st->current_x) * HB_TWO_THIRD, - st->current_y + (control_y - st->current_y) * HB_TWO_THIRD, - to_x + (control_x - to_x) * HB_TWO_THIRD, - to_y + (control_y - to_y) * HB_TWO_THIRD, + (float) (current_x + (cx - current_x) * HB_TWO_THIRD), + (float) (current_y + (cy - current_y) * HB_TWO_THIRD), + (float) (tx + (cx - tx) * HB_TWO_THIRD), + (float) (ty + (cy - ty) * HB_TWO_THIRD), to_x, to_y); #undef HB_TWO_THIRD } @@ -88,6 +96,19 @@ hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UN hb_draw_state_t *st HB_UNUSED, void *user_data HB_UNUSED) {} +static hb_bool_t +hb_draw_set_budget_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + int64_t budget HB_UNUSED, + void *user_data HB_UNUSED) { return false; } + +static int64_t +hb_draw_get_budget_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + void *user_data HB_UNUSED) { return HB_BUDGET_DEFAULT; } + +static int64_t * +hb_draw_get_budget_remaining_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + void *user_data HB_UNUSED) { return nullptr; } + static bool _hb_draw_funcs_set_preamble (hb_draw_funcs_t *dfuncs, @@ -347,6 +368,67 @@ hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs) return hb_object_is_immutable (dfuncs); } +/** + * hb_draw_set_budget: + * @dfuncs: draw functions object + * @draw_data: associated draw data + * @budget: the new work-budget policy + * + * Sets the work-budget policy and recharges the live work budget. Negative + * values other than #HB_BUDGET_DEFAULT are clamped to zero. + * + * Return value: `true` if the draw functions support work budgets + * + * Since: 14.5.0 + **/ +hb_bool_t +hb_draw_set_budget (hb_draw_funcs_t *dfuncs, void *draw_data, int64_t budget) +{ + return dfuncs->set_budget (draw_data, budget); +} + +/** + * hb_draw_get_budget: + * @dfuncs: draw functions object + * @draw_data: associated draw data + * + * Fetches the configured work-budget policy. + * + * Return value: the configured policy, or #HB_BUDGET_DEFAULT if unsupported + * + * Since: 14.5.0 + **/ +int64_t +hb_draw_get_budget (hb_draw_funcs_t *dfuncs, void *draw_data) +{ + return dfuncs->get_budget (draw_data); +} + +/** + * hb_draw_get_budget_remaining: + * @dfuncs: draw functions object + * @draw_data: associated draw data + * + * Fetches the live work budget. A negative value means the budget was + * exhausted. Zero means the preceding work fit exactly, but no positive-cost + * work can start. + * + * Return value: the live work budget; if it is not tracked, the concrete + * configured policy or #HB_BUDGET_UNLIMITED + * + * Since: 14.5.0 + **/ +int64_t +hb_draw_get_budget_remaining (hb_draw_funcs_t *dfuncs, void *draw_data) +{ + int64_t *remaining = dfuncs->get_budget_remaining_ptr (draw_data); + if (remaining) + return *remaining; + + int64_t budget = dfuncs->get_budget (draw_data); + return budget == HB_BUDGET_DEFAULT ? HB_BUDGET_UNLIMITED : budget; +} + /** * hb_draw_move_to: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.h b/src/java.desktop/share/native/libharfbuzz/hb-draw.h index 7c3358beed8..b4bcaa59046 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-draw.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.h @@ -195,6 +195,61 @@ typedef void (*hb_draw_close_path_func_t) (hb_draw_funcs_t *dfuncs, void *draw_d hb_draw_state_t *st, void *user_data); +/** + * hb_draw_set_budget_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @budget: the new work-budget policy + * @user_data: User data pointer passed to hb_draw_funcs_set_set_budget_func() + * + * Sets the work-budget policy and recharges the live work budget. @budget is + * #HB_BUDGET_DEFAULT, #HB_BUDGET_UNLIMITED, or a non-negative concrete value. + * + * Return value: `true` if the budget was set, `false` if unsupported + * + * Since: 14.5.0 + **/ +typedef hb_bool_t (*hb_draw_set_budget_func_t) (hb_draw_funcs_t *dfuncs, + void *draw_data, + int64_t budget, + void *user_data); + +/** + * hb_draw_get_budget_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed to hb_draw_funcs_set_get_budget_func() + * + * Fetches the configured work-budget policy. + * + * Return value: the configured work-budget policy + * + * Since: 14.5.0 + **/ +typedef int64_t (*hb_draw_get_budget_func_t) (hb_draw_funcs_t *dfuncs, + void *draw_data, + void *user_data); + +/** + * hb_draw_get_budget_remaining_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed to + * hb_draw_funcs_set_get_budget_remaining_func() + * + * Fetches the address of the live work budget. The returned address must stay + * valid while @draw_data is used with @dfuncs. The live value must be concrete; + * it must not contain #HB_BUDGET_DEFAULT. + * + * Return value: (nullable) (transfer none): the live work budget, or `NULL` if + * live budget accounting is unsupported + * + * Since: 14.5.0 + **/ +typedef int64_t *(*hb_draw_get_budget_remaining_func_t) (hb_draw_funcs_t *dfuncs, + void *draw_data, + void *user_data); + /** * hb_draw_funcs_set_move_to_func: * @dfuncs: draw functions object @@ -275,6 +330,54 @@ hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs, hb_draw_close_path_func_t func, void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_set_budget_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): budget setter + * @user_data: Data to pass to @func + * @destroy: (nullable): callback to destroy @user_data + * + * Sets the budget setter callback. + * + * Since: 14.5.0 + **/ +HB_EXTERN void +hb_draw_funcs_set_set_budget_func (hb_draw_funcs_t *dfuncs, + hb_draw_set_budget_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_draw_funcs_set_get_budget_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): budget getter + * @user_data: Data to pass to @func + * @destroy: (nullable): callback to destroy @user_data + * + * Sets the budget-policy getter callback. + * + * Since: 14.5.0 + **/ +HB_EXTERN void +hb_draw_funcs_set_get_budget_func (hb_draw_funcs_t *dfuncs, + hb_draw_get_budget_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_draw_funcs_set_get_budget_remaining_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): live-budget getter + * @user_data: Data to pass to @func + * @destroy: (nullable): callback to destroy @user_data + * + * Sets the live-budget getter callback. + * + * Since: 14.5.0 + **/ +HB_EXTERN void +hb_draw_funcs_set_get_budget_remaining_func (hb_draw_funcs_t *dfuncs, + hb_draw_get_budget_remaining_func_t func, + void *user_data, hb_destroy_func_t destroy); + HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_create (void); @@ -306,6 +409,16 @@ hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs); HB_EXTERN hb_bool_t hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs); +HB_EXTERN hb_bool_t +hb_draw_set_budget (hb_draw_funcs_t *dfuncs, void *draw_data, + int64_t budget); + +HB_EXTERN int64_t +hb_draw_get_budget (hb_draw_funcs_t *dfuncs, void *draw_data); + +HB_EXTERN int64_t +hb_draw_get_budget_remaining (hb_draw_funcs_t *dfuncs, void *draw_data); + HB_EXTERN void hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.hh b/src/java.desktop/share/native/libharfbuzz/hb-draw.hh index 224e10939fe..3a4173fce81 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-draw.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.hh @@ -38,6 +38,9 @@ HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \ HB_DRAW_FUNC_IMPLEMENT (cubic_to) \ HB_DRAW_FUNC_IMPLEMENT (close_path) \ + HB_DRAW_FUNC_IMPLEMENT (set_budget) \ + HB_DRAW_FUNC_IMPLEMENT (get_budget) \ + HB_DRAW_FUNC_IMPLEMENT (get_budget_remaining) \ /* ^--- Add new callbacks here */ struct hb_draw_funcs_t @@ -92,6 +95,20 @@ struct hb_draw_funcs_t { func.close_path (this, draw_data, &st, !user_data ? nullptr : user_data->close_path); } + bool set_budget (void *draw_data, int64_t budget) + { + if (budget < 0 && budget != HB_BUDGET_DEFAULT) + budget = 0; + return func.set_budget (this, draw_data, budget, + !user_data ? nullptr : user_data->set_budget); + } + int64_t get_budget (void *draw_data) + { return func.get_budget (this, draw_data, + !user_data ? nullptr : user_data->get_budget); } + int64_t *get_budget_remaining_ptr (void *draw_data) + { return func.get_budget_remaining (this, draw_data, + !user_data ? nullptr : user_data->get_budget_remaining); } + void HB_ALWAYS_INLINE @@ -176,8 +193,12 @@ DECLARE_NULL_INSTANCE (hb_draw_funcs_t); struct hb_draw_session_t { hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_) - : funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT - {} + : funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT, + local_budget {HB_BUDGET_GLYPH}, budget {funcs->get_budget_remaining_ptr (draw_data)} + { + if (!budget) + budget = &local_budget; + } ~hb_draw_session_t () { close_path (); } @@ -219,10 +240,14 @@ struct hb_draw_session_t funcs->close_path (draw_data, st); } + int64_t &get_budget () { return *budget; } + public: hb_draw_funcs_t *funcs; void *draw_data; hb_draw_state_t st; + int64_t local_budget; + int64_t *budget; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc index d660063716f..776e646369f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc @@ -181,15 +181,18 @@ _hb_face_builder_get_table_tags (const hb_face_t *face HB_UNUSED, // Not much to do... } sorted_tags.qsort ([] (const hb_tag_t &a, const hb_tag_t &b) { - return a < b; + return (a > b) - (a < b); }); auto array = sorted_tags.as_array ().sub_array (start_offset, table_count); - auto out = hb_array (table_tags, *table_count); + if (table_tags) + { + auto out = hb_array (table_tags, *table_count); - + array.iter () - | hb_sink (out) - ; + + array.iter () + | hb_sink (out) + ; + } return population; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-face.cc index a0f497eea7f..4adf39d85ea 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-face.cc @@ -909,7 +909,7 @@ hb_face_set_get_table_tags_func (hb_face_t *face, * @start_offset: The index of first table tag to retrieve * @table_count: (inout): Input = the maximum number of table tags to return; * Output = the actual number of table tags returned (may be zero) - * @table_tags: (out) (array length=table_count): The array of table tags found + * @table_tags: (out) (array length=table_count) (nullable): The array of table tags found * * Fetches a list of all table tags for a face, if possible. The list returned will * begin at the offset provided diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.h b/src/java.desktop/share/native/libharfbuzz/hb-face.h index 2c130f00fee..063ea3e8f91 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-face.h @@ -169,7 +169,7 @@ hb_face_get_glyph_count (const hb_face_t *face); * @start_offset: The index of first table tag to retrieve * @table_count: (inout): Input = the maximum number of table tags to return; * Output = the actual number of table tags returned (may be zero) - * @table_tags: (out) (array length=table_count): The array of table tags found + * @table_tags: (out) (array length=table_count) (nullable): The array of table tags found * @user_data: User data pointer passed by the caller * * Callback function for hb_face_get_table_tags(). diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-font.cc index c8ddbd00765..f68ef86689a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.cc @@ -731,6 +731,31 @@ hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st); } +static hb_bool_t +hb_draw_set_budget_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + int64_t budget, + void *user_data HB_UNUSED) +{ + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; + return adaptor->draw_funcs->set_budget (adaptor->draw_data, budget); +} + +static int64_t +hb_draw_get_budget_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + void *user_data HB_UNUSED) +{ + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; + return adaptor->draw_funcs->get_budget (adaptor->draw_data); +} + +static int64_t * +hb_draw_get_budget_remaining_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + void *user_data HB_UNUSED) +{ + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; + return adaptor->draw_funcs->get_budget_remaining_ptr (adaptor->draw_data); +} + static const hb_draw_funcs_t _hb_draw_funcs_default = { HB_OBJECT_HEADER_STATIC, @@ -1670,9 +1695,7 @@ hb_font_t::paint_glyph (hb_codepoint_t glyph, return; /* Fallback for outline glyph. */ - paint_funcs->push_clip_glyph (paint_data, glyph, this); - paint_funcs->color (paint_data, true, foreground); - paint_funcs->pop_clip (paint_data); + paint_funcs->fill_glyph (paint_data, glyph, this, true, foreground); } @@ -2446,6 +2469,7 @@ hb_font_get_parent (hb_font_t *font) return font->parent; } +#ifndef HB_DISABLE_DEPRECATED /** * hb_font_set_face: * @font: #hb_font_t to work upon @@ -2453,7 +2477,13 @@ hb_font_get_parent (hb_font_t *font) * * Sets @face as the font-face value of @font. * + * Font functions and their data may hold pointers into the old face, + * so the font functions of @font are released and replaced with the + * default ones for @face, as hb_font_create() would set up. Other + * font properties, such as scale and variations, are kept. + * * Since: 1.4.3 + * Deprecated: 15.0.0: Use hb_font_create() instead. **/ void hb_font_set_face (hb_font_t *font, @@ -2474,11 +2504,16 @@ hb_font_set_face (hb_font_t *font, font->face = hb_face_reference (face); font->changed (); + /* Release the old font funcs while the old face is still alive. */ + hb_font_set_funcs (font, nullptr, nullptr, nullptr); + hb_font_set_funcs_using (font, nullptr); + hb_face_destroy (old); font->changed (); font->serial_coords = font->serial; } +#endif /** * hb_font_get_face: @@ -2500,9 +2535,9 @@ hb_font_get_face (hb_font_t *font) /** * hb_font_set_funcs: * @font: #hb_font_t to work upon - * @klass: (closure font_data) (destroy destroy) (scope notified): The font-functions structure. + * @klass: The font-functions structure. * @font_data: Data to attach to @font - * @destroy: (nullable): The function to call when @font_data is not needed anymore + * @destroy: (nullable) (scope async) (closure font_data): The function to call when @font_data is not needed anymore * * Replaces the font-functions structure attached to a font, updating * the font's user-data with @font-data and the @destroy callback. @@ -2540,8 +2575,8 @@ hb_font_set_funcs (hb_font_t *font, /** * hb_font_set_funcs_data: * @font: #hb_font_t to work upon - * @font_data: (destroy destroy) (scope notified): Data to attach to @font - * @destroy: (nullable): The function to call when @font_data is not needed anymore + * @font_data: Data to attach to @font + * @destroy: (nullable) (scope async) (closure font_data): The function to call when @font_data is not needed anymore * * Replaces the user data attached to a font, updating the font's * @destroy callback. @@ -3116,10 +3151,10 @@ hb_font_set_variation (hb_font_t *font, return; } - /* Initialize design coords. */ - if (font->design_coords) + /* Initialize design coords. + * The font's coords may belong to another face after hb_font_set_face(). */ + if (font->design_coords && font->num_coords == coords_length) { - assert (coords_length == font->num_coords); for (unsigned int i = 0; i < coords_length; i++) design_coords[i] = font->design_coords[i]; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.h b/src/java.desktop/share/native/libharfbuzz/hb-font.h index 2d06b659278..c2c5a1d2d3c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.h @@ -1159,10 +1159,6 @@ hb_font_set_parent (hb_font_t *font, HB_EXTERN hb_font_t * hb_font_get_parent (hb_font_t *font); -HB_EXTERN void -hb_font_set_face (hb_font_t *font, - hb_face_t *face); - HB_EXTERN hb_face_t * hb_font_get_face (hb_font_t *font); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.hh b/src/java.desktop/share/native/libharfbuzz/hb-font.hh index a89b5db8cbc..dbf2fbd516c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.hh @@ -158,12 +158,12 @@ struct hb_font_t /* Convert from font-space to user-space */ int64_t dir_mult (hb_direction_t direction) { 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_scale_x (int32_t v) { return em_mult (v, x_mult); } + hb_position_t em_scale_y (int32_t v) { return em_mult (v, y_mult); } 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_fscale_x (int32_t v) { return em_fmult (v, x_multf); } + float em_fscale_y (int32_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) @@ -200,15 +200,15 @@ struct hb_font_t void scale_glyph_extents (hb_glyph_extents_t *extents) { - float x1 = em_scale_x (extents->x_bearing); - float y1 = em_scale_y (extents->y_bearing); - float x2 = em_scale_x (extents->x_bearing + extents->width); - float y2 = em_scale_y (extents->y_bearing + extents->height); - - extents->x_bearing = roundf (x1); - extents->y_bearing = roundf (y1); - extents->width = roundf (x2) - extents->x_bearing; - extents->height = roundf (y2) - extents->y_bearing; + float x1 = em_fscale_x (extents->x_bearing); + float y1 = em_fscale_y (extents->y_bearing); + float x2 = x1 + em_fscale_x (extents->width); + float y2 = y1 + em_fscale_y (extents->height); + + extents->x_bearing = floorf (x1); + extents->y_bearing = floorf (y1); + extents->width = ceilf (x2) - extents->x_bearing; + extents->height = ceilf (y2) - extents->y_bearing; } void synthetic_glyph_extents (hb_glyph_extents_t *extents) @@ -216,16 +216,17 @@ struct hb_font_t /* Slant. */ if (slant_xy) { - hb_position_t x1 = extents->x_bearing; - hb_position_t y1 = extents->y_bearing; - hb_position_t x2 = extents->x_bearing + extents->width; - hb_position_t y2 = extents->y_bearing + extents->height; + /* x_bearing/width and y_bearing/height are each clamped to the full + * hb_position_t range independently by the extent producers, so their + * sums and differences can overflow int32. Accumulate in int64. */ + int64_t y1 = extents->y_bearing; + int64_t y2 = (int64_t) extents->y_bearing + extents->height; - x1 += floorf (hb_min (y1 * slant_xy, y2 * slant_xy)); - x2 += ceilf (hb_max (y1 * slant_xy, y2 * slant_xy)); + int64_t x1 = (int64_t) extents->x_bearing + (int64_t) floorf (hb_min (y1 * slant_xy, y2 * slant_xy)); + int64_t x2 = (int64_t) extents->x_bearing + extents->width + (int64_t) ceilf (hb_max (y1 * slant_xy, y2 * slant_xy)); - extents->x_bearing = x1; - extents->width = x2 - extents->x_bearing; + extents->x_bearing = hb_clamp_to (x1); + extents->width = hb_clamp_to (x2 - x1); } /* Embolden. */ @@ -234,15 +235,15 @@ struct hb_font_t /* Y */ int y_shift = y_strength; if (y_scale < 0) y_shift = -y_shift; - extents->y_bearing += y_shift; - extents->height -= y_shift; + extents->y_bearing = hb_clamp_to ((int64_t) extents->y_bearing + y_shift); + extents->height = hb_clamp_to ((int64_t) extents->height - y_shift); /* X */ int x_shift = x_strength; if (x_scale < 0) x_shift = -x_shift; if (embolden_in_place) - extents->x_bearing -= x_shift / 2; - extents->width += x_shift; + extents->x_bearing = hb_clamp_to ((int64_t) extents->x_bearing - x_shift / 2); + extents->width = hb_clamp_to ((int64_t) extents->width + x_shift); } } @@ -710,6 +711,7 @@ struct hb_font_t #ifndef HB_NO_OUTLINE hb_outline_t outline; + outline.budget_remaining = draw_funcs->get_budget_remaining_ptr (draw_data); if (!klass->get.f.draw_glyph_or_fail (this, user_data, glyph, hb_outline_recording_pen_get_funcs (), &outline, @@ -1144,10 +1146,8 @@ struct hb_font_t 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; + x_mult = (int64_t) x_scale * 0x10000 / upem; + y_mult = (int64_t) y_scale * 0x10000 / upem; is_synthetic = x_embolden || y_embolden || slant; @@ -1161,13 +1161,13 @@ struct hb_font_t serial++; } - hb_position_t em_mult (int16_t v, int64_t mult) + hb_position_t em_mult (int32_t v, int64_t mult) { return (hb_position_t) ((v * mult + 32768) >> 16); } 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) + float em_fmult (int32_t v, float mult) { return (float) v * mult; } }; DECLARE_NULL_INSTANCE (hb_font_t); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc index f02069f0c0c..7963e6636cb 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc @@ -88,12 +88,15 @@ using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>; +static void _hb_ft_face_destroy_static (void *data); + struct hb_ft_font_t { int load_flags; bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ bool transform; /* Whether to apply FT_Face's transform. */ + bool static_library; /* Whether ft_face uses static_ft_library. */ mutable hb_mutex_t lock; /* Protects members below. */ FT_Face ft_face; @@ -102,7 +105,7 @@ struct hb_ft_font_t }; static hb_ft_font_t * -_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) +_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref, bool static_library) { hb_ft_font_t *ft_font = (hb_ft_font_t *) hb_calloc (1, sizeof (hb_ft_font_t)); if (unlikely (!ft_font)) return nullptr; @@ -111,6 +114,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) ft_font->ft_face = ft_face; ft_font->symbol = symbol; ft_font->unref = unref; + ft_font->static_library = static_library; ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; @@ -132,7 +136,24 @@ _hb_ft_font_destroy (void *data) hb_ft_font_t *ft_font = (hb_ft_font_t *) data; if (ft_font->unref) - _hb_ft_face_destroy (ft_font->ft_face); + { + if (ft_font->static_library) + { + /* ft_font->ft_face->generic.data is the blob that hb_ft_font_set_funcs() + * hooked up as this internal FT_Face's finalizer target (_release_blob). + * FT_Done_Face() below runs that finalizer while static_ft_library_mutex + * is held; if dropping its reference were to free the blob right there, + * the blob's attached destroy_ft_library() user-data callback would try + * to re-lock the same non-recursive mutex and self-deadlock. Hold an + * extra reference across the locked call so the blob (and thus that + * callback) can only be freed after the lock is released. */ + hb_blob_t *blob = hb_blob_reference ((hb_blob_t *) ft_font->ft_face->generic.data); + _hb_ft_face_destroy_static (ft_font->ft_face); + hb_blob_destroy (blob); + } + else + _hb_ft_face_destroy (ft_font->ft_face); + } ft_font->lock.fini (); @@ -508,23 +529,24 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, for (unsigned int i = 0; i < count; i++) { - FT_Fixed v = 0; + hb_position_t advance; hb_codepoint_t glyph = *first_glyph; unsigned int cv; if (ft_font->advance_cache.get (glyph, &cv)) - v = cv; + advance = (hb_position_t) cv; else { + FT_Fixed v = 0; FT_Get_Advance (ft_face, glyph, load_flags, &v); /* Work around bug that FreeType seems to return negative advance * for variable-set fonts if x_scale is negative! */ - v = abs (v); - v = (int) (v * x_mult + (1<<9)) >> 10; - ft_font->advance_cache.set (glyph, v); + double scaled = trunc (fabs ((double) v) * (double) x_mult + (1<<9)) / (1<<10); + advance = hb_clamp_to (floor (scaled)); + ft_font->advance_cache.set (glyph, advance); } - *first_advance = v; + *first_advance = advance; first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } @@ -562,9 +584,9 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ - v = ((-v + (1<<9)) >> 10); + double advance = floor ((-(double) v + (1<<9)) / (1<<10)); - return (hb_position_t) (y_mult * v); + return hb_clamp_to ((double) y_mult * advance); } #endif @@ -605,11 +627,12 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ - *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; - *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); - - *x = (hb_position_t) (x_mult * *x); - *y = (hb_position_t) (y_mult * *y); + *x = hb_clamp_to ((double) x_mult * + ((double) ft_face->glyph->metrics.horiBearingX - + ft_face->glyph->metrics.vertBearingX)); + *y = hb_clamp_to ((double) y_mult * + ((double) ft_face->glyph->metrics.horiBearingY + + ft_face->glyph->metrics.vertBearingY)); return true; } @@ -633,7 +656,7 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font, if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv)) return 0; - return kerningv.x; + return hb_clamp_to ((int64_t) kerningv.x); } #endif @@ -717,10 +740,15 @@ hb_ft_get_glyph_extents (hb_font_t *font, float x2 = x1 + x_mult * ft_face->glyph->metrics.width; float y2 = y1 + y_mult * -ft_face->glyph->metrics.height; - extents->x_bearing = roundf (x1); - extents->y_bearing = roundf (y1); - extents->width = roundf (x2) - extents->x_bearing; - extents->height = roundf (y2) - extents->y_bearing; + double rx1 = (double) roundf (x1); + double ry1 = (double) roundf (y1); + double rx2 = (double) roundf (x2); + double ry2 = (double) roundf (y2); + + extents->x_bearing = hb_clamp_to (rx1); + extents->y_bearing = hb_clamp_to (ry1); + extents->width = hb_clamp_to (rx2 - rx1); + extents->height = hb_clamp_to (ry2 - ry1); return true; } @@ -841,22 +869,24 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, if (ft_face->units_per_EM != 0) { - 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); + double ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); + double descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); + double height = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ); + metrics->ascender = hb_clamp_to ((double) y_mult * ascender); + metrics->descender = hb_clamp_to ((double) y_mult * descender); + metrics->line_gap = hb_clamp_to ((double) y_mult * (height - (ascender - descender))); } else { /* Bitmap-only font, eg. color bitmap font. */ - metrics->ascender = ft_face->size->metrics.ascender; - metrics->descender = ft_face->size->metrics.descender; - metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender); + double ascender = ft_face->size->metrics.ascender; + double descender = ft_face->size->metrics.descender; + double height = ft_face->size->metrics.height; + metrics->ascender = hb_clamp_to ((double) y_mult * ascender); + metrics->descender = hb_clamp_to ((double) y_mult * descender); + metrics->line_gap = hb_clamp_to ((double) y_mult * (height - (ascender - descender))); } - metrics->ascender = (hb_position_t) (y_mult * metrics->ascender); - metrics->descender = (hb_position_t) (y_mult * metrics->descender); - metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap); - return true; } @@ -1088,11 +1118,12 @@ _hb_ft_get_font_funcs () } static void -_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) +_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref, + bool static_library = false) { bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL; - hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref); + hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref, static_library); if (unlikely (!ft_font)) return; hb_font_set_funcs (font, @@ -1152,23 +1183,29 @@ _hb_ft_get_table_tags (const hb_face_t *face HB_UNUSED, if (!table_count) return population; - else - *table_count = 0; if (unlikely (start_offset >= population)) + { + *table_count = 0; return population; + } - unsigned end_offset = hb_min (start_offset + *table_count, (unsigned) population); - if (unlikely (end_offset < start_offset)) + unsigned end_offset = start_offset + *table_count; + if (unlikely (end_offset < start_offset)) /* Overflow. */ + { + *table_count = 0; return population; + } + end_offset = hb_min (end_offset, (unsigned) population); *table_count = end_offset - start_offset; - for (unsigned i = start_offset; i < end_offset; i++) - { - FT_ULong tag = 0, length; - FT_Sfnt_Table_Info (ft_face, i, &tag, &length); - table_tags[i - start_offset] = tag; - } + if (table_tags) + for (unsigned i = start_offset; i < end_offset; i++) + { + FT_ULong tag = 0, length; + FT_Sfnt_Table_Info (ft_face, i, &tag, &length); + table_tags[i - start_offset] = tag; + } return population; } @@ -1176,8 +1213,8 @@ _hb_ft_get_table_tags (const hb_face_t *face HB_UNUSED, /** * hb_ft_face_create: - * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon - * @destroy: (nullable): A callback to call when the face object is not needed anymore + * @ft_face: FT_Face to work upon + * @destroy: (nullable) (scope async): A callback to call when the face object is not needed anymore * * Creates an #hb_face_t face object from the specified FT_Face. * @@ -1300,8 +1337,8 @@ hb_ft_face_create_cached (FT_Face ft_face) /** * hb_ft_font_create: - * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon - * @destroy: (nullable): A callback to call when the font object is not needed anymore + * @ft_face: FT_Face to work upon + * @destroy: (nullable) (scope async): A callback to call when the font object is not needed anymore * * Creates an #hb_font_t font object from the specified FT_Face. * @@ -1486,6 +1523,31 @@ static FT_MemoryRec_ m = }; static inline void free_static_ft_library (); +static inline void free_static_ft_library_mutex (); + +static struct hb_ft_library_mutex_lazy_loader_t : hb_lazy_loader_t +{ + static hb_mutex_t *create () + { + hb_mutex_t *lock = (hb_mutex_t *) hb_calloc (1, sizeof (hb_mutex_t)); + if (unlikely (!lock)) + return nullptr; + + lock = new (lock) hb_mutex_t; + hb_atexit (free_static_ft_library_mutex); + return lock; + } + static void destroy (hb_mutex_t *lock) + { + lock->~hb_mutex_t (); + hb_free (lock); + } + static hb_mutex_t *get_null () + { + return nullptr; + } +} static_ft_library_mutex; static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t, hb_ft_library_lazy_loader_t> @@ -1513,15 +1575,26 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_tgeneric.data = ft_library; ft_face->generic.finalizer = finalize_ft_library; @@ -1609,7 +1715,7 @@ _destroy_blob (void *p) * Creates an #hb_face_t face object from the specified * font blob and face index. * - * This is similar in functionality to hb_face_create_from_blob_or_fail(), + * This is similar in functionality to hb_face_create_or_fail(), * but uses the FreeType library for loading the font blob. This can * be useful, for example, to load WOFF and WOFF2 font data. * @@ -1634,15 +1740,19 @@ hb_ft_face_create_from_blob_or_fail (hb_blob_t *blob, const char *blob_data = hb_blob_get_data (blob, &blob_size); FT_Face ft_face; - if (unlikely (FT_New_Memory_Face (ft_library, + if (unlikely (new_ft_memory_face (ft_library, (const FT_Byte *) blob_data, blob_size, index, &ft_face))) + { + destroy_ft_library (ft_library); return nullptr; + } - hb_face_t *face = hb_ft_face_create_referenced (ft_face); - FT_Done_Face (ft_face); + FT_Reference_Face (ft_face); + hb_face_t *face = hb_ft_face_create (ft_face, _hb_ft_face_destroy_static); + _hb_ft_face_destroy_static (ft_face); ft_face->generic.data = ft_library; ft_face->generic.finalizer = finalize_ft_library; @@ -1725,13 +1835,14 @@ hb_ft_font_set_funcs (hb_font_t *font) } FT_Face ft_face = nullptr; - if (unlikely (FT_New_Memory_Face (ft_library, + if (unlikely (new_ft_memory_face (ft_library, (const FT_Byte *) blob_data, blob_length, hb_face_get_index (font->face), &ft_face))) { hb_blob_destroy (blob); + destroy_ft_library (ft_library); DEBUG_MSG (FT, font, "FT_New_Memory_Face() failed"); return; } @@ -1747,11 +1858,12 @@ hb_ft_font_set_funcs (hb_font_t *font) if (unlikely (!hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true))) { DEBUG_MSG (FT, font, "hb_blob_set_user_data() failed"); - FT_Done_Face (ft_face); + _hb_ft_face_destroy_static (ft_face); + destroy_ft_library (ft_library); return; } - _hb_ft_font_set_funcs (font, ft_face, true); + _hb_ft_font_set_funcs (font, ft_face, true, true); hb_ft_font_set_load_flags (font, load_flags); _hb_ft_hb_font_changed (font, ft_face); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh index 661e6771a4a..a294cf36fa4 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh @@ -460,7 +460,22 @@ struct hb_filter_iter_t : __item_t__ __item__ () const { return *it; } bool __more__ () const { return bool (it); } void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); } - void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); } + void __prev__ () + { + unsigned count = 0; + do + { + Iter old = it; + --it; + if (!(it != old)) + { + it += count; + return; + } + count++; + } + while (!hb_has (p.get (), hb_get (f.get (), *it))); + } hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it._end (), p, f); } bool operator != (const hb_filter_iter_t& o) const { return it != o.it; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh index cf08c16689f..faba71bd76d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh @@ -43,7 +43,6 @@ struct hb_kern_machine_t driver (driver_), crossStream (crossStream_) {} - HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW void kern (hb_font_t *font, hb_buffer_t *buffer, hb_mask_t kern_mask, @@ -72,9 +71,9 @@ struct hb_kern_machine_t skippy_iter.reset_fast (idx); unsigned unsafe_to; - if (!skippy_iter.next (&unsafe_to)) + if (unlikely (!skippy_iter.next (&unsafe_to))) { - idx++; + idx = unsafe_to; continue; } @@ -101,9 +100,9 @@ struct hb_kern_machine_t { hb_position_t kern1 = kern >> 1; hb_position_t kern2 = kern - kern1; - pos[i].x_advance += kern1; - pos[j].x_advance += kern2; - pos[j].x_offset += kern2; + pos[i].x_advance = hb_saturate_add (pos[i].x_advance, kern1); + pos[j].x_advance = hb_saturate_add (pos[j].x_advance, kern2); + pos[j].x_offset = hb_saturate_add (pos[j].x_offset, kern2); } } else @@ -119,9 +118,9 @@ struct hb_kern_machine_t { hb_position_t kern1 = kern >> 1; hb_position_t kern2 = kern - kern1; - pos[i].y_advance += kern1; - pos[j].y_advance += kern2; - pos[j].y_offset += kern2; + pos[i].y_advance = hb_saturate_add (pos[i].y_advance, kern1); + pos[j].y_advance = hb_saturate_add (pos[j].y_advance, kern2); + pos[j].y_offset = hb_saturate_add (pos[j].y_offset, kern2); } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh index 9d6c7ec6822..e724055146c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh @@ -58,6 +58,10 @@ #define HB_MAX_CONTEXT_LENGTH 64 #endif +#ifndef HB_MAX_SYLLABLE_LENGTH +#define HB_MAX_SYLLABLE_LENGTH 64 +#endif + #ifndef HB_CLOSURE_MAX_STAGES /* * The maximum number of times a lookup can be applied during shaping. @@ -81,7 +85,7 @@ #endif #ifndef HB_MAX_FEATURE_INDICES -#define HB_MAX_FEATURE_INDICES 1500 +#define HB_MAX_FEATURE_INDICES 8000 #endif #ifndef HB_MAX_LOOKUP_VISIT_COUNT @@ -89,7 +93,7 @@ #endif #ifndef HB_MAX_GRAPH_EDGE_COUNT -#define HB_MAX_GRAPH_EDGE_COUNT 2048 +#define HB_MAX_GRAPH_EDGE_COUNT 16384 #endif #ifndef HB_VAR_COMPOSITE_MAX_AXES @@ -116,25 +120,118 @@ #define HB_GPU_DRAW_MAX_CURVES 65536 #endif +/* Total bytes of sub-blobs (gradient color stops, clip outlines) in one + * hb_gpu_paint_t walk; exceeding it makes the paint unsupported. */ +#ifndef HB_GPU_PAINT_MAX_SUB_BYTES +#define HB_GPU_PAINT_MAX_SUB_BYTES ((unsigned) 64 << 20) +#endif + +/* Tiles emitted by one hb_paint_sweep_gradient_tiles() call. Also + * sets the angular resolution (2π over this) below which a repeating + * color line is filled with its average color instead of tiled; + * a repeat/reflect color line whose stops span a tiny angle could + * otherwise emit millions of patches while covering 0..2π. */ +#ifndef HB_PAINT_MAX_SWEEP_TILES +#define HB_PAINT_MAX_SWEEP_TILES 4096 +#endif + #ifndef HB_SVG_MAX_DOCUMENT_SIZE #define HB_SVG_MAX_DOCUMENT_SIZE ((size_t) 16 << 20) #endif +/* Maximum size of one serialized vector document (SVG or PDF) produced by + * the vector backends. Bounds output that is not outline-derived -- most + * of a path, but especially sweep-gradient meshes and embedded bitmaps -- + * which the outline work budget cannot see. vector is one glyph per + * context, so a flat cap suffices. Unsigned (not size_t like the SVG-table + * limit above) to match hb_vector_buf_t's unsigned length arithmetic. */ +#ifndef HB_VECTOR_MAX_DOCUMENT_SIZE +#define HB_VECTOR_MAX_DOCUMENT_SIZE ((unsigned) 16 << 20) +#endif + #ifndef HB_RASTER_MAX_BUFFER_SIZE #define HB_RASTER_MAX_BUFFER_SIZE ((size_t) 1 << 30) #endif +/* Maximum surface dimension (pixels per side) when extents are derived + * from font data (glyph extents or accumulated outline bounds). Bounds + * attacker-controlled allocations; extents set explicitly through + * hb_raster_{draw,paint}_set_extents() are not limited. */ +#ifndef HB_RASTER_MAX_AUTO_DIMENSION +#define HB_RASTER_MAX_AUTO_DIMENSION 4096 +#endif + +/* + * Cumulative work budgets. + * + * The limits above bound work within one subsystem: points per glyf + * glyph, ops per CFF charstring, nodes in a COLR or VARC graph, + * pixels per raster surface. When one subsystem drives another -- + * COLR driving a paint backend, a paint backend or VARC loading + * glyf/CFF outlines -- those limits multiply. Each driving session + * therefore carries one cumulative budget, initialized once per + * top-level entry and only ever decremented, shared by everything + * the session consumes. Once a budget is exhausted, further work + * is skipped best-effort. + */ + +/* Fixed relative weights. Keep the value in the name so charge sites are + * easy to audit; tune the common session cap, not these values. */ +#define HB_BUDGET_1 1u +#define HB_BUDGET_2 2u +#define HB_BUDGET_4 4u +#define HB_BUDGET_8 8u +#define HB_BUDGET_16 16u +#define HB_BUDGET_32 32u +#define HB_BUDGET_64 64u +#define HB_BUDGET_128 128u +#define HB_BUDGET_256 256u +#define HB_BUDGET_512 512u +#define HB_BUDGET_1024 1024u + +/* The common finite default for one top-level glyph rendering session. + * Nested outline and paint work shares the same live counter. */ +#ifndef HB_BUDGET_GLYPH +#define HB_BUDGET_GLYPH ((int64_t) 1 << 24) +#endif + +/* Precharge COST * MULT. Callers bound COST and MULT structurally, and live + * budgets are concrete non-negative values when a session starts. */ +static HB_ALWAYS_INLINE bool +hb_budget_spend (int64_t &budget, unsigned int cost, unsigned int mult = 1) +{ + budget -= (int64_t) cost * mult; + return budget >= 0; +} + +/* The flat pixel-work floor for one raster paint session. Pixel and + * outline work use separate live counters, so keep this independent of + * the common outline budget above. */ +#ifndef HB_BUDGET_RASTER_PIXELS +#define HB_BUDGET_RASTER_PIXELS ((int64_t) 1 << 26) +#endif + +/* Very large raster surfaces still get a few full-surface operations. */ +#ifndef HB_BUDGET_RASTER_PAINT_PASSES +#define HB_BUDGET_RASTER_PAINT_PASSES 4 +#endif + +/* One raster draw session, in accumulated non-horizontal edges. */ +#ifndef HB_RASTER_MAX_DRAW_EDGES +#define HB_RASTER_MAX_DRAW_EDGES ((int64_t) 1 << 20) +#endif + #ifndef HB_REPACKER_MAX_ITERATIONS #define HB_REPACKER_MAX_ITERATIONS 500 #endif #ifndef HB_REPACKER_MAX_VERTICES -#define HB_REPACKER_MAX_VERTICES 100000 +#define HB_REPACKER_MAX_VERTICES 800000 #endif #ifndef HB_REPACKER_MAX_SPACES -#define HB_REPACKER_MAX_SPACES 1024 +#define HB_REPACKER_MAX_SPACES 8000 #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh index 8685ac29306..aa575dd08e4 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh @@ -206,15 +206,25 @@ struct hb_lazy_loader_t : hb_data_wrapper_t static void do_destroy (Stored *p) { - if (p && p != const_cast (Funcs::get_null ())) - Funcs::destroy (p); + if (Funcs::tag_null ? !p || is_tagged_null (p) : + !p || p == const_cast (Funcs::get_null ())) + return; + Funcs::destroy (p); } const Returned * operator -> () const { return get (); } template const U & operator * () const { return *get (); } explicit operator bool () const - { return get_stored () != Funcs::get_null (); } + { + Stored *p = get_stored (); + if (Funcs::tag_null) + { + Stored *raw = this->instance.get_relaxed (); + return raw && !is_tagged_null (raw); + } + return p != Funcs::get_null (); + } template operator const C * () const { return get (); } Stored * get_stored () const @@ -228,7 +238,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t p = this->template call_create (); if (unlikely (!p)) - p = const_cast (Funcs::get_null ()); + p = tagged_null (const_cast (Funcs::get_null ())); if (unlikely (!cmpexch (nullptr, p))) { @@ -236,11 +246,11 @@ struct hb_lazy_loader_t : hb_data_wrapper_t goto retry; } } - return p; + return untagged (p); } Stored * get_stored_relaxed () const { - return this->instance.get_relaxed (); + return untagged (this->instance.get_relaxed ()); } bool cmpexch (Stored *current, Stored *value) const @@ -259,6 +269,18 @@ struct hb_lazy_loader_t : hb_data_wrapper_t /* By default null/init/fini the object. */ static const Stored* get_null () { return &Null (Stored); } + + /* When tag_null is set, a failed create () is cached as get_null () with + * its low bit set, and destroy recognizes it by that bit rather than by + * address. Needed when get_null () is a per-library Null object: another + * library sharing the object would not recognize its address. */ + static constexpr bool tag_null = false; + static bool is_tagged_null (Stored *p) + { return Funcs::tag_null && ((uintptr_t) (void *) p & 1); } + static Stored *tagged_null (Stored *p) + { return Funcs::tag_null ? (Stored *) (void *) ((uintptr_t) (void *) p | 1) : p; } + static Stored *untagged (Stored *p) + { return Funcs::tag_null ? (Stored *) (void *) ((uintptr_t) (void *) p & ~(uintptr_t) 1) : p; } static Stored *create (Data *data) { Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); @@ -291,21 +313,22 @@ struct hb_face_lazy_loader_t : hb_lazy_loader_t, hb_face_t, WheresFace> { + /* get_null () is this library's Null object; see tag_null. */ + static constexpr bool tag_null = true; + // Hack; have them here for API parity with hb_table_lazy_loader_t hb_blob_t *get_blob () { return this->get ()->get_blob (); } }; -template +template struct hb_table_lazy_loader_t : hb_lazy_loader_t, + hb_table_lazy_loader_t, hb_face_t, WheresFace, hb_blob_t> { static hb_blob_t *create (hb_face_t *face) { hb_sanitize_context_t c; - if (core) - c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs return c.reference_table (face); } static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-map.hh index ae35e715d54..1d467590233 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-map.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-map.hh @@ -49,11 +49,16 @@ struct hb_hashmap_t void _copy (const hb_hashmap_t& o) { + if (unlikely (!o.successful)) + { + successful = false; + return; + } if (unlikely (!o.mask)) return; if (hb_is_trivially_copy_assignable (item_t)) { - items = (item_t *) hb_malloc (sizeof (item_t) * (o.mask + 1)); + items = (item_t *) hb_malloc2 ((o.mask + 1), sizeof (item_t)); if (unlikely (!items)) { successful = false; @@ -199,12 +204,20 @@ struct hb_hashmap_t bool alloc (unsigned new_population = 0) { if (unlikely (!successful)) return false; + if (unlikely (population > 0x3FFFFFFFu || new_population > 0x3FFFFFFFu)) + { + // Population sizes >0x3FFFFFFF will result in power + // being larger than 31, which in turn leads to a new size + // that overflows u32. + successful = false; + return false; + } if (new_population != 0 && (new_population + new_population / 2) < mask) return true; unsigned int power = hb_bit_storage (hb_max (hb_max ((unsigned) population, new_population) * 2, 4u)); unsigned int new_size = 1u << power; - item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); + item_t *new_items = (item_t *) hb_malloc2 ((size_t) new_size, sizeof (item_t)); if (unlikely (!new_items)) { successful = false; @@ -244,11 +257,32 @@ struct hb_hashmap_t return true; } + template + bool in_storage (const T &v) const + { + uintptr_t p = (uintptr_t) std::addressof (v); + return items && + (uintptr_t) items <= p && p < (uintptr_t) (items + size ()); + } + template bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool overwrite = true) { if (unlikely (!successful)) return false; - if (unlikely ((occupancy + occupancy / 2) >= mask && !alloc ())) return false; + if (unlikely ((occupancy + occupancy / 2) >= mask)) + { + /* key or value may live in our own storage, eg. m.set (k, m.get (j)). + * alloc() frees that storage, so copy them out first. */ + if (unlikely (in_storage (key) || in_storage (value))) + { + K key_copy; + key_copy = std::forward (key); + V value_copy; + value_copy = std::forward (value); + return set_with_hash (std::move (key_copy), hash, std::move (value_copy), overwrite); + } + if (unlikely (!alloc ())) return false; + } hash &= 0x3FFFFFFF; // We only store lower 30bit of hash unsigned int tombstone = (unsigned int) -1; @@ -288,7 +322,7 @@ struct hb_hashmap_t occupancy++; population++; - if (unlikely (length > max_chain_length) && occupancy * 8 > mask) + if (unlikely (length > max_chain_length) && occupancy > mask / 8) alloc (mask - 8); // This ensures we jump to next larger size return true; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh index 07f3ebe0c7d..8c707e5d0da 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh @@ -1,7 +1,5 @@ - -#line 1 "hb-number-parser.rl" /* - * Copyright © 2019 Ebrahim Byagowi + * Copyright © 2019-2026 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -30,74 +28,13 @@ #include "hb.hh" - -#line 32 "hb-number-parser.hh" -static const unsigned char _double_parser_trans_keys[] = { - 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, - 46u, 101u, 0 -}; - -static const char _double_parser_key_spans[] = { - 0, 15, 12, 10, 15, 10, 54, 10, - 56 -}; - -static const unsigned char _double_parser_index_offsets[] = { - 0, 0, 16, 29, 40, 56, 67, 122, - 133 -}; - -static const char _double_parser_indicies[] = { - 0, 1, 2, 3, 1, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 1, 3, 1, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 1, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 1, 6, 1, 7, 1, 1, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 1, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 1, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 9, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 9, 1, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 1, 3, 1, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 9, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 9, 1, 0 -}; - -static const char _double_parser_trans_targs[] = { - 2, 0, 2, 3, 8, 6, 5, 5, - 7, 4 -}; - -static const char _double_parser_trans_actions[] = { - 0, 0, 1, 0, 2, 3, 0, 4, - 5, 0 -}; - -static const int double_parser_start = 1; -static const int double_parser_first_final = 6; -static const int double_parser_error = 0; - -static const int double_parser_en_main = 1; - - -#line 68 "hb-number-parser.rl" - - -/* Works only for n < 512 */ +// Handles 0..308; anything larger overflows double and returns HUGE_VAL. static inline double _pow10 (unsigned exponent) { + // DBL_MAX is between 10^308 and 10^309 + if (unlikely (exponent > 308)) return HUGE_VAL; + static const double _powers_of_10[] = { 1.0e+256, @@ -117,118 +54,157 @@ _pow10 (unsigned exponent) return result; } -/* a variant of strtod that also gets end of buffer in its second argument */ -static inline double -strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) +struct _hb_fraction { - double value = 0; - double frac = 0; - double frac_count = 0; - unsigned exp = 0; - bool neg = false, exp_neg = false, exp_overflow = false; - const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */ - const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */ + void add (int digit) + { + if (likely (fraction <= MAX_FRACT / 10)) + { + fraction = fraction * 10. + digit; + ++count; + } + else if (drop < 0) drop = digit; + else if (digit != 0) sticky = true; + } + + double get_value () const + { + double result = fraction; + // Round-to-nearest-even using the recorded tail + if (drop > 5 || (drop == 5 && ((((uint64_t) fraction) & 1) || sticky))) + result += 1; + return result / _pow10 (count); + } + bool is_empty () const { return !count; } + +private: + unsigned count = 0; + double fraction = 0; + int drop = -1; // drop is the first digit we couldn't accumulate + bool sticky = false; // sticky is set when any later digit was nonzero. + static constexpr uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */ +}; + +// A variant of strtod that also gets end of buffer in its second argument. +// +// Grammar (with backtracking on partial exponents): +// +// number := sign? mantissa exponent? +// sign := '+' | '-' +// mantissa:= digits ('.' digits?)? +// | '.' digits +// exponent:= ('e'|'E') sign? digits +// +// On success, *end_ptr is set just past the longest well-formed prefix. +// On no match, *end_ptr is left at the original p (matching strtod's +// "no conversion performed" behavior, so the caller's pointer is unchanged). +static inline double +hb_strtod (const char *p, const char **end_ptr /* IN/OUT */) +{ + const char *p_original = p; const char *pe = *end_ptr; + + // Skip leading whitespace while (p < pe && ISSPACE (*p)) p++; - int cs; + // Sign + bool neg = false; + if (p < pe && (*p == '+' || *p == '-')) + { + neg = (*p == '-'); + p++; + } -#line 132 "hb-number-parser.hh" - { - cs = double_parser_start; - } + double value = 0; -#line 135 "hb-number-parser.hh" - { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; - if ( cs == 0 ) - goto _out; -_resume: - _keys = _double_parser_trans_keys + (cs<<1); - _inds = _double_parser_indicies + _double_parser_index_offsets[cs]; - - _slen = _double_parser_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && - (*p) <= _keys[1] ? - (*p) - _keys[0] : _slen ]; - - cs = _double_parser_trans_targs[_trans]; - - if ( _double_parser_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _double_parser_trans_actions[_trans] ) { - case 1: -#line 37 "hb-number-parser.rl" - { neg = true; } - break; - case 4: -#line 38 "hb-number-parser.rl" - { exp_neg = true; } - break; - case 2: -#line 40 "hb-number-parser.rl" - { - value = value * 10. + ((*p) - '0'); -} - break; - case 3: -#line 43 "hb-number-parser.rl" - { - if (likely (frac <= MAX_FRACT / 10)) - { - frac = frac * 10. + ((*p) - '0'); - ++frac_count; - } -} - break; - case 5: -#line 50 "hb-number-parser.rl" - { - if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP)) - exp = exp * 10 + ((*p) - '0'); + // Integer and fraction + { + const char *int_start = p; + while (p < pe && '0' <= *p && *p <= '9') + { + value = value * 10. + (*p - '0'); + p++; + } + bool has_int = p > int_start; + + _hb_fraction frac; + if (p < pe && *p == '.') + { + p++; + while (p < pe && '0' <= *p && *p <= '9') + { + frac.add (*p - '0'); + p++; + } + } + + if (!frac.is_empty ()) value += frac.get_value (); + else if (!has_int) + { + // Nothing could be parsed + *end_ptr = p_original; + return .0; + } + } + + // Exponent + unsigned exp = 0; + bool exp_neg = false, exp_overflow = false; + if (p < pe && (*p == 'e' || *p == 'E')) + { + constexpr unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */ + const char *before_exponent = p; + p++; + if (p < pe && (*p == '+' || *p == '-')) + { + exp_neg = (*p == '-'); + p++; + } + + if (p < pe && '0' <= *p && *p <= '9') + do + { + if (likely (exp * 10 + (*p - '0') <= MAX_EXP)) + exp = exp * 10 + (*p - '0'); else exp_overflow = true; -} - break; -#line 187 "hb-number-parser.hh" - } - -_again: - if ( cs == 0 ) - goto _out; - if ( ++p != pe ) - goto _resume; - _test_eof: {} - _out: {} - } - -#line 113 "hb-number-parser.rl" - - + p++; + } while (p < pe && '0' <= *p && *p <= '9'); + else + p = before_exponent; // rewind + } *end_ptr = p; - if (frac_count) value += frac / _pow10 (frac_count); if (neg) value *= -1.; if (unlikely (exp_overflow)) { if (value == 0) return value; - if (exp_neg) return neg ? -DBL_MIN : DBL_MIN; + if (exp_neg) return neg ? -.0 : .0; else return neg ? -DBL_MAX : DBL_MAX; } if (exp) { - if (exp_neg) value /= _pow10 (exp); - else value *= _pow10 (exp); + if (exp_neg) + { + // 10^308 is the largest finite power of ten, so two reductions of 308 suffice. + if (unlikely (exp > 308)) + { + value /= 1e308; + exp -= 308; + if (unlikely (exp > 308)) + { + value /= 1e308; + exp -= 308; + } + } + value /= _pow10 (exp); + } + else + value *= _pow10 (exp); } return value; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number.cc b/src/java.desktop/share/native/libharfbuzz/hb-number.cc index f09366760fa..a9aaa01f0b5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-number.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-number.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2019 Ebrahim Byagowi + * Copyright © 2019-2026 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -31,55 +31,117 @@ #include "hb-number.hh" #include "hb-number-parser.hh" -template +bool +hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer) +{ + const char *pend = end; + double value = hb_strtod (*pp, &pend); + if (unlikely (*pp == pend)) return false; + if (unlikely (whole_buffer && end != pend)) return false; + *pv = value; + *pp = pend; + return true; +} + +/* Returns the digit value of c in the given base (2..36), or -1 if c + * isn't a digit in that base. */ +static int +_hb_digit_value (char c, int base) +{ + int d; + if ('0' <= c && c <= '9') d = c - '0'; + else if ('a' <= c && c <= 'z') d = c - 'a' + 10; + else if ('A' <= c && c <= 'Z') d = c - 'A' + 10; + else return -1; + return d < base ? d : -1; +} + +/* Consumes digits in [p, pe) into *value (magnitude). Sets *overflow + * if the value would exceed UINT64_MAX. Sets *any_digits if at least + * one digit was consumed. Returns the position past the last digit. */ +static const char * +_hb_scan_digits (const char *p, const char *pe, int base, + uint64_t *value, bool *overflow, bool *any_digits) +{ + const uint64_t cutoff = UINT64_MAX / (unsigned) base; + const uint64_t cutlim = UINT64_MAX % (unsigned) base; + uint64_t v = 0; + bool ov = false, any = false; + + for (; p < pe; p++) + { + int d = _hb_digit_value (*p, base); + if (d < 0) break; + any = true; + if (v > cutoff || (v == cutoff && (uint64_t) d > cutlim)) + ov = true; + else + v = v * (unsigned) base + (uint64_t) d; + } + + *value = v; + *overflow = ov; + *any_digits = any; + return p; +} + +template static bool _parse_number (const char **pp, const char *end, T *pv, - bool whole_buffer, Func f) + bool whole_buffer, int base, Postprocess post) { - char buf[32]; - unsigned len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned) (end - *pp)); - strncpy (buf, *pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - - errno = 0; - *pv = f (p, &pend); - if (unlikely (errno || p == pend || - /* Check if consumed whole buffer if is requested */ - (whole_buffer && pend - p != end - *pp))) - return false; - - *pp += pend - p; + const char *pend = end; + const char *p = *pp; + bool neg = false, any = false, overflow = false; + + while (p < pend && ISSPACE (*p)) p++; + if (p < pend && (*p == '+' || *p == '-')) { neg = (*p == '-'); p++; } + + /* Skip an optional "0x"/"0X" prefix for base 16, but only when a hex + * digit follows — "0x" alone parses as the digit 0, matching strtoul. */ + if (base == 16 && p + 2 < pend && p[0] == '0' && + (p[1] == 'x' || p[1] == 'X') && _hb_digit_value (p[2], 16) >= 0) + p += 2; + + uint64_t v = 0; + p = _hb_scan_digits (p, pend, base, &v, &overflow, &any); + if (unlikely (!any || overflow)) return false; + + T out; + if (unlikely (!post (v, neg, &out))) return false; + if (unlikely (whole_buffer && p != pend)) return false; + + *pv = out; + *pp = p; return true; } bool hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer) { - return _parse_number (pp, end, pv, whole_buffer, - [] (const char *p, char **end) - { return strtol (p, end, 10); }); + return _parse_number (pp, end, pv, whole_buffer, 10, + [] (uint64_t v, bool neg, int *out) { + /* INT_MAX = 2^31-1, INT_MIN magnitude = 2^31 */ + uint64_t limit = neg ? (uint64_t) INT_MAX + 1 : (uint64_t) INT_MAX; + if (unlikely (v > limit)) return false; + *out = (int) (neg ? -(int64_t) v : (int64_t) v); + return true; + }); } bool hb_parse_uint (const char **pp, const char *end, unsigned *pv, bool whole_buffer, int base) { - return _parse_number (pp, end, pv, whole_buffer, - [base] (const char *p, char **end) - { return strtoul (p, end, base); }); -} - -bool -hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer) -{ - const char *pend = end; - *pv = strtod_rl (*pp, &pend); - if (unlikely (*pp == pend)) return false; - *pp = pend; - return !whole_buffer || end == pend; + return _parse_number (pp, end, pv, whole_buffer, base, + [] (uint64_t v, bool neg, unsigned *out) { + if (unlikely (v > UINT_MAX)) return false; + /* Negate in unsigned so -1 wraps to UINT_MAX, matching strtoul + * truncated to unsigned. */ + unsigned u = (unsigned) v; + *out = neg ? (unsigned) (0u - u) : u; + return true; + }); } #endif /* HB_NUMBER_CC pacify */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh index 538240b6416..f4b39820a6c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh @@ -88,7 +88,7 @@ typedef struct OpenTypeOffsetTable unsigned int *table_count, /* IN/OUT */ hb_tag_t *table_tags /* OUT */) const { - if (table_count) + if (table_count && table_tags) { + tables.as_array ().sub_array (start_offset, table_count) | hb_map (&TableRecord::tag) @@ -220,20 +220,48 @@ struct TTCHeaderVersion1 { friend struct TTCHeader; - unsigned int get_face_count () const { return table.len; } - const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } + using DirectoryList = Array32Of>; + + unsigned int get_face_count () const { return get_directory_list ().len; } + const OpenTypeFontFace& get_face (unsigned int i) const + { return this+get_directory_list ()[i]; } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); +#ifndef HB_NO_BEYOND_64K + if (version.minor >= 1) + { + if (unlikely (!table.sanitize_shallow (c))) + return_trace (false); + unsigned extra_size = version.major == 2 ? 12 : 0; + if (unlikely (!c->check_range (&table, table.get_size () + extra_size))) + return_trace (false); + const DirectoryList &table2 = StructAtOffset (&table, + table.get_size () + extra_size); + return_trace (table2.sanitize (c, this)); + } +#endif return_trace (table.sanitize (c, this)); } + private: + const DirectoryList& get_directory_list () const + { +#ifndef HB_NO_BEYOND_64K + if (version.minor >= 1) + { + unsigned extra_size = version.major == 2 ? 12 : 0; + return StructAtOffset (&table, table.get_size () + extra_size); + } +#endif + return table; + } + protected: Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ - FixedVersion<>version; /* Version of the TTC Header (1.0), - * 0x00010000u */ - Array32Of> + FixedVersion<>version; /* Version of the TTC Header. */ + DirectoryList table; /* Array of offsets to the OffsetTable for each font * from the beginning of the file */ public: @@ -474,8 +502,8 @@ struct OpenTypeFontFile case TrueTag: case Typ1Tag: case TrueTypeTag: return 1; - case TTCTag: return u.ttcHeader.get_face_count (); - case DFontTag: return u.rfHeader.get_face_count (); + case TTCTag: hb_barrier (); return u.ttcHeader.get_face_count (); + case DFontTag: hb_barrier (); return u.rfHeader.get_face_count (); default: return 0; } } @@ -490,9 +518,9 @@ struct OpenTypeFontFile case CFFTag: /* All the non-collection tags */ case TrueTag: case Typ1Tag: - case TrueTypeTag: return u.fontFace; - case TTCTag: return u.ttcHeader.get_face (i); - case DFontTag: return u.rfHeader.get_face (i, base_offset); + case TrueTypeTag: hb_barrier (); return u.fontFace; + case TTCTag: hb_barrier (); return u.ttcHeader.get_face (i); + case DFontTag: hb_barrier (); return u.rfHeader.get_face (i, base_offset); default: return Null (OpenTypeFontFace); } } @@ -518,9 +546,9 @@ struct OpenTypeFontFile case CFFTag: /* All the non-collection tags */ case TrueTag: case Typ1Tag: - case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); - case TTCTag: return_trace (u.ttcHeader.sanitize (c)); - case DFontTag: return_trace (u.rfHeader.sanitize (c)); + case TrueTypeTag: hb_barrier (); return_trace (u.fontFace.sanitize (c)); + case TTCTag: hb_barrier (); return_trace (u.ttcHeader.sanitize (c)); + case DFontTag: hb_barrier (); return_trace (u.rfHeader.sanitize (c)); default: return_trace (true); } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh index 29fc201ba04..d750b5c6caf 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh @@ -197,17 +197,12 @@ struct HBUINT32VAR else if (b0 < 0xF0) return ((b0 & 0x0F) << 24) | (v[1] << 16) | (v[2] << 8) | v[3]; else - return (v[1] << 24) | (v[2] << 16) | (v[3] << 8) | v[4]; + return (uint32_t (v[1]) << 24) | (v[2] << 16) | (v[3] << 8) | v[4]; } - static bool serialize (hb_serialize_context_t *c, uint32_t v) + static unsigned serialize_unsafe (unsigned char *buf, uint32_t v) { unsigned len = get_size (v); - - unsigned char *buf = c->allocate_size (len, false); - if (unlikely (!buf)) - return false; - unsigned char *p = buf + len; for (unsigned i = 0; i < len; i++) { @@ -218,6 +213,17 @@ struct HBUINT32VAR if (len > 1) buf[0] |= ((1 << (len - 1)) - 1) << (9 - len); + return len; + } + + static bool serialize (hb_serialize_context_t *c, uint32_t v) + { + unsigned len = get_size (v); + unsigned char *buf = c->allocate_size (len, false); + if (unlikely (!buf)) + return false; + + serialize_unsafe (buf, v); return true; } @@ -564,7 +570,7 @@ struct UnsizedArrayOf } static size_t get_size (unsigned int len) - { return len * Type::static_size; } + { return hb_unsigned_mul_saturate (len, Type::static_size); } template operator T * () { return arrayZ; } template operator const T * () const { return arrayZ; } @@ -726,7 +732,7 @@ struct ArrayOf } size_t get_size () const - { return len.static_size + len * Type::static_size; } + { return hb_unsigned_mul_add_saturate (len, Type::static_size, len.static_size); } explicit operator bool () const { return len; } @@ -910,7 +916,7 @@ struct HeadlessArrayOf return arrayZ[i-1]; } size_t get_size () const - { return lenP1.static_size + get_length () * Type::static_size; } + { return hb_unsigned_mul_add_saturate (get_length (), Type::static_size, lenP1.static_size); } unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } @@ -1004,7 +1010,7 @@ struct ArrayOfM1 return arrayZ[i]; } size_t get_size () const - { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } + { return hb_unsigned_mul_add_saturate (lenM1 + 1, Type::static_size, lenM1.static_size); } template HB_ALWAYS_INLINE @@ -1198,7 +1204,7 @@ struct VarSizedBinSearchArrayOf unsigned int get_length () const { return header.nUnits - last_is_terminator (); } size_t get_size () const - { return header.static_size + header.nUnits * header.unitSize; } + { return hb_unsigned_mul_add_saturate (header.nUnits, header.unitSize, header.static_size); } template HB_ALWAYS_INLINE @@ -1464,7 +1470,8 @@ struct CFFIndex size_t get_size () const { if (count) - return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); + return hb_unsigned_add_saturate (min_size, offSize.static_size, + offset_array_size (), offset_at (count) - 1); return min_size; /* empty CFFIndex contains count only */ } @@ -1813,6 +1820,33 @@ struct TupleValues return true; } + static bool skip (const unsigned char *&p /* IN/OUT */, + const unsigned char *end, + unsigned count) + { + unsigned seen = 0; + while (seen < count) + { + if (unlikely (p >= end)) return false; + unsigned control = *p++; + unsigned run_count = (control & VALUE_RUN_COUNT_MASK) + 1; + if (unlikely (run_count > count - seen)) return false; + + unsigned width = 0; + switch (control & VALUES_SIZE_MASK) + { + case VALUES_ARE_ZEROS: break; + case VALUES_ARE_BYTES: width = HBINT8::static_size; break; + case VALUES_ARE_WORDS: width = HBINT16::static_size; break; + case VALUES_ARE_LONGS: width = HBINT32::static_size; break; + } + if (unlikely (unsigned (end - p) < run_count * width)) return false; + p += run_count * width; + seen += run_count; + } + return true; + } + struct iter_t : hb_iter_with_fallback_t { iter_t (const unsigned char *p_, unsigned len_) @@ -1974,11 +2008,11 @@ struct TupleValues } private: - template - void _add_to (hb_array_t out, float scale = 1.0f) + template + void _add_to (hb_array_t out, T scale = T (1)) { unsigned n = out.length; - float *arrayZ = out.arrayZ; + T *arrayZ = out.arrayZ; for (unsigned i = 0; i < n;) { @@ -2046,7 +2080,8 @@ struct TupleValues } public: - void add_to (hb_array_t out, float scale = 1.0f) + template + void add_to (hb_array_t out, float scale = 1.0f) { #ifndef HB_OPTIMIZE_SIZE // The following branch is supposed to speed things up by avoiding @@ -2056,7 +2091,7 @@ struct TupleValues _add_to (out); else #endif - _add_to (out, scale); + _add_to (out, (T) scale); } }; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh index 8db85e4f08c..d595f91e25a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh @@ -183,13 +183,15 @@ struct FDArray : CFFIndex /* FDSelect */ struct FDSelect0 { - bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount, + unsigned int glyph_count = HB_CODEPOINT_INVALID) const { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this)))) return_trace (false); hb_barrier (); - if (unlikely (!c->check_array (fds, c->get_num_glyphs ()))) + if (unlikely (!c->check_array (fds, glyph_count == HB_CODEPOINT_INVALID ? + c->get_num_glyphs () : glyph_count))) return_trace (false); return_trace (true); @@ -202,7 +204,7 @@ struct FDSelect0 { { return {fds[glyph], glyph + 1}; } size_t get_size (unsigned int num_glyphs) const - { return HBUINT8::static_size * num_glyphs; } + { return hb_unsigned_mul_saturate (HBUINT8::static_size, num_glyphs); } HBUINT8 fds[HB_VAR_ARRAY]; @@ -230,9 +232,10 @@ template struct FDSelect3_4 { size_t get_size () const - { return GID_TYPE::static_size * 2 + ranges.get_size (); } + { return hb_unsigned_add_saturate ((size_t) GID_TYPE::static_size * 2, ranges.get_size ()); } - bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount, + unsigned int min_glyphs = HB_CODEPOINT_INVALID) const { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this) && @@ -248,7 +251,10 @@ struct FDSelect3_4 if (unlikely (!(sentinel().sanitize (c) && hb_barrier () && - (sentinel() == c->get_num_glyphs ())))) + sentinel() > ranges[nRanges () - 1].first && + sentinel() <= c->get_num_glyphs () && + sentinel() >= (min_glyphs == HB_CODEPOINT_INVALID ? + c->get_num_glyphs () : min_glyphs)))) return_trace (false); return_trace (true); @@ -308,8 +314,8 @@ struct FDSelect { switch (format) { - case 0: hb_barrier (); return format.static_size + u.format0.get_size (num_glyphs); - case 3: hb_barrier (); return format.static_size + u.format3.get_size (); + case 0: hb_barrier (); return hb_unsigned_add_saturate (format.static_size, u.format0.get_size (num_glyphs)); + case 3: hb_barrier (); return hb_unsigned_add_saturate (format.static_size, u.format3.get_size ()); default:return 0; } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc index d0e078bffdb..173c0382f68 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc @@ -364,7 +364,7 @@ struct cff1_path_procs_extents_t : path_procs_t { @@ -379,8 +379,8 @@ struct cff1_cs_opset_extents_t : cff1_cs_opset_tis_valid () || (glyph >= cff->num_glyphs))) return false; @@ -402,12 +402,12 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun env.set_in_seac (in_seac); cff1_cs_interpreter_t interp (env); cff1_extents_param_t param (cff); - if (unlikely (!interp.interpret (param))) return false; + if (unlikely (!interp.interpret (param, budget))) return false; bounds = param.bounds; return true; } -bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const +bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, int64_t *budget) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ @@ -416,7 +416,10 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph bounds_t bounds; - if (!_get_bounds (this, glyph, bounds)) + int64_t stack_budget = HB_BUDGET_GLYPH; + if (!budget) budget = &stack_budget; + + if (!_get_bounds (this, glyph, bounds, false, budget)) return false; if (bounds.min.x >= bounds.max.x) @@ -426,8 +429,9 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph } else { - extents->x_bearing = roundf (bounds.min.x.to_real ()); - extents->width = roundf (bounds.max.x.to_real () - extents->x_bearing); + double x_bearing = roundf (bounds.min.x.to_real ()); + extents->x_bearing = hb_clamp_to (x_bearing); + extents->width = hb_clamp_to ((double) roundf (bounds.max.x.to_real ()) - x_bearing); } if (bounds.min.y >= bounds.max.y) { @@ -436,8 +440,9 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph } else { - extents->y_bearing = roundf (bounds.max.y.to_real ()); - extents->height = roundf (bounds.min.y.to_real () - extents->y_bearing); + double y_bearing = roundf (bounds.max.y.to_real ()); + extents->y_bearing = hb_clamp_to (y_bearing); + extents->height = hb_clamp_to ((double) roundf (bounds.min.y.to_real ()) - y_bearing); } font->scale_glyph_extents (extents); @@ -515,7 +520,8 @@ struct cff1_path_procs_path_t : path_procs_t { @@ -532,14 +538,15 @@ struct cff1_cs_opset_path_t : cff1_cs_opset_tstd_code_to_glyph (env.argStack[n-1].to_int ()); if (unlikely (!(!env.in_seac && base && accent - && _get_path (param.cff, param.font, base, *param.draw_session, true) - && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta)))) + && _get_path (param.cff, param.font, base, *param.draw_session, true, nullptr, env.get_budget ()) + && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta, env.get_budget ())))) env.set_error (); } }; bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, - hb_draw_session_t &draw_session, bool in_seac, point_t *delta) + hb_draw_session_t &draw_session, bool in_seac, point_t *delta, + int64_t *budget) { if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; @@ -549,7 +556,7 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin env.set_in_seac (in_seac); cff1_cs_interpreter_t interp (env); cff1_path_param_t param (cff, font, draw_session, delta); - if (unlikely (!interp.interpret (param))) return false; + if (unlikely (!interp.interpret (param, budget))) return false; /* Let's end the path specially since it is called inside seac also */ param.end_path (); @@ -557,14 +564,17 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin return true; } -bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const +bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, int64_t *budget) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ return true; #endif - return _get_path (this, font, glyph, draw_session); + int64_t stack_budget = HB_BUDGET_GLYPH; + if (!budget) budget = &stack_budget; + + return _get_path (this, font, glyph, draw_session, false, nullptr, budget); } struct get_seac_param_t @@ -591,12 +601,41 @@ struct cff1_cs_opset_seac_t : cff1_cs_opset_t= 2 && + OpCode_TwoBytePosInt0 <= str[end - 2] && + str[end - 2] <= OpCode_TwoByteNegInt3) + return true; + if (end >= 3 && str[end - 3] == OpCode_shortint) + return true; + if (end >= 5 && str[end - 5] == OpCode_fixedcs) + return true; + + /* A subroutine can leave the seac operands on the shared stack. */ + return last == OpCode_callsubr || last == OpCode_callgsubr; +} + bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const { if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); const hb_ubytes_t str = (*charStrings)[glyph]; + if (unlikely (!_cff1_charstring_may_end_in_seac (str))) return false; cff1_cs_interp_env_t env (str, *this, fd); cff1_cs_interpreter_t interp (env); get_seac_param_t param (this); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh index 92163ac8bd3..3212269be8f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh @@ -28,6 +28,7 @@ #define HB_OT_CFF1_TABLE_HH #include "hb-ot-cff-common.hh" +#include "hb-depend-data.hh" #include "hb-subset-cff-common.hh" #include "hb-draw.hh" #include "hb-paint.hh" @@ -236,14 +237,14 @@ struct Encoding size_t get_size () const { - unsigned int size = min_size; + size_t size = min_size; switch (table_format ()) { - case 0: hb_barrier (); size += u.format0.get_size (); break; - case 1: hb_barrier (); size += u.format1.get_size (); break; + case 0: hb_barrier (); size = hb_unsigned_add_saturate (size, u.format0.get_size ()); break; + case 1: hb_barrier (); size = hb_unsigned_add_saturate (size, u.format1.get_size ()); break; } if (has_supplement ()) - size += suppEncData ().get_size (); + size = hb_unsigned_add_saturate (size, suppEncData ().get_size ()); return size; } @@ -326,7 +327,7 @@ struct Charset0 void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { - mapping->resize_dirty (num_glyphs); + if (!mapping->resize_dirty (num_glyphs)) return; for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++) mapping->arrayZ[gid] = {sids[gid - 1], gid}; } @@ -426,10 +427,12 @@ struct Charset1_2 { void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { - mapping->resize_dirty (num_glyphs); + if (!mapping->resize_dirty (num_glyphs)) return; + hb_codepoint_t gid = 1; if (gid >= num_glyphs) return; + for (unsigned i = 0;; i++) { hb_codepoint_t sid = ranges[i].first; @@ -567,9 +570,9 @@ struct Charset { switch (format) { - case 0: hb_barrier (); return min_size + u.format0.get_size (num_glyphs); - case 1: hb_barrier (); return min_size + u.format1.get_size (num_glyphs); - case 2: hb_barrier (); return min_size + u.format2.get_size (num_glyphs); + case 0: hb_barrier (); return hb_unsigned_add_saturate (min_size, u.format0.get_size (num_glyphs)); + case 1: hb_barrier (); return hb_unsigned_add_saturate (min_size, u.format1.get_size (num_glyphs)); + case 2: hb_barrier (); return hb_unsigned_add_saturate (min_size, u.format2.get_size (num_glyphs)); default:return 0; } } @@ -770,8 +773,7 @@ struct cff1_top_dict_opset_t : top_dict_opset_t { static void process_op (op_code_t op, cff1_top_dict_interp_env_t& env, cff1_top_dict_values_t& dictval) { - cff1_top_dict_val_t val; - val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */ + cff1_top_dict_val_t val {}; switch (op) { case OpCode_version: @@ -815,6 +817,9 @@ struct cff1_top_dict_opset_t : top_dict_opset_t dictval.nameSIDs[name_dict_values_t::ordering] = env.argStack.pop_uint (); dictval.nameSIDs[name_dict_values_t::registry] = env.argStack.pop_uint (); env.clear_args (); + if (unlikely (env.in_error ())) return; + assert (env.last_offset > dictval.opStart); + val.last_arg_offset = (env.last_offset - 1) - dictval.opStart; /* offset to the last argument */ break; case OpCode_Encoding: @@ -1463,8 +1468,8 @@ struct cff1 return true; } - HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; - HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; + HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, int64_t *budget = nullptr) const; + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, int64_t *budget = nullptr) const; private: struct gname_t @@ -1533,6 +1538,20 @@ struct cff1_accelerator_t : cff1::accelerator_t { struct cff1_subset_accelerator_t : cff1::accelerator_subset_t { cff1_subset_accelerator_t (hb_face_t *face) : cff1::accelerator_subset_t (face) {} + + void depend (hb_depend_data_builder_t *builder) const + { + if (!is_valid ()) return; + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t base_gid, accent_gid; + if (get_seac_components (gid, &base_gid, &accent_gid)) + { + builder->add_depend (gid, HB_TAG('C','F','F',' '), base_gid); + builder->add_depend (gid, HB_TAG('C','F','F',' '), accent_gid); + } + } + } }; } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc index 94d768a0308..0b4dc1694bd 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc @@ -113,7 +113,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, bool OT::cff2::accelerator_t::get_extents_at (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, - hb_array_t coords) const + hb_array_t coords, + int64_t *budget) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ @@ -122,12 +123,15 @@ bool OT::cff2::accelerator_t::get_extents_at (hb_font_t *font, if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; + int64_t stack_budget = HB_BUDGET_GLYPH; + if (!budget) budget = &stack_budget; + unsigned int fd = fdSelect->get_fd (glyph); const hb_ubytes_t str = (*charStrings)[glyph]; cff2_cs_interp_env_t env (str, *this, fd, coords.arrayZ, coords.length); cff2_cs_interpreter_t interp (env); cff2_extents_param_t param; - if (unlikely (!interp.interpret (param))) return false; + if (unlikely (!interp.interpret (param, budget))) return false; if (param.min_x >= param.max_x) { @@ -136,8 +140,9 @@ bool OT::cff2::accelerator_t::get_extents_at (hb_font_t *font, } else { - extents->x_bearing = roundf (param.min_x.to_real ()); - extents->width = roundf (param.max_x.to_real () - extents->x_bearing); + double x_bearing = roundf (param.min_x.to_real ()); + extents->x_bearing = hb_clamp_to (x_bearing); + extents->width = hb_clamp_to ((double) roundf (param.max_x.to_real ()) - x_bearing); } if (param.min_y >= param.max_y) { @@ -146,8 +151,9 @@ bool OT::cff2::accelerator_t::get_extents_at (hb_font_t *font, } else { - extents->y_bearing = roundf (param.max_y.to_real ()); - extents->height = roundf (param.min_y.to_real () - extents->y_bearing); + double y_bearing = roundf (param.max_y.to_real ()); + extents->y_bearing = hb_clamp_to (y_bearing); + extents->height = hb_clamp_to ((double) roundf (param.min_y.to_real ()) - y_bearing); } font->scale_glyph_extents (extents); @@ -204,16 +210,22 @@ struct cff2_path_procs_path_t : path_procs_t {}; -bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const +bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, + hb_draw_session_t &draw_session, + int64_t *budget) const { + int64_t stack_budget = HB_BUDGET_GLYPH; + if (!budget) budget = &stack_budget; + return get_path_at (font, glyph, draw_session, hb_array (font->coords, - font->has_nonzero_coords ? font->num_coords : 0)); + font->has_nonzero_coords ? font->num_coords : 0), + budget); } -bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords) const +bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords, int64_t *budget) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ @@ -222,12 +234,15 @@ bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; + int64_t stack_budget = HB_BUDGET_GLYPH; + if (!budget) budget = &stack_budget; + unsigned int fd = fdSelect->get_fd (glyph); const hb_ubytes_t str = (*charStrings)[glyph]; cff2_cs_interp_env_t env (str, *this, fd, coords.arrayZ, coords.length); cff2_cs_interpreter_t interp (env); cff2_path_param_t param (font, draw_session); - if (unlikely (!interp.interpret (param))) return false; + if (unlikely (!interp.interpret (param, budget))) return false; return true; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh index 84c593362cf..198c72a7f35 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh @@ -83,7 +83,8 @@ struct CFF2FDSelect } } - bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount, + unsigned int charstring_count = HB_CODEPOINT_INVALID) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) @@ -92,9 +93,9 @@ struct CFF2FDSelect switch (format) { - case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount)); - case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount)); - case 4: hb_barrier (); return_trace (u.format4.sanitize (c, fdcount)); + case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount, charstring_count)); + case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount, charstring_count)); + case 4: hb_barrier (); return_trace (u.format4.sanitize (c, fdcount, charstring_count)); default:return_trace (false); } } @@ -302,6 +303,9 @@ struct cff2_private_dict_opset_t : dict_opset_t env.clear_args (); break; case OpCode_blenddict: + /* Hint values are ignored here. Discard each group so raw operands + * from successive blends cannot overflow the stack. */ + env.clear_args (); break; default: @@ -346,6 +350,12 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t env.clear_args (); break; + case OpCode_vsindexdict: + env.process_vsindex (); + dictval.ivs = env.get_ivs (); + env.clear_args (); + break; + default: SUPER::process_op (op, env); if (!env.argStack.is_empty ()) return; @@ -428,7 +438,6 @@ struct cff2 varStore = &StructAtOffsetOrNull (cff2, topDict.vstoreOffset, sc); charStrings = &StructAtOffsetOrNull (cff2, topDict.charStringsOffset, sc); fdArray = &StructAtOffsetOrNull (cff2, topDict.FDArrayOffset, sc); - fdSelect = &StructAtOffsetOrNull (cff2, topDict.FDSelectOffset, sc, fdArray->count); if (charStrings == &Null (CFF2CharStrings) || globalSubrs == &Null (CFF2Subrs) || @@ -437,6 +446,18 @@ struct cff2 num_glyphs = charStrings->count; if (num_glyphs != sc.get_num_glyphs ()) + { + /* VARC can define glyphs beyond the CFF2 CharStrings INDEX. */ + hb_blob_t *varc = face->reference_table (HB_TAG ('V','A','R','C')); + bool valid_count = num_glyphs < sc.get_num_glyphs () && + hb_blob_get_length (varc); + hb_blob_destroy (varc); + if (!valid_count) goto fail; + } + + fdSelect = &StructAtOffsetOrNull (cff2, topDict.FDSelectOffset, sc, + fdArray->count, num_glyphs); + if (topDict.FDSelectOffset && fdSelect == &Null (CFF2FDSelect)) goto fail; fdCount = fdArray->count; @@ -531,9 +552,10 @@ struct cff2 HB_INTERNAL bool get_extents_at (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, - hb_array_t coords) const; - HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; - HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords) const; + hb_array_t coords, + int64_t *budget = nullptr) const; + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, int64_t *budget = nullptr) const; + HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords, int64_t *budget = nullptr) const; }; struct accelerator_subset_t : accelerator_templ_t diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh index a3e75abef1d..233635d8fe0 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh @@ -30,6 +30,7 @@ #include "hb-ot-os2-table.hh" #include "hb-ot-shaper-arabic-pua.hh" #include "hb-open-type.hh" +#include "hb-ot-dual.hh" #include "hb-set.hh" #include "hb-cache.hh" @@ -38,6 +39,7 @@ * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap */ #define HB_OT_TAG_cmap HB_TAG('c','m','a','p') +#define HB_OT_TAG_DMAP HB_TAG('D','M','A','P') namespace OT { @@ -349,7 +351,9 @@ struct CmapSubtableFormat4 } } - // TODO(grieger): handle case where delta is legitimately 0, mark range offset array instead? + // A zero delta is also the marker for ranges that need a + // glyphIdArray; serialize_rangeoffset_glyid() tells the two cases + // apart by re-checking the mapping. if (should_split) { if (start == prev_run_start) range_writer (start, run_start - 1, previous_run_delta); @@ -443,9 +447,29 @@ struct CmapSubtableFormat4 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; })) + for (unsigned i : hb_range (segcount)) { + /* A non-zero delta is always a real run. A zero delta is + * ambiguous: identity mapping, or the marker for a range that + * needs a glyphIdArray. Only zero deltas need a check. */ + int delta = idDelta[i]; + if (delta) + continue; + bool use_delta = true; + for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++) + { + hb_codepoint_t gid = cp_to_gid.get (cp); + if (gid == HB_MAP_VALUE_INVALID) + gid = 0; + if (gid != cp) + { + use_delta = false; + break; + } + } + if (use_delta) + continue; + idRangeOffset[i] = 2 * (c->start_embed () - idRangeOffset - i); for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++) { @@ -658,6 +682,7 @@ struct CmapSubtableFormat4 hb_codepoint_t gid = this->glyphIdArray[index]; if (unlikely (!gid)) continue; + gid = (gid + this->idDelta[i]) & 0xFFFFu; unicodes->add (codepoint); mapping->set (codepoint, gid); } @@ -1122,7 +1147,7 @@ struct DefaultUVS : SortedArray32Of count += 1; if (lastCode == HB_SET_VALUE_INVALID) lastCode = curEntry; - else if (lastCode + count != curEntry) + else if (lastCode + count != curEntry || count > 255) { UnicodeValueRange rec; rec.startUnicodeValue = lastCode; @@ -1162,8 +1187,11 @@ struct DefaultUVS : SortedArray32Of DEFINE_SIZE_ARRAY (4, *this); }; +template struct UVSMapping { + using GlyphID = typename Types::HBGlyphID; + int cmp (const hb_codepoint_t &codepoint) const { return unicodeValue.cmp (codepoint); } @@ -1174,23 +1202,27 @@ struct UVSMapping } HBUINT24 unicodeValue; /* Base Unicode value of the UVS */ - HBGlyphID16 glyphID; /* Glyph ID of the UVS */ + GlyphID + glyphID; /* Glyph ID of the UVS. */ public: - DEFINE_SIZE_STATIC (5); + DEFINE_SIZE_STATIC (3 + GlyphID::static_size); }; -struct NonDefaultUVS : SortedArray32Of +template +struct NonDefaultUVS : SortedArray32Of> { + using Mapping = UVSMapping; + void collect_unicodes (hb_set_t *out) const { - for (const auto& a : as_array ()) + for (const auto& a : this->as_array ()) out->add (a.unicodeValue); } void collect_mapping (hb_set_t *unicodes, /* OUT */ hb_map_t *mapping /* OUT */) const { - for (const auto& a : as_array ()) + for (const auto& a : this->as_array ()) { hb_codepoint_t unicode = a.unicodeValue; hb_codepoint_t glyphid = a.glyphID; @@ -1202,9 +1234,9 @@ struct NonDefaultUVS : SortedArray32Of void closure_glyphs (const hb_set_t *unicodes, hb_set_t *glyphset) const { - + as_array () - | hb_filter (unicodes, &UVSMapping::unicodeValue) - | hb_map (&UVSMapping::glyphID) + + this->as_array () + | hb_filter (unicodes, &Mapping::unicodeValue) + | hb_map (&Mapping::glyphID) | hb_sink (glyphset) ; } @@ -1216,8 +1248,8 @@ struct NonDefaultUVS : SortedArray32Of { auto *out = c->start_embed (); auto it = - + as_array () - | hb_filter ([&] (const UVSMapping& _) + + this->as_array () + | hb_filter ([&] (const Mapping& _) { return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID); }) @@ -1229,12 +1261,12 @@ struct NonDefaultUVS : SortedArray32Of len = it.len (); if (unlikely (!c->copy (len))) return nullptr; - for (const UVSMapping& _ : it) + for (const Mapping& _ : it) { - UVSMapping mapping; + Mapping mapping; mapping.unicodeValue = _.unicodeValue; mapping.glyphID = glyph_map->get (_.glyphID); - c->copy (mapping); + c->copy (mapping); } return out; @@ -1244,6 +1276,7 @@ struct NonDefaultUVS : SortedArray32Of DEFINE_SIZE_ARRAY (4, *this); }; +template struct VariationSelectorRecord { glyph_variant_t get_glyph (hb_codepoint_t codepoint, @@ -1252,7 +1285,7 @@ struct VariationSelectorRecord { if ((base+defaultUVS).bfind (codepoint)) return GLYPH_VARIANT_USE_DEFAULT; - const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint); + const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint); if (nonDefault.glyphID) { *glyph = nonDefault.glyphID; @@ -1342,14 +1375,19 @@ struct VariationSelectorRecord HBUINT24 varSelector; /* Variation selector. */ Offset32To defaultUVS; /* Offset to Default UVS Table. May be 0. */ - Offset32To + Offset32To> nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ public: DEFINE_SIZE_STATIC (11); }; -struct CmapSubtableFormat14 +template +struct CmapSubtableFormat14_15 { + static constexpr unsigned format_value = Types::size == 2 ? 14 : 15; + using Record = VariationSelectorRecord; + using NonDefault = NonDefaultUVS; + glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const @@ -1375,9 +1413,9 @@ struct CmapSubtableFormat14 const char* init_tail = c->tail; if (unlikely (!c->extend_min (this))) return; - this->format = 14; + this->format = format_value; - auto src_tbl = reinterpret_cast (base); + auto src_tbl = reinterpret_cast (base); /* * Some versions of OTS require that offsets are in order. Due to the use @@ -1403,7 +1441,7 @@ struct CmapSubtableFormat14 obj_indices.push (result); } - if (c->length () - table_initpos == CmapSubtableFormat14::min_size) + if (c->length () - table_initpos == CmapSubtableFormat14_15::min_size) { c->revert (snap); return; @@ -1416,8 +1454,8 @@ struct CmapSubtableFormat14 c->check_assign (this->length, c->length () - table_initpos + tail_len, HB_SERIALIZE_ERROR_INT_OVERFLOW); c->check_assign (this->record.len, - (c->length () - table_initpos - CmapSubtableFormat14::min_size) / - VariationSelectorRecord::static_size, + (c->length () - table_initpos - CmapSubtableFormat14_15::min_size) / + Record::static_size, HB_SERIALIZE_ERROR_INT_OVERFLOW); /* Correct the incorrect write order by reversing the order of the variation @@ -1453,24 +1491,24 @@ struct CmapSubtableFormat14 hb_set_t *glyphset) const { + hb_iter (record) - | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS) - | hb_filter (unicodes, &VariationSelectorRecord::varSelector) - | hb_map (&VariationSelectorRecord::nonDefaultUVS) + | hb_filter (hb_bool, &Record::nonDefaultUVS) + | hb_filter (unicodes, &Record::varSelector) + | hb_map (&Record::nonDefaultUVS) | hb_map (hb_add (this)) - | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); }) + | hb_apply ([=] (const NonDefault& _) { _.closure_glyphs (unicodes, glyphset); }) ; } void collect_unicodes (hb_set_t *out) const { - for (const VariationSelectorRecord& _ : record) + for (const Record& _ : record) _.collect_unicodes (out, this); } void collect_mapping (hb_set_t *unicodes, /* OUT */ hb_map_t *mapping /* OUT */) const { - for (const VariationSelectorRecord& _ : record) + for (const Record& _ : record) _.collect_mapping (this, unicodes, mapping); } @@ -1482,9 +1520,9 @@ struct CmapSubtableFormat14 } protected: - HBUINT16 format; /* Format number is set to 14. */ + HBUINT16 format; /* Format number is set to 14 or 15. */ HBUINT32 length; /* Byte length of this subtable. */ - SortedArray32Of + SortedArray32Of record; /* Variation selector records; sorted * in increasing order of `varSelector'. */ public: @@ -1495,6 +1533,66 @@ struct CmapSubtable { /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ + bool is_variation_selector () const + { + switch (u.format.v) { + case 14: +#ifndef HB_NO_BEYOND_64K + case 15: +#endif + return true; + default: + return false; + } + } + + glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) const + { + switch (u.format.v) { + case 14: hb_barrier (); return u.format14.get_glyph_variant (codepoint, variation_selector, glyph); +#ifndef HB_NO_BEYOND_64K + case 15: hb_barrier (); return u.format15.get_glyph_variant (codepoint, variation_selector, glyph); +#endif + default: return GLYPH_VARIANT_NOT_FOUND; + } + } + + void collect_variation_selectors (hb_set_t *out) const + { + switch (u.format.v) { + case 14: hb_barrier (); u.format14.collect_variation_selectors (out); return; +#ifndef HB_NO_BEYOND_64K + case 15: hb_barrier (); u.format15.collect_variation_selectors (out); return; +#endif + default: return; + } + } + + void collect_variation_unicodes (hb_codepoint_t variation_selector, + hb_set_t *out) const + { + switch (u.format.v) { + case 14: hb_barrier (); u.format14.collect_variation_unicodes (variation_selector, out); return; +#ifndef HB_NO_BEYOND_64K + case 15: hb_barrier (); u.format15.collect_variation_unicodes (variation_selector, out); return; +#endif + default: return; + } + } + + void closure_glyphs (const hb_set_t *unicodes, hb_set_t *glyphset) const + { + switch (u.format.v) { + case 14: hb_barrier (); u.format14.closure_glyphs (unicodes, glyphset); return; +#ifndef HB_NO_BEYOND_64K + case 15: hb_barrier (); u.format15.closure_glyphs (unicodes, glyphset); return; +#endif + default: return; + } + } + bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph, unsigned int subtable_data_size = 0) const @@ -1579,6 +1677,9 @@ struct CmapSubtable case 4: hb_barrier (); return u.format4.serialize (c, it); case 12: hb_barrier (); return u.format12.serialize (c, it); case 14: hb_barrier (); return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base); +#ifndef HB_NO_BEYOND_64K + case 15: hb_barrier (); return u.format15.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base); +#endif default: return; } } @@ -1596,6 +1697,9 @@ struct CmapSubtable case 12: hb_barrier (); return_trace (u.format12.sanitize (c)); case 13: hb_barrier (); return_trace (u.format13.sanitize (c)); case 14: hb_barrier (); return_trace (u.format14.sanitize (c)); +#ifndef HB_NO_BEYOND_64K + case 15: hb_barrier (); return_trace (u.format15.sanitize (c)); +#endif default:return_trace (true); } } @@ -1609,7 +1713,12 @@ struct CmapSubtable CmapSubtableFormat10 format10; CmapSubtableFormat12 format12; CmapSubtableFormat13 format13; - CmapSubtableFormat14 format14; + CmapSubtableFormat14_15 + format14; +#ifndef HB_NO_BEYOND_64K + CmapSubtableFormat14_15 + format15; +#endif } u; public: DEFINE_SIZE_UNION (2, format.v); @@ -1823,6 +1932,9 @@ struct cmap this->version = 0; unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; +#ifndef HB_NO_BEYOND_64K + unsigned format15objidx = 0; +#endif auto snap = c->snapshot (); SubtableUnicodesCache local_unicodes_cache (base, source_table_length); @@ -1839,7 +1951,11 @@ struct cmap return false; unsigned format = (base+_.subtable).u.format.v; - if (format != 4 && format != 12 && format != 14) continue; + if (format != 4 && format != 12 && format != 14 +#ifndef HB_NO_BEYOND_64K + && format != 15 +#endif + ) continue; const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache); @@ -1871,6 +1987,9 @@ struct cmap c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx); } else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); +#ifndef HB_NO_BEYOND_64K + else if (format == 15) c->copy (_, it, 15u, base, plan, &format15objidx); +#endif } unsigned length = c->length (); unsigned available = length > cmap::min_size ? length - cmap::min_size : 0; @@ -1943,12 +2062,15 @@ struct cmap + hb_iter (encodingRecord) | hb_map (&EncodingRecord::subtable) | hb_map (hb_add (this)) - | hb_filter ([&] (const CmapSubtable& _) { return _.u.format.v == 14; }) - | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); }) + | hb_filter (&CmapSubtable::is_variation_selector) + | hb_apply ([=] (const CmapSubtable& _) { _.closure_glyphs (unicodes, glyphset); }) ; } bool subset (hb_subset_context_t *c) const + { return subset (c, false); } + + bool subset (hb_subset_context_t *c, bool is_dmap) const { TRACE_SUBSET (this); @@ -1978,8 +2100,8 @@ struct cmap else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table; } - if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false); - if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); + if (unlikely (!is_dmap && !has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false); + if (unlikely (!is_dmap && has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); auto it = + c->plan->unicode_to_new_gid_list.iter () @@ -2050,16 +2172,19 @@ struct cmap using cache_t = hb_cache_t<21, 19>; static_assert (sizeof (cache_t) == 1024, ""); - accelerator_t (hb_face_t *face) + accelerator_t (hb_face_t *face, hb_tag_t table_tag = cmap::tableTag) { - this->table = hb_sanitize_context_t ().reference_table (face); + this->table = hb_sanitize_context_t ().reference_table (face, table_tag); + if (!this->table.get_length ()) + return; + bool symbol, mac, macroman; this->subtable = table->find_best_subtable (&symbol, &mac, ¯oman); - this->subtable_uvs = &Null (CmapSubtableFormat14); + this->subtable_uvs = &Null (CmapSubtable); { - const CmapSubtable *st = table->find_subtable (0, 5); - if (st && st->u.format.v == 14) - subtable_uvs = &st->u.format14; + const CmapSubtable *st = table->find_variation_selector_subtable (); + if (st) + subtable_uvs = st; } #ifndef HB_NO_OT_FONT_CMAP_CACHE @@ -2140,6 +2265,7 @@ struct cmap break; case 4: { + hb_barrier (); this->format4_accel.init (&subtable->u.format4, get_subtable_data_size (subtable)); this->get_glyph_data = &this->format4_accel; @@ -2209,9 +2335,7 @@ struct cmap hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const { - switch (this->subtable_uvs->get_glyph_variant (unicode, - variation_selector, - glyph)) + switch (get_glyph_variant (unicode, variation_selector, glyph)) { case GLYPH_VARIANT_NOT_FOUND: return false; case GLYPH_VARIANT_FOUND: return true; @@ -2221,6 +2345,17 @@ struct cmap return get_nominal_glyph (unicode, glyph); } + glyph_variant_t get_glyph_variant (hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) const + { + return this->subtable_uvs->get_glyph_variant (unicode, + variation_selector, + glyph); + } + + bool has_data () const { return table.get_length (); } + void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const { subtable->collect_unicodes (out, num_glyphs, get_subtable_data_size (subtable)); } void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping, @@ -2301,7 +2436,7 @@ struct cmap private: hb_nonnull_ptr_t subtable; - hb_nonnull_ptr_t subtable_uvs; + hb_nonnull_ptr_t subtable_uvs; hb_cmap_get_glyph_func_t get_glyph_funcZ = nullptr; const void *get_glyph_data = nullptr; @@ -2332,6 +2467,25 @@ struct cmap return &(this+result.subtable); } + const CmapSubtable *find_variation_selector_subtable () const + { + const CmapSubtable *format14 = nullptr; + for (const EncodingRecord& record : encodingRecord) + { + if (record.platformID != 0 || record.encodingID != 5) + continue; + + const CmapSubtable *subtable = &(this+record.subtable); +#ifndef HB_NO_BEYOND_64K + if (subtable->u.format.v == 15) + return subtable; +#endif + if (subtable->u.format.v == 14) + format14 = subtable; + } + return format14; + } + public: bool sanitize (hb_sanitize_context_t *c) const @@ -2353,7 +2507,7 @@ struct cmap (_.platformID == 0 && _.encodingID == 4) || (_.platformID == 3 && _.encodingID == 1) || (_.platformID == 3 && _.encodingID == 10) || - (cmap + _.subtable).u.format.v == 14; + (cmap + _.subtable).is_variation_selector (); } protected: @@ -2364,8 +2518,128 @@ struct cmap DEFINE_SIZE_ARRAY (4, encodingRecord); }; -struct cmap_accelerator_t : cmap::accelerator_t { - cmap_accelerator_t (hb_face_t *face) : cmap::accelerator_t (face) {} +struct DMAP : cmap +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_DMAP; + + bool subset (hb_subset_context_t *c) const + { return cmap::subset (c, true); } +}; + +struct cmap_accelerator_t +{ + cmap_accelerator_t (hb_face_t *face) : + dmap (face, HB_OT_TAG_DMAP), + base (face) + {} + + bool get_nominal_glyph (hb_codepoint_t unicode, + hb_codepoint_t *glyph) const + { + return dmap.get_nominal_glyph (unicode, glyph) || + base.get_nominal_glyph (unicode, glyph); + } + + unsigned int get_nominal_glyphs (unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride) const + { + if (likely (!dmap.has_data ())) + return base.get_nominal_glyphs (count, + first_unicode, unicode_stride, + first_glyph, glyph_stride); + + unsigned int done; + for (done = 0; + done < count && get_nominal_glyph (*first_unicode, first_glyph); + done++) + { + first_unicode = &StructAtOffsetUnaligned (first_unicode, unicode_stride); + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + } + return done; + } + + bool get_variation_glyph (hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) const + { + glyph_variant_t result = dmap.get_glyph_variant (unicode, + variation_selector, + glyph); + if (result == GLYPH_VARIANT_NOT_FOUND) + result = base.get_glyph_variant (unicode, variation_selector, glyph); + + switch (result) + { + case GLYPH_VARIANT_NOT_FOUND: return false; + case GLYPH_VARIANT_FOUND: return true; + case GLYPH_VARIANT_USE_DEFAULT: break; + } + + return get_nominal_glyph (unicode, glyph); + } + + void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const + { + base.collect_unicodes (out, num_glyphs); + dmap.collect_unicodes (out, num_glyphs); + } + + void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping, + unsigned num_glyphs = UINT_MAX) const + { + base.collect_mapping (unicodes, mapping, num_glyphs); + dmap.collect_mapping (unicodes, mapping, num_glyphs); + } + + void collect_variation_selectors (hb_set_t *out) const + { + base.collect_variation_selectors (out); + dmap.collect_variation_selectors (out); + } + + void collect_variation_unicodes (hb_codepoint_t variation_selector, + hb_set_t *out) const + { + base.collect_variation_unicodes (variation_selector, out); + dmap.collect_variation_unicodes (variation_selector, out); + } + + void closure_glyphs (const hb_set_t *unicodes, + hb_set_t *glyphset) const + { + if (likely (!dmap.has_data ())) + { + base.table->closure_glyphs (unicodes, glyphset); + return; + } + + hb_set_t variation_selectors; + collect_variation_selectors (&variation_selectors); + for (hb_codepoint_t variation_selector : variation_selectors) + { + if (!unicodes->has (variation_selector)) + continue; + + hb_set_t variation_unicodes; + collect_variation_unicodes (variation_selector, &variation_unicodes); + for (hb_codepoint_t unicode : variation_unicodes) + { + if (!unicodes->has (unicode)) + continue; + + hb_codepoint_t glyph; + if (get_variation_glyph (unicode, variation_selector, &glyph)) + glyphset->add (glyph); + } + } + } + + cmap::accelerator_t dmap; + cmap::accelerator_t base; }; } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-dual.hh similarity index 51% rename from src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh rename to src/java.desktop/share/native/libharfbuzz/hb-ot-dual.hh index 5cf9eb368aa..76da5382b13 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-dual.hh @@ -26,14 +26,11 @@ * Google Author(s): Behdad Esfahbod, Garret Rieger */ -#ifndef OT_LAYOUT_TYPES_HH -#define OT_LAYOUT_TYPES_HH +#ifndef HB_OT_DUAL_HH +#define HB_OT_DUAL_HH -using hb_ot_layout_mapping_cache_t = hb_cache_t<16, 8, 8>; -static_assert (sizeof (hb_ot_layout_mapping_cache_t) == 512, ""); +#include "hb-open-type.hh" -using hb_ot_layout_binary_cache_t = hb_cache_t<14, 1, 8>; -static_assert (sizeof (hb_ot_layout_binary_cache_t) == 256, ""); namespace OT { namespace Layout { @@ -42,10 +39,14 @@ struct SmallTypes { static constexpr unsigned size = 2; using large_int = uint32_t; using HBUINT = HBUINT16; + using HBLUINT = HBUINT16; using HBGlyphID = HBGlyphID16; using Offset = Offset16; + using LOffset = Offset16; template using OffsetTo = OT::Offset16To; + template + using LOffsetTo = OT::Offset16To; template using ArrayOf = OT::Array16Of; template @@ -56,10 +57,15 @@ struct MediumTypes { static constexpr unsigned size = 3; using large_int = uint64_t; using HBUINT = HBUINT24; + using HBLUINT = HBUINT32; using HBGlyphID = HBGlyphID24; using Offset = Offset24; + /* Long offsets for large tables. */ + using LOffset = Offset32; template using OffsetTo = OT::Offset24To; + template + using LOffsetTo = OT::Offset32To; template using ArrayOf = OT::Array24Of; template @@ -69,4 +75,71 @@ struct MediumTypes { } } -#endif /* OT_LAYOUT_TYPES_HH */ + +template +struct hb_dual_accelerator_t +{ + hb_dual_accelerator_t (hb_face_t *face) : +#ifndef HB_NO_BEYOND_64K + upper (face), +#endif + lower ( +#ifndef HB_NO_BEYOND_64K + upper.has_data () ? hb_face_get_empty () : +#endif + face) + {} + + bool has_data () const + { +#ifndef HB_NO_BEYOND_64K + if (upper.has_data ()) return true; +#endif + return lower.has_data (); + } + + bool has_upper_data () const + { +#ifndef HB_NO_BEYOND_64K + return upper.has_data (); +#else + return false; +#endif + } + +#ifndef HB_NO_BEYOND_64K + Upper upper; +#endif + Lower lower; +}; + +template +struct hb_table_accelerator_t +{ + hb_table_accelerator_t (hb_face_t *face) : + table (hb_sanitize_context_t ().reference_table (face)) + {} + ~hb_table_accelerator_t () { table.destroy (); } + + bool has_data () const { return table->has_data (); } + + hb_blob_ptr_t
table; +}; + +template +struct hb_dual_table_t : hb_dual_accelerator_t, + hb_table_accelerator_t> +{ + hb_dual_table_t (hb_face_t *face) : + hb_dual_accelerator_t, + hb_table_accelerator_t> (face) {} +}; + +#ifndef HB_NO_BEYOND_64K +#define HB_DUAL_GET(accel, expr) ((accel).upper.has_data () ? (accel).upper.expr : (accel).lower.expr) +#else +#define HB_DUAL_GET(accel, expr) ((accel).lower.expr) +#endif + + +#endif /* HB_OT_DUAL_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh index 9047b2880ab..abd0a2c0cb2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh @@ -32,11 +32,6 @@ #define HB_OT_FACE_TABLE_LIST_HH #endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */ -#ifndef HB_OT_CORE_TABLE -#define HB_OT_CORE_TABLE(Namespace, Type) HB_OT_TABLE (Namespace, Type) -#define _HB_OT_CORE_TABLE_UNDEF -#endif - #ifndef HB_OT_ACCELERATOR #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) #define _HB_OT_ACCELERATOR_UNDEF @@ -51,14 +46,14 @@ /* OpenType fundamentals. */ -HB_OT_CORE_TABLE (OT, head) -HB_OT_CORE_TABLE (OT, maxp) +HB_OT_TABLE (OT, head) +HB_OT_ACCELERATOR (OT, maxp) #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT) HB_OT_ACCELERATOR (OT, cmap) #endif -HB_OT_CORE_TABLE (OT, hhea) +HB_OT_ACCELERATOR (OT, hhea) HB_OT_ACCELERATOR (OT, hmtx) -HB_OT_CORE_TABLE (OT, OS2) +HB_OT_TABLE (OT, OS2) #if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE) HB_OT_ACCELERATOR (OT, post) #endif @@ -66,7 +61,7 @@ HB_OT_ACCELERATOR (OT, post) HB_OT_ACCELERATOR (OT, name) #endif #ifndef HB_NO_STYLE -HB_OT_CORE_TABLE (OT, STAT) +HB_OT_TABLE (OT, STAT) #endif #ifndef HB_NO_META HB_OT_ACCELERATOR (OT, meta) @@ -74,13 +69,13 @@ HB_OT_ACCELERATOR (OT, meta) /* Vertical layout. */ #ifndef HB_NO_VERTICAL -HB_OT_CORE_TABLE (OT, vhea) +HB_OT_ACCELERATOR (OT, vhea) HB_OT_ACCELERATOR (OT, vmtx) -HB_OT_CORE_TABLE (OT, VORG) +HB_OT_TABLE (OT, VORG) #endif /* TrueType outlines. */ -HB_OT_CORE_TABLE (OT, loca) // Also used to determine number of glyphs +HB_OT_TABLE (OT, loca) HB_OT_ACCELERATOR (OT, glyf) /* CFF outlines. */ @@ -91,14 +86,11 @@ HB_OT_ACCELERATOR (OT, cff2) /* OpenType variations. */ #ifndef HB_NO_VAR -HB_OT_CORE_TABLE (OT, fvar) -HB_OT_CORE_TABLE (OT, avar) -HB_OT_CORE_TABLE (OT, cvar) +HB_OT_TABLE (OT, fvar) +HB_OT_TABLE (OT, avar) +HB_OT_TABLE (OT, cvar) HB_OT_ACCELERATOR (OT, gvar) -#ifndef HB_NO_BEYOND_64K -HB_OT_ACCELERATOR (OT, GVAR) -#endif -HB_OT_CORE_TABLE (OT, MVAR) +HB_OT_TABLE (OT, MVAR) #ifndef HB_NO_VAR_COMPOSITES HB_OT_ACCELERATOR (OT, VARC) #endif @@ -114,12 +106,12 @@ HB_OT_ACCELERATOR (OT, kern) HB_OT_ACCELERATOR (OT, GDEF) HB_OT_ACCELERATOR (OT, GSUB) HB_OT_ACCELERATOR (OT, GPOS) -//HB_OT_CORE_TABLE (OT, JSTF) +//HB_OT_TABLE (OT, JSTF) #endif /* OpenType baseline. */ #ifndef HB_NO_BASE -HB_OT_CORE_TABLE (OT, BASE) +HB_OT_TABLE (OT, BASE) #endif /* AAT shaping. */ @@ -137,7 +129,7 @@ HB_OT_TABLE (AAT, feat) /* OpenType color fonts. */ #ifndef HB_NO_COLOR HB_OT_ACCELERATOR (OT, COLR) -HB_OT_CORE_TABLE (OT, CPAL) +HB_OT_TABLE (OT, CPAL) HB_OT_ACCELERATOR (OT, CBDT) HB_OT_ACCELERATOR (OT, sbix) #ifndef HB_NO_SVG @@ -147,14 +139,10 @@ HB_OT_ACCELERATOR (OT, SVG) /* OpenType math. */ #ifndef HB_NO_MATH -HB_OT_CORE_TABLE (OT, MATH) +HB_OT_TABLE (OT, MATH) #endif #ifdef _HB_OT_ACCELERATOR_UNDEF #undef HB_OT_ACCELERATOR #endif - -#ifdef _HB_OT_CORE_TABLE_UNDEF -#undef HB_OT_CORE_TABLE -#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh index 415dae8e209..e24d380bca8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh @@ -63,13 +63,10 @@ struct hb_ot_face_t hb_face_t *face; /* MUST be JUST before the lazy loaders. */ #define HB_OT_TABLE(Namespace, Type) \ hb_table_lazy_loader_t Type; -#define HB_OT_CORE_TABLE(Namespace, Type) \ - hb_table_lazy_loader_t Type; #define HB_OT_ACCELERATOR(Namespace, Type) \ hb_face_lazy_loader_t Type; #include "hb-ot-face-table-list.hh" #undef HB_OT_ACCELERATOR -#undef HB_OT_CORE_TABLE #undef HB_OT_TABLE }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-fetch.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-fetch.h new file mode 100644 index 00000000000..99b10073dec --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-fetch.h @@ -0,0 +1,101 @@ +/* + * Copyright © 2026 Khaled Hosny + * + * 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. + */ + +#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) +#error "Include instead." +#endif + +#ifndef HB_OT_FETCH_H +#define HB_OT_FETCH_H + +#include "hb.h" + +HB_BEGIN_DECLS + +/** + * hb_ot_bits_tag_t: + * @HB_OT_BITS_TAG_FS_TYPE: `fsType` of the `OS/2` table. + * @HB_OT_BITS_TAG_FS_SELECTION: `fsSelection` of the `OS/2` table. + * @HB_OT_BITS_TAG_MAC_STYLE: `macStyle` of the `head` table. + * @HB_OT_BITS_TAG_IS_FIXED_PITCH: `isFixedPitch` of the `post` table. + * @HB_OT_BITS_TAG_UNICODE_RANGE_1: `ulUnicodeRange1` of the `OS/2` table. + * @HB_OT_BITS_TAG_UNICODE_RANGE_2: `ulUnicodeRange2` of the `OS/2` table. + * @HB_OT_BITS_TAG_UNICODE_RANGE_3: `ulUnicodeRange3` of the `OS/2` table. + * @HB_OT_BITS_TAG_UNICODE_RANGE_4: `ulUnicodeRange4` of the `OS/2` table. + * @HB_OT_BITS_TAG_CODE_PAGE_RANGE_1: `ulCodePageRange1` of the `OS/2` table. + * @HB_OT_BITS_TAG_CODE_PAGE_RANGE_2: `ulCodePageRange2` of the `OS/2` table. + * + * Bit fields that can be fetched with hb_ot_fetch_bits(). + * + * Since: 14.3.0 + **/ +typedef enum { + HB_OT_BITS_TAG_FS_TYPE = HB_TAG ('f','s','t','p'), + HB_OT_BITS_TAG_FS_SELECTION = HB_TAG ('f','s','s','l'), + HB_OT_BITS_TAG_MAC_STYLE = HB_TAG ('m','c','s','t'), + HB_OT_BITS_TAG_IS_FIXED_PITCH = HB_TAG ('f','x','p','t'), + HB_OT_BITS_TAG_UNICODE_RANGE_1 = HB_TAG ('u','r','n','1'), + HB_OT_BITS_TAG_UNICODE_RANGE_2 = HB_TAG ('u','r','n','2'), + HB_OT_BITS_TAG_UNICODE_RANGE_3 = HB_TAG ('u','r','n','3'), + HB_OT_BITS_TAG_UNICODE_RANGE_4 = HB_TAG ('u','r','n','4'), + HB_OT_BITS_TAG_CODE_PAGE_RANGE_1 = HB_TAG ('c','p','r','1'), + HB_OT_BITS_TAG_CODE_PAGE_RANGE_2 = HB_TAG ('c','p','r','2'), + + /*< private >*/ + _HB_OT_BITS_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ +} hb_ot_bits_tag_t; + + +HB_EXTERN uint32_t +hb_ot_fetch_bits (hb_face_t *face, + hb_ot_bits_tag_t tag); + +/** + * hb_ot_number_tag_t: + * @HB_OT_NUMBER_TAG_FONT_X_MIN: `xMin` of the `head` table. + * @HB_OT_NUMBER_TAG_FONT_Y_MIN: `yMin` of the `head` table. + * @HB_OT_NUMBER_TAG_FONT_X_MAX: `xMax` of the `head` table. + * @HB_OT_NUMBER_TAG_FONT_Y_MAX: `yMax` of the `head` table. + * + * Numbers that can be fetched with hb_ot_fetch_number(). + * + * Since: 14.3.0 + **/ +typedef enum { + HB_OT_NUMBER_TAG_FONT_X_MIN = HB_TAG ('x','m','i','n'), + HB_OT_NUMBER_TAG_FONT_Y_MIN = HB_TAG ('y','m','i','n'), + HB_OT_NUMBER_TAG_FONT_X_MAX = HB_TAG ('x','m','a','x'), + HB_OT_NUMBER_TAG_FONT_Y_MAX = HB_TAG ('y','m','a','x'), + + /*< private >*/ + _HB_OT_NUMBER_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ +} hb_ot_number_tag_t; + +HB_EXTERN int32_t +hb_ot_fetch_number (hb_face_t *face, + hb_ot_number_tag_t tag); + +HB_END_DECLS + +#endif /* HB_OT_FETCH_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc index 997fbe5be04..6ecc76deb9d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc @@ -289,7 +289,7 @@ struct hb_ot_font_t void check_serial (hb_font_t *font) const { - int font_serial = font->serial_coords.get_acquire (); + int font_serial = font->serial.get_acquire (); if (cached_serial.get_acquire () != font_serial) { /* These caches are dependent on scale and synthetic settings. @@ -644,6 +644,8 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, 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; + ot_font->check_serial (font); + /* First, set all the x values to half the advance width. */ font->get_glyph_h_advances (count, first_glyph, glyph_stride, @@ -732,9 +734,12 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, ot_font->v_origin.release_origin_cache (origin_cache); return false; } - OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ? + OT::hb_scalar_cache_t *gvar_cache = nullptr; +#ifndef HB_NO_VAR + gvar_cache = font->has_nonzero_coords ? ot_font->draw.acquire_gvar_cache (*ot_face->gvar) : nullptr; +#endif for (unsigned i = 0; i < count; i++) { @@ -754,8 +759,10 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, first_y = &StructAtOffsetUnaligned (first_y, y_stride); } +#ifndef HB_NO_VAR if (gvar_cache) ot_font->draw.release_gvar_cache (gvar_cache); +#endif glyf.release_scratch (scratch); ot_font->v_origin.release_origin_cache (origin_cache); return true; @@ -780,7 +787,8 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, { hb_glyph_extents_t extents = {0}; if (likely (font->get_glyph_extents (*first_glyph, &extents))) - origin = extents.y_bearing + ((font_advance - -extents.height) >> 1); + origin = hb_clamp_to ((int64_t) extents.y_bearing + + (((int64_t) font_advance + extents.height) >> 1)); else origin = font_extents.ascender; @@ -912,11 +920,14 @@ hb_ot_draw_glyph_or_fail (hb_font_t *font, if (font->face->table.VARC->get_path (font, glyph, draw_session)) return true; #endif // Keep the following in synch with VARC::get_path_at() - if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) return true; + if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache, + &draw_session.get_budget ())) return true; #ifndef HB_NO_CFF - if (font->face->table.cff2->get_path (font, glyph, draw_session)) return true; - if (font->face->table.cff1->get_path (font, glyph, draw_session)) return true; + if (font->face->table.cff2->get_path (font, glyph, draw_session, + &draw_session.get_budget ())) return true; + if (font->face->table.cff1->get_path (font, glyph, draw_session, + &draw_session.get_budget ())) return true; #endif return false; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh index 77c2894bbc8..ac6438d0459 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh @@ -42,7 +42,7 @@ namespace OT { struct DeviceRecord { static size_t get_size (unsigned count) - { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); } + { return hb_ceil_to_4 (hb_unsigned_mul_add_saturate (count, HBUINT8::static_size, min_size)); } template @@ -88,7 +88,7 @@ struct hdmx static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx; size_t get_size () const - { return min_size + numRecords * sizeDeviceRecord; } + { return hb_unsigned_mul_add_saturate (numRecords, sizeDeviceRecord, min_size); } template diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh index 34535e2286d..1b70929050c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh @@ -99,6 +99,8 @@ struct head bool is_condensed () const { return macStyle & CONDENSED; } bool is_expanded () const { return macStyle & EXPANDED; } + unsigned get_mac_style () const { return macStyle; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh index 5e3be5be525..2bdd7ed1a08 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh @@ -28,6 +28,7 @@ #define HB_OT_HHEA_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-dual.hh" /* * hhea -- Horizontal Header @@ -36,15 +37,22 @@ * https://docs.microsoft.com/en-us/typography/opentype/spec/vhea */ #define HB_OT_TAG_hhea HB_TAG('h','h','e','a') +#define HB_OT_TAG_HHEA HB_TAG('H','H','E','A') #define HB_OT_TAG_vhea HB_TAG('v','h','e','a') +#define HB_OT_TAG_VHEA HB_TAG('V','H','E','A') namespace OT { -template +template struct _hea { + using LongMetricCount = typename Types::HBLUINT; + + static constexpr unsigned long_metric_count_max () + { return LongMetricCount::static_size == 4 ? 0xFFFFFFFFu : 0xFFFFu; } + bool has_data () const { return version.major; } bool sanitize (hb_sanitize_context_t *c) const @@ -85,19 +93,38 @@ struct _hea HBINT16 reserved3; /* Set to 0. */ HBINT16 reserved4; /* Set to 0. */ HBINT16 metricDataFormat;/* 0 for current format. */ - HBUINT16 numberOfLongMetrics; + LongMetricCount + numberOfLongMetrics; /* Number of LongMetric entries in metric * table. */ public: - DEFINE_SIZE_STATIC (36); + DEFINE_SIZE_STATIC (34 + Types::HBLUINT::static_size); }; -struct hhea : _hea { +struct hhea : _hea { static constexpr hb_tag_t tableTag = HB_OT_TAG_hhea; }; -struct vhea : _hea { +struct HHEA : _hea { + static constexpr hb_tag_t tableTag = HB_OT_TAG_HHEA; +}; +struct vhea : _hea { static constexpr hb_tag_t tableTag = HB_OT_TAG_vhea; }; +struct VHEA : _hea { + static constexpr hb_tag_t tableTag = HB_OT_TAG_VHEA; +}; + +struct hhea_accelerator_t : hb_dual_table_t +{ + hhea_accelerator_t (hb_face_t *face) : + hb_dual_table_t (face) {} +}; + +struct vhea_accelerator_t : hb_dual_table_t +{ + vhea_accelerator_t (hb_face_t *face) : + hb_dual_table_t (face) {} +}; } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh index e679e22c7a9..9d2e8b069b4 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh @@ -28,6 +28,7 @@ #define HB_OT_HMTX_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-dual.hh" #include "hb-ot-maxp-table.hh" #include "hb-ot-hhea-table.hh" #include "hb-ot-os2-table.hh" @@ -42,7 +43,9 @@ * https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx */ #define HB_OT_TAG_hmtx HB_TAG('h','m','t','x') +#define HB_OT_TAG_HMTX HB_TAG('H','M','T','X') #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x') +#define HB_OT_TAG_VMTX HB_TAG('V','M','T','X') namespace OT { @@ -193,11 +196,8 @@ struct hmtxvmtx lm.advance = mtx.first; lm.sb = mtx.second; } - // TODO(beyond-64k): This assumes that maxp.numGlyphs is 0xFFFF. - else if (gid < 0x10000u) - short_metrics[gid] = mtx.second; else - ((UFWORD*) short_metrics)[gid] = mtx.first; + short_metrics[gid] = mtx.second; } } @@ -216,7 +216,7 @@ struct hmtxvmtx // TODO Don't consider retaingid holes here. - num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu); + num_long_metrics = hb_min (plan->num_output_glyphs (), H::long_metric_count_max ()); unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); while (num_long_metrics > 1 && last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) @@ -264,9 +264,13 @@ struct hmtxvmtx { friend struct hmtxvmtx; - accelerator_t (hb_face_t *face) + accelerator_t (hb_face_t *face) : + accelerator_t (face, T::tableTag, get_num_long_metrics (face)) + {} + + accelerator_t (hb_face_t *face, hb_tag_t tableTag, unsigned num_long_metrics_) { - table = hb_sanitize_context_t ().reference_table (face, T::tableTag); + table = hb_sanitize_context_t ().reference_table (face, tableTag); var_table = hb_sanitize_context_t ().reference_table (face, T::variationsTag); default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face); @@ -277,15 +281,8 @@ struct hmtxvmtx if (len & 1) len--; - num_long_metrics = T::is_horizontal ? - face->table.hhea->numberOfLongMetrics : -#ifndef HB_NO_VERTICAL - face->table.vhea->numberOfLongMetrics -#else - 0 -#endif - ; - if (unlikely (num_long_metrics * 4 > len)) + num_long_metrics = num_long_metrics_; + if (unlikely (num_long_metrics > len / 4)) num_long_metrics = len / 4; len -= num_long_metrics * 4; @@ -336,33 +333,15 @@ struct hmtxvmtx unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const { - /* OpenType case. */ if (glyph < num_bearings) return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance; /* If num_advances is zero, it means we don't have the metrics table - * for this direction: return default advance. Otherwise, there's a - * well-defined answer. */ + * for this direction: return default advance. */ if (unlikely (!num_advances)) return default_advance; -#ifdef HB_NO_BEYOND_64K return 0; -#endif - - if (unlikely (glyph >= num_glyphs)) - return 0; - - /* num_bearings <= glyph < num_glyphs; - * num_bearings <= num_advances */ - - if (num_bearings == num_advances) - return get_advance_without_var_unscaled (num_bearings - 1); - - const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; - const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics]; - - return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)]; } #ifndef HB_NO_VAR @@ -371,7 +350,7 @@ struct hmtxvmtx hb_scalar_cache_t *store_cache = nullptr) const { unsigned int advance = get_advance_without_var_unscaled (glyph); - return hb_max(0.0f, advance + roundf (var_table->get_advance_delta_unscaled (glyph, + return hb_clamp_to (advance + roundf (var_table->get_advance_delta_unscaled (glyph, font->coords, font->num_coords, store_cache))); } @@ -389,6 +368,15 @@ struct hmtxvmtx public: hb_blob_ptr_t table; hb_blob_ptr_t var_table; + + private: + static unsigned get_num_long_metrics (hb_face_t *face) + { + hb_blob_ptr_t hea = hb_sanitize_context_t ().reference_table (face); + unsigned ret = hea->numberOfLongMetrics; + hea.destroy (); + return ret; + } }; /* get advance: when no variations, call get_advance_without_var_unscaled. @@ -442,18 +430,107 @@ struct hmtx : hmtxvmtx { static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; static constexpr bool is_horizontal = true; }; +struct HMTX : hmtxvmtx { + static constexpr hb_tag_t tableTag = HB_OT_TAG_HMTX; + static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; + static constexpr bool is_horizontal = true; +}; struct vmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; static constexpr bool is_horizontal = false; }; +struct VMTX : hmtxvmtx { + static constexpr hb_tag_t tableTag = HB_OT_TAG_VMTX; + static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; + static constexpr bool is_horizontal = false; +}; + +struct hmtx_accelerator_t : hb_dual_accelerator_t +{ + hmtx_accelerator_t (hb_face_t *face) : + hb_dual_accelerator_t (face) + { + var_table = hb_sanitize_context_t ().reference_table (face); + } + + ~hmtx_accelerator_t () + { + var_table.destroy (); + } + + void get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph, + int *lsb) const + { + HB_DUAL_GET (*this, get_leading_bearing_without_var_unscaled (glyph, lsb)); + } -struct hmtx_accelerator_t : hmtx::accelerator_t { - hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {} + unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const + { + return HB_DUAL_GET (*this, get_advance_without_var_unscaled (glyph)); + } + +#ifndef HB_NO_VAR + unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, + hb_font_t *font, + hb_scalar_cache_t *store_cache = nullptr) const + { + unsigned int advance = get_advance_without_var_unscaled (glyph); + return hb_clamp_to (advance + roundf (var_table->get_advance_delta_unscaled (glyph, + font->coords, font->num_coords, + store_cache))); + } +#endif + + hb_blob_ptr_t var_table; }; + +#ifndef HB_NO_VERTICAL +struct vmtx_accelerator_t : hb_dual_accelerator_t +{ + vmtx_accelerator_t (hb_face_t *face) : + hb_dual_accelerator_t (face) + { + var_table = hb_sanitize_context_t ().reference_table (face); + } + + ~vmtx_accelerator_t () + { + var_table.destroy (); + } + + void get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph, + int *lsb) const + { + HB_DUAL_GET (*this, get_leading_bearing_without_var_unscaled (glyph, lsb)); + } + + unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const + { + return HB_DUAL_GET (*this, get_advance_without_var_unscaled (glyph)); + } + +#ifndef HB_NO_VAR + unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, + hb_font_t *font, + hb_scalar_cache_t *store_cache = nullptr) const + { + unsigned int advance = get_advance_without_var_unscaled (glyph); + return hb_clamp_to (advance + roundf (var_table->get_advance_delta_unscaled (glyph, + font->coords, font->num_coords, + store_cache))); + } +#endif + + hb_blob_ptr_t var_table; +}; +#else struct vmtx_accelerator_t : vmtx::accelerator_t { vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {} }; +#endif } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh index f83bee29d7e..331d9a19a0d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh @@ -144,13 +144,13 @@ struct KernSubTable unsigned int subtable_type = get_type (); TRACE_DISPATCH (this, subtable_type); switch (subtable_type) { - case 0: return_trace (c->dispatch (u.format0)); + case 0: hb_barrier (); return_trace (c->dispatch (u.format0)); #ifndef HB_NO_AAT_SHAPE - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); #endif - case 2: return_trace (c->dispatch (u.format2)); + case 2: hb_barrier (); return_trace (c->dispatch (u.format2)); #ifndef HB_NO_AAT_SHAPE - case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); + case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); #endif default: return_trace (c->default_return_value ()); } @@ -161,10 +161,14 @@ struct KernSubTable { unsigned int subtable_type = get_type (); switch (subtable_type) { - case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return; - case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return; - case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return; - case 3: u.format3.collect_glyphs (left_set, right_set, num_glyphs); return; + case 0: hb_barrier (); u.format0.collect_glyphs (left_set, right_set, num_glyphs); return; +#ifndef HB_NO_AAT_SHAPE + case 1: hb_barrier (); u.format1.collect_glyphs (left_set, right_set, num_glyphs); return; +#endif + case 2: hb_barrier (); u.format2.collect_glyphs (left_set, right_set, num_glyphs); return; +#ifndef HB_NO_AAT_SHAPE + case 3: hb_barrier (); u.format3.collect_glyphs (left_set, right_set, num_glyphs); return; +#endif default: return; } } @@ -184,9 +188,13 @@ struct KernSubTable union { KernSubTableHeader header; AAT::KerxSubTableFormat0 format0; +#ifndef HB_NO_AAT_SHAPE AAT::KerxSubTableFormat1 format1; +#endif AAT::KerxSubTableFormat2 format2; +#ifndef HB_NO_AAT_SHAPE KernSubTableFormat3 format3; +#endif } u; public: DEFINE_SIZE_MIN (KernSubTableHeader::static_size); @@ -352,9 +360,9 @@ struct kern unsigned int subtable_type = get_type (); TRACE_DISPATCH (this, subtable_type); switch (subtable_type) { - case 0: return_trace (c->dispatch (u.ot, std::forward (ds)...)); + case 0: hb_barrier (); return_trace (c->dispatch (u.ot, std::forward (ds)...)); #ifndef HB_NO_AAT_SHAPE - case 1: return_trace (c->dispatch (u.aat, std::forward (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.aat, std::forward (ds)...)); #endif default: return_trace (c->default_return_value ()); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh index b9baaca2a23..cb75b4af7fc 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh @@ -65,7 +65,8 @@ struct BaseCoordFormat1 DEFINE_SIZE_STATIC (4); }; -struct BaseCoordFormat2 +template +struct BaseCoordFormat2_4 { hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const { @@ -79,8 +80,12 @@ struct BaseCoordFormat2 auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); + hb_codepoint_t *new_gid; + if (!c->plan->glyph_map->has (referenceGlyph, &new_gid)) + return_trace (false); + return_trace (c->serializer->check_assign (out->referenceGlyph, - c->plan->glyph_map->get (referenceGlyph), + *new_gid, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -91,13 +96,14 @@ struct BaseCoordFormat2 } protected: - HBUINT16 format; /* Format identifier--format = 2 */ + HBUINT16 format; /* Format identifier--format = 2 or 4 */ FWORD coordinate; /* X or Y value, in design units */ - HBGlyphID16 referenceGlyph; /* Glyph ID of control glyph */ + typename Types::HBGlyphID + referenceGlyph; /* Glyph ID of control glyph */ HBUINT16 coordPoint; /* Index of contour point on the * reference glyph */ public: - DEFINE_SIZE_STATIC (8); + DEFINE_SIZE_STATIC (6 + Types::HBGlyphID::static_size); }; struct BaseCoordFormat3 @@ -109,8 +115,8 @@ struct BaseCoordFormat3 const Device &device = this+deviceTable; return HB_DIRECTION_IS_HORIZONTAL (direction) - ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store) - : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store); + ? hb_saturate_add (font->em_scale_y (coordinate), device.get_y_delta (font, var_store)) + : hb_saturate_add (font->em_scale_x (coordinate), device.get_x_delta (font, var_store)); } void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const @@ -139,10 +145,12 @@ struct BaseCoordFormat3 return_trace (false); } } - return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, - this, 0, - hb_serialize_context_t::Head, - &c->plan->base_variation_idx_map)); + + out->deviceTable.serialize_copy (c->serializer, deviceTable, + this, 0, + hb_serialize_context_t::Head, + &c->plan->base_variation_idx_map); + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const @@ -175,6 +183,9 @@ struct BaseCoord case 1: hb_barrier (); return u.format1.get_coord (font, direction); case 2: hb_barrier (); return u.format2.get_coord (font, direction); case 3: hb_barrier (); return u.format3.get_coord (font, var_store, direction); +#ifndef HB_NO_BEYOND_64K + case 4: hb_barrier (); return u.format4.get_coord (font, direction); +#endif default:return 0; } } @@ -196,6 +207,9 @@ struct BaseCoord case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward (ds)...)); case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } @@ -209,6 +223,9 @@ struct BaseCoord case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); +#ifndef HB_NO_BEYOND_64K + case 4: hb_barrier (); return_trace (u.format4.sanitize (c)); +#endif default:return_trace (false); } } @@ -217,8 +234,13 @@ struct BaseCoord union { struct { HBUINT16 v; } format; BaseCoordFormat1 format1; - BaseCoordFormat2 format2; + BaseCoordFormat2_4 + format2; BaseCoordFormat3 format3; +#ifndef HB_NO_BEYOND_64K + BaseCoordFormat2_4 + format4; +#endif } u; public: DEFINE_SIZE_UNION (2, format.v); @@ -255,10 +277,10 @@ struct FeatMinMaxRecord TRACE_SUBSET (this); auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); - if (!(out->minCoord.serialize_subset (c, minCoord, base))) - return_trace (false); - return_trace (out->maxCoord.serialize_subset (c, maxCoord, base)); + bool ret = out->minCoord.serialize_subset (c, minCoord, base); + ret |= out->maxCoord.serialize_subset (c, maxCoord, base); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c, const void *base) const @@ -315,9 +337,8 @@ struct MinMax auto *out = c->serializer->start_embed (*this); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); - if (!(out->minCoord.serialize_subset (c, minCoord, this)) || - !(out->maxCoord.serialize_subset (c, maxCoord, this))) - return_trace (false); + bool ret = out->minCoord.serialize_subset (c, minCoord, this); + ret |= out->maxCoord.serialize_subset (c, maxCoord, this); unsigned len = 0; for (const FeatMinMaxRecord& _ : featMinMaxRecords) @@ -326,9 +347,13 @@ struct MinMax if (!c->plan->layout_features.has (feature_tag)) continue; - if (!_.subset (c, this)) return false; - len++; + auto snap = c->serializer->snapshot (); + if (!_.subset (c, this)) c->serializer->revert (snap); + else len++; } + + if (len > 0) ret = true; + if (!ret) return_trace (false); return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -380,11 +405,15 @@ struct BaseValues if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); out->defaultIndex = defaultIndex; + bool ret = false; for (const auto& _ : baseCoords) - if (!subset_offset_array (c, out->baseCoords, this) (_)) - return_trace (false); + { + auto *o = out->baseCoords.serialize_append (c->serializer); + if (unlikely (!o)) return_trace (false); + ret |= o->serialize_subset (c, _, this); + } - return_trace (bool (out->baseCoords)); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -478,16 +507,22 @@ struct BaseScript auto *out = c->serializer->start_embed (*this); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); - if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this)) - return_trace (false); - - if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this)) - return_trace (false); + bool ret = out->baseValues.serialize_subset (c, baseValues, this); + ret |= out->defaultMinMax.serialize_subset (c, defaultMinMax, this); + unsigned len = 0; for (const auto& _ : baseLangSysRecords) - if (!_.subset (c, this)) return_trace (false); + { + auto snap = c->serializer->snapshot (); + if (_.subset (c, this)) { + ret = true; + len++; + } + else c->serializer->revert (snap); + } - return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len, + if (!ret) return_trace (false); + return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, len, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -594,9 +629,12 @@ struct BaseScriptList if (!c->plan->layout_scripts.has (script_tag)) continue; - if (!_.subset (c, this)) return false; - len++; + auto snap = c->serializer->snapshot (); + if (!_.subset (c, this)) c->serializer->revert (snap); + else len++; } + + if (!len) return_trace (false); return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -672,8 +710,9 @@ struct Axis auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); - out->baseTagList.serialize_copy (c->serializer, baseTagList, this); - return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this)); + bool ret = out->baseTagList.serialize_copy (c->serializer, baseTagList, this); + ret |= out->baseScriptList.serialize_subset (c, baseScriptList, this); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -767,16 +806,13 @@ struct BASE if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); out->version = version; - if (has_var_store () && !subset_varstore (c, out)) - return_trace (false); - - if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this)) - return_trace (false); + bool ret = false; + if (version.to_int () >= 0x00010001u) ret |= subset_varstore (c, out); - if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this)) - return_trace (false); + ret |= out->hAxis.serialize_subset (c, hAxis, this); + ret |= out->vAxis.serialize_subset (c, vAxis, this); - return_trace (true); + return_trace (ret); } bool get_baseline (hb_font_t *font, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh index 17971e770c1..064e84c48b9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh @@ -35,9 +35,15 @@ #include "hb-set.hh" #include "hb-bimap.hh" #include "hb-cache.hh" +#include "hb-ot-dual.hh" + +using hb_ot_layout_mapping_cache_t = hb_cache_t<16, 8, 8>; +static_assert (sizeof (hb_ot_layout_mapping_cache_t) == 512, ""); + +using hb_ot_layout_binary_cache_t = hb_cache_t<14, 1, 8>; +static_assert (sizeof (hb_ot_layout_binary_cache_t) == 256, ""); #include "OT/Layout/Common/Coverage.hh" -#include "OT/Layout/types.hh" // TODO(garretrieger): cleanup these after migration. using OT::Layout::Common::Coverage; @@ -59,6 +65,8 @@ static bool ClassDef_remap_and_serialize ( hb_sorted_vector_t &glyph_and_klass, /* IN/OUT */ hb_map_t *klass_map /*IN/OUT*/); +struct ItemVarStoreInstancer; + struct hb_collect_feature_substitutes_with_var_context_t { const hb_map_t *axes_index_tag_map; @@ -74,6 +82,8 @@ struct hb_collect_feature_substitutes_with_var_context_t bool universal; unsigned cur_record_idx; hb_hashmap_t, unsigned> *conditionset_map; + ItemVarStoreInstancer *instancer; + bool all_axes_pinned; }; struct hb_prune_langsys_context_t @@ -143,11 +153,13 @@ struct hb_subset_layout_context_t : const hb_map_t *feature_index_map; const hb_map_t *feature_map_w_duplicates; const hb_hashmap_t *feature_substitutes_map; + const hb_hashmap_t> *lookup_variations; hb_hashmap_t> *feature_record_cond_idx_map; const hb_set_t *catch_all_record_feature_idxes; const hb_hashmap_t> *feature_idx_tag_map; unsigned cur_script_index; + unsigned cur_feature_index; unsigned cur_feature_var_record_idx; hb_subset_layout_context_t (hb_subset_context_t *c_, @@ -155,6 +167,7 @@ struct hb_subset_layout_context_t : subset_context (c_), table_tag (tag_), cur_script_index (0xFFFFu), + cur_feature_index (Index::NOT_FOUND_INDEX), cur_feature_var_record_idx (0u), script_count (0), langsys_count (0), @@ -168,6 +181,7 @@ struct hb_subset_layout_context_t : feature_index_map = &c_->plan->gsub_features; feature_map_w_duplicates = &c_->plan->gsub_features_w_duplicates; feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map; + lookup_variations = &c_->plan->gsub_lookup_variations; feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map; catch_all_record_feature_idxes = &c_->plan->gsub_old_features; feature_idx_tag_map = &c_->plan->gsub_old_feature_idx_tag_map; @@ -179,6 +193,7 @@ struct hb_subset_layout_context_t : feature_index_map = &c_->plan->gpos_features; feature_map_w_duplicates = &c_->plan->gpos_features_w_duplicates; feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map; + lookup_variations = &c_->plan->gpos_lookup_variations; feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map; catch_all_record_feature_idxes = &c_->plan->gpos_old_features; feature_idx_tag_map = &c_->plan->gpos_old_feature_idx_tag_map; @@ -203,6 +218,7 @@ struct hb_collect_variation_indices_context_t : hb_set_t *layout_variation_indices; const hb_set_t *glyph_set; const hb_map_t *gpos_lookups; + hb_hashmap_t> *condition_values = nullptr; hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, const hb_set_t *glyph_set_, @@ -370,13 +386,15 @@ struct serialize_math_record_array_t { serialize_math_record_array_t (hb_serialize_context_t *serialize_context_, OutputArray& out_, - const void *base_) : serialize_context (serialize_context_), - out (out_), base (base_) {} + const void *base_, + const hb_hashmap_t> *variation_map_) : + serialize_context (serialize_context_), + out (out_), base (base_), variation_map (variation_map_) {} template bool operator () (T&& record) { - if (!serialize_context->copy (record, base)) return false; + if (!serialize_context->copy (record, base, variation_map)) return false; out.len++; return true; } @@ -385,6 +403,7 @@ struct serialize_math_record_array_t hb_serialize_context_t *serialize_context; OutputArray &out; const void *base; + const hb_hashmap_t> *variation_map; }; /* @@ -395,8 +414,9 @@ struct template serialize_math_record_array_t operator () (hb_serialize_context_t *serialize_context, OutputArray& out, - const void *base) const - { return serialize_math_record_array_t (serialize_context, out, base); } + const void *base, + const hb_hashmap_t> *variation_map) const + { return serialize_math_record_array_t (serialize_context, out, base, variation_map); } } HB_FUNCOBJ (serialize_math_record_array); @@ -441,7 +461,7 @@ struct IndexArray : Array16Of unsigned int *_count /* IN/OUT */, unsigned int *_indexes /* OUT */) const { - if (_count) + if (_count && _indexes) { + this->as_array ().sub_array (start_offset, _count) | hb_sink (hb_array (_indexes, *_count)) @@ -628,7 +648,7 @@ struct FeatureParamsCharacterVariants unsigned get_characters (unsigned start_offset, unsigned *char_count, hb_codepoint_t *chars) const { - if (char_count) + if (char_count && chars) { + characters.as_array ().sub_array (start_offset, char_count) | hb_sink (hb_array (chars, *char_count)) @@ -638,7 +658,7 @@ struct FeatureParamsCharacterVariants } size_t get_size () const - { return min_size + characters.len * HBUINT24::static_size; } + { return hb_unsigned_mul_add_saturate (characters.len, HBUINT24::static_size, min_size); } void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const { @@ -706,7 +726,7 @@ struct FeatureParams return true; #endif TRACE_SANITIZE (this); - if (tag == HB_TAG ('s','i','z','e')) + if (tag == HB_TAG ('s','i','z','e') && hb_barrier ()) return_trace (u.size.sanitize (c)); if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ return_trace (u.stylisticSet.sanitize (c)); @@ -720,7 +740,7 @@ struct FeatureParams #ifdef HB_NO_LAYOUT_FEATURE_PARAMS return; #endif - if (tag == HB_TAG ('s','i','z','e')) + if (tag == HB_TAG ('s','i','z','e') && hb_barrier ()) return (u.size.collect_name_ids (nameids_to_retain)); if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ return (u.stylisticSet.collect_name_ids (nameids_to_retain)); @@ -730,9 +750,12 @@ struct FeatureParams bool subset (hb_subset_context_t *c, const Tag* tag) const { +#ifdef HB_NO_LAYOUT_FEATURE_PARAMS + return false; +#endif TRACE_SUBSET (this); if (!tag) return_trace (false); - if (*tag == HB_TAG ('s','i','z','e')) + if (*tag == HB_TAG ('s','i','z','e') && hb_barrier ()) return_trace (u.size.subset (c)); if ((*tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ return_trace (u.stylisticSet.subset (c)); @@ -744,7 +767,7 @@ struct FeatureParams #ifndef HB_NO_LAYOUT_FEATURE_PARAMS const FeatureParamsSize& get_size_params (hb_tag_t tag) const { - if (tag == HB_TAG ('s','i','z','e')) + if (tag == HB_TAG ('s','i','z','e') && hb_barrier ()) return u.size; return Null (FeatureParamsSize); } @@ -812,13 +835,26 @@ struct Feature out->featureParams.serialize_subset (c, featureParams, this, tag); - auto it = - + hb_iter (lookupIndex) - | hb_filter (l->lookup_index_map) - | hb_map (l->lookup_index_map) - ; - - out->lookupIndex.serialize (c->serializer, l, it); + hb::shared_ptr *lookup_variations; + if (l->cur_feature_index != Index::NOT_FOUND_INDEX && + l->lookup_variations->has (l->cur_feature_index, &lookup_variations)) + { + auto it = + + hb_iter (**lookup_variations) + | hb_filter (l->lookup_index_map) + | hb_map (l->lookup_index_map) + ; + out->lookupIndex.serialize (c->serializer, l, it); + } + else + { + auto it = + + hb_iter (lookupIndex) + | hb_filter (l->lookup_index_map) + | hb_map (l->lookup_index_map) + ; + out->lookupIndex.serialize (c->serializer, l, it); + } // The decision to keep or drop this feature is already made before we get here // so always retain it. return_trace (true); @@ -900,7 +936,7 @@ struct RecordArrayOf : SortedArray16Of> unsigned int *record_count /* IN/OUT */, hb_tag_t *record_tags /* OUT */) const { - if (record_count) + if (record_count && record_tags) { + this->as_array ().sub_array (start_offset, record_count) | hb_map (&Record::tag) @@ -959,7 +995,9 @@ struct RecordListOfFeature : RecordListOf if (l->feature_substitutes_map->has (_.first, &f)) f_sub = *f; + l->cur_feature_index = _.first; subset_record_array (l, out, this, f_sub) (_.second); + l->cur_feature_index = Index::NOT_FOUND_INDEX; }) ; @@ -1426,7 +1464,7 @@ struct Lookup }; template -using LookupList = List16OfOffsetTo; +using LookupList = List16OfOffsetTo; template struct LookupOffsetList : List16OfOffsetTo @@ -1449,7 +1487,7 @@ struct LookupOffsetList : List16OfOffsetTo bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (List16OfOffset16To::sanitize (c, this)); + return_trace ((List16OfOffsetTo::sanitize (c, this))); } }; @@ -1482,13 +1520,15 @@ static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c, } + if (unlikely (!c->propagate_error (glyph_and_klass, klasses, klass_map))) + return false; + 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); return ClassDef_serialize (c, glyph_and_klass.iter ()); } @@ -1522,7 +1562,7 @@ struct ClassDefFormat1_3 if (unlikely (!it)) { - classFormat = 1; + classFormat = Types::size == 2 ? 1 : 3; startGlyph = 0; classValue.len = 0; return_trace (true); @@ -1551,7 +1591,6 @@ struct ClassDefFormat1_3 const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - const hb_map_t &glyph_map = c->plan->glyph_map_gsub; hb_sorted_vector_t glyph_and_klass; hb_set_t orig_klasses; @@ -1561,7 +1600,7 @@ struct ClassDefFormat1_3 for (const hb_codepoint_t gid : + hb_range (start, end)) { - hb_codepoint_t new_gid = glyph_map[gid]; + hb_codepoint_t new_gid = c->plan->map_gsub_glyph (gid); if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has(gid)) continue; @@ -1574,9 +1613,10 @@ struct ClassDefFormat1_3 if (use_class_zero) { + const hb_set_t& glyphset = *c->plan->glyphset_gsub (); unsigned glyph_count = glyph_filter - ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter)) - : glyph_map.get_population (); + ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) + : glyphset.get_population (); use_class_zero = glyph_count <= glyph_and_klass.length; } if (!ClassDef_remap_and_serialize (c->serializer, @@ -1637,7 +1677,7 @@ struct ClassDefFormat1_3 if (classValue[iter - start]) return true; return false; } - bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const + bool intersects_class (const hb_set_t *glyphs, unsigned klass) const { unsigned int count = classValue.len; if (klass == 0) @@ -1652,7 +1692,7 @@ struct ClassDefFormat1_3 } /* TODO Speed up, using set overlap first? */ /* TODO(iter) Rewrite as dagger. */ - const HBUINT16 *arr = classValue.arrayZ; + const typename Types::HBUINT *arr = classValue.arrayZ; for (unsigned int i = 0; i < count; i++) if (arr[i] == klass && glyphs->has (startGlyph + i)) return true; @@ -1695,6 +1735,17 @@ struct ClassDefFormat1_3 void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const { if (glyphs->is_empty ()) return; + + /* An empty ClassDef assigns class zero to every glyph, so every glyph in + * `glyphs` intersects class zero. Handle it up front: `end_glyph` below + * underflows when startGlyph is zero, and neither comparison can then be + * true. */ + if (!classValue.len) + { + intersect_classes->add (0); + return; + } + hb_codepoint_t end_glyph = startGlyph + classValue.len - 1; if (glyphs->get_min () < startGlyph || glyphs->get_max () > end_glyph) @@ -1712,7 +1763,7 @@ struct ClassDefFormat1_3 HBUINT16 classFormat; /* Format identifier--format = 1 */ typename Types::HBGlyphID startGlyph; /* First GlyphID of the classValueArray */ - typename Types::template ArrayOf + typename Types::template ArrayOf classValue; /* Array of Class Values--one per GlyphID */ public: DEFINE_SIZE_ARRAY (2 + 2 * Types::size, classValue); @@ -1747,7 +1798,7 @@ struct ClassDefFormat2_4 if (unlikely (!it)) { - classFormat = 2; + classFormat = Types::size == 2 ? 2 : 4; rangeRecord.len = 0; return_trace (true); } @@ -1810,7 +1861,6 @@ struct ClassDefFormat2_4 const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - const hb_map_t &glyph_map = c->plan->glyph_map_gsub; const hb_set_t &glyph_set = *c->plan->glyphset_gsub (); hb_sorted_vector_t glyph_and_klass; @@ -1823,7 +1873,7 @@ struct ClassDefFormat2_4 { unsigned klass = get_class (g); if (!klass) continue; - hb_codepoint_t new_gid = glyph_map[g]; + hb_codepoint_t new_gid = c->plan->map_gsub_glyph (g); if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has (g)) continue; glyph_and_klass.push (hb_pair (new_gid, klass)); @@ -1841,7 +1891,7 @@ struct ClassDefFormat2_4 hb_codepoint_t end = hb_min (range.last + 1, num_source_glyphs); for (hb_codepoint_t g = start; g < end; g++) { - hb_codepoint_t new_gid = glyph_map[g]; + hb_codepoint_t new_gid = c->plan->map_gsub_glyph (g); if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has (g)) continue; @@ -1854,7 +1904,7 @@ struct ClassDefFormat2_4 const hb_set_t& glyphset = *c->plan->glyphset_gsub (); unsigned glyph_count = glyph_filter ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) - : glyph_map.get_population (); + : glyphset.get_population (); use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; if (!ClassDef_remap_and_serialize (c->serializer, orig_klasses, @@ -1908,10 +1958,17 @@ struct ClassDefFormat2_4 return hb_any (+ hb_iter (rangeRecord) | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (*glyphs) && range.value; })); } - bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const + bool intersects_class (const hb_set_t *glyphs, unsigned klass) const { if (klass == 0) { + /* An empty ClassDef assigns class zero to every glyph, so it intersects + * class zero as long as there is any glyph at all. The loop below is a + * no-op when there are no ranges, and the `g != HB_SET_VALUE_INVALID` + * guard after it would then wrongly report no intersection. */ + if (!rangeRecord.len) + return !glyphs->is_empty (); + /* Match if there's any glyph that is not listed! */ hb_codepoint_t g = HB_SET_VALUE_INVALID; hb_codepoint_t last = HB_SET_VALUE_INVALID; @@ -1993,6 +2050,16 @@ struct ClassDefFormat2_4 { if (glyphs->is_empty ()) return; + /* An empty ClassDef assigns class zero to every glyph, so every glyph in + * `glyphs` intersects class zero. Handle it up front: the loops below are + * no-ops when there are no ranges, and the `g != HB_SET_VALUE_INVALID` + * guard would then wrongly skip adding class zero. */ + if (!rangeRecord.len) + { + intersect_classes->add (0); + return; + } + hb_codepoint_t g = HB_SET_VALUE_INVALID; for (auto &range : rangeRecord) { @@ -2073,25 +2140,25 @@ struct ClassDef TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - auto it = + it_with_class_zero | hb_filter (hb_second); + auto glyphs = + it_with_class_zero | hb_filter (hb_second); unsigned format = 2; hb_codepoint_t glyph_max = 0; - if (likely (it)) + unsigned class_max = 0; + if (likely (glyphs)) { - hb_codepoint_t glyph_min = (*it).first; + hb_codepoint_t glyph_min = (*glyphs).first; glyph_max = glyph_min; - unsigned num_glyphs = 0; unsigned num_ranges = 1; hb_codepoint_t prev_gid = glyph_min; - unsigned prev_klass = (*it).second; + unsigned prev_klass = (*glyphs).second; - for (const auto gid_klass_pair : it) + for (const auto gid_klass_pair : + glyphs) { hb_codepoint_t cur_gid = gid_klass_pair.first; unsigned cur_klass = gid_klass_pair.second; - num_glyphs++; + if (cur_klass > class_max) class_max = cur_klass; if (cur_gid == glyph_min) continue; if (cur_gid > glyph_max) glyph_max = cur_gid; if (cur_gid != prev_gid + 1 || @@ -2102,31 +2169,43 @@ struct ClassDef prev_klass = cur_klass; } - if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3) - format = 1; - } - + uint64_t best_size = UINT64_MAX; + unsigned glyph_span = glyph_max - glyph_min + 1; + auto consider = [&] (unsigned candidate, uint64_t size) + { + if (size >= best_size) return; + best_size = size; + format = candidate; + }; + + if (glyph_max <= 0xFFFFu && glyph_span <= 0xFFFFu && class_max <= 0xFFFFu) + consider (1, 6 + (uint64_t) HBUINT16::static_size * glyph_span); + if (glyph_max <= 0xFFFFu && num_ranges <= 0xFFFFu && class_max <= 0xFFFFu) + consider (2, 4 + (uint64_t) num_ranges * + (2 * HBGlyphID16::static_size + HBUINT16::static_size)); #ifndef HB_NO_BEYOND_64K - if (glyph_max > 0xFFFFu) - u.format.v += 2; - if (unlikely (glyph_max > 0xFFFFFFu)) -#else - if (unlikely (glyph_max > 0xFFFFu)) + if (glyph_max <= 0xFFFFFFu && glyph_span <= 0xFFFFFFu && class_max <= 0xFFFFFFu) + consider (3, 8 + (uint64_t) HBUINT24::static_size * glyph_span); + if (glyph_max <= 0xFFFFFFu && num_ranges <= 0xFFFFFFu && class_max <= 0xFFFFu) + consider (4, 5 + (uint64_t) num_ranges * + (2 * HBGlyphID24::static_size + HBUINT16::static_size)); #endif - { - c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW); - return_trace (false); + if (unlikely (best_size == UINT64_MAX)) + { + c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW); + return_trace (false); + } } u.format.v = format; switch (u.format.v) { - case 1: hb_barrier (); return_trace (u.format1.serialize (c, it)); - case 2: hb_barrier (); return_trace (u.format2.serialize (c, it)); + case 1: hb_barrier (); return_trace (u.format1.serialize (c, + it_with_class_zero | hb_filter (hb_second))); + case 2: hb_barrier (); return_trace (u.format2.serialize (c, + it_with_class_zero | hb_filter (hb_second))); #ifndef HB_NO_BEYOND_64K - case 3: hb_barrier (); return_trace (u.format3.serialize (c, it)); - case 4: hb_barrier (); return_trace (u.format4.serialize (c, it)); + case 3: hb_barrier (); return_trace (u.format3.serialize (c, + it_with_class_zero | hb_filter (hb_second))); + case 4: hb_barrier (); return_trace (u.format4.serialize (c, + it_with_class_zero | hb_filter (hb_second))); #endif default:return_trace (false); } @@ -2411,6 +2490,9 @@ struct delta_row_encoding_t bool is_empty () const { return !items; } + bool in_error () const + { return chars.in_error () || items.in_error (); } + static inline unsigned get_chars_overhead (unsigned num_columns) { unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header @@ -2527,10 +2609,25 @@ struct SparseVarRegionAxis return_trace (c->check_struct (this)); } - bool serialize (hb_serialize_context_t *c) const + bool serialize (hb_serialize_context_t *c, + const SparseVarRegionAxis *src, + const hb_map_t *axis_map) { TRACE_SERIALIZE (this); - return_trace (c->embed (this)); + auto *out = c->embed (src); + if (unlikely (!out)) return_trace (false); + if (axis_map) + { + if (unlikely (!axis_map->has (out->axisIndex))) + { + c->err (HB_SERIALIZE_ERROR_OTHER); + return_trace (false); + } + if (unlikely (!c->check_assign (out->axisIndex, axis_map->get (out->axisIndex), + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + } + return_trace (true); } public: @@ -2544,9 +2641,7 @@ struct hb_scalar_cache_t { private: static constexpr unsigned STATIC_LENGTH = 128; - static constexpr int INVALID = INT_MIN; - static constexpr float MULTIPLIER = 1 << ((sizeof (int) * 8) - 2); - static constexpr float DIVISOR = 1.f / MULTIPLIER; + static constexpr float INVALID = NAN; public: hb_scalar_cache_t () {} @@ -2611,16 +2706,10 @@ struct hb_scalar_cache_t } auto *values = &static_values[0]; auto *cached_value = &values[i]; - // Super hot. Most common path is that we have a cached value of 0. - int v = *cached_value; - if (likely (!v)) - { - *value = 0.f; - return true; - } - if (v == INVALID) + float v = *cached_value; + if (std::isnan (v)) return false; - *value = v * DIVISOR; + *value = v; return true; } @@ -2630,12 +2719,13 @@ struct hb_scalar_cache_t if (unlikely (i >= length)) return; auto *values = &static_values[0]; auto *cached_value = &values[i]; - *cached_value = roundf(value * MULTIPLIER); + *cached_value = value; } - private: + public: unsigned length; - mutable hb_atomic_t static_values[STATIC_LENGTH]; + private: + mutable hb_atomic_t static_values[STATIC_LENGTH]; }; struct VarRegionList @@ -2791,7 +2881,10 @@ struct VarRegionList return !regions.in_error (); } - size_t get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; } + size_t get_size () const + { return hb_unsigned_add_saturate (min_size, + hb_unsigned_mul_saturate (VarRegionAxis::static_size, + axisCount, regionCount)); } public: HBUINT16 axisCount; @@ -2803,21 +2896,79 @@ struct VarRegionList DEFINE_SIZE_ARRAY (4, axesZ); }; -struct SparseVariationRegion : Array16Of +/* Whether a variation region is unreachable given per-axis reachable + * final-coordinate ranges, in F2Dot14 units (avar2 partial-instancing + * culling; see hb_subset_plan_t::avar2_reachable_ranges). A region is dead + * if some axis's tent evaluates to zero over the axis's entire reachable + * range. Mirrors the runtime evaluation: invalid tents evaluate as + * constant 1 and never kill a region. */ +static inline bool +_hb_avar2_region_is_dead (const hb_hashmap_t &axis_tuples, + const hb_hashmap_t &reachable_ranges) +{ + for (auto _ : axis_tuples) + { + Triple *range; + if (!reachable_ranges.has (_.first, &range)) continue; + const Triple &tent = _.second; + int start = (int) roundf ((float) tent.minimum * 16384.f); + int peak = (int) roundf ((float) tent.middle * 16384.f); + int end = (int) roundf ((float) tent.maximum * 16384.f); + if (!peak) continue; + if (start > peak || peak > end) continue; + if (start < 0 && end > 0) continue; + int lo = (int) roundf ((float) range->minimum * 16384.f); + int hi = (int) roundf ((float) range->maximum * 16384.f); + /* Strict comparisons: the scalar is 1 (not 0) at v == peak, so a tent + * whose peak sits exactly on the range boundary is still live there. + * (Reachable ranges are padded by one F2Dot14 unit at their producer, + * which already covers this; strictness keeps the predicate correct on + * its own terms.) */ + if (hi < start || lo > end) + return true; + } + return false; +} + +struct SparseVariationRegion { float evaluate (const int *coords, unsigned int coord_len) const { float v = 1.f; - unsigned int count = len; + unsigned int count = axes.len; for (unsigned int i = 0; i < count; i++) { - float factor = arrayZ[i].evaluate (coords, coord_len); + float factor = (this+axes[i]).evaluate (coords, coord_len); if (factor == 0.f) return 0.; v *= factor; } return v; } + + bool serialize (hb_serialize_context_t *c, + const SparseVariationRegion *src, + const hb_map_t *axis_map) + { + TRACE_SERIALIZE (this); + if (unlikely (!axes.serialize (c, (unsigned) src->axes.len))) return_trace (false); + for (unsigned i = 0; i < axes.len; i++) + if (unlikely (src->axes[i].is_null () || + !axes[i].serialize_serialize (c, &(src+src->axes[i]), axis_map))) + return_trace (false); + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (axes.sanitize (c, this)); + } + + protected: + Array16Of> axes; + public: + DEFINE_SIZE_ARRAY (2, axes); }; struct SparseVarRegionList @@ -2849,11 +3000,33 @@ struct SparseVarRegionList return_trace (regions.sanitize (c, this)); } + bool serialize (hb_serialize_context_t *c, + const SparseVarRegionList *src, + const hb_inc_bimap_t ®ion_map, + const hb_map_t *axis_map) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + regions.len = region_map.get_population (); + if (unlikely (!c->extend (regions))) return_trace (false); + + for (unsigned i = 0; i < regions.len; i++) + { + unsigned old_index = region_map.backward (i); + if (unlikely (old_index >= src->regions.len || + !regions[i].serialize_serialize (c, + &(src+src->regions[old_index]), + axis_map))) + return_trace (false); + } + return_trace (true); + } + public: - Array16Of> + Array32Of> regions; public: - DEFINE_SIZE_ARRAY (2, regions); + DEFINE_SIZE_ARRAY (4, regions); }; @@ -2868,16 +3041,16 @@ struct VarData unsigned get_region_index (unsigned i) const { return i >= regionIndices.len ? -1 : regionIndices[i]; } - unsigned int get_row_size () const + size_t get_row_size () const { return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); } size_t get_size () const - { return min_size - - regionIndices.min_size + regionIndices.get_size () - + itemCount * get_row_size (); - } + { return hb_unsigned_add_saturate (min_size - regionIndices.min_size, + regionIndices.get_size (), + hb_unsigned_mul_saturate (itemCount, get_row_size ())); } - float _get_delta (unsigned int inner, + template + Float _get_delta (unsigned int inner, const int *coords, unsigned int coord_count, const VarRegionList ®ions, hb_scalar_cache_t *cache = nullptr) const @@ -2893,7 +3066,7 @@ struct VarData const HBUINT8 *bytes = get_delta_bytes (); const HBUINT8 *row = bytes + inner * get_row_size (); - float delta = 0.; + Float delta = 0; unsigned int i = 0; const HBINT32 *lcursor = reinterpret_cast (row); @@ -2901,7 +3074,7 @@ struct VarData { float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); if (scalar) - delta += scalar * *lcursor; + delta += (Float) scalar * (int) *lcursor; lcursor++; } const HBINT16 *scursor = reinterpret_cast (lcursor); @@ -2909,7 +3082,7 @@ struct VarData { float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); if (scalar) - delta += scalar * *scursor; + delta += (Float) scalar * (int) *scursor; scursor++; } const HBINT8 *bcursor = reinterpret_cast (scursor); @@ -2917,22 +3090,23 @@ struct VarData { float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); if (scalar) - delta += scalar * *bcursor; + delta += (Float) scalar * (int) *bcursor; bcursor++; } return delta; } + template HB_ALWAYS_INLINE - float get_delta (unsigned int inner, + Float get_delta (unsigned int inner, const int *coords, unsigned int coord_count, const VarRegionList ®ions, hb_scalar_cache_t *cache = nullptr) const { unsigned int count = regionIndices.len; - if (!count) return 0.f; // This is quite common, so optimize it. - return _get_delta (inner, coords, coord_count, regions, cache); + if (!count) return Float (0); // This is quite common, so optimize it. + return _get_delta (inner, coords, coord_count, regions, cache); } void get_region_scalars (const int *coords, unsigned int coord_count, @@ -2975,8 +3149,8 @@ struct VarData HB_SERIALIZE_ERROR_INT_OVERFLOW))) return_trace (false); - int min_threshold = has_long ? -65536 : -128; - int max_threshold = has_long ? +65535 : +127; + int min_threshold = has_long ? -32768 : -128; + int max_threshold = has_long ? +32767 : +127; enum delta_size_t { kZero=0, kNonWord, kWord }; hb_vector_t delta_sz; unsigned num_regions = rows[0]->length; @@ -3044,7 +3218,8 @@ struct VarData bool serialize (hb_serialize_context_t *c, const VarData *src, const hb_inc_bimap_t &inner_map, - const hb_inc_bimap_t ®ion_map) + const hb_inc_bimap_t ®ion_map, + const hb_set_t *culled_regions = nullptr) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); @@ -3073,7 +3248,7 @@ struct VarData for (unsigned old_gid : inner_map.keys()) { int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size); - if (delta < -65536 || 65535 < delta) + if (delta < -32768 || 32767 < delta) { has_long = true; break; @@ -3082,13 +3257,15 @@ struct VarData } } - signed min_threshold = has_long ? -65536 : -128; - signed max_threshold = has_long ? +65535 : +127; + signed min_threshold = has_long ? -32768 : -128; + signed max_threshold = has_long ? +32767 : +127; for (r = 0; r < ri_count; r++) { bool short_circuit = src_long_words == has_long && src_word_count <= r; delta_sz[r] = kZero; + if (culled_regions && culled_regions->has (src->regionIndices[r])) + continue; /* unreachable region: drop its column */ for (unsigned old_gid : inner_map.keys()) { int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size); @@ -3244,18 +3421,19 @@ struct VarData struct MultiVarData { size_t get_size () const - { return min_size - - regionIndices.min_size + regionIndices.get_size () - + StructAfter (regionIndices).get_size (); - } + { return hb_unsigned_add_saturate (min_size - regionIndices.min_size, + regionIndices.get_size ()); } + + const TupleList &get_delta_sets () const + { return this+StructAfter (regionIndices); } void get_delta (unsigned int inner, const int *coords, unsigned int coord_count, const SparseVarRegionList ®ions, - hb_array_t out, + hb_array_t out, hb_scalar_cache_t *cache = nullptr) const { - auto &deltaSets = StructAfter (regionIndices); + auto &deltaSets = get_delta_sets (); auto values_iter = deltaSets.fetcher (inner); unsigned regionCount = regionIndices.len; @@ -3288,15 +3466,67 @@ struct MultiVarData format == 1 && regionIndices.sanitize (c) && hb_barrier () && - StructAfter (regionIndices).sanitize (c)); + StructAfter (regionIndices).sanitize (c, this)); + } + + unsigned get_item_count () const + { return get_delta_sets ().count; } + + void collect_region_refs (hb_set_t ®ion_indices) const + { + for (unsigned region : regionIndices) + region_indices.add (region); + } + + bool serialize (hb_serialize_context_t *c, + const MultiVarData *src, + const hb_inc_bimap_t &inner_map, + const hb_inc_bimap_t ®ion_map) + { + TRACE_SERIALIZE (this); + unsigned region_count = src->regionIndices.len; + unsigned header_size = HBUINT8::static_size + + Array16Of::min_size + + region_count * HBUINT16::static_size + + HBUINT32::static_size; + if (unlikely (!c->extend_size (this, header_size, false))) + return_trace (false); + format = 1; + regionIndices.len = region_count; + for (unsigned i = 0; i < regionIndices.len; i++) + { + unsigned old_region = src->regionIndices[i]; + if (unlikely (!region_map.has (old_region))) + return_trace (false); + regionIndices[i] = region_map.get (old_region); + } + + const auto &src_delta_sets = src->get_delta_sets (); + hb_vector_t delta_sets; + unsigned data_size = 0; + if (unlikely (!delta_sets.alloc_exact (inner_map.get_population ()))) + return_trace (false); + for (unsigned i = 0; i < inner_map.get_population (); i++) + { + unsigned old_inner = inner_map.backward (i); + if (unlikely (old_inner >= src_delta_sets.count)) return_trace (false); + hb_ubytes_t bytes = static_cast (src_delta_sets)[old_inner]; + data_size = hb_unsigned_add_saturate (data_size, bytes.length); + delta_sets.push (bytes); + } + if (unlikely (data_size == UINT_MAX || delta_sets.in_error ())) + return_trace (false); + + auto &out_delta_sets = StructAfter (regionIndices); + return_trace (out_delta_sets.serialize_serialize (c, delta_sets.iter (), &data_size)); } protected: HBUINT8 format; // 1 Array16Of regionIndices; - TupleList deltaSetsX; + Offset32To deltaSetsX; public: - DEFINE_SIZE_MIN (8); + DEFINE_SIZE_MIN (7); }; struct ItemVariationStore @@ -3317,37 +3547,52 @@ struct ItemVariationStore } private: - float get_delta (unsigned int outer, unsigned int inner, + template + Float get_delta (unsigned int outer, unsigned int inner, const int *coords, unsigned int coord_count, hb_scalar_cache_t *cache = nullptr) const { #ifdef HB_NO_VAR - return 0.f; + return Float (0); #endif if (unlikely (outer >= dataSets.len)) - return 0.f; + return Float (0); - return (this+dataSets[outer]).get_delta (inner, + return (this+dataSets[outer]).get_delta (inner, coords, coord_count, this+regions, cache); } public: - float get_delta (unsigned int index, + bool has_delta_set (unsigned int index) const + { +#ifdef HB_NO_VAR + return false; +#endif + + unsigned int outer = index >> 16; + unsigned int inner = index & 0xFFFF; + return outer < dataSets.len && + inner < (this+dataSets[outer]).get_item_count (); + } + + template + Float get_delta (unsigned int index, const int *coords, unsigned int coord_count, hb_scalar_cache_t *cache = nullptr) const { unsigned int outer = index >> 16; unsigned int inner = index & 0xFFFF; - return get_delta (outer, inner, coords, coord_count, cache); + return get_delta (outer, inner, coords, coord_count, cache); } - float get_delta (unsigned int index, + template + Float get_delta (unsigned int index, hb_array_t coords, hb_scalar_cache_t *cache = nullptr) const { - return get_delta (index, + return get_delta (index, coords.arrayZ, coords.length, cache); } @@ -3398,7 +3643,8 @@ struct ItemVariationStore bool serialize (hb_serialize_context_t *c, const ItemVariationStore *src, - const hb_array_t &inner_maps) + const hb_array_t &inner_maps, + const hb_set_t *culled_regions = nullptr) { TRACE_SERIALIZE (this); #ifdef HB_NO_VAR @@ -3425,6 +3671,9 @@ struct ItemVariationStore region_indices.del_range ((src_regions).regionCount, hb_set_t::INVALID); + if (culled_regions) + region_indices.subtract (*culled_regions); + /* TODO use constructor when our data-structures support that. */ hb_inc_bimap_t region_map; + hb_iter (region_indices) @@ -3446,7 +3695,8 @@ struct ItemVariationStore { if (!inner_maps[i].get_population ()) continue; if (unlikely (!dataSets[set_index++] - .serialize_serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map))) + .serialize_serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map, + culled_regions))) return_trace (false); } @@ -3478,6 +3728,30 @@ struct ItemVariationStore return_trace (out); } + /* Collect regions that a partial avar2 instance can never reach, per the + * plan's reachable final-coordinate ranges. */ + bool collect_dead_regions (const hb_map_t &axes_old_index_tag_map, + const hb_hashmap_t &reachable_ranges, + hb_set_t &dead_regions /* OUT */) const + { +#ifndef HB_NO_VAR + if (!reachable_ranges.get_population ()) return true; + const VarRegionList ®ion_list = this+regions; + unsigned count = region_list.regionCount; + for (unsigned i = 0; i < count; i++) + { + hb_hashmap_t axis_tuples; + if (!region_list.get_var_region (i, axes_old_index_tag_map, axis_tuples)) + return false; + if (_hb_avar2_region_is_dead (axis_tuples, reachable_ranges)) + dead_regions.add (i); + } + return !dead_regions.in_error (); +#else + return true; +#endif + } + bool subset (hb_subset_context_t *c, const hb_array_t &inner_maps) const { TRACE_SUBSET (this); @@ -3488,7 +3762,16 @@ struct ItemVariationStore ItemVariationStore *varstore_prime = c->serializer->start_embed (); if (unlikely (!varstore_prime)) return_trace (false); - varstore_prime->serialize (c->serializer, this, inner_maps); + /* avar2 partial instancing: cull unreachable regions. */ + hb_set_t dead_regions; + if (c->plan->has_avar2) + if (!collect_dead_regions (c->plan->axes_old_index_tag_map, + c->plan->avar2_reachable_ranges, + dead_regions)) + return_trace (false); + + varstore_prime->serialize (c->serializer, this, inner_maps, + dead_regions.get_population () ? &dead_regions : nullptr); return_trace ( !c->serializer->in_error() @@ -3573,7 +3856,7 @@ struct MultiItemVariationStore private: void get_delta (unsigned int outer, unsigned int inner, const int *coords, unsigned int coord_count, - hb_array_t out, + hb_array_t out, hb_scalar_cache_t *cache = nullptr) const { #ifdef HB_NO_VAR @@ -3593,7 +3876,7 @@ struct MultiItemVariationStore public: void get_delta (unsigned int index, const int *coords, unsigned int coord_count, - hb_array_t out, + hb_array_t out, hb_scalar_cache_t *cache = nullptr) const { unsigned int outer = index >> 16; @@ -3602,7 +3885,7 @@ struct MultiItemVariationStore } void get_delta (unsigned int index, hb_array_t coords, - hb_array_t out, + hb_array_t out, hb_scalar_cache_t *cache = nullptr) const { return get_delta (index, @@ -3625,6 +3908,80 @@ struct MultiItemVariationStore dataSets.sanitize (c, this)); } + bool create_subset_plan (const hb_set_t &var_indices, + hb_vector_t *inner_maps, + hb_map_t *varidx_map) const + { + if (unlikely (!inner_maps->resize (dataSets.len))) return false; + for (hb_codepoint_t var_idx : var_indices) + { + unsigned outer = var_idx >> 16; + unsigned inner = var_idx & 0xFFFFu; + if (unlikely (outer >= dataSets.len || + inner >= (this+dataSets[outer]).get_item_count ())) + return false; + (*inner_maps)[outer].add (inner); + } + + unsigned new_outer = 0; + for (unsigned outer = 0; outer < inner_maps->length; outer++) + { + const hb_inc_bimap_t &inner_map = (*inner_maps)[outer]; + if (!inner_map.get_population ()) continue; + if (unlikely (inner_map.in_error ())) return false; + for (unsigned new_inner = 0; + new_inner < inner_map.get_population (); + new_inner++) + { + unsigned old_inner = inner_map.backward (new_inner); + varidx_map->set ((outer << 16) | old_inner, + (new_outer << 16) | new_inner); + } + new_outer++; + } + return !inner_maps->in_error () && !varidx_map->in_error (); + } + + bool serialize (hb_serialize_context_t *c, + const MultiItemVariationStore *src, + const hb_array_t &inner_maps, + const hb_map_t *axis_map) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this) || + inner_maps.length < src->dataSets.len)) + return_trace (false); + format = 1; + + const auto &src_regions = src+src->regions; + hb_set_t region_indices; + unsigned set_count = 0; + for (unsigned i = 0; i < src->dataSets.len; i++) + { + if (!inner_maps[i].get_population ()) continue; + set_count++; + (src+src->dataSets[i]).collect_region_refs (region_indices); + } + region_indices.del_range (src_regions.regions.len, hb_set_t::INVALID); + hb_inc_bimap_t region_map; + region_map.add_set (®ion_indices); + if (unlikely (region_indices.in_error () || region_map.in_error () || + !regions.serialize_serialize (c, &src_regions, region_map, axis_map))) + return_trace (false); + + dataSets.len = set_count; + if (unlikely (!c->extend (dataSets))) return_trace (false); + unsigned set_index = 0; + for (unsigned i = 0; i < src->dataSets.len; i++) + { + if (!inner_maps[i].get_population ()) continue; + if (unlikely (!dataSets[set_index++].serialize_serialize ( + c, &(src+src->dataSets[i]), inner_maps[i], region_map))) + return_trace (false); + } + return_trace (true); + } + protected: HBUINT16 format; // 1 Offset32To regions; @@ -3639,7 +3996,7 @@ struct DeltaSetIndexMapFormat01 friend struct DeltaSetIndexMap; size_t get_size () const - { return min_size + mapCount * get_width (); } + { return hb_unsigned_mul_add_saturate (mapCount, get_width (), min_size); } private: DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const @@ -3838,6 +4195,10 @@ struct ItemVarStoreInstancer { if (!varStore) varStore = &Null(ItemVariationStore); + /* Like hb_font_t::has_nonzero_coords, treat explicit all-zero coordinates + * as the default instance, which uses unadjusted values (OFF 7.1). */ + if (!hb_any (coords)) + this->coords = {}; } operator bool () const { return varStore && bool (coords); } @@ -3846,14 +4207,22 @@ struct ItemVarStoreInstancer { return (*this) (varIdx); } float operator() (uint32_t varIdx, unsigned short offset = 0) const + { return get_delta (varIdx, offset); } + + double get_condition_delta (uint32_t varIdx) const + { return get_delta (varIdx); } + + template + Float get_delta (uint32_t varIdx, unsigned short offset = 0) const { + /* Ordinary stores do not apply deltas at the default instance. */ if (!coords || varIdx == VarIdx::NO_VARIATION) - return 0.f; + return Float (0); varIdx += offset; if (varIdxMap) varIdx = varIdxMap->map (varIdx); - return varStore->get_delta (varIdx, coords, cache); + return varStore->get_delta (varIdx, coords, cache); } const ItemVariationStore *varStore; @@ -3874,18 +4243,22 @@ struct MultiItemVarStoreInstancer varStore = &Null(MultiItemVariationStore); } - operator bool () const { return varStore && bool (coords); } + operator bool () const { return varStore; } - float operator[] (uint32_t varIdx) const + double get_condition_delta (uint32_t varIdx) const + { return (double) (*this)[varIdx]; } + + double operator[] (uint32_t varIdx) const { - float v = 0; + double v = 0; (*this) (hb_array (&v, 1), varIdx); return v; } - void operator() (hb_array_t out, uint32_t varIdx, unsigned short offset = 0) const + void operator() (hb_array_t out, uint32_t varIdx, unsigned short offset = 0) const { - if (coords && varIdx != VarIdx::NO_VARIATION) + /* Static VARC fonts can have constant deltas even with empty coordinates. */ + if (varIdx != VarIdx::NO_VARIATION) { varIdx += offset; if (varIdxMap) @@ -3894,7 +4267,7 @@ struct MultiItemVarStoreInstancer } else for (unsigned i = 0; i < out.length; i++) - out.arrayZ[i] = 0.f; + out.arrayZ[i] = 0.; } const MultiItemVariationStore *varStore; @@ -3915,6 +4288,14 @@ enum Cond_with_Var_flag_t DROP_RECORD_WITH_VAR = 3, }; +enum lookup_condition_subset_result_t +{ + LOOKUP_CONDITION_SUBSET_ERROR, + LOOKUP_CONDITION_SUBSET_FALSE, + LOOKUP_CONDITION_SUBSET_TRUE, + LOOKUP_CONDITION_SUBSET_KEEP, +}; + struct Condition; template @@ -4025,6 +4406,7 @@ struct ConditionAxisRange return filterRangeMinValue.to_int () <= coord && coord <= filterRangeMaxValue.to_int (); } + public: bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -4047,8 +4429,31 @@ struct ConditionValue bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (varIdx == VarIdx::NO_VARIATION) + return_trace (true); + + hb_pair_t *condition_value; + if (c->plan->layout_condition_idx_value_map.has ((uintptr_t) this, &condition_value)) + { + out->defaultValue = condition_value->second; + out->varIdx = condition_value->first; + return_trace (true); + } + + hb_pair_t *new_varidx_delta; + if (!c->plan->layout_variation_idx_delta_map.has (varIdx, &new_varidx_delta)) + return_trace (false); + + if (unlikely (!c->serializer->check_assign ( + out->defaultValue, + defaultValue + hb_second (*new_varidx_delta), + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + out->varIdx = hb_first (*new_varidx_delta); + return_trace (true); } private: @@ -4056,20 +4461,12 @@ struct ConditionValue bool evaluate (const int *coords, unsigned int coord_len, Instancer *instancer) const { - float value = defaultValue; - value += (*instancer)[varIdx]; + double value = defaultValue; + value += instancer->get_condition_delta (varIdx); return value > 0; } - bool subset (hb_subset_context_t *c, - hb_subset_layout_context_t *l, - bool insert_catch_all) const - { - TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); - } - + public: bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -4091,8 +4488,24 @@ struct ConditionAnd bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + auto *out = c->serializer->start_embed (this); + if (unlikely (!out || !c->serializer->extend_min (out))) + return_trace (false); + out->format = format; + + for (const auto &offset : conditions) + { + if (offset.is_null ()) + { + auto *out_offset = out->conditions.serialize_append (c->serializer); + if (unlikely (!out_offset)) return_trace (false); + *out_offset = 0; + } + else if (unlikely (!subset_offset_array (c, out->conditions, this) (offset))) + return_trace (false); + } + + return_trace (true); } private: @@ -4109,15 +4522,7 @@ struct ConditionAnd return true; } - bool subset (hb_subset_context_t *c, - hb_subset_layout_context_t *l, - bool insert_catch_all) const - { - TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); - } - + public: bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -4138,8 +4543,24 @@ struct ConditionOr bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + auto *out = c->serializer->start_embed (this); + if (unlikely (!out || !c->serializer->extend_min (out))) + return_trace (false); + out->format = format; + + for (const auto &offset : conditions) + { + if (offset.is_null ()) + { + auto *out_offset = out->conditions.serialize_append (c->serializer); + if (unlikely (!out_offset)) return_trace (false); + *out_offset = 0; + } + else if (unlikely (!subset_offset_array (c, out->conditions, this) (offset))) + return_trace (false); + } + + return_trace (true); } private: @@ -4156,15 +4577,7 @@ struct ConditionOr return false; } - bool subset (hb_subset_context_t *c, - hb_subset_layout_context_t *l, - bool insert_catch_all) const - { - TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); - } - + public: bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -4185,9 +4598,15 @@ struct ConditionNegate bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); - } + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + if (condition.is_null ()) + { + out->condition = 0; + return_trace (true); + } + return_trace (out->condition.serialize_subset (c, condition, this)); + } private: template @@ -4199,15 +4618,7 @@ struct ConditionNegate instancer); } - bool subset (hb_subset_context_t *c, - hb_subset_layout_context_t *l, - bool insert_catch_all) const - { - TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); - } - + public: bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -4223,11 +4634,31 @@ struct ConditionNegate struct Condition { + friend struct ConditionSet; + + static bool serialize_constant (hb_serialize_context_t *c, bool value) + { + auto *out = c->start_embed (); + if (unlikely (!out || !c->extend_min (out))) return false; + out->format = 2; + out->defaultValue = value ? 1 : 0; + out->varIdx = VarIdx::NO_VARIATION; + return true; + } + + lookup_condition_subset_result_t subset_lookup_condition ( + hb_subset_context_t *c, + unsigned depth = HB_MAX_NESTING_LEVEL, + bool materialize_true = false) const; + template bool evaluate (const int *coords, unsigned int coord_len, Instancer *instancer) const { switch (u.format.v) { + /* A null condition offset resolves to the nil Condition, whose reserved + * format 0 represents the True condition required by the specification. */ + case 0: return true; case 1: hb_barrier (); return u.format1.evaluate (coords, coord_len, instancer); case 2: hb_barrier (); return u.format2.evaluate (coords, coord_len, instancer); case 3: hb_barrier (); return u.format3.evaluate (coords, coord_len, instancer); @@ -4238,13 +4669,65 @@ struct Condition } Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c, - hb_map_t *condition_map /* OUT */) const + hb_map_t *condition_map /* OUT */, + unsigned depth = HB_MAX_NESTING_LEVEL) const { + if (unlikely (!depth)) + { + c->apply = false; + return DROP_RECORD_WITH_VAR; + } + switch (u.format.v) { + case 0: return KEEP_RECORD_WITH_VAR; case 1: hb_barrier (); return u.format1.keep_with_variations (c, condition_map); - // TODO(subset) - default: c->apply = false; return KEEP_COND_WITH_VAR; + case 2: case 3: case 4: case 5: break; + default: c->apply = false; return DROP_RECORD_WITH_VAR; } + + hb_barrier (); + bool applies = evaluate (c->instancer->coords.arrayZ, + c->instancer->coords.length, c->instancer); + c->apply &= applies; + if (c->all_axes_pinned) + return applies ? DROP_COND_WITH_VAR : DROP_RECORD_WITH_VAR; + + if (u.format.v == 2) + return u.format2.varIdx == VarIdx::NO_VARIATION || + !c->instancer->varStore->has_delta_set (u.format2.varIdx) ? + (applies ? KEEP_RECORD_WITH_VAR : DROP_RECORD_WITH_VAR) : + KEEP_COND_WITH_VAR; + + auto classify_child = [c, condition_map, depth] (const Condition &child) + { + auto child_context = *c; + child_context.apply = true; + return child.keep_with_variations (&child_context, condition_map, depth - 1); + }; + + if (u.format.v == 5) + { + auto result = classify_child (&u.format5 + u.format5.condition); + return result == DROP_RECORD_WITH_VAR ? KEEP_RECORD_WITH_VAR : + result == KEEP_COND_WITH_VAR ? KEEP_COND_WITH_VAR : + DROP_RECORD_WITH_VAR; + } + + bool is_and = u.format.v == 3; + bool variable = false; + const auto &conditions = is_and ? u.format3.conditions : u.format4.conditions; + const void *base = is_and ? (const void *) &u.format3 : (const void *) &u.format4; + for (const auto &offset : conditions) + { + auto result = classify_child (base + offset); + if (is_and && result == DROP_RECORD_WITH_VAR) + return DROP_RECORD_WITH_VAR; + if (!is_and && (result == DROP_COND_WITH_VAR || result == KEEP_RECORD_WITH_VAR)) + return KEEP_RECORD_WITH_VAR; + variable |= result == KEEP_COND_WITH_VAR; + } + return variable ? KEEP_COND_WITH_VAR : + is_and ? KEEP_RECORD_WITH_VAR : DROP_RECORD_WITH_VAR; } template @@ -4265,18 +4748,27 @@ struct Condition bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.v.sanitize (c)) return_trace (false); - hb_barrier (); - switch (u.format.v) { - case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); - case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); - case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); - case 4: hb_barrier (); return_trace (u.format4.sanitize (c)); - case 5: hb_barrier (); return_trace (u.format5.sanitize (c)); - default:return_trace (true); - } + + if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL))) + return_trace (c->no_dispatch_return_value ()); + + return_trace (c->end_recursion (this->dispatch (c))); } + bool collect_var_indices (hb_set_t *var_indices, + unsigned depth = HB_MAX_NESTING_LEVEL, + hb_hashmap_t> *condition_values = nullptr) const; + + bool serialize (hb_serialize_context_t *c, + const Condition *src, + const hb_map_t &varidx_map, + const hb_map_t *axis_map = nullptr); + + private: + lookup_condition_subset_result_t subset_lookup_condition_impl ( + hb_subset_context_t *c, + unsigned depth) const; + protected: union { struct { HBUINT16 v; } format; /* Format identifier */ @@ -4305,6 +4797,29 @@ struct ConditionList const Condition& operator[] (unsigned i) const { return this+conditions[i]; } + unsigned get_count () const { return conditions.len; } + + bool serialize (hb_serialize_context_t *c, + const ConditionList *src, + const hb_inc_bimap_t &condition_map, + const hb_map_t &varidx_map, + const hb_map_t *axis_map) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + conditions.len = condition_map.get_population (); + if (unlikely (!c->extend (conditions))) return_trace (false); + for (unsigned i = 0; i < conditions.len; i++) + { + unsigned old_index = condition_map.backward (i); + if (unlikely (old_index >= src->conditions.len || + !conditions[i].serialize_serialize ( + c, &(src+src->conditions[old_index]), varidx_map, axis_map))) + return_trace (false); + } + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -4317,6 +4832,375 @@ struct ConditionList DEFINE_SIZE_ARRAY (4, conditions); }; +inline bool +Condition::collect_var_indices (hb_set_t *var_indices, unsigned depth, + hb_hashmap_t> *condition_values) const +{ + if (unlikely (!depth)) return false; + switch (u.format.v) + { + case 0: + case 1: + return true; + case 2: + if (u.format2.varIdx != VarIdx::NO_VARIATION) + { + var_indices->add (u.format2.varIdx); + if (condition_values && + !condition_values->set ((uintptr_t) &u.format2, + hb_pair (unsigned (u.format2.varIdx), int (u.format2.defaultValue)))) + return false; + } + return !var_indices->in_error (); + case 3: + for (const auto &offset : u.format3.conditions) + if (unlikely (!(&u.format3+offset).collect_var_indices (var_indices, + depth - 1, condition_values))) + return false; + return true; + case 4: + for (const auto &offset : u.format4.conditions) + if (unlikely (!(&u.format4+offset).collect_var_indices (var_indices, + depth - 1, condition_values))) + return false; + return true; + case 5: + return (&u.format5+u.format5.condition).collect_var_indices (var_indices, + depth - 1, condition_values); + default: + return false; + } +} + +inline bool +Condition::serialize (hb_serialize_context_t *c, + const Condition *src, + const hb_map_t &varidx_map, + const hb_map_t *axis_map) +{ + TRACE_SERIALIZE (this); + switch (src->u.format.v) + { + case 0: + { + auto *out = c->start_embed (); + if (unlikely (!out || !c->extend_min (out))) return_trace (false); + out->format = 2; + out->defaultValue = 1; + out->varIdx = VarIdx::NO_VARIATION; + return_trace (true); + } + case 1: + { + auto *out = c->embed (&src->u.format1); + if (unlikely (!out)) return_trace (false); + if (axis_map) + { + if (unlikely (!axis_map->has (out->axisIndex))) + { + c->err (HB_SERIALIZE_ERROR_OTHER); + return_trace (false); + } + if (unlikely (!c->check_assign (out->axisIndex, axis_map->get (out->axisIndex), + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + } + return_trace (true); + } + case 2: + { + auto *out = c->embed (&src->u.format2); + if (unlikely (!out || + (src->u.format2.varIdx != VarIdx::NO_VARIATION && + !varidx_map.has (src->u.format2.varIdx)))) + return_trace (false); + out->varIdx = src->u.format2.varIdx == VarIdx::NO_VARIATION ? + src->u.format2.varIdx : varidx_map.get (src->u.format2.varIdx); + return_trace (true); + } + case 3: + { + auto *out = c->start_embed (); + if (unlikely (!c->extend_min (out))) return_trace (false); + out->format = 3; + out->conditions.len = src->u.format3.conditions.len; + if (unlikely (!c->extend (out->conditions))) return_trace (false); + for (unsigned i = 0; i < out->conditions.len; i++) + if (unlikely (!out->conditions[i].serialize_serialize ( + c, &(&src->u.format3+src->u.format3.conditions[i]), + varidx_map, axis_map))) + return_trace (false); + return_trace (true); + } + case 4: + { + auto *out = c->start_embed (); + if (unlikely (!c->extend_min (out))) return_trace (false); + out->format = 4; + out->conditions.len = src->u.format4.conditions.len; + if (unlikely (!c->extend (out->conditions))) return_trace (false); + for (unsigned i = 0; i < out->conditions.len; i++) + if (unlikely (!out->conditions[i].serialize_serialize ( + c, &(&src->u.format4+src->u.format4.conditions[i]), + varidx_map, axis_map))) + return_trace (false); + return_trace (true); + } + case 5: + { + auto *out = c->embed (&src->u.format5); + if (unlikely (!out || + !out->condition.serialize_serialize ( + c, &(&src->u.format5+src->u.format5.condition), + varidx_map, axis_map))) + return_trace (false); + return_trace (true); + } + default: + return_trace (false); + } +} + +inline lookup_condition_subset_result_t +Condition::subset_lookup_condition (hb_subset_context_t *c, + unsigned depth, + bool materialize_true) const +{ + auto snap = c->serializer->snapshot (); + lookup_condition_subset_result_t result = + subset_lookup_condition_impl (c, depth); + if (result == LOOKUP_CONDITION_SUBSET_KEEP) + return result; + + c->serializer->revert (snap); + if (result != LOOKUP_CONDITION_SUBSET_TRUE || !materialize_true) + return result; + + return serialize_constant (c->serializer, true) ? + LOOKUP_CONDITION_SUBSET_KEEP : LOOKUP_CONDITION_SUBSET_ERROR; +} + +inline lookup_condition_subset_result_t +Condition::subset_lookup_condition_impl (hb_subset_context_t *c, + unsigned depth) const +{ + if (unlikely (!depth)) + return LOOKUP_CONDITION_SUBSET_ERROR; + + auto subset_offset = [c, depth] (Array8OfOffset24To &out, + const Condition &condition) + -> lookup_condition_subset_result_t + { + auto snap = c->serializer->snapshot (); + auto *offset = out.serialize_append (c->serializer); + if (unlikely (!offset)) + return LOOKUP_CONDITION_SUBSET_ERROR; + + c->serializer->push (); + lookup_condition_subset_result_t result = + condition.subset_lookup_condition (c, depth - 1); + if (result == LOOKUP_CONDITION_SUBSET_KEEP) + c->serializer->add_link (*offset, c->serializer->pop_pack ()); + else + { + c->serializer->pop_discard (); + out.pop (); + c->serializer->revert (snap); + } + return result; + }; + + switch (u.format.v) + { + case 0: + return LOOKUP_CONDITION_SUBSET_TRUE; + + case 1: + { + const ConditionAxisRange &src = u.format1; + if (c->plan->user_axes_location.is_empty ()) + return c->serializer->embed (&src) ? + LOOKUP_CONDITION_SUBSET_KEEP : + LOOKUP_CONDITION_SUBSET_ERROR; + + hb_codepoint_t *axis_tag; + if (!c->plan->axes_old_index_tag_map.has (src.axisIndex, &axis_tag)) + return LOOKUP_CONDITION_SUBSET_ERROR; + + Triple axis_limit {-1.f, 0.f, 1.f}; + Triple *normalized_limit; + if (c->plan->axes_location.has (*axis_tag, &normalized_limit)) + axis_limit = *normalized_limit; + + float filter_min = src.filterRangeMinValue.to_float (); + float filter_max = src.filterRangeMaxValue.to_float (); + if (filter_min > filter_max) + return LOOKUP_CONDITION_SUBSET_FALSE; + if (axis_limit.is_point ()) + return filter_min <= axis_limit.middle && + axis_limit.middle <= filter_max ? + LOOKUP_CONDITION_SUBSET_TRUE : + LOOKUP_CONDITION_SUBSET_FALSE; + if (axis_limit.maximum < filter_min || + filter_max < axis_limit.minimum) + return LOOKUP_CONDITION_SUBSET_FALSE; + if (filter_min <= axis_limit.minimum && + axis_limit.maximum <= filter_max) + return LOOKUP_CONDITION_SUBSET_TRUE; + if (!c->plan->axes_index_map.has (src.axisIndex)) + return LOOKUP_CONDITION_SUBSET_ERROR; + + auto *out = c->serializer->embed (&src); + if (unlikely (!out)) + return LOOKUP_CONDITION_SUBSET_ERROR; + + TripleDistances axis_distances {1.f, 1.f}; + TripleDistances *distances; + if (c->plan->axes_triple_distances.has (*axis_tag, &distances)) + axis_distances = *distances; + + out->filterRangeMinValue.set_float ( + renormalizeValue (filter_min, axis_limit, axis_distances, false)); + out->filterRangeMaxValue.set_float ( + renormalizeValue (filter_max, axis_limit, axis_distances, false)); + if (unlikely (!c->serializer->check_assign ( + out->axisIndex, + c->plan->axes_index_map.get (src.axisIndex), + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return LOOKUP_CONDITION_SUBSET_ERROR; + return LOOKUP_CONDITION_SUBSET_KEEP; + } + + case 2: + { + const ConditionValue &src = u.format2; + auto *out = c->serializer->embed (&src); + if (unlikely (!out)) + return LOOKUP_CONDITION_SUBSET_ERROR; + + if (src.varIdx == VarIdx::NO_VARIATION) + return c->plan->user_axes_location.is_empty () ? + LOOKUP_CONDITION_SUBSET_KEEP : + ((int) src.defaultValue > 0 ? + LOOKUP_CONDITION_SUBSET_TRUE : + LOOKUP_CONDITION_SUBSET_FALSE); + + hb_pair_t *condition_value; + if (c->plan->layout_condition_idx_value_map.has ((uintptr_t) &src, &condition_value)) + { + out->defaultValue = condition_value->second; + out->varIdx = condition_value->first; + if (out->varIdx == VarIdx::NO_VARIATION) + return out->defaultValue > 0 ? LOOKUP_CONDITION_SUBSET_TRUE : + LOOKUP_CONDITION_SUBSET_FALSE; + return LOOKUP_CONDITION_SUBSET_KEEP; + } + + hb_pair_t *new_varidx_delta; + if (!c->plan->layout_variation_idx_delta_map.has (src.varIdx, + &new_varidx_delta)) + return c->plan->user_axes_location.is_empty () ? + LOOKUP_CONDITION_SUBSET_KEEP : + ((int) src.defaultValue > 0 ? + LOOKUP_CONDITION_SUBSET_TRUE : + LOOKUP_CONDITION_SUBSET_FALSE); + + if (!c->plan->user_axes_location.is_empty () && + hb_first (*new_varidx_delta) == VarIdx::NO_VARIATION) + { + // Conditions becoming constant depend on the unrounded sign, not + // the integer delta used to instance positioning values. + double value = (int) src.defaultValue + + c->plan->layout_variation_delta (src.varIdx); + return value > 0 ? LOOKUP_CONDITION_SUBSET_TRUE : + LOOKUP_CONDITION_SUBSET_FALSE; + } + + int default_value = (int) src.defaultValue + + hb_second (*new_varidx_delta); + if (unlikely (!c->serializer->check_assign ( + out->defaultValue, + default_value, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return LOOKUP_CONDITION_SUBSET_ERROR; + out->varIdx = hb_first (*new_varidx_delta); + + return LOOKUP_CONDITION_SUBSET_KEEP; + } + + case 3: + { + const ConditionAnd &src = u.format3; + auto *out = c->serializer->start_embed (&src); + if (unlikely (!out || !c->serializer->extend_min (out))) + return LOOKUP_CONDITION_SUBSET_ERROR; + out->format = 3; + + for (const auto &offset : src.conditions) + { + lookup_condition_subset_result_t result = + subset_offset (out->conditions, &src + offset); + if (result == LOOKUP_CONDITION_SUBSET_ERROR || + result == LOOKUP_CONDITION_SUBSET_FALSE) + return result; + } + return out->conditions ? + LOOKUP_CONDITION_SUBSET_KEEP : + LOOKUP_CONDITION_SUBSET_TRUE; + } + + case 4: + { + const ConditionOr &src = u.format4; + auto *out = c->serializer->start_embed (&src); + if (unlikely (!out || !c->serializer->extend_min (out))) + return LOOKUP_CONDITION_SUBSET_ERROR; + out->format = 4; + + for (const auto &offset : src.conditions) + { + lookup_condition_subset_result_t result = + subset_offset (out->conditions, &src + offset); + if (result == LOOKUP_CONDITION_SUBSET_ERROR || + result == LOOKUP_CONDITION_SUBSET_TRUE) + return result; + } + return out->conditions ? + LOOKUP_CONDITION_SUBSET_KEEP : + LOOKUP_CONDITION_SUBSET_FALSE; + } + + case 5: + { + const ConditionNegate &src = u.format5; + auto *out = c->serializer->embed (&src); + if (unlikely (!out)) + return LOOKUP_CONDITION_SUBSET_ERROR; + out->condition = 0; + + c->serializer->push (); + lookup_condition_subset_result_t result = + (&src + src.condition).subset_lookup_condition (c, depth - 1); + if (result == LOOKUP_CONDITION_SUBSET_KEEP) + { + c->serializer->add_link (out->condition, + c->serializer->pop_pack ()); + return result; + } + + c->serializer->pop_discard (); + if (result == LOOKUP_CONDITION_SUBSET_TRUE) + return LOOKUP_CONDITION_SUBSET_FALSE; + if (result == LOOKUP_CONDITION_SUBSET_FALSE) + return LOOKUP_CONDITION_SUBSET_TRUE; + return result; + } + + default: + return LOOKUP_CONDITION_SUBSET_FALSE; + } +} + struct ConditionSet { bool evaluate (const int *coords, unsigned int coord_len, @@ -4341,13 +5225,20 @@ struct ConditionSet c->apply = true; bool should_keep = false; + /* The range map cannot identify value or boolean expressions uniquely. */ + bool can_deduplicate = true; unsigned num_kept_cond = 0, cond_idx = 0; for (const auto& offset : conditions) { - Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map); + const Condition &condition = this+offset; + can_deduplicate &= condition.u.format.v <= 1; + Cond_with_Var_flag_t ret = condition.keep_with_variations (c, condition_map); // condition is not met or condition out of range, drop the entire record if (ret == DROP_RECORD_WITH_VAR) + { + c->apply = false; return; + } if (ret == KEEP_COND_WITH_VAR) { @@ -4362,17 +5253,19 @@ struct ConditionSet cond_idx++; } - if (!should_keep) return; + /* Satisfied pinned conditions still terminate first-match processing. + * Keep their universal record when other axes remain variable. */ + c->universal = num_kept_cond == 0; + if (!should_keep && c->all_axes_pinned) return; //check if condition_set is unique with variations - if (c->conditionset_map->has (p)) + if (can_deduplicate && c->conditionset_map->has (p)) //duplicate found, drop the entire record return; - c->conditionset_map->set (p, 1); + if (can_deduplicate) + c->conditionset_map->set (p, 1); c->record_cond_idx_map->set (c->cur_record_idx, s); - if (should_keep && num_kept_cond == 0) - c->universal = true; } bool subset (hb_subset_context_t *c, @@ -4394,7 +5287,28 @@ struct ConditionSet { if (retained_cond_set != nullptr && !retained_cond_set->has (i)) continue; - subset_offset_array (c, out->conditions, this) (conditions[i]); + const Condition &condition = this+conditions[i]; + if (condition.u.format.v == 1) + { + subset_offset_array (c, out->conditions, this) (conditions[i]); + continue; + } + + auto *offset = out->conditions.serialize_append (c->serializer); + if (unlikely (!offset)) return_trace (false); + c->serializer->push (); + auto result = condition.subset_lookup_condition (c, HB_MAX_NESTING_LEVEL, true); + if (result == LOOKUP_CONDITION_SUBSET_FALSE) + /* A false condition must not become a null (true) ConditionSet. */ + result = Condition::serialize_constant (c->serializer, false) ? + LOOKUP_CONDITION_SUBSET_KEEP : LOOKUP_CONDITION_SUBSET_ERROR; + if (unlikely (result == LOOKUP_CONDITION_SUBSET_ERROR)) + { + c->serializer->pop_discard (); + c->serializer->check_success (false); + return_trace (false); + } + c->serializer->add_link (*offset, c->serializer->pop_pack ()); } return_trace (bool (out->conditions)); @@ -4406,6 +5320,15 @@ struct ConditionSet return_trace (conditions.sanitize (c, this)); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const auto &offset : conditions) + if (unlikely (!(this+offset).collect_var_indices (c->layout_variation_indices, + HB_MAX_NESTING_LEVEL, + c->condition_values))) + c->layout_variation_indices->err (); + } + protected: Array16OfOffset32To conditions; public: @@ -4475,13 +5398,22 @@ struct FeatureTableSubstitutionRecord if (unlikely (!out)) return_trace (false); out->featureIndex = *new_feature_index; - return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c)); + hb_pair_t *original; + if (!c->feature_idx_tag_map->has (featureIndex, &original)) + return_trace (false); + const Tag *tag = reinterpret_cast (original->second); + return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c, tag)); } - bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base, + const FeatureList *feature_list) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && feature.sanitize (c, base)); + if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); + /* The substitute is read with the tag of the feature it replaces. */ + const Record_sanitize_closure_t closure = {feature_list->get_tag (featureIndex), base}; + return_trace (feature.sanitize (c, base, &closure)); } protected: @@ -4493,6 +5425,12 @@ struct FeatureTableSubstitutionRecord struct FeatureTableSubstitution { + void collect_feature_indices (hb_set_t *feature_indices) const + { + for (const FeatureTableSubstitutionRecord &record : substitutions) + feature_indices->add (record.featureIndex); + } + const Feature *find_substitute (unsigned int feature_index) const { unsigned int count = substitutions.len; @@ -4515,6 +5453,16 @@ struct FeatureTableSubstitution ; } + template + void collect_name_ids (const hb_map_t *feature_index_map, + TagGetter get_tag, + hb_set_t *nameids_to_retain) const + { + for (const FeatureTableSubstitutionRecord &record : substitutions) + if (feature_index_map->has (record.featureIndex)) + (this+record.feature).collect_name_ids (get_tag (record.featureIndex), nameids_to_retain); + } + void closure_features (const hb_map_t *lookup_indexes, hb_set_t *feature_indexes /* OUT */) const { @@ -4573,13 +5521,13 @@ struct FeatureTableSubstitution return_trace (bool (out->substitutions)); } - bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c, const FeatureList *feature_list) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && hb_barrier () && likely (version.major == 1) && - substitutions.sanitize (c, this)); + substitutions.sanitize (c, this, feature_list)); } protected: @@ -4601,6 +5549,15 @@ struct FeatureVariationRecord return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes); } + template + void collect_name_ids (const void *base, + const hb_map_t *feature_index_map, + TagGetter get_tag, + hb_set_t *nameids_to_retain) const + { + (base+substitutions).collect_name_ids (feature_index_map, get_tag, nameids_to_retain); + } + void closure_features (const void *base, const hb_map_t *lookup_indexes, hb_set_t *feature_indexes /* OUT */) const @@ -4631,19 +5588,30 @@ struct FeatureVariationRecord auto *out = c->subset_context->serializer->embed (this); if (unlikely (!out)) return_trace (false); - out->conditions.serialize_subset (c->subset_context, conditions, base, c, insert_catch_all); + hb_set_t *retained_conditions = c->feature_record_cond_idx_map ? + c->feature_record_cond_idx_map->get (c->cur_feature_var_record_idx).get () : nullptr; + if (!insert_catch_all && retained_conditions && retained_conditions->is_empty ()) + /* A null ConditionSet is the unconditional first-match record. */ + out->conditions = 0; + else + out->conditions.serialize_subset (c->subset_context, conditions, base, c, insert_catch_all); out->substitutions.serialize_subset (c->subset_context, substitutions, base, c, insert_catch_all); return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const void *base, + const FeatureList *feature_list) const { TRACE_SANITIZE (this); return_trace (conditions.sanitize (c, base) && - substitutions.sanitize (c, base)); + substitutions.sanitize (c, base, feature_list)); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *base) const + { (base+conditions).collect_variation_indices (c); } + protected: Offset32To conditions; @@ -4653,10 +5621,326 @@ struct FeatureVariationRecord DEFINE_SIZE_STATIC (8); }; +struct LookupIndexList +{ + void add_lookup_indexes_to (hb_set_t *lookup_indexes) const + { lookupIndices.add_indexes_to (lookup_indexes); } + + bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const + { return lookupIndices.intersects (lookup_indexes); } + + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (this); + if (unlikely (!out || !c->serializer->extend_min (out))) + return_trace (false); + + auto it = + + hb_iter (lookupIndices) + | hb_filter (l->lookup_index_map) + | hb_map (l->lookup_index_map) + ; + out->lookupIndices.serialize (c->serializer, l, it); + return_trace (bool (out->lookupIndices)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (lookupIndices.sanitize (c)); + } + + protected: + IndexArray lookupIndices; + public: + DEFINE_SIZE_ARRAY_SIZED (2, lookupIndices); +}; + +struct LookupConditionRecord +{ + unsigned get_condition_offset (const void *base, const void *variations) const + { return (const char *) &(base+condition) - (const char *) variations; } + + template + bool evaluate (const void *base, + const int *coords, + unsigned int coord_len, + Instancer *instancer) const + { return (base+condition).evaluate (coords, coord_len, instancer); } + + bool evaluate (const void *base, + const void *variations, + hb_sorted_array_t conditions) const + { + return !condition || hb_bsearch (get_condition_offset (base, variations), + conditions.arrayZ, conditions.length, + sizeof (unsigned), + _hb_cmp_operator); + } + + bool collect_condition (const void *base, + const void *variations, + const int *coords, + unsigned int coord_len, + ItemVarStoreInstancer *instancer, + hb_set_t *visited, + hb_vector_t *conditions) const + { + /* Null conditions always apply and need no key state. */ + if (!condition) return true; + + unsigned offset = get_condition_offset (base, variations); + if (visited->has (offset)) return true; + visited->add (offset); + if (unlikely (visited->in_error ())) return false; + + if (evaluate (base, coords, coord_len, instancer)) + conditions->push (offset); + return !conditions->in_error (); + } + + void add_lookup_indexes_to (const void *base, + hb_set_t *lookup_indexes) const + { (base+lookupIndices).add_lookup_indexes_to (lookup_indexes); } + + bool intersects_lookup_indexes (const void *base, + const hb_map_t *lookup_indexes) const + { return (base+lookupIndices).intersects_lookup_indexes (lookup_indexes); } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *base) const + { + if (unlikely (!(base+condition).collect_var_indices (c->layout_variation_indices, + HB_MAX_NESTING_LEVEL, + c->condition_values))) + c->layout_variation_indices->err (); + } + + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l, + const void *base) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + out->condition = 0; + c->serializer->push (); + lookup_condition_subset_result_t result = + (base + condition).subset_lookup_condition (c, + HB_MAX_NESTING_LEVEL, + true); + if (result != LOOKUP_CONDITION_SUBSET_KEEP) + { + c->serializer->pop_discard (); + return_trace (false); + } + c->serializer->add_link (out->condition, c->serializer->pop_pack ()); + + return_trace (out->lookupIndices.serialize_subset (c, lookupIndices, base, l)); + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (condition.sanitize (c, base) && + lookupIndices.sanitize (c, base)); + } + + protected: + Offset32To condition; + Offset32To lookupIndices; + public: + DEFINE_SIZE_STATIC (8); +}; + +struct FeatureLookupsTable +{ + bool adds_default_lookups () const { return flags & 0x0001u; } + + bool collect_conditions (const void *variations, + const int *coords, + unsigned int coord_len, + ItemVarStoreInstancer *instancer, + hb_set_t *visited, + hb_vector_t *conditions) const + { + for (const LookupConditionRecord &record : records) + if (unlikely (!record.collect_condition (this, variations, coords, coord_len, + instancer, visited, conditions))) + return false; + return true; + } + + void collect_lookups (const void *variations, + hb_sorted_array_t conditions, + hb_set_t *lookup_indexes) const + { + for (const LookupConditionRecord &record : records) + if (record.evaluate (this, variations, conditions)) + record.add_lookup_indexes_to (this, lookup_indexes); + } + + template + void collect_lookups (const int *coords, + unsigned int coord_len, + Instancer *instancer, + hb_set_t *lookup_indexes) const + { + for (const LookupConditionRecord &record : records) + if (record.evaluate (this, coords, coord_len, instancer)) + record.add_lookup_indexes_to (this, lookup_indexes); + } + + void collect_lookups (hb_set_t *lookup_indexes) const + { + for (const LookupConditionRecord &record : records) + record.add_lookup_indexes_to (this, lookup_indexes); + } + + bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const + { + for (const LookupConditionRecord &record : records) + if (record.intersects_lookup_indexes (this, lookup_indexes)) + return true; + return false; + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const LookupConditionRecord &record : records) + record.collect_variation_indices (c, this); + } + + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (this); + if (unlikely (!out || !c->serializer->extend_min (out))) + return_trace (false); + + out->version.major = version.major; + out->version.minor = version.minor; + out->flags = flags; + + for (const LookupConditionRecord &record : records) + { + auto snap = c->serializer->snapshot (); + if (record.subset (c, l, this)) + out->records.len++; + else + c->serializer->revert (snap); + } + + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + hb_barrier () && + likely (version.major == 1) && + records.sanitize (c, this)); + } + + protected: + FixedVersion<> version; /* Version--0x00010000u */ + HBUINT16 flags; + Array32Of + records; + public: + DEFINE_SIZE_ARRAY (10, records); +}; + +struct LookupVariationRecord +{ + friend struct FeatureVariations; + + unsigned get_feature_index () const { return featureIndex; } + + void collect_lookups (const void *base, + const Feature &feature, + hb_sorted_array_t conditions, + hb_set_t *lookup_indexes) const + { + const FeatureLookupsTable &feature_lookups = base+featureLookups; + if (feature_lookups.adds_default_lookups ()) + feature.add_lookup_indexes_to (lookup_indexes); + feature_lookups.collect_lookups (base, conditions, lookup_indexes); + } + + void collect_lookups (const void *base, + const hb_set_t *feature_indexes, + hb_set_t *lookup_indexes) const + { + if (feature_indexes->has (featureIndex)) + (base+featureLookups).collect_lookups (lookup_indexes); + } + + void closure_features (const void *base, + const hb_map_t *lookup_indexes, + hb_set_t *feature_indexes) const + { + if ((base+featureLookups).intersects_lookup_indexes (lookup_indexes)) + feature_indexes->add (featureIndex); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *base) const + { (base+featureLookups).collect_variation_indices (c); } + + bool subset (hb_subset_layout_context_t *l, const void *base) const + { + hb_subset_context_t *c = l->subset_context; + TRACE_SUBSET (this); + uint32_t *new_feature_index; + if (!l->feature_map_w_duplicates->has (featureIndex, &new_feature_index)) + return_trace (false); + + auto *out = c->serializer->embed (this); + if (unlikely (!out || + !c->serializer->check_assign (out->featureIndex, + *new_feature_index, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + + return_trace (out->featureLookups.serialize_subset (c, featureLookups, base, l)); + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + featureLookups.sanitize (c, base)); + } + + protected: + HBUINT16 featureIndex; + Offset32To featureLookups; + public: + DEFINE_SIZE_STATIC (6); +}; + struct FeatureVariations { static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu; + const Array32Of &get_lookup_variation_records () const + { + if (version.to_int () < 0x00010001u) + return Null (Array32Of); + return StructAfter> (varRecords); + } + + unsigned record_count () const + { + return varRecords.len; + } + bool find_index (const int *coords, unsigned int coord_len, unsigned int *index, ItemVarStoreInstancer *instancer) const @@ -4682,6 +5966,47 @@ struct FeatureVariations return (this+record.substitutions).find_substitute (feature_index); } + bool collect_lookup_conditions (const int *coords, + unsigned int coord_len, + ItemVarStoreInstancer *instancer, + hb_vector_t *state) const + { + hb_set_t visited_tables, visited_conditions; + for (const LookupVariationRecord &record : get_lookup_variation_records ()) + { + unsigned offset = record.featureLookups; + if (visited_tables.has (offset)) continue; + visited_tables.add (offset); + if (unlikely (visited_tables.in_error ())) return false; + + const FeatureLookupsTable &feature_lookups = this+record.featureLookups; + if (unlikely (!feature_lookups.collect_conditions (this, coords, coord_len, + instancer, &visited_conditions, + state))) + return false; + } + + /* Key size depends on distinct conditions, not expanded lookup sets. + * Sorting makes it independent of their first traversal order. */ + state->qsort (_hb_cmp_operator); + return true; + } + + bool get_lookup_variations (unsigned feature_index, + const Feature &feature, + hb_sorted_array_t conditions, + hb_set_t *lookup_indexes) const + { + for (const LookupVariationRecord &record : get_lookup_variation_records ()) + { + if (record.featureIndex != feature_index) continue; + + record.collect_lookups (this, feature, conditions, lookup_indexes); + return true; + } + return false; + } + void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const { unsigned int count = varRecords.len; @@ -4714,6 +6039,29 @@ struct FeatureVariations continue; varRecords[i].collect_lookups (this, feature_indexes, lookup_indexes); } + + collect_lookup_variation_lookups (feature_indexes, lookup_indexes); + } + + template + void collect_name_ids (const hb_map_t *feature_index_map, + const hb_hashmap_t> *feature_record_cond_idx_map, + TagGetter get_tag, + hb_set_t *nameids_to_retain) const + { + for (unsigned i = 0; i < varRecords.len; i++) + { + if (feature_record_cond_idx_map && !feature_record_cond_idx_map->has (i)) + continue; + varRecords[i].collect_name_ids (this, feature_index_map, get_tag, nameids_to_retain); + } + } + + void collect_lookup_variation_lookups (const hb_set_t *feature_indexes, + hb_set_t *lookup_indexes /* OUT */) const + { + for (const LookupVariationRecord &record : get_lookup_variation_records ()) + record.collect_lookups (this, feature_indexes, lookup_indexes); } void closure_features (const hb_map_t *lookup_indexes, @@ -4728,6 +6076,35 @@ struct FeatureVariations continue; varRecords[i].closure_features (this, lookup_indexes, feature_indexes); } + + for (const LookupVariationRecord &record : get_lookup_variation_records ()) + record.closure_features (this, lookup_indexes, feature_indexes); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const FeatureVariationRecord &record : varRecords) + record.collect_variation_indices (c, this); + for (const LookupVariationRecord &record : get_lookup_variation_records ()) + record.collect_variation_indices (c, this); + } + + void collect_feature_indices (hb_set_t *feature_indices) const + { + for (const FeatureVariationRecord &record : varRecords) + (this+record.substitutions).collect_feature_indices (feature_indices); + } + + bool has_lookup_variations (unsigned feature_index) const + { + for (const LookupVariationRecord &record : get_lookup_variation_records ()) + { + if (record.featureIndex == feature_index) + return true; + if (record.featureIndex > feature_index) + break; + } + return false; } bool subset (hb_subset_context_t *c, @@ -4765,16 +6142,31 @@ struct FeatureVariations subset_record_array (l, &(out->varRecords), this, insert_catch_all_record) (varRecords[0]); } - return_trace (bool (out->varRecords)); + Array32Of *out_lookup_records = nullptr; + if (version.minor >= 1) + { + out_lookup_records = &StructAfter> (out->varRecords); + if (unlikely (!c->serializer->extend_min (out_lookup_records))) + return_trace (false); + + + get_lookup_variation_records ().iter () + | hb_apply (subset_record_array (l, out_lookup_records, this)) + ; + } + + return_trace (bool (out->varRecords) || + (out_lookup_records && bool (*out_lookup_records))); } - bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c, const FeatureList *feature_list) const { TRACE_SANITIZE (this); return_trace (version.sanitize (c) && hb_barrier () && likely (version.major == 1) && - varRecords.sanitize (c, this)); + varRecords.sanitize (c, this, feature_list) && + (version.minor < 1 || + get_lookup_variation_records ().sanitize (c, this))); } protected: @@ -4888,6 +6280,16 @@ struct VariationDevice hb_scalar_cache_t *store_cache = nullptr) const { return !font->has_nonzero_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); } + float get_x_delta_f (hb_font_t *font, + const ItemVariationStore &store, + hb_scalar_cache_t *store_cache) const + { return !font->has_nonzero_coords ? 0.f : font->em_fscalef_x (get_delta (font, store, store_cache)); } + + float get_y_delta_f (hb_font_t *font, + const ItemVariationStore &store, + hb_scalar_cache_t *store_cache) const + { return !font->has_nonzero_coords ? 0.f : font->em_fscalef_y (get_delta (font, store, store_cache)); } + VariationDevice* copy (hb_serialize_context_t *c, const hb_hashmap_t> *layout_variation_idx_delta_map) const { @@ -4897,6 +6299,11 @@ struct VariationDevice hb_pair_t *v; if (!layout_variation_idx_delta_map->has (varIdx, &v)) return_trace (nullptr); + /* The varidx was mapped to "no variations" during instancing (e.g. the + * instantiated row is all zeros). Drop the device instead of emitting one + * with an out-of-range varidx. */ + if (hb_first (*v) == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + return_trace (nullptr); c->start_zerocopy (this->static_size); auto *out = c->embed (this); @@ -4945,6 +6352,36 @@ struct DeviceHeader struct Device { + // Anchors retain fractional coordinates until their difference is rounded. + // Hinting adjustments and value records keep their integer semantics. + float get_x_delta_f (hb_font_t *font, + const ItemVariationStore &store, + hb_scalar_cache_t *store_cache = nullptr) const + { +#ifndef HB_NO_VAR + if (u.b.format == 0x8000) + { + hb_barrier (); + return u.variation.get_x_delta_f (font, store, store_cache); + } +#endif + return get_x_delta (font, store, store_cache); + } + + float get_y_delta_f (hb_font_t *font, + const ItemVariationStore &store, + hb_scalar_cache_t *store_cache = nullptr) const + { +#ifndef HB_NO_VAR + if (u.b.format == 0x8000) + { + hb_barrier (); + return u.variation.get_y_delta_f (font, store, store_cache); + } +#endif + return get_y_delta (font, store, store_cache); + } + hb_position_t get_x_delta (hb_font_t *font, const ItemVariationStore &store=Null (ItemVariationStore), hb_scalar_cache_t *store_cache = nullptr) const @@ -4953,10 +6390,12 @@ struct Device { #ifndef HB_NO_HINTING case 1: case 2: case 3: + hb_barrier (); return u.hinting.get_x_delta (font); #endif #ifndef HB_NO_VAR case 0x8000: + hb_barrier (); return u.variation.get_x_delta (font, store, store_cache); #endif default: @@ -4971,10 +6410,12 @@ struct Device { case 1: case 2: case 3: #ifndef HB_NO_HINTING + hb_barrier (); return u.hinting.get_y_delta (font); #endif #ifndef HB_NO_VAR case 0x8000: + hb_barrier (); return u.variation.get_y_delta (font, store, store_cache); #endif default: @@ -4989,10 +6430,12 @@ struct Device switch (u.b.format) { #ifndef HB_NO_HINTING case 1: case 2: case 3: + hb_barrier (); return_trace (u.hinting.sanitize (c)); #endif #ifndef HB_NO_VAR case 0x8000: + hb_barrier (); return_trace (u.variation.sanitize (c)); #endif default: @@ -5009,10 +6452,12 @@ struct Device case 1: case 2: case 3: + hb_barrier (); return_trace (reinterpret_cast (u.hinting.copy (c))); #endif #ifndef HB_NO_VAR case 0x8000: + hb_barrier (); return_trace (reinterpret_cast (u.variation.copy (c, layout_variation_idx_delta_map))); #endif default: @@ -5031,6 +6476,7 @@ struct Device #endif #ifndef HB_NO_VAR case 0x8000: + hb_barrier (); u.variation.collect_variation_index (c); return; #endif @@ -5044,6 +6490,7 @@ struct Device switch (u.b.format) { #ifndef HB_NO_VAR case 0x8000: + hb_barrier (); return u.variation.varIdx; #endif default: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh index 8d5e1f18638..c46fd68de29 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh @@ -58,6 +58,24 @@ template return l.dispatch (c); } +/*static*/ hb_depend_context_t::return_t SubstLookup::depend_glyphs_recurse_func (hb_depend_context_t *c, unsigned lookup_index, hb_bit_page_t *covered_seq_indices, unsigned seq_index, unsigned end_index) +{ + const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); + /* After a non-1-to-1 lookup (expansion/contraction), subsequent lookups in the same + * contextual rule see all glyphs, not position-specific ones. This matches closure behavior. + * Mark sequence positions as covered so later lookups use the full glyph set. */ + if (l.may_have_non_1to1 ()) + covered_seq_indices->add_range (seq_index, end_index); + + hb_depend_context_t::recurse_key_t key; + if (!c->get_recurse_key (lookup_index, &key)) + return hb_empty_t (); + + hb_depend_context_t::return_t ret = l.dispatch (c); + c->finish_recurse (key); + return ret; +} + template <> inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index) @@ -96,7 +114,98 @@ inline bool SubstLookup::dispatch_recurse_func (hb_ot_app } /* namespace GSUB_impl */ } /* namespace Layout */ -} /* namespace OT */ +inline void +GSUB_accelerator_t::depend (hb_depend_data_builder_t *builder, hb_face_t *face) const +{ + if (!this->table->has_data ()) return; + + unsigned num_features = this->table->get_feature_count (); + unsigned num_lookups = this->table->get_lookup_count (); + + hb_vector_t feature_tags; + if (!builder->check_success (feature_tags.resize (num_features))) + return; + this->table->get_feature_tags (0, &num_features, feature_tags.arrayZ); + + if (!builder->init_lookup_features (num_lookups)) + return; + + hb_vector_t feature_query_v; + feature_query_v.resize (2); + feature_query_v[1] = 0; + + hb_set_t seen_features; + hb_set_t feature_indexes, lookup_indexes; + + for (auto ft : feature_tags) + { + if (seen_features.has (ft)) continue; + seen_features.add (ft); + feature_query_v[0] = ft; + feature_indexes.reset (); + hb_ot_layout_collect_features (face, HB_OT_TAG_GSUB, nullptr, nullptr, + feature_query_v.arrayZ, &feature_indexes); + lookup_indexes.reset (); + for (auto feature_index : feature_indexes) + this->table->get_feature (feature_index).add_lookup_indexes_to (&lookup_indexes); + + for (auto lookup_index : lookup_indexes) + if (unlikely (!builder->add_lookup_feature (lookup_index, ft))) + return; + + auto &fv = this->table->get_feature_variations (); + auto fi_count = fv.record_count (); + for (unsigned i = 0; i < fi_count; i++) + { + lookup_indexes.reset (); + for (auto feature_index : feature_indexes) + { + auto feature_ptr = fv.find_substitute (i, feature_index); + if (feature_ptr != nullptr) + feature_ptr->add_lookup_indexes_to (&lookup_indexes); + } + for (auto lookup_index : lookup_indexes) + if (unlikely (!builder->add_lookup_feature (lookup_index, ft))) + return; + } + +#ifndef HB_NO_VAR + lookup_indexes.reset (); + fv.collect_lookup_variation_lookups (&feature_indexes, &lookup_indexes); + for (auto lookup_index : lookup_indexes) + if (unlikely (!builder->add_lookup_feature (lookup_index, ft))) + return; +#endif + } + + if (unlikely (!builder->finish_lookup_features ())) + return; + + hb_set_t all_glyphs; + all_glyphs.add_range (0, face->get_num_glyphs () - 1); + + hb_depend_context_t c (builder, face, &all_glyphs); + + for (unsigned i = 0; i < num_lookups; i++) + { + auto features = builder->get_lookup_features (i); + if (!features) + { + DEBUG_MSG_LEVEL (DEPEND, nullptr, 1, 0, + "Skipping lookup %u (no features)", i); + continue; + } + DEBUG_MSG_LEVEL (DEPEND, nullptr, 1, 0, + "Processing lookup %u with features:", i); + c.lookup_index = i; + c.reset_recurse_cache (); + c.lookups_seen.clear (); + c.lookups_seen.add (i); /* Seed for A→B→A cycle detection in recurse(). */ + this->table->get_lookup (i).depend (&c); + } +} + +} /* namespace OT */ #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh index a2a45af9e76..eed4817e5f0 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh @@ -36,6 +36,7 @@ #include "hb-ot-map.hh" #include "hb-ot-layout-common.hh" #include "hb-ot-layout-gdef-table.hh" +#include "hb-depend-data.hh" namespace OT { @@ -105,9 +106,12 @@ struct hb_closure_context_t : return true; /* Have we visited this lookup with the current set of glyphs? */ - if (done_lookups_glyph_count->get (lookup_index) != glyphs->get_population ()) + unsigned pop = glyphs->get_population (); + if (unlikely (pop == HB_MAP_VALUE_INVALID)) // Avoid sentinel interference. + pop--; + if (done_lookups_glyph_count->get (lookup_index) != pop) { - done_lookups_glyph_count->set (lookup_index, glyphs->get_population ()); + done_lookups_glyph_count->set (lookup_index, pop); if (!done_lookups_glyph_set->has (lookup_index)) { @@ -375,7 +379,417 @@ struct hb_collect_glyphs_context_t : void set_recurse_func (recurse_func_t func) { recurse_func = func; } }; +struct hb_depend_context_t : + hb_dispatch_context_t +{ + enum glyph_set_type_t + { + GLYPH_SET_CLASS, + GLYPH_SET_COVERAGE, + GLYPH_SET_SINGLE + }; + + static constexpr hb_codepoint_t SINGLE_GLYPH_ACTIVE_FLAG = 0x80000000u; + + struct glyph_set_cache_key_t + { + glyph_set_cache_key_t () = default; + glyph_set_cache_key_t (const void *data_, unsigned value_, glyph_set_type_t type_) + : data (data_), value (value_), type (type_) {} + + bool operator == (const glyph_set_cache_key_t &o) const + { return data == o.data && value == o.value && type == o.type; } + + uint32_t hash () const + { + uint32_t current = hb_hash ((uintptr_t) data); + current = current * 31 + hb_hash (value); + return current * 31 + hb_hash ((unsigned) type); + } + + const void *data = nullptr; + unsigned value = 0; + glyph_set_type_t type = GLYPH_SET_CLASS; + }; + + struct context_set_cache_key_t + { + context_set_cache_key_t () = default; + context_set_cache_key_t (const void *rule_, + const void *record_, + const void *data_, + hb_codepoint_t active_glyphs_, + unsigned value_, + unsigned format_) + : rule (rule_), record (record_), data (data_), active_glyphs (active_glyphs_), + value (value_), format (format_) {} + + bool operator == (const context_set_cache_key_t &o) const + { + return rule == o.rule && + record == o.record && + data == o.data && + active_glyphs == o.active_glyphs && + value == o.value && + format == o.format; + } + + uint32_t hash () const + { + uint32_t current = hb_hash ((uintptr_t) rule); + current = current * 31 + hb_hash ((uintptr_t) record); + current = current * 31 + hb_hash ((uintptr_t) data); + current = current * 31 + hb_hash (active_glyphs); + current = current * 31 + hb_hash (value); + return current * 31 + hb_hash (format); + } + + const void *rule = nullptr; + const void *record = nullptr; + const void *data = nullptr; + hb_codepoint_t active_glyphs = HB_CODEPOINT_INVALID; + unsigned value = 0; + unsigned format = 0; + }; + + struct recurse_key_t + { + recurse_key_t () = default; + recurse_key_t (unsigned lookup_index_, + hb_codepoint_t active_glyphs_, + hb_codepoint_t recurse_path_, + hb_codepoint_t context_set_) + : lookup_index (lookup_index_), + active_glyphs (active_glyphs_), + recurse_path (recurse_path_), + context_set (context_set_) {} + + bool operator == (const recurse_key_t &o) const + { + return lookup_index == o.lookup_index && + active_glyphs == o.active_glyphs && + recurse_path == o.recurse_path && + context_set == o.context_set; + } + + uint32_t hash () const + { + uint32_t current = 0x84222325; + current = (current ^ hb_hash (lookup_index)) * 16777619; + current = (current ^ hb_hash (active_glyphs)) * 16777619; + current = (current ^ hb_hash (recurse_path)) * 16777619; + current = (current ^ hb_hash (context_set)) * 16777619; + return current; + } + + unsigned lookup_index = 0; + hb_codepoint_t active_glyphs = 0; + hb_codepoint_t recurse_path = 0; + hb_codepoint_t context_set = HB_CODEPOINT_INVALID; + }; + + typedef return_t (*recurse_func_t) (hb_depend_context_t *c, unsigned lookup_index, hb_bit_page_t *covered_seq_indices, unsigned seq_index, unsigned end_index); + /* return_t is hb_empty_t — dispatch is purely for side-effects, like hb_closure_context_t. */ + template + return_t dispatch (const T &obj) { obj.depend (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } + + void recurse (unsigned lookup_idx, hb_bit_page_t *covered_seq_indices, unsigned seq_index, unsigned end_index) + { + /* Cycle detection using call-stack semantics: block re-entry of a + * lookup that is currently on the execution stack, but allow it again + * once it has returned. + * + * A flat "visited" set would be wrong: the same lookup legitimately + * appears more than once when a rule iterates over multiple sequence + * positions — each such call is independent and must be processed. + * + * Cutting an in-progress cycle is safe because the active glyph set + * can only stay the same or shrink as we recurse. If we re-encounter + * lookup L while it is still on the stack, L is already executing + * with a context at least as broad, so any edges a re-entry would add + * are a subset of what L is already in the process of registering. + * + * lookups_seen is pre-seeded with the top-level lookup index in + * GSUB_accelerator_t::depend before the direct depend() call, so + * that indirect cycles of the form A→B→A are also caught here. */ + if (lookups_seen.has (lookup_idx)) return; + lookups_seen.add (lookup_idx); + + /* Intern the ordered recursion path instead of copying and interning the + * lookups_seen set. Path identity is more specific than set identity but + * never merges states with different cycle-detection behavior. */ + hb_codepoint_t parent_path = recurse_path; + uint64_t path_key = (uint64_t) parent_path << 32 | lookup_idx; + hb_codepoint_t *path = nullptr; + hb_codepoint_t path_index; + if (!recurse_path_to_index.has (path_key, &path)) + { + path_index = recurse_path_to_index.get_population () + 1; + if (unlikely (!recurse_path_to_index.set (path_key, path_index))) + { + depend_data->fail (); + lookups_seen.del (lookup_idx); + return; + } + } + else + path_index = *path; + recurse_path = path_index; + recurse_func (this, lookup_idx, covered_seq_indices, seq_index, end_index); + recurse_path = parent_path; + lookups_seen.del (lookup_idx); + } + + struct active_glyphs_frame_t + { + hb_set_t glyphs; + hb_codepoint_t active_idx = HB_CODEPOINT_INVALID; + bool use_root = false; + }; + + const hb_set_t& parent_active_glyphs () + { + if (!active_glyphs_stack_depth) + return *glyphs; + + const active_glyphs_frame_t &frame = active_glyphs_stack[active_glyphs_stack_depth - 1]; + return frame.use_root ? *glyphs : frame.glyphs; + } + + hb_set_t* push_cur_active_glyphs (hb_codepoint_t active_idx = HB_CODEPOINT_INVALID) + { + if (active_glyphs_stack_depth == active_glyphs_stack.length && + unlikely (!active_glyphs_stack.push_or_fail ())) + return nullptr; + + active_glyphs_frame_t &frame = active_glyphs_stack[active_glyphs_stack_depth++]; + frame.glyphs.clear (); + frame.active_idx = active_idx; + frame.use_root = false; + return &frame.glyphs; + } + + bool push_root_active_glyphs () + { + if (active_glyphs_stack_depth == active_glyphs_stack.length && + unlikely (!active_glyphs_stack.push_or_fail ())) + return false; + + active_glyphs_stack[active_glyphs_stack_depth++].use_root = true; + return true; + } + + bool pop_cur_done_glyphs () + { + if (!active_glyphs_stack_depth) + return false; + + active_glyphs_stack_depth--; + return true; + } + + bool get_parent_active_glyphs_index (hb_codepoint_t *active_idx) + { + if (!active_glyphs_stack_depth || + active_glyphs_stack[active_glyphs_stack_depth - 1].use_root) + { + *active_idx = HB_CODEPOINT_INVALID; + return true; + } + + active_glyphs_frame_t &frame = active_glyphs_stack[active_glyphs_stack_depth - 1]; + *active_idx = frame.active_idx; + if (*active_idx != HB_CODEPOINT_INVALID) + return true; + + hb_codepoint_t glyph; + if (frame.glyphs.get_singleton (&glyph) && + likely (glyph < SINGLE_GLYPH_ACTIVE_FLAG)) + *active_idx = glyph | SINGLE_GLYPH_ACTIVE_FLAG; + else if (!find_or_create_recurse_set (frame.glyphs, active_idx)) + return false; + + frame.active_idx = *active_idx; + return true; + } + + bool get_context_set_cache_key (const void *rule, + const void *record, + const void *data, + unsigned value, + unsigned format, + context_set_cache_key_t *key) + { + hb_codepoint_t active_idx; + if (!get_parent_active_glyphs_index (&active_idx)) + return false; + *key = context_set_cache_key_t (rule, record, data, active_idx, value, format); + return true; + } + + bool get_recurse_key (unsigned lookup_idx, recurse_key_t *key) + { + /* The active glyphs and in-progress lookup set are part of the state. + * Omitting the latter would make memoization incorrect for cyclic lookup + * graphs whose available recursive paths depend on their ancestry. + * Edge flags are not part of the state: they affect neither traversal nor + * edge identity, so revisiting with different flags can only find edges + * that the deduplication table already contains. */ + hb_codepoint_t active_idx; + if (!get_parent_active_glyphs_index (&active_idx)) + return false; + + *key = recurse_key_t (lookup_idx, + active_idx, + recurse_path, + depend_data->current_context_set_index); + return !completed_recursions.has (*key); + } + + void finish_recurse (const recurse_key_t &key) + { depend_data->check_success (completed_recursions.set (key, true)); } + + void reset_recurse_cache () + { + completed_recursions.clear (); + recurse_path_to_index.clear (); + recurse_path = 0; + } + + bool find_or_create_recurse_set (const hb_set_t &set, hb_codepoint_t *index) + { + hb_codepoint_t *existing = nullptr; + if (recurse_set_to_index.has (&set, &existing)) + { + *index = *existing; + return true; + } + + hb_set_t *copy = hb_object_create (); + if (unlikely (!copy)) + return depend_data->fail (); + copy->set (set); + if (unlikely (copy->in_error ())) + { + hb_set_destroy (copy); + return depend_data->fail (); + } + + *index = recurse_sets.length; + if (unlikely (*index & SINGLE_GLYPH_ACTIVE_FLAG)) + { + hb_set_destroy (copy); + return depend_data->fail (); + } + if (unlikely (!recurse_sets.push_or_fail (hb::unique_ptr {copy}))) + return depend_data->fail (); + if (unlikely (!recurse_set_to_index.set (recurse_sets[*index].get (), *index))) + return depend_data->fail (); + return true; + } + + const hb_set_t *find_or_create_glyph_set (const void *data, + unsigned value, + glyph_set_type_t type); + hb_codepoint_t find_or_create_cached_context_set (const hb_set_t *set); + + struct depend_scratch_t + { + void clear () + { + preliminary_context.clear (); + position_scratch.clear (); + pos_glyphs.clear (); + position_context.clear (); + disjunctive_indices.clear (); + filtered_disjunctive_indices.clear (); + backtrack_sets.clear (); + lookahead_sets.clear (); + input_position_glyphs.clear (); + cached_context_sets.clear (); + compact_workspace.clear (); + } + + hb_set_t preliminary_context; + hb_set_t position_scratch; + hb_set_t pos_glyphs; + hb_set_t position_context; + hb_set_t disjunctive_indices; + hb_set_t filtered_disjunctive_indices; + hb_vector_t backtrack_sets; + hb_vector_t lookahead_sets; + hb_vector_t input_position_glyphs; + hb_vector_t cached_context_sets; + hb_vector_t compact_workspace; + depend_scratch_t *next = nullptr; + }; + + depend_scratch_t *acquire_depend_scratch () + { + depend_scratch_t *scratch = depend_scratch_pool; + if (scratch) + depend_scratch_pool = scratch->next; + else + { + scratch = (depend_scratch_t *) hb_malloc (sizeof (depend_scratch_t)); + if (unlikely (!scratch)) + { + depend_data->fail (); + return nullptr; + } + new (scratch) depend_scratch_t (); + } + + scratch->next = nullptr; + scratch->clear (); + return scratch; + } + + void release_depend_scratch (depend_scratch_t *scratch) + { + scratch->next = depend_scratch_pool; + depend_scratch_pool = scratch; + } + hb_depend_data_builder_t *depend_data; + hb_face_t *face; + hb_set_t *glyphs; + hb_vector_t active_glyphs_stack; + unsigned active_glyphs_stack_depth = 0; + recurse_func_t recurse_func; + hb_codepoint_t lookup_index = HB_CODEPOINT_INVALID; + hb_bit_set_t lookups_seen; + hb_vector_t> recurse_sets; + hb_hashmap_t recurse_set_to_index; + hb_hashmap_t recurse_path_to_index; + hb_codepoint_t recurse_path = 0; + hb_hashmap_t completed_recursions; + hb_vector_t> glyph_sets; + hb_hashmap_t glyph_set_to_index; + hb_hashmap_t cached_context_set_indices; + hb_hashmap_t context_set_cache; + depend_scratch_t *depend_scratch_pool = nullptr; + + hb_depend_context_t (hb_depend_data_builder_t *depend_data_, + hb_face_t *face_, + hb_set_t *glyphs_) + : depend_data (depend_data_), + face(face_), + glyphs (glyphs_), + recurse_func (nullptr) {} + ~hb_depend_context_t () + { + while (depend_scratch_pool) + { + depend_scratch_t *scratch = depend_scratch_pool; + depend_scratch_pool = scratch->next; + scratch->~depend_scratch_t (); + hb_free (scratch); + } + } + void set_recurse_func (recurse_func_t func) { recurse_func = func; } +}; template struct hb_collect_coverage_context_t : @@ -481,6 +895,33 @@ struct matcher_t const void *match_data = nullptr; }; +/* A view of 16- or 24-bit glyph IDs or coverage offsets. */ +struct glyph_data_t +{ + template + glyph_data_t (const T *data_) : data (data_) +#ifndef HB_NO_BEYOND_64K + , wide (sizeof (T) == 3) +#endif + { + static_assert (sizeof (T) == 2 || sizeof (T) == 3, "invalid glyph data size"); + } + + unsigned operator [] (unsigned i) const + { +#ifndef HB_NO_BEYOND_64K + if (wide) + return ((const HBUINT24 *) data)[i]; +#endif + return ((const HBUINT16 *) data)[i]; + } + + const void *data; +#ifndef HB_NO_BEYOND_64K + bool wide; +#endif +}; + template struct skipping_iterator_t { @@ -503,20 +944,15 @@ struct skipping_iterator_t { matcher.set_match_func (match_func_, match_data_); } - void set_glyph_data (const HBUINT16 glyph_data[]) + void set_glyph_data (glyph_data_t glyph_data) { - match_glyph_data16 = glyph_data; #ifndef HB_NO_BEYOND_64K - match_glyph_data24 = nullptr; + match_glyph_data16 = glyph_data.wide ? nullptr : (const HBUINT16 *) glyph_data.data; + match_glyph_data24 = glyph_data.wide ? (const HBUINT24 *) glyph_data.data : nullptr; +#else + match_glyph_data16 = (const HBUINT16 *) glyph_data.data; #endif } -#ifndef HB_NO_BEYOND_64K - void set_glyph_data (const HBUINT24 glyph_data[]) - { - match_glyph_data16 = nullptr; - match_glyph_data24 = glyph_data; - } -#endif #ifndef HB_OPTIMIZE_SIZE HB_ALWAYS_INLINE @@ -577,9 +1013,6 @@ struct skipping_iterator_t return SKIP; } -#ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE -#endif bool next (unsigned *unsafe_to = nullptr) { auto *info = c->buffer->info; @@ -608,9 +1041,6 @@ struct skipping_iterator_t *unsafe_to = end; return false; } -#ifndef HB_OPTIMIZE_SIZE - HB_ALWAYS_INLINE -#endif bool prev (unsigned *unsafe_from = nullptr) { auto *out_info = c->buffer->out_info; @@ -721,7 +1151,6 @@ struct hb_ot_apply_context_t : recurse_func_t recurse_func = nullptr; const GDEF &gdef; const GDEF::accelerator_t &gdef_accel; - const hb_ot_layout_lookup_accelerator_t *lookup_accel = nullptr; const ItemVariationStore &var_store; hb_scalar_cache_t *var_store_cache; @@ -851,7 +1280,10 @@ struct hb_ot_apply_context_t : * match_props has the set index. */ if (match_props & LookupFlag::UseMarkFilteringSet) - return gdef_accel.mark_set_covers (match_props >> 16, info->codepoint); + { + unsigned set_index = match_props >> 16; + return gdef_accel.mark_set_covers (set_index, info->codepoint); + } /* The second byte of match_props has the meaning * "ignore marks of attachment type different than @@ -967,6 +1399,16 @@ enum class hb_ot_subtable_cache_op_t struct hb_accelerate_subtables_context_t : hb_dispatch_context_t { + template + static inline auto collect_second_glyphs_ (const T &obj, + hb_set_digest_t *digest, + hb_priority<1>) HB_RETURN (void, obj.collect_second_glyphs (digest) ) + template + static inline void collect_second_glyphs_ (const T &obj HB_UNUSED, + hb_set_digest_t *digest, + hb_priority<0>) + { *digest = hb_set_digest_t::full (); } + template static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) ) template @@ -1042,6 +1484,10 @@ struct hb_accelerate_subtables_context_t : { return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, nullptr); } + bool apply_no_digest (hb_ot_apply_context_t *c) const + { + return apply_func (obj, c, nullptr); + } #else bool apply (hb_ot_apply_context_t *c) const { @@ -1051,6 +1497,14 @@ struct hb_accelerate_subtables_context_t : { return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c, external_cache); } + bool apply_no_digest (hb_ot_apply_context_t *c) const + { + return apply_func (obj, c, external_cache); + } + bool apply_cached_no_digest (hb_ot_apply_context_t *c) const + { + return apply_cached_func (obj, c, external_cache); + } bool cache_enter (hb_ot_apply_context_t *c) const { @@ -1089,6 +1543,8 @@ struct hb_accelerate_subtables_context_t : template return_t dispatch (const T &obj) { + collect_second_glyphs_ (obj, &digest_second, hb_prioritize); + #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE void *external_cache = nullptr; if (i < 8) @@ -1132,6 +1588,7 @@ struct hb_accelerate_subtables_context_t : hb_applicable_t *array; unsigned i = 0; + hb_set_digest_t digest_second; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE unsigned subtable_cache_user_idx = (unsigned) -1; @@ -1144,6 +1601,19 @@ typedef bool (*intersects_func_t) (const hb_set_t *glyphs, unsigned value, const typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache); typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, unsigned value, const void *data); typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data); +typedef unsigned (*get_value_func_t) (hb_glyph_info_t &info, const void *data); + +/* One word per RuleSet, summarizing the classes accepted at the first + * input position after the current glyph. Collisions only cause extra work. */ +struct hb_ot_layout_ruleset_digest_t +{ + void init () { mask = 0; } + void set_full () { mask = (uint64_t) -1; } + void add (unsigned value) { mask |= (uint64_t) 1 << (value & 63); } + bool may_have (unsigned value) const { return mask & ((uint64_t) 1 << (value & 63)); } + + uint64_t mask; +}; struct ContextClosureFuncs { @@ -1184,7 +1654,7 @@ static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, con } static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data, void *cache HB_UNUSED) { - Offset16To coverage; + Offset32To coverage; coverage = value; return (data+coverage).intersects (glyphs); } @@ -1221,22 +1691,21 @@ static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache) { - Offset16To coverage; + Offset32To coverage; coverage = value; (data+coverage).intersect_set (*glyphs, *intersected_glyphs); } -template static inline bool array_is_subset_of (const hb_set_t *glyphs, unsigned int count, - const HBUINT values[], + glyph_data_t values, intersects_func_t intersects_func, const void *intersects_data, void *cache) { - for (const auto &_ : + hb_iter (values, count)) - if (!intersects_func (glyphs, _, intersects_data, cache)) return false; + for (unsigned i = 0; i < count; i++) + if (!intersects_func (glyphs, values[i], intersects_data, cache)) return false; return true; } @@ -1252,22 +1721,82 @@ static inline void collect_class (hb_set_t *glyphs, unsigned value, const void * } static inline void collect_coverage (hb_set_t *glyphs, unsigned value, const void *data) { - Offset16To coverage; + Offset32To coverage; coverage = value; (data+coverage).collect_coverage (glyphs); } -template + +inline const hb_set_t * +hb_depend_context_t::find_or_create_glyph_set (const void *data, + unsigned value, + glyph_set_type_t type) +{ + /* Class definitions and coverages are immutable for the lifetime of the + * context, so their expanded glyph sets can be shared across traversals. */ + glyph_set_cache_key_t key (data, value, type); + hb_codepoint_t *existing = nullptr; + if (glyph_set_to_index.has (key, &existing)) + return glyph_sets[*existing].get (); + + hb_set_t *set = hb_object_create (); + if (unlikely (!set)) + { + depend_data->fail (); + return nullptr; + } + + if (type == GLYPH_SET_COVERAGE) + collect_coverage (set, value, data); + else if (type == GLYPH_SET_CLASS) + collect_class (set, value, data); + else + set->add (value); + if (unlikely (set->in_error ())) + { + hb_set_destroy (set); + depend_data->fail (); + return nullptr; + } + + hb_codepoint_t index = glyph_sets.length; + if (unlikely (!glyph_sets.push_or_fail (hb::unique_ptr {set}))) + { + depend_data->fail (); + return nullptr; + } + if (unlikely (!glyph_set_to_index.set (key, index))) + { + depend_data->fail (); + return nullptr; + } + return glyph_sets[index].get (); +} + +inline hb_codepoint_t +hb_depend_context_t::find_or_create_cached_context_set (const hb_set_t *set) +{ + uintptr_t key = (uintptr_t) set; + hb_codepoint_t *existing = nullptr; + if (cached_context_set_indices.has (key, &existing)) + return *existing; + + hb_codepoint_t index = depend_data->find_or_create_context_set (*set); + if (unlikely (index == HB_CODEPOINT_INVALID)) + return HB_CODEPOINT_INVALID; + if (unlikely (!cached_context_set_indices.set (key, index))) + return depend_data->fail_invalid (); + return index; +} + static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, hb_set_t *glyphs, unsigned int count, - const HBUINT values[], + glyph_data_t values, collect_glyphs_func_t collect_func, const void *collect_data) { - return - + hb_iter (values, count) - | hb_apply ([&] (const HBUINT &_) { collect_func (glyphs, _, collect_data); }) - ; + for (unsigned i = 0; i < count; i++) + collect_func (glyphs, values[i], collect_data); } @@ -1284,6 +1813,26 @@ static inline bool match_class (hb_glyph_info_t &info, unsigned value, const voi const ClassDef &class_def = *reinterpret_cast(data); return class_def.get_class (info.codepoint) == value; } +static inline unsigned get_class_value (hb_glyph_info_t &info, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast (data); + return class_def.get_class (info.codepoint); +} +struct match_class_cache_data_t +{ + const ClassDef *class_def; + hb_ot_layout_mapping_cache_t *cache; +}; +static inline bool match_class_cache (hb_glyph_info_t &info, unsigned value, const void *data) +{ + const auto &cache_data = *reinterpret_cast (data); + return cache_data.class_def->get_class (info.codepoint, cache_data.cache) == value; +} +static inline unsigned get_class_cache_value (hb_glyph_info_t &info, const void *data) +{ + const auto &cache_data = *reinterpret_cast (data); + return cache_data.class_def->get_class (info.codepoint, cache_data.cache); +} static inline unsigned get_class_cached (const ClassDef &class_def, hb_glyph_info_t &info) { unsigned klass = info.syllable(); @@ -1299,6 +1848,11 @@ static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, co const ClassDef &class_def = *reinterpret_cast(data); return get_class_cached (class_def, info) == value; } +static inline unsigned get_class_cached_value (hb_glyph_info_t &info, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast (data); + return get_class_cached (class_def, info); +} static inline unsigned get_class_cached1 (const ClassDef &class_def, hb_glyph_info_t &info) { unsigned klass = info.syllable() & 0x0F; @@ -1329,17 +1883,21 @@ static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, c const ClassDef &class_def = *reinterpret_cast(data); return get_class_cached2 (class_def, info) == value; } +static inline unsigned get_class_cached2_value (hb_glyph_info_t &info, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast (data); + return get_class_cached2 (class_def, info); +} static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data) { - Offset16To coverage; + Offset32To coverage; coverage = value; return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED; } -template static inline bool would_match_input (hb_would_apply_context_t *c, unsigned int count, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ match_func_t match_func, const void *match_data) { @@ -1356,13 +1914,14 @@ static inline bool would_match_input (hb_would_apply_context_t *c, return true; } -template #ifndef HB_OPTIMIZE_SIZE HB_ALWAYS_INLINE +#else +inline #endif static bool match_input (hb_ot_apply_context_t *c, unsigned int count, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ match_func_t match_func, const void *match_data, unsigned int *end_position, @@ -1484,7 +2043,7 @@ static bool match_input (hb_ot_apply_context_t *c, return_trace (false); } - total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); + total_component_count += _hb_glyph_info_get_lig_num_comps_in_ligation (&buffer->info[skippy_iter.idx]); } *end_position = skippy_iter.idx + 1; @@ -1588,7 +2147,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, } last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); - last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); + last_num_components = _hb_glyph_info_get_lig_num_comps_in_ligation (&buffer->cur()); components_so_far += last_num_components; /* Skip the base glyph */ @@ -1614,13 +2173,14 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, return_trace (true); } -template #ifndef HB_OPTIMIZE_SIZE HB_ALWAYS_INLINE +#else +inline #endif static bool match_backtrack (hb_ot_apply_context_t *c, unsigned int count, - const HBUINT backtrack[], + glyph_data_t backtrack, match_func_t match_func, const void *match_data, unsigned int *match_start) @@ -1652,13 +2212,14 @@ static bool match_backtrack (hb_ot_apply_context_t *c, return_trace (true); } -template #ifndef HB_OPTIMIZE_SIZE HB_ALWAYS_INLINE +#else +inline #endif static bool match_lookahead (hb_ot_apply_context_t *c, unsigned int count, - const HBUINT lookahead[], + glyph_data_t lookahead, match_func_t match_func, const void *match_data, unsigned int start_index, @@ -1720,9 +2281,9 @@ struct LookupRecord DEFINE_SIZE_STATIC (4); }; -static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c, - const hb_array_t lookupRecords, - const hb_map_t *lookup_map) +static inline unsigned serialize_lookuprecord_array (hb_serialize_context_t *c, + const hb_array_t lookupRecords, + const hb_map_t *lookup_map) { unsigned count = 0; for (const LookupRecord& r : lookupRecords) @@ -1740,9 +2301,47 @@ static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c, enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 }; -template -static void context_closure_recurse_lookups (hb_closure_context_t *c, - unsigned inputCount, const HBUINT input[], +static inline const hb_set_t * +depend_position_glyphs (hb_depend_context_t *c, + ContextFormat context_format, + const void *data, + unsigned value, + bool filter_class_by_parent, + hb_set_t *scratch, + hb_vector_t *compact_workspace = nullptr) +{ + switch (context_format) + { + case ContextFormat::SimpleContext: + return c->find_or_create_glyph_set (nullptr, value, + hb_depend_context_t::GLYPH_SET_SINGLE); + case ContextFormat::ClassBasedContext: + { + const hb_set_t *class_set = c->find_or_create_glyph_set ( + data, value, hb_depend_context_t::GLYPH_SET_CLASS); + if (unlikely (!class_set)) + return nullptr; + if (!filter_class_by_parent) + return class_set; + scratch->set (*class_set); + scratch->intersect (c->parent_active_glyphs (), compact_workspace); + break; + } + case ContextFormat::CoverageBasedContext: + return c->find_or_create_glyph_set ( + data, value, hb_depend_context_t::GLYPH_SET_COVERAGE); + } + + if (unlikely (scratch->in_error ())) + { + c->depend_data->fail (); + return nullptr; + } + return scratch; +} + +static inline void context_closure_recurse_lookups (hb_closure_context_t *c, + unsigned inputCount, glyph_data_t input, unsigned lookupCount, const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */, unsigned value, @@ -1780,7 +2379,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, } else { - const void *input_data = input; + const void *input_data = input.data; unsigned input_value = seqIndex - 1; if (context_format != ContextFormat::SimpleContext) { @@ -1812,32 +2411,320 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, } } -template -static inline void recurse_lookups (context_t *c, - unsigned int lookupCount, - const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) -{ - for (unsigned int i = 0; i < lookupCount; i++) - c->recurse (lookupRecord[i].lookupListIndex); -} - -static inline void apply_lookup (hb_ot_apply_context_t *c, - unsigned int count, /* Including the first glyph */ - unsigned int lookupCount, - const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ - unsigned int match_end) +static bool +context_depend_sets_are_cached (hb_depend_context_t *c, + unsigned input_count, + unsigned lookup_count, + const LookupRecord lookup_records[], + const void *rule, + unsigned value, + ContextFormat context_format, + const void *data, + hb_vector_t *cached_context_sets) { - hb_buffer_t *buffer = c->buffer; - int end; - - /* All positions are distance from beginning of *output* buffer. - * Adjust. */ + hb_codepoint_t active_idx = HB_CODEPOINT_INVALID; + bool have_active_idx = false; + for (unsigned i = 0; i < lookup_count; i++) { - unsigned int bl = buffer->backtrack_len (); - end = bl + match_end - buffer->idx; + if (lookup_records[i].sequenceIndex >= input_count) + continue; - int delta = bl - buffer->idx; - /* Convert positions to new indexing. */ + if (!have_active_idx) + { + if (unlikely (!c->get_parent_active_glyphs_index (&active_idx))) + return false; + have_active_idx = true; + } + + hb_depend_context_t::context_set_cache_key_t key ( + rule, &lookup_records[i], data, active_idx, value, context_format); + hb_codepoint_t *cached_context_set = nullptr; + if (!c->context_set_cache.has (key, &cached_context_set)) + return false; + if (unlikely (!cached_context_sets->push_or_fail (*cached_context_set))) + return c->depend_data->fail (); + } + /* A rule with no valid records has no cache entries, and its preparation + * can still allocate dependency sets in an observable order. */ + return have_active_idx; +} + +static inline void context_depend_recurse_lookups (hb_depend_context_t *c, + unsigned inputCount, glyph_data_t input, + unsigned lookupCount, + const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */, + const void *rule, + unsigned value, + ContextFormat context_format, + const void *data, + intersected_glyphs_func_t intersected_glyphs_func, + void *cache, + const hb_set_t &preliminary_context, + const hb_vector_t *input_position_glyphs, + const hb_vector_t *cached_context_sets, + hb_depend_context_t::depend_scratch_t *scratch) +{ + /* For depend graph extraction, we filter active glyphs by InputCoverage constraints + * (same as closure), but we do NOT do sequential accumulation of outputs. + * + * - Position filtering (InputCoverage): Required. The contextual rule can only match + * glyphs in its InputCoverage. Edges for other glyphs are spurious. + * - Sequential accumulation: Not done. We want ALL possible edges, so we don't + * limit later lookups based on outputs from earlier lookups in the same rule. */ + + /* Sequence positions are tracked in one allocation-free bit page below. + * A rule longer than HB_MAX_CONTEXT_LENGTH never applies during shaping + * (the apply path rejects it), so skip it here instead of running past + * the fixed page in add_range(). */ + if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) + return; + + hb_bit_page_t covered_seq_indices; + hb_set_t &pos_glyphs = scratch->pos_glyphs; + hb_set_t &position_context = scratch->position_context; + hb_set_t &disjunctive_indices = scratch->disjunctive_indices; + hb_set_t &filtered_disjunctive_indices = scratch->filtered_disjunctive_indices; + unsigned cached_context_index = 0; + for (unsigned int i = 0; i < lookupCount; i++) + { + unsigned seqIndex = lookupRecord[i].sequenceIndex; + if (seqIndex >= inputCount) + continue; + + hb_depend_context_t::context_set_cache_key_t context_cache_key; + if (unlikely (!c->get_context_set_cache_key (rule, &lookupRecord[i], data, value, + context_format, &context_cache_key))) + return; + + hb_codepoint_t context_set_idx; + hb_codepoint_t *cached_context_set_idx; + if (cached_context_sets) + context_set_idx = (*cached_context_sets)[cached_context_index++]; + else if (c->context_set_cache.has (context_cache_key, &cached_context_set_idx)) + context_set_idx = *cached_context_set_idx; + else + { + if (unlikely (!input_position_glyphs)) + { + c->depend_data->fail (); + return; + } + + /* Build position-specific context_set for this lookup. */ + position_context.clear (); // Will hold direct glyphs + disjunctive_indices.clear (); // Will hold encoded set references + filtered_disjunctive_indices.clear (); + + /* Process preliminary_context in one pass. */ + hb_codepoint_t elem = HB_SET_VALUE_INVALID; + while (preliminary_context.next (&elem)) { + if (!(elem & HB_DEPEND_CONTEXT_SET_FLAG)) { + /* Direct glyph */ + position_context.add (elem); + } else { + /* Encoded set reference - defer processing until we have all direct requirements */ + disjunctive_indices.add (elem); + } + } + + /* Add singleton glyphs from OTHER input positions. */ + for (unsigned j = 0; j < input_position_glyphs->length; j++) { + if (j != seqIndex && (*input_position_glyphs)[j]->get_population () == 1) { + position_context.add ((*input_position_glyphs)[j]->get_min ()); + } + } + + /* Now position_context has all direct requirements. + * Process deferred encoded sets and filter them. */ + elem = HB_SET_VALUE_INVALID; + while (disjunctive_indices.next (&elem)) { + hb_codepoint_t set_idx = elem & 0x7FFFFFFF; + const hb_set_t *original_set = c->depend_data->get_set_from_index (set_idx); + if (unlikely (!original_set)) continue; + + /* Dependency context sets are never inverted. */ + if (!original_set->intersects (position_context)) { + /* No overlap with position_context - add full requirement */ + filtered_disjunctive_indices.add (elem); + } + /* Otherwise: position_context intersects with original_set. + * Since disjunctive requirements need only ONE glyph from the set, + * and position_context already has a glyph from this set, the + * requirement is satisfied - no need to add anything. */ + } + + /* Process non-singleton input positions. */ + for (unsigned j = 0; j < input_position_glyphs->length; j++) { + if (j != seqIndex && (*input_position_glyphs)[j]->get_population () > 1) { + /* Input-position sets are also never inverted. */ + if (!(*input_position_glyphs)[j]->intersects (position_context)) { + /* No overlap with position_context - add full requirement */ + bool cached_set = context_format == ContextFormat::CoverageBasedContext || + (context_format == ContextFormat::ClassBasedContext && j != 0); + hb_codepoint_t idx = cached_set + ? c->find_or_create_cached_context_set ((*input_position_glyphs)[j]) + : c->depend_data->find_or_create_context_set (*(*input_position_glyphs)[j]); + if (unlikely (idx == HB_CODEPOINT_INVALID)) + return; + filtered_disjunctive_indices.add (HB_DEPEND_CONTEXT_SET_FLAG | idx); + } + /* Otherwise: position_context intersects, requirement satisfied */ + } + } + + /* Combine direct + disjunctive. */ + position_context.union_ (filtered_disjunctive_indices); + if (unlikely (position_context.in_error () || + filtered_disjunctive_indices.in_error ())) + { + c->depend_data->fail (); + return; + } + + context_set_idx = position_context.is_empty () + ? HB_CODEPOINT_INVALID + : c->depend_data->find_or_create_context_set (position_context); + if (unlikely (!position_context.is_empty () && + context_set_idx == HB_CODEPOINT_INVALID)) + return; + + if (unlikely (!c->context_set_cache.set (context_cache_key, context_set_idx))) + { + c->depend_data->fail (); + return; + } + } + + /* Save outer context to restore after this lookup. When a contextual lookup + * calls another contextual lookup, we want each lookup in this rule to see + * the same outer context, not context from a sibling lookup. */ + hb_codepoint_t saved_context_set_index = c->depend_data->current_context_set_index; + hb_subset_depend_edge_flags_t saved_edge_flags = c->depend_data->current_edge_flags; + + /* Detect nested contextual: if we already have a context set, we're inside + * an outer contextual rule that called this one. The outer context will be + * lost, so edges created here may over-approximate. */ + bool nested_contextual = (saved_context_set_index != HB_CODEPOINT_INVALID); + + /* Set for this position's edges */ + c->depend_data->current_context_set_index = context_set_idx; + + /* Mark edges from multi-position rules (inputCount > 1) as potentially + * over-approximate. Depend extraction records edges based on what glyphs + * COULD be at each position per the static input coverage/class. But during + * closure computation, lookups within the rule are applied sequentially: + * lookups at earlier positions may transform later positions, and multiple + * lookups at the same position may interact (one produces a glyph, another + * immediately consumes it as an "intermediate"). So a glyph matching the + * coverage might not persist at that position when closure traverses. */ + c->depend_data->current_edge_flags = HB_SUBSET_DEPEND_EDGE_FLAG_NONE; + if (inputCount > 1) { + c->depend_data->current_edge_flags |= HB_SUBSET_DEPEND_EDGE_FLAG_FROM_CONTEXT_POSITION; + } + if (nested_contextual) { + c->depend_data->current_edge_flags |= HB_SUBSET_DEPEND_EDGE_FLAG_FROM_NESTED_CONTEXT; + } + + bool has_pos_glyphs = false; + + if (!covered_seq_indices.has (seqIndex)) + { + has_pos_glyphs = true; + pos_glyphs.clear (); + if (seqIndex == 0) + { + switch (context_format) { + case ContextFormat::SimpleContext: + pos_glyphs.add (value); + break; + case ContextFormat::ClassBasedContext: + intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs, cache); + break; + case ContextFormat::CoverageBasedContext: + pos_glyphs.set (c->parent_active_glyphs ()); + break; + } + } + else + { + const void *input_data = input.data; + unsigned input_value = seqIndex - 1; + if (context_format != ContextFormat::SimpleContext) + { + input_data = data; + input_value = input[seqIndex - 1]; + } + + intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs, cache); + } + } + + covered_seq_indices.add (seqIndex); + if (has_pos_glyphs) + { + hb_codepoint_t active_idx = HB_CODEPOINT_INVALID; + if (context_format == ContextFormat::SimpleContext) + { + hb_codepoint_t glyph = seqIndex ? pos_glyphs.get_min () : value; + if (likely (glyph < hb_depend_context_t::SINGLE_GLYPH_ACTIVE_FLAG)) + active_idx = glyph | hb_depend_context_t::SINGLE_GLYPH_ACTIVE_FLAG; + } + hb_set_t *cur_active_glyphs = c->push_cur_active_glyphs (active_idx); + if (unlikely (!cur_active_glyphs)) + { + c->depend_data->current_context_set_index = saved_context_set_index; + c->depend_data->current_edge_flags = saved_edge_flags; + return; + } + *cur_active_glyphs = std::move (pos_glyphs); + } + else if (unlikely (!c->push_root_active_glyphs ())) + { + c->depend_data->current_context_set_index = saved_context_set_index; + c->depend_data->current_edge_flags = saved_edge_flags; + return; + } + + unsigned endIndex = inputCount; + if (context_format == ContextFormat::CoverageBasedContext) + endIndex += 1; + + c->recurse (lookupRecord[i].lookupListIndex, &covered_seq_indices, seqIndex, endIndex); + c->pop_cur_done_glyphs (); + + /* Restore outer context after this lookup, so subsequent lookups in this + * rule see the original context rather than this lookup's context. */ + c->depend_data->current_context_set_index = saved_context_set_index; + c->depend_data->current_edge_flags = saved_edge_flags; + } +} + +template +static inline void recurse_lookups (context_t *c, + unsigned int lookupCount, + const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) +{ + for (unsigned int i = 0; i < lookupCount; i++) + c->recurse (lookupRecord[i].lookupListIndex); +} + +static inline void apply_lookup (hb_ot_apply_context_t *c, + unsigned int count, /* Including the first glyph */ + unsigned int lookupCount, + const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ + unsigned int match_end) +{ + hb_buffer_t *buffer = c->buffer; + int end; + + /* All positions are distance from beginning of *output* buffer. + * Adjust. */ + { + unsigned int bl = buffer->backtrack_len (); + end = bl + match_end - buffer->idx; + + int delta = bl - buffer->idx; + /* Convert positions to new indexing. */ for (unsigned int j = 0; j < count; j++) c->match_positions.arrayZ[j] += delta; } @@ -1978,6 +2865,8 @@ struct ContextClosureLookupContext void *intersected_glyphs_cache; }; +typedef ContextClosureLookupContext ContextDependLookupContext; + struct ContextCollectGlyphsLookupContext { ContextCollectGlyphsFuncs funcs; @@ -1988,12 +2877,12 @@ struct ContextApplyLookupContext { ContextApplyFuncs funcs; const void *match_data; + get_value_func_t get_value; }; -template static inline bool context_intersects (const hb_set_t *glyphs, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ ContextClosureLookupContext &lookup_context) { return array_is_subset_of (glyphs, @@ -2003,10 +2892,9 @@ static inline bool context_intersects (const hb_set_t *glyphs, lookup_context.intersects_cache); } -template static inline void context_closure_lookup (hb_closure_context_t *c, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookupCount, const LookupRecord lookupRecord[], unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */ @@ -2025,10 +2913,88 @@ static inline void context_closure_lookup (hb_closure_context_t *c, lookup_context.intersected_glyphs_cache); } -template +static inline void context_depend_lookup (hb_depend_context_t *c, + unsigned int inputCount, /* Including the first glyph (not matched) */ + glyph_data_t input, /* Array of input values--start with second glyph */ + unsigned int lookupCount, + const LookupRecord lookupRecord[], + const void *rule, + unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */ + ContextDependLookupContext &lookup_context) +{ + if (!context_intersects (c->glyphs, + inputCount, input, + lookup_context)) + return; + + hb_depend_context_t::depend_scratch_t *scratch = c->acquire_depend_scratch (); + if (unlikely (!scratch)) + return; + HB_SCOPE_GUARD (c->release_depend_scratch (scratch)); + + bool context_sets_cached = context_depend_sets_are_cached ( + c, inputCount, lookupCount, lookupRecord, rule, value, + lookup_context.context_format, lookup_context.intersects_data, + &scratch->cached_context_sets); + if (unlikely (!c->depend_data->successful)) + return; + + /* Build preliminary_context (empty for ContextSubst - no backtrack/lookahead) */ + hb_set_t &preliminary_context = scratch->preliminary_context; + + /* Build glyph sets for ALL input positions */ + hb_set_t &position_scratch = scratch->position_scratch; + hb_vector_t &input_position_glyphs = scratch->input_position_glyphs; + + /* Cached labels no longer need the expanded input-position sets. */ + if (!context_sets_cached) + { + /* Position 0 (Coverage glyph) — must be in both the class AND the + * coverage, so intersect with parent_active_glyphs (= coverage ∩ glyphs + * set by the ContextFormat2/3 caller). */ + const hb_set_t *pos0_glyphs = depend_position_glyphs ( + c, lookup_context.context_format, lookup_context.intersects_data, value, + true, &position_scratch, &scratch->compact_workspace); + if (unlikely (!pos0_glyphs || + !input_position_glyphs.push_or_fail (pos0_glyphs))) + { + c->depend_data->fail (); + return; + } + + /* Positions 1+ (Input array) */ + for (unsigned i = 0; i + 1 < inputCount; i++) + { + const hb_set_t *pos_glyphs = depend_position_glyphs ( + c, lookup_context.context_format, lookup_context.intersects_data, + input[i], false, &position_scratch); + if (unlikely (!pos_glyphs || + !input_position_glyphs.push_or_fail (pos_glyphs))) + { + c->depend_data->fail (); + return; + } + } + } + + context_depend_recurse_lookups (c, + inputCount, input, + lookupCount, lookupRecord, + rule, + value, + lookup_context.context_format, + lookup_context.intersects_data, + lookup_context.funcs.intersected_glyphs, + lookup_context.intersected_glyphs_cache, + preliminary_context, + context_sets_cached ? nullptr : &input_position_glyphs, + context_sets_cached ? &scratch->cached_context_sets : nullptr, + scratch); +} + static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookupCount, const LookupRecord lookupRecord[], ContextCollectGlyphsLookupContext &lookup_context) @@ -2040,10 +3006,9 @@ static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c lookupCount, lookupRecord); } -template static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookupCount HB_UNUSED, const LookupRecord lookupRecord[] HB_UNUSED, const ContextApplyLookupContext &lookup_context) @@ -2053,10 +3018,9 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, lookup_context.funcs.match, lookup_context.match_data); } -template static inline bool context_apply_lookup (hb_ot_apply_context_t *c, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookupCount, const LookupRecord lookupRecord[], const ContextApplyLookupContext &lookup_context) @@ -2114,8 +3078,8 @@ static inline bool context_cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_ template struct Rule { - template - friend struct RuleSet; + template + friend struct RuleSetOf; bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const { @@ -2124,6 +3088,17 @@ struct Rule lookup_context); } + void depend (hb_depend_context_t *c, unsigned value, ContextDependLookupContext &lookup_context) const + { + const auto &lookupRecord = StructAfter> + (inputZ.as_array ((inputCount ? inputCount - 1 : 0))); + context_depend_lookup (c, + inputCount, inputZ.arrayZ, + lookupCount, lookupRecord.arrayZ, + this, + value, lookup_context); + } + void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const { if (unlikely (c->lookup_limit_exceeded ())) return; @@ -2158,6 +3133,24 @@ struct Rule lookup_context); } + void collect_second_glyphs (hb_set_digest_t *digest, + const ClassDef *class_def = nullptr) const + { + if (inputCount <= 1) + { + *digest = hb_set_digest_t::full (); + return; + } + + unsigned second = inputZ.arrayZ[0]; + if (!class_def) + digest->add (second); + else if (!second) + *digest = hb_set_digest_t::full (); + else + class_def->collect_class (digest, second); + } + bool would_apply (hb_would_apply_context_t *c, const ContextApplyLookupContext &lookup_context) const { @@ -2190,7 +3183,7 @@ struct Rule const auto input = inputZ.as_array (inputCount - 1); for (const auto org : input) { - HBUINT16 d; + typename Types::HBUINT d; d = input_mapping->get (org); c->copy (d); } @@ -2241,22 +3234,43 @@ struct Rule DEFINE_SIZE_ARRAY (4, inputZ); }; -template -struct RuleSet +template +struct RuleSetOf { - using Rule = OT::Rule; - bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const { return + hb_iter (rule) | hb_map (hb_add (this)) - | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); }) + | hb_map ([&] (const RuleType &_) { return _.intersects (glyphs, lookup_context); }) | hb_any ; } + void collect_first_input_classes (hb_ot_layout_ruleset_digest_t *digest) const + { + digest->init (); + for (unsigned i = 0; i < rule.len; i++) + { + const RuleType &r = this+rule.arrayZ[i]; + if (r.inputCount <= 1) + { + digest->set_full (); + return; + } + digest->add (r.inputZ.arrayZ[0]); + } + } + + void depend (hb_depend_context_t *c, unsigned value, ContextDependLookupContext &lookup_context) const + { + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([&] (const RuleType &_) { _.depend (c, value, lookup_context); }) + ; + } + void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const { @@ -2265,7 +3279,7 @@ struct RuleSet return + hb_iter (rule) | hb_map (hb_add (this)) - | hb_apply ([&] (const Rule &_) { _.closure (c, value, lookup_context); }) + | hb_apply ([&] (const RuleType &_) { _.closure (c, value, lookup_context); }) ; } @@ -2275,7 +3289,7 @@ struct RuleSet if (unlikely (c->lookup_limit_exceeded ())) return; + hb_iter (rule) | hb_map (hb_add (this)) - | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); }) + | hb_apply ([&] (const RuleType &_) { _.closure_lookups (c, lookup_context); }) ; } @@ -2285,7 +3299,16 @@ struct RuleSet return + hb_iter (rule) | hb_map (hb_add (this)) - | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); }) + | hb_apply ([&] (const RuleType &_) { _.collect_glyphs (c, lookup_context); }) + ; + } + + void collect_second_glyphs (hb_set_digest_t *digest, + const ClassDef *class_def = nullptr) const + { + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([=] (const RuleType &_) { _.collect_second_glyphs (digest, class_def); }) ; } @@ -2295,13 +3318,14 @@ struct RuleSet return + hb_iter (rule) | hb_map (hb_add (this)) - | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); }) + | hb_map ([&] (const RuleType &_) { return _.would_apply (c, lookup_context); }) | hb_any ; } bool apply (hb_ot_apply_context_t *c, - const ContextApplyLookupContext &lookup_context) const + const ContextApplyLookupContext &lookup_context, + const hb_ot_layout_ruleset_digest_t *digest = nullptr) const { TRACE_APPLY (this); @@ -2315,7 +3339,7 @@ struct RuleSet return_trace ( + hb_iter (rule) | hb_map (hb_add (this)) - | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); }) + | hb_map ([&] (const RuleType &_) { return _.apply (c, lookup_context); }) | hb_any ) ; @@ -2337,7 +3361,7 @@ struct RuleSet skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); unsigned unsafe_to = (unsigned) -1, unsafe_to1, unsafe_to2 = 0; hb_glyph_info_t *first = nullptr, *second = nullptr; - bool matched = skippy_iter.next (); + bool matched = skippy_iter.next (&unsafe_to1); if (likely (matched)) { if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) @@ -2349,19 +3373,32 @@ struct RuleSet first = &c->buffer->info[skippy_iter.idx]; unsafe_to1 = skippy_iter.idx + 1; + + if (digest && lookup_context.get_value && + !digest->may_have (lookup_context.get_value (*first, lookup_context.match_data))) + { + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to1); + return_trace (false); + } } else { - /* Failed to match a next glyph. Only try applying rules that have - * no further input. */ - return_trace ( + bool unsafe_to_concat = false; + bool ret = + hb_iter (rule) | hb_map (hb_add (this)) - | hb_filter ([&] (const Rule &_) { return _.inputCount <= 1; }) - | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); }) + | hb_filter ([&] (const RuleType &_) + { + if (_.inputCount <= 1) return true; + unsafe_to_concat = true; + return false; + }) + | hb_map ([&] (const RuleType &_) { return _.apply (c, lookup_context); }) | hb_any - ) ; + if (unsafe_to_concat) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to1); + return_trace (ret); } matched = skippy_iter.next (); if (likely (matched)) @@ -2436,7 +3473,7 @@ struct RuleSet auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - for (const Offset16To& _ : rule) + for (const auto& _ : rule) { if (!_) continue; auto o_snap = c->serializer->snapshot (); @@ -2463,13 +3500,19 @@ struct RuleSet } protected: - Array16OfOffset16To + Array16Of> rule; /* Array of Rule tables * ordered by preference */ public: DEFINE_SIZE_ARRAY (2, rule); }; +template +struct RuleSet : RuleSetOf> {}; + +template +struct ClassRuleSet : RuleSetOf> {}; + template struct ContextFormat1_4 @@ -2497,6 +3540,31 @@ struct ContextFormat1_4 bool may_have_non_1to1 () const { return true; } + void depend (hb_depend_context_t *c) const + { + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; + get_coverage ().intersect_set (*c->glyphs, *cur_active_glyphs); + + ContextDependLookupContext lookup_context = { + {intersects_glyph, intersected_glyph}, + ContextFormat::SimpleContext, + nullptr, + nullptr, /* intersects_cache */ + nullptr /* intersected_glyphs_cache */ + }; + + + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len)) + | hb_filter ([&] (hb_codepoint_t _) { + return c->parent_active_glyphs ().has (_); + }, hb_first) + | hb_map ([&](const hb_pair_t _) { return hb_pair_t (_.first, this+ruleSet[_.second]); }) + | hb_apply ([&] (const hb_pair_t& _) { _.second.depend (c, _.first, lookup_context); }) + ; + + c->pop_cur_done_glyphs (); + } + void closure (hb_closure_context_t *c) const { hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); @@ -2553,6 +3621,14 @@ struct ContextFormat1_4 ; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([digest] (const RuleSet &_) { _.collect_second_glyphs (digest); }) + ; + } + bool would_apply (hb_would_apply_context_t *c) const { const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; @@ -2612,21 +3688,21 @@ struct ContextFormat1_4 protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of table */ - Array16Of> + typename Types::template ArrayOf> ruleSet; /* Array of RuleSet tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + Types::HBUINT::static_size, ruleSet); }; template struct ContextFormat2_5 { - using RuleSet = OT::RuleSet; + using RuleSet = OT::ClassRuleSet; bool intersects (const hb_set_t *glyphs) const { @@ -2665,6 +3741,41 @@ struct ContextFormat2_5 bool may_have_non_1to1 () const { return true; } + void depend (hb_depend_context_t *c) const + { + if (!(this+coverage).intersects (c->glyphs)) + return; + + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; + get_coverage ().intersect_set (*c->glyphs, *cur_active_glyphs); + + const ClassDef &class_def = this+classDef; + + hb_map_t cache; + intersected_class_cache_t intersected_cache; + ContextDependLookupContext lookup_context = { + {intersects_class, intersected_class_glyphs}, + ContextFormat::ClassBasedContext, + &class_def, + &cache, + &intersected_cache + }; + + + hb_enumerate (ruleSet) + | hb_filter ([&] (unsigned _) + { return class_def.intersects_class (&c->parent_active_glyphs (), _); }, + hb_first) + | hb_apply ([&] (const hb_pair_t&> _) + { + const RuleSet& rule_set = this+_.second; + rule_set.depend (c, _.first, lookup_context); + }) + ; + + c->pop_cur_done_glyphs (); + } + void closure (hb_closure_context_t *c) const { if (!(this+coverage).intersects (c->glyphs)) @@ -2744,6 +3855,15 @@ struct ContextFormat2_5 ; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { + const ClassDef &class_def = this+classDef; + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([=, &class_def] (const RuleSet &_) { _.collect_second_glyphs (digest, &class_def); }) + ; + } + bool would_apply (hb_would_apply_context_t *c) const { const ClassDef &class_def = this+classDef; @@ -2770,13 +3890,20 @@ struct ContextFormat2_5 struct external_cache_t { hb_ot_layout_binary_cache_t coverage; + hb_ot_layout_ruleset_digest_t rule_sets[HB_VAR_ARRAY]; }; void *external_cache_create () const { - external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); + unsigned count = ruleSet.len; + unsigned size = sizeof (external_cache_t) - + HB_VAR_ARRAY * sizeof (hb_ot_layout_ruleset_digest_t) + + count * sizeof (hb_ot_layout_ruleset_digest_t); + external_cache_t *cache = (external_cache_t *) hb_malloc (size); if (likely (cache)) { cache->coverage.clear (); + for (unsigned i = 0; i < count; i++) + (this+ruleSet[i]).collect_first_input_classes (&cache->rule_sets[i]); } return cache; } @@ -2797,12 +3924,18 @@ struct ContextFormat2_5 struct ContextApplyLookupContext lookup_context = { {cached ? match_class_cached : match_class}, - &class_def + &class_def, + cached ? get_class_cached_value : get_class_value }; index = cached ? get_class_cached (class_def, c->buffer->cur()) : class_def.get_class (c->buffer->cur().codepoint); const RuleSet &rule_set = this+ruleSet[index]; - return_trace (rule_set.apply (c, lookup_context)); +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + const hb_ot_layout_ruleset_digest_t *digest = cache && index < ruleSet.len ? &cache->rule_sets[index] : nullptr; +#else + const hb_ot_layout_ruleset_digest_t *digest = nullptr; +#endif + return_trace (rule_set.apply (c, lookup_context, digest)); } bool subset (hb_subset_context_t *c) const @@ -2869,21 +4002,22 @@ struct ContextFormat2_5 protected: HBUINT16 format; /* Format identifier--format = 2 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of table */ - typename Types::template OffsetTo + typename Types::template LOffsetTo classDef; /* Offset to glyph ClassDef table--from * beginning of table */ - Array16Of> + typename Types::template ArrayOf> ruleSet; /* Array of RuleSet tables * ordered by class */ public: - DEFINE_SIZE_ARRAY (4 + 2 * Types::size, ruleSet); + DEFINE_SIZE_ARRAY (2 + 2 * Types::LOffset::static_size + Types::HBUINT::static_size, ruleSet); }; -struct ContextFormat3 +template +struct ContextFormat3_6 { using RuleSet = OT::RuleSet; @@ -2898,13 +4032,39 @@ struct ContextFormat3 this }; return context_intersects (glyphs, - glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), + glyphCount, coverageZ.arrayZ + 1, lookup_context); } bool may_have_non_1to1 () const { return true; } + void depend (hb_depend_context_t *c) const + { + if (!(this+coverageZ[0]).intersects (c->glyphs)) + return; + + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; + get_coverage ().intersect_set (*c->glyphs, *cur_active_glyphs); + + const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); + ContextDependLookupContext lookup_context = { + {intersects_coverage, intersected_coverage_glyphs}, + ContextFormat::CoverageBasedContext, + this, + nullptr, /* intersects_cache */ + nullptr /* intersected_glyphs_cache */ + }; + context_depend_lookup (c, + glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), + lookupCount, lookupRecord, + this, + coverageZ[0], lookup_context); + + c->pop_cur_done_glyphs (); + } + void closure (hb_closure_context_t *c) const { if (!(this+coverageZ[0]).intersects (c->glyphs)) @@ -2922,7 +4082,7 @@ struct ContextFormat3 this }; context_closure_lookup (c, - glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), + glyphCount, coverageZ.arrayZ + 1, lookupCount, lookupRecord, 0, lookup_context); @@ -2950,11 +4110,19 @@ struct ContextFormat3 }; context_collect_glyphs_lookup (c, - glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), + glyphCount, coverageZ.arrayZ + 1, lookupCount, lookupRecord, lookup_context); } + void collect_second_glyphs (hb_set_digest_t *digest) const + { + if (glyphCount <= 1) + *digest = hb_set_digest_t::full (); + else + (this+coverageZ[1]).collect_coverage (digest); + } + bool would_apply (hb_would_apply_context_t *c) const { const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); @@ -2963,7 +4131,7 @@ struct ContextFormat3 this }; return context_would_apply_lookup (c, - glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), + glyphCount, coverageZ.arrayZ + 1, lookupCount, lookupRecord, lookup_context); } @@ -2981,7 +4149,11 @@ struct ContextFormat3 {match_coverage}, this }; - return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context)); + return_trace (context_apply_lookup (c, + glyphCount, + coverageZ.arrayZ + 1, + lookupCount, lookupRecord, + lookup_context)); } bool subset (hb_subset_context_t *c) const @@ -2995,10 +4167,10 @@ struct ContextFormat3 auto coverages = coverageZ.as_array (glyphCount); - for (const Offset16To& offset : coverages) + for (const auto& offset : coverages) { /* TODO(subset) This looks like should not be necessary to write this way. */ - auto *o = c->serializer->allocate_size> (Offset16To::static_size); + auto *o = c->serializer->allocate_size> (Types::Offset::static_size); if (unlikely (!o)) return_trace (false); if (!o->serialize_subset (c, offset, this)) return_trace (false); } @@ -3030,7 +4202,7 @@ struct ContextFormat3 HBUINT16 glyphCount; /* Number of glyphs in the input glyph * sequence */ HBUINT16 lookupCount; /* Number of LookupRecords */ - UnsizedArrayOf> + UnsizedArrayOf> coverageZ; /* Array of offsets to Coverage * table in glyph sequence order */ /*UnsizedArrayOf @@ -3054,6 +4226,7 @@ struct Context #ifndef HB_NO_BEYOND_64K case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward (ds)...)); case 5: hb_barrier (); return_trace (c->dispatch (u.format5, std::forward (ds)...)); + case 6: hb_barrier (); return_trace (c->dispatch (u.format6, std::forward (ds)...)); #endif default:return_trace (c->default_return_value ()); } @@ -3064,10 +4237,11 @@ struct Context struct { HBUINT16 v; } format; /* Format identifier */ ContextFormat1_4 format1; ContextFormat2_5 format2; - ContextFormat3 format3; + ContextFormat3_6 format3; #ifndef HB_NO_BEYOND_64K ContextFormat1_4 format4; ContextFormat2_5 format5; + ContextFormat3_6 format6; #endif } u; }; @@ -3084,6 +4258,8 @@ struct ChainContextClosureLookupContext void *intersected_glyphs_cache; }; +typedef ChainContextClosureLookupContext ChainContextDependLookupContext; + struct ChainContextCollectGlyphsLookupContext { ContextCollectGlyphsFuncs funcs; @@ -3094,43 +4270,44 @@ struct ChainContextApplyLookupContext { ChainContextApplyFuncs funcs; const void *match_data[3]; + get_value_func_t get_input_value; }; -template static inline bool chain_context_intersects (const hb_set_t *glyphs, unsigned int backtrackCount, - const HBUINT backtrack[], + glyph_data_t backtrack, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookaheadCount, - const HBUINT lookahead[], + glyph_data_t lookahead, ChainContextClosureLookupContext &lookup_context) { - return array_is_subset_of (glyphs, + bool bt_ok = array_is_subset_of (glyphs, backtrackCount, backtrack, lookup_context.funcs.intersects, lookup_context.intersects_data[0], - lookup_context.intersects_cache[0]) - && array_is_subset_of (glyphs, + lookup_context.intersects_cache[0]); + bool in_ok = array_is_subset_of (glyphs, inputCount ? inputCount - 1 : 0, input, lookup_context.funcs.intersects, lookup_context.intersects_data[1], - lookup_context.intersects_cache[1]) - && array_is_subset_of (glyphs, + lookup_context.intersects_cache[1]); + bool la_ok = array_is_subset_of (glyphs, lookaheadCount, lookahead, lookup_context.funcs.intersects, lookup_context.intersects_data[2], lookup_context.intersects_cache[2]); + + return bt_ok && in_ok && la_ok; } -template static inline void chain_context_closure_lookup (hb_closure_context_t *c, unsigned int backtrackCount, - const HBUINT backtrack[], + glyph_data_t backtrack, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookaheadCount, - const HBUINT lookahead[], + glyph_data_t lookahead, unsigned int lookupCount, const LookupRecord lookupRecord[], unsigned value, @@ -3151,14 +4328,185 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c, lookup_context.intersected_glyphs_cache); } -template +static inline void chain_context_depend_lookup (hb_depend_context_t *c, + unsigned int backtrackCount, + glyph_data_t backtrack, + unsigned int inputCount, /* Including the first glyph (not matched) */ + glyph_data_t input, /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + glyph_data_t lookahead, + unsigned int lookupCount, + const LookupRecord lookupRecord[], + const void *rule, + unsigned value, + ChainContextDependLookupContext &lookup_context) +{ + if (!chain_context_intersects (c->glyphs, + backtrackCount, backtrack, + inputCount, input, + lookaheadCount, lookahead, + lookup_context)) + return; + + hb_depend_context_t::depend_scratch_t *scratch = c->acquire_depend_scratch (); + if (unlikely (!scratch)) + return; + HB_SCOPE_GUARD (c->release_depend_scratch (scratch)); + + bool context_sets_cached = context_depend_sets_are_cached ( + c, inputCount, lookupCount, lookupRecord, rule, value, + lookup_context.context_format, lookup_context.intersects_data[1], + &scratch->cached_context_sets); + if (unlikely (!c->depend_data->successful)) + return; + if (context_sets_cached) + { + context_depend_recurse_lookups (c, + inputCount, input, + lookupCount, lookupRecord, + rule, + value, + lookup_context.context_format, + lookup_context.intersects_data[1], + lookup_context.funcs.intersected_glyphs, + lookup_context.intersected_glyphs_cache, + scratch->preliminary_context, + nullptr, + &scratch->cached_context_sets, + scratch); + return; + } + + /* Cache misses and rules without valid records still perform the original + * dependency-set interning in its observable order. */ + hb_set_t &position_scratch = scratch->position_scratch; + hb_vector_t &backtrack_sets = scratch->backtrack_sets; + hb_vector_t &lookahead_sets = scratch->lookahead_sets; + + /* Extract backtrack glyphs */ + for (unsigned i = 0; i < backtrackCount; i++) + { + const hb_set_t *pos_glyphs = depend_position_glyphs ( + c, lookup_context.context_format, lookup_context.intersects_data[0], + backtrack[i], false, &position_scratch); + if (unlikely (!pos_glyphs)) + return; + if (!pos_glyphs->is_empty ()) + { + if (unlikely (!backtrack_sets.push_or_fail (pos_glyphs))) + { + c->depend_data->fail (); + return; + } + } + } + + /* Extract lookahead glyphs */ + for (unsigned i = 0; i < lookaheadCount; i++) + { + const hb_set_t *pos_glyphs = depend_position_glyphs ( + c, lookup_context.context_format, lookup_context.intersects_data[2], + lookahead[i], false, &position_scratch); + if (unlikely (!pos_glyphs)) + return; + if (!pos_glyphs->is_empty ()) + { + if (unlikely (!lookahead_sets.push_or_fail (pos_glyphs))) + { + c->depend_data->fail (); + return; + } + } + } + + /* Build preliminary_context with backtrack + lookahead encoded */ + hb_set_t &preliminary_context = scratch->preliminary_context; + for (const hb_set_t *back_set : backtrack_sets) + { + if (back_set->get_population () == 1) { + preliminary_context.add (back_set->get_min ()); // Direct glyph + } else if (back_set->get_population () > 1) { + hb_codepoint_t set_idx = lookup_context.context_format == ContextFormat::SimpleContext + ? c->depend_data->find_or_create_context_set (*back_set) + : c->find_or_create_cached_context_set (back_set); + if (unlikely (set_idx == HB_CODEPOINT_INVALID)) + return; + preliminary_context.add (HB_DEPEND_CONTEXT_SET_FLAG | set_idx); // Encoded set reference + } + } + for (const hb_set_t *look_set : lookahead_sets) + { + if (look_set->get_population () == 1) { + preliminary_context.add (look_set->get_min ()); // Direct glyph + } else if (look_set->get_population () > 1) { + hb_codepoint_t set_idx = lookup_context.context_format == ContextFormat::SimpleContext + ? c->depend_data->find_or_create_context_set (*look_set) + : c->find_or_create_cached_context_set (look_set); + if (unlikely (set_idx == HB_CODEPOINT_INVALID)) + return; + preliminary_context.add (HB_DEPEND_CONTEXT_SET_FLAG | set_idx); // Encoded set reference + } + } + if (unlikely (preliminary_context.in_error ())) + { + c->depend_data->fail (); + return; + } + + /* Build glyph sets for ALL input positions */ + hb_vector_t &input_position_glyphs = scratch->input_position_glyphs; + + if (!context_sets_cached) + { + /* Position 0 (first input coverage/class/glyph) — must be in both the + * class AND the coverage, so intersect with parent_active_glyphs. */ + const hb_set_t *pos0_glyphs = depend_position_glyphs ( + c, lookup_context.context_format, lookup_context.intersects_data[1], value, + true, &position_scratch, &scratch->compact_workspace); + if (unlikely (!pos0_glyphs || + !input_position_glyphs.push_or_fail (pos0_glyphs))) + { + c->depend_data->fail (); + return; + } + + /* Positions 1+ (Input array) */ + for (unsigned i = 0; i + 1 < inputCount; i++) + { + const hb_set_t *pos_glyphs = depend_position_glyphs ( + c, lookup_context.context_format, lookup_context.intersects_data[1], + input[i], false, &position_scratch); + if (unlikely (!pos_glyphs || + !input_position_glyphs.push_or_fail (pos_glyphs))) + { + c->depend_data->fail (); + return; + } + } + } + + context_depend_recurse_lookups (c, + inputCount, input, + lookupCount, lookupRecord, + rule, + value, + lookup_context.context_format, + lookup_context.intersects_data[1], + lookup_context.funcs.intersected_glyphs, + lookup_context.intersected_glyphs_cache, + preliminary_context, + context_sets_cached ? nullptr : &input_position_glyphs, + context_sets_cached ? &scratch->cached_context_sets : nullptr, + scratch); +} + static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, unsigned int backtrackCount, - const HBUINT backtrack[], + glyph_data_t backtrack, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookaheadCount, - const HBUINT lookahead[], + glyph_data_t lookahead, unsigned int lookupCount, const LookupRecord lookupRecord[], ChainContextCollectGlyphsLookupContext &lookup_context) @@ -3176,14 +4524,13 @@ static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_contex lookupCount, lookupRecord); } -template static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, unsigned int backtrackCount, - const HBUINT backtrack[] HB_UNUSED, + glyph_data_t backtrack HB_UNUSED, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookaheadCount, - const HBUINT lookahead[] HB_UNUSED, + glyph_data_t lookahead HB_UNUSED, unsigned int lookupCount HB_UNUSED, const LookupRecord lookupRecord[] HB_UNUSED, const ChainContextApplyLookupContext &lookup_context) @@ -3194,14 +4541,13 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c lookup_context.funcs.match[1], lookup_context.match_data[1]); } -template static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, unsigned int backtrackCount, - const HBUINT backtrack[], + glyph_data_t backtrack, unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ + glyph_data_t input, /* Array of input values--start with second glyph */ unsigned int lookaheadCount, - const HBUINT lookahead[], + glyph_data_t lookahead, unsigned int lookupCount, const LookupRecord lookupRecord[], const ChainContextApplyLookupContext &lookup_context) @@ -3246,8 +4592,8 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, template struct ChainRule { - template - friend struct ChainRuleSet; + template + friend struct ChainRuleSetOf; bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const { @@ -3260,6 +4606,21 @@ struct ChainRule lookup_context); } + void depend (hb_depend_context_t *c, unsigned value, ChainContextDependLookupContext &lookup_context) const + { + const auto &input = StructAfter (backtrack); + const auto &lookahead = StructAfter (input); + const auto &lookup = StructAfter (lookahead); + chain_context_depend_lookup (c, + backtrack.len, backtrack.arrayZ, + input.lenP1, input.arrayZ, + lookahead.len, lookahead.arrayZ, + lookup.len, lookup.arrayZ, + this, + value, + lookup_context); + } + void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const { @@ -3303,6 +4664,39 @@ struct ChainRule lookup_context); } + void collect_second_glyphs (hb_set_digest_t *digest, + const ClassDef *input_class_def = nullptr, + const ClassDef *lookahead_class_def = nullptr) const + { + const auto &input = StructAfter (backtrack); + const auto &lookahead = StructAfter (input); + + unsigned second; + const ClassDef *class_def; + if (input.lenP1 > 1) + { + second = input.arrayZ[0]; + class_def = input_class_def; + } + else if (lookahead.len) + { + second = lookahead.arrayZ[0]; + class_def = lookahead_class_def; + } + else + { + *digest = hb_set_digest_t::full (); + return; + } + + if (!class_def) + digest->add (second); + else if (!second) + *digest = hb_set_digest_t::full (); + else + class_def->collect_class (digest, second); + } + bool would_apply (hb_would_apply_context_t *c, const ChainContextApplyLookupContext &lookup_context) const { @@ -3338,7 +4732,11 @@ struct ChainRule { c->copy (len); for (const auto g : it) - c->copy ((HBUINT16) g); + { + typename Types::HBUINT d; + d = g; + c->copy (d); + } } bool serialize (hb_serialize_context_t *c, @@ -3440,20 +4838,41 @@ struct ChainRule DEFINE_SIZE_MIN (8); }; -template -struct ChainRuleSet +template +struct ChainRuleSetOf { - using ChainRule = OT::ChainRule; - bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const { return + hb_iter (rule) | hb_map (hb_add (this)) - | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); }) + | hb_map ([&] (const ChainRuleType &_) { return _.intersects (glyphs, lookup_context); }) | hb_any ; } + + void collect_first_input_classes (hb_ot_layout_ruleset_digest_t *digest) const + { + digest->init (); + for (unsigned i = 0; i < rule.len; i++) + { + const ChainRuleType &r = this+rule.arrayZ[i]; + const auto &input = StructAfter (r.backtrack); + if (input.lenP1 <= 1) + { + digest->set_full (); + return; + } + digest->add (input.arrayZ[0]); + } + } + void depend (hb_depend_context_t *c, unsigned value, ChainContextDependLookupContext &lookup_context) const + { + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRuleType &_) { _.depend (c, value, lookup_context); }) + ; + } void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const { if (unlikely (c->lookup_limit_exceeded ())) return; @@ -3461,7 +4880,7 @@ struct ChainRuleSet return + hb_iter (rule) | hb_map (hb_add (this)) - | hb_apply ([&] (const ChainRule &_) { _.closure (c, value, lookup_context); }) + | hb_apply ([&] (const ChainRuleType &_) { _.closure (c, value, lookup_context); }) ; } @@ -3472,7 +4891,7 @@ struct ChainRuleSet + hb_iter (rule) | hb_map (hb_add (this)) - | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); }) + | hb_apply ([&] (const ChainRuleType &_) { _.closure_lookups (c, lookup_context); }) ; } @@ -3481,7 +4900,18 @@ struct ChainRuleSet return + hb_iter (rule) | hb_map (hb_add (this)) - | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); }) + | hb_apply ([&] (const ChainRuleType &_) { _.collect_glyphs (c, lookup_context); }) + ; + } + + void collect_second_glyphs (hb_set_digest_t *digest, + const ClassDef *input_class_def = nullptr, + const ClassDef *lookahead_class_def = nullptr) const + { + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([=] (const ChainRuleType &_) + { _.collect_second_glyphs (digest, input_class_def, lookahead_class_def); }) ; } @@ -3491,13 +4921,14 @@ struct ChainRuleSet return + hb_iter (rule) | hb_map (hb_add (this)) - | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); }) + | hb_map ([&] (const ChainRuleType &_) { return _.would_apply (c, lookup_context); }) | hb_any ; } bool apply (hb_ot_apply_context_t *c, - const ChainContextApplyLookupContext &lookup_context) const + const ChainContextApplyLookupContext &lookup_context, + const hb_ot_layout_ruleset_digest_t *digest = nullptr) const { TRACE_APPLY (this); @@ -3511,7 +4942,7 @@ struct ChainRuleSet return_trace ( + hb_iter (rule) | hb_map (hb_add (this)) - | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); }) + | hb_map ([&] (const ChainRuleType &_) { return _.apply (c, lookup_context); }) | hb_any ) ; @@ -3533,7 +4964,7 @@ struct ChainRuleSet skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); unsigned unsafe_to = (unsigned) -1, unsafe_to1, unsafe_to2 = 0; hb_glyph_info_t *first = nullptr, *second = nullptr; - bool matched = skippy_iter.next (); + bool matched = skippy_iter.next (&unsafe_to1); if (likely (matched)) { if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) @@ -3545,24 +4976,34 @@ struct ChainRuleSet first = &c->buffer->info[skippy_iter.idx]; unsafe_to1 = skippy_iter.idx + 1; + + if (digest && lookup_context.get_input_value && + !digest->may_have (lookup_context.get_input_value (*first, lookup_context.match_data[1]))) + { + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to1); + return_trace (false); + } } else { - /* Failed to match a next glyph. Only try applying rules that have - * no further input and lookahead. */ - return_trace ( + bool unsafe_to_concat = false; + bool ret = + hb_iter (rule) | hb_map (hb_add (this)) - | hb_filter ([&] (const ChainRule &_) + | hb_filter ([&] (const ChainRuleType &_) { const auto &input = StructAfter (_.backtrack); const auto &lookahead = StructAfter (input); - return input.lenP1 <= 1 && lookahead.len == 0; + if (input.lenP1 <= 1 && lookahead.len == 0) return true; + unsafe_to_concat = true; + return false; }) - | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); }) + | hb_map ([&] (const ChainRuleType &_) { return _.apply (c, lookup_context); }) | hb_any - ) ; + if (unsafe_to_concat) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to1); + return_trace (ret); } matched = skippy_iter.next (); if (likely (matched)) @@ -3652,7 +5093,7 @@ struct ChainRuleSet auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - for (const Offset16To& _ : rule) + for (const auto& _ : rule) { if (!_) continue; auto o_snap = c->serializer->snapshot (); @@ -3683,13 +5124,22 @@ struct ChainRuleSet } protected: - Array16OfOffset16To + Array16Of> rule; /* Array of ChainRule tables * ordered by preference */ public: DEFINE_SIZE_ARRAY (2, rule); }; +template +struct ChainRuleSet : ChainRuleSetOf> {}; + +static_assert (sizeof (ChainRuleSet) == + HBUINT16::static_size + Offset24::static_size, ""); + +template +struct ChainClassRuleSet : ChainRuleSetOf> {}; + template struct ChainContextFormat1_4 { @@ -3716,6 +5166,31 @@ struct ChainContextFormat1_4 bool may_have_non_1to1 () const { return true; } + void depend (hb_depend_context_t *c) const + { + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; + get_coverage ().intersect_set (*c->glyphs, *cur_active_glyphs); + + ChainContextDependLookupContext lookup_context = { + {intersects_glyph, intersected_glyph}, + ContextFormat::SimpleContext, + {nullptr, nullptr, nullptr}, + {nullptr, nullptr, nullptr}, /* intersects_cache */ + nullptr /* intersected_glyphs_cache */ + }; + + + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len)) + | hb_filter ([&] (hb_codepoint_t _) { + return c->parent_active_glyphs ().has (_); + }, hb_first) + | hb_map ([&](const hb_pair_t _) { return hb_pair_t (_.first, this+ruleSet[_.second]); }) + | hb_apply ([&] (const hb_pair_t& _) { _.second.depend (c, _.first, lookup_context); }) + ; + + c->pop_cur_done_glyphs (); + } + void closure (hb_closure_context_t *c) const { hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); @@ -3773,6 +5248,14 @@ struct ChainContextFormat1_4 ; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([digest] (const ChainRuleSet &_) { _.collect_second_glyphs (digest); }) + ; + } + bool would_apply (hb_would_apply_context_t *c) const { const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; @@ -3831,20 +5314,20 @@ struct ChainContextFormat1_4 protected: HBUINT16 format; /* Format identifier--format = 1 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of table */ - Array16Of> + typename Types::template ArrayOf> ruleSet; /* Array of ChainRuleSet tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet); + DEFINE_SIZE_ARRAY (2 + Types::LOffset::static_size + Types::HBUINT::static_size, ruleSet); }; template struct ChainContextFormat2_5 { - using ChainRuleSet = OT::ChainRuleSet; + using ChainRuleSet = OT::ChainClassRuleSet; bool intersects (const hb_set_t *glyphs) const { @@ -3886,6 +5369,45 @@ struct ChainContextFormat2_5 bool may_have_non_1to1 () const { return true; } + void depend (hb_depend_context_t *c) const + { + if (!(this+coverage).intersects (c->glyphs)) + return; + + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; + get_coverage ().intersect_set (*c->glyphs, *cur_active_glyphs); + + const ClassDef &backtrack_class_def = this+backtrackClassDef; + const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; + + hb_map_t caches[3] = {}; + intersected_class_cache_t intersected_cache; + ChainContextDependLookupContext lookup_context = { + {intersects_class, intersected_class_glyphs}, + ContextFormat::ClassBasedContext, + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def}, + {&caches[0], &caches[1], &caches[2]}, + &intersected_cache + }; + + + hb_enumerate (ruleSet) + | hb_filter ([&] (unsigned _) + { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); }, + hb_first) + | hb_apply ([&] (const hb_pair_t&> _) + { + const ChainRuleSet& chainrule_set = this+_.second; + chainrule_set.depend (c, _.first, lookup_context); + }) + ; + + c->pop_cur_done_glyphs (); + } + void closure (hb_closure_context_t *c) const { if (!(this+coverage).intersects (c->glyphs)) @@ -3979,6 +5501,17 @@ struct ChainContextFormat2_5 ; } + void collect_second_glyphs (hb_set_digest_t *digest) const + { + const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([digest, &input_class_def, &lookahead_class_def] (const ChainRuleSet &_) + { _.collect_second_glyphs (digest, &input_class_def, &lookahead_class_def); }) + ; + } + bool would_apply (hb_would_apply_context_t *c) const { const ClassDef &backtrack_class_def = this+backtrackClassDef; @@ -4010,13 +5543,24 @@ struct ChainContextFormat2_5 struct external_cache_t { hb_ot_layout_binary_cache_t coverage; + hb_ot_layout_mapping_cache_t input_class; + hb_ot_layout_mapping_cache_t lookahead_class; + hb_ot_layout_ruleset_digest_t rule_sets[HB_VAR_ARRAY]; }; void *external_cache_create () const { - external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); + unsigned count = ruleSet.len; + unsigned size = sizeof (external_cache_t) - + HB_VAR_ARRAY * sizeof (hb_ot_layout_ruleset_digest_t) + + count * sizeof (hb_ot_layout_ruleset_digest_t); + external_cache_t *cache = (external_cache_t *) hb_malloc (size); if (likely (cache)) { cache->coverage.clear (); + cache->input_class.clear (); + cache->lookahead_class.clear (); + for (unsigned i = 0; i < count; i++) + (this+ruleSet[i]).collect_first_input_classes (&cache->rule_sets[i]); } return cache; } @@ -4037,22 +5581,67 @@ struct ChainContextFormat2_5 const ClassDef &input_class_def = this+inputClassDef; const ClassDef &lookahead_class_def = this+lookaheadClassDef; +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + match_class_cache_data_t input_cache_data = { + &input_class_def, + cache ? &cache->input_class : nullptr + }; + match_class_cache_data_t lookahead_cache_data = { + &lookahead_class_def, + cache ? &cache->lookahead_class : nullptr + }; + const void *input_match_data = cached + ? static_cast (&input_class_def) + : static_cast (&input_cache_data); + const void *lookahead_match_data = cached + ? static_cast (&lookahead_class_def) + : static_cast (&lookahead_cache_data); + bool backtrack_uses_lookahead_cache = + !cached && &backtrack_class_def == &lookahead_class_def; + const void *backtrack_match_data = backtrack_uses_lookahead_cache + ? static_cast (&lookahead_cache_data) + : static_cast (&backtrack_class_def); +#endif + /* match_class_caches1 is slightly faster. Use it for lookahead, * which is typically longer. */ struct ChainContextApplyLookupContext lookup_context = { +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached1 : + backtrack_uses_lookahead_cache ? match_class_cache : match_class, + cached ? match_class_cached2 : match_class_cache, + cached ? match_class_cached1 : match_class_cache}}, + {backtrack_match_data, + input_match_data, + lookahead_match_data}, + cached ? get_class_cached2_value : get_class_cache_value +#else {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached1 : match_class, cached ? match_class_cached2 : match_class, cached ? match_class_cached1 : match_class}}, {&backtrack_class_def, &input_class_def, - &lookahead_class_def} + &lookahead_class_def}, + cached ? get_class_cached2_value : get_class_value +#endif }; +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + index = cached + ? get_class_cached2 (input_class_def, c->buffer->cur()) + : input_class_def.get_class (c->buffer->cur().codepoint, input_cache_data.cache); +#else index = cached ? get_class_cached2 (input_class_def, c->buffer->cur()) : input_class_def.get_class (c->buffer->cur().codepoint); +#endif const ChainRuleSet &rule_set = this+ruleSet[index]; - return_trace (rule_set.apply (c, lookup_context)); +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + const hb_ot_layout_ruleset_digest_t *digest = cache && index < ruleSet.len ? &cache->rule_sets[index] : nullptr; +#else + const hb_ot_layout_ruleset_digest_t *digest = nullptr; +#endif + return_trace (rule_set.apply (c, lookup_context, digest)); } bool subset (hb_subset_context_t *c) const @@ -4134,18 +5723,18 @@ struct ChainContextFormat2_5 protected: HBUINT16 format; /* Format identifier--format = 2 */ - typename Types::template OffsetTo + typename Types::template LOffsetTo coverage; /* Offset to Coverage table--from * beginning of table */ - typename Types::template OffsetTo + typename Types::template LOffsetTo backtrackClassDef; /* Offset to glyph ClassDef table * containing backtrack sequence * data--from beginning of table */ - typename Types::template OffsetTo + typename Types::template LOffsetTo inputClassDef; /* Offset to glyph ClassDef * table containing input sequence * data--from beginning of table */ - typename Types::template OffsetTo + typename Types::template LOffsetTo lookaheadClassDef; /* Offset to glyph ClassDef table * containing lookahead sequence * data--from beginning of table */ @@ -4153,9 +5742,10 @@ struct ChainContextFormat2_5 ruleSet; /* Array of ChainRuleSet tables * ordered by class */ public: - DEFINE_SIZE_ARRAY (4 + 4 * Types::size, ruleSet); + DEFINE_SIZE_ARRAY (4 + 4 * Types::LOffset::static_size, ruleSet); }; +template struct ChainContextFormat3 { using RuleSet = OT::RuleSet; @@ -4174,15 +5764,47 @@ struct ChainContextFormat3 {this, this, this} }; return chain_context_intersects (glyphs, - backtrack.len, (const HBUINT16 *) backtrack.arrayZ, - input.len, (const HBUINT16 *) input.arrayZ + 1, - lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + backtrack.len, backtrack.arrayZ, + input.len, input.arrayZ + 1, + lookahead.len, lookahead.arrayZ, lookup_context); } bool may_have_non_1to1 () const { return true; } + void depend (hb_depend_context_t *c) const + { + const auto &input = StructAfter (backtrack); + + if (!(this+input[0]).intersects (c->glyphs)) + return; + + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) + return; + get_coverage ().intersect_set (*c->glyphs, *cur_active_glyphs); + + const auto &lookahead = StructAfter (input); + const auto &lookup = StructAfter (lookahead); + ChainContextDependLookupContext lookup_context = { + {intersects_coverage, intersected_coverage_glyphs}, + ContextFormat::CoverageBasedContext, + {this, this, this}, + {nullptr, nullptr, nullptr}, /* intersects_cache */ + nullptr /* intersected_glyphs_cache */ + }; + chain_context_depend_lookup (c, + backtrack.len, (const HBUINT16 *) backtrack.arrayZ, + input.len, (const HBUINT16 *) input.arrayZ + 1, + lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + lookup.len, lookup.arrayZ, + this, + input[0], lookup_context); + + c->pop_cur_done_glyphs (); + } + void closure (hb_closure_context_t *c) const { const auto &input = StructAfter (backtrack); @@ -4204,9 +5826,9 @@ struct ChainContextFormat3 {this, this, this} }; chain_context_closure_lookup (c, - backtrack.len, (const HBUINT16 *) backtrack.arrayZ, - input.len, (const HBUINT16 *) input.arrayZ + 1, - lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + backtrack.len, backtrack.arrayZ, + input.len, input.arrayZ + 1, + lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, 0, lookup_context); @@ -4240,13 +5862,25 @@ struct ChainContextFormat3 {this, this, this} }; chain_context_collect_glyphs_lookup (c, - backtrack.len, (const HBUINT16 *) backtrack.arrayZ, - input.len, (const HBUINT16 *) input.arrayZ + 1, - lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + backtrack.len, backtrack.arrayZ, + input.len, input.arrayZ + 1, + lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context); } + void collect_second_glyphs (hb_set_digest_t *digest) const + { + const auto &input = StructAfter (backtrack); + const auto &lookahead = StructAfter (input); + if (input.len > 1) + (this+input[1]).collect_coverage (digest); + else if (lookahead.len) + (this+lookahead[0]).collect_coverage (digest); + else + *digest = hb_set_digest_t::full (); + } + bool would_apply (hb_would_apply_context_t *c) const { const auto &input = StructAfter (backtrack); @@ -4257,9 +5891,9 @@ struct ChainContextFormat3 {this, this, this} }; return chain_context_would_apply_lookup (c, - backtrack.len, (const HBUINT16 *) backtrack.arrayZ, - input.len, (const HBUINT16 *) input.arrayZ + 1, - lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + backtrack.len, backtrack.arrayZ, + input.len, input.arrayZ + 1, + lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context); } @@ -4284,9 +5918,9 @@ struct ChainContextFormat3 {this, this, this} }; return_trace (chain_context_apply_lookup (c, - backtrack.len, (const HBUINT16 *) backtrack.arrayZ, - input.len, (const HBUINT16 *) input.arrayZ + 1, - lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + backtrack.len, backtrack.arrayZ, + input.len, input.arrayZ + 1, + lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context)); } @@ -4295,10 +5929,8 @@ struct ChainContextFormat3 bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const { TRACE_SERIALIZE (this); - auto *out = c->serializer->start_embed> (); - - if (unlikely (!c->serializer->allocate_size (HBUINT16::static_size))) - return_trace (false); + auto *out = c->serializer->start_embed>> (); + if (unlikely (!out->serialize (c->serializer, 0u))) return_trace (false); for (auto& offset : it) { auto *o = out->serialize_append (c->serializer); @@ -4354,15 +5986,15 @@ struct ChainContextFormat3 protected: HBUINT16 format; /* Format identifier--format = 3 */ - Array16OfOffset16To + Array16Of> backtrack; /* Array of coverage tables * in backtracking sequence, in glyph * sequence order */ - Array16OfOffset16To + Array16Of> inputX ; /* Array of coverage * tables in input sequence, in glyph * sequence order */ - Array16OfOffset16To + Array16Of> lookaheadX; /* Array of coverage tables * in lookahead sequence, in glyph * sequence order */ @@ -4397,10 +6029,12 @@ struct ChainContext struct { HBUINT16 v; } format; /* Format identifier */ ChainContextFormat1_4 format1; ChainContextFormat2_5 format2; - ChainContextFormat3 format3; + ChainContextFormat3 format3; #ifndef HB_NO_BEYOND_64K ChainContextFormat1_4 format4; ChainContextFormat2_5 format5; + /* The beyond-64k spec adds sequence-context format 6, but no + * corresponding chained-context coverage format. */ #endif } u; }; @@ -4541,9 +6175,16 @@ struct hb_ot_layout_lookup_accelerator_t hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables); lookup.dispatch (&c_accelerate_subtables); + /* Invalid subtables do not collect and leave zeroed tail entries + * (see the calloc note above); trim them so the apply paths never + * see a null apply func. */ + while (count && !thiz->subtables[count - 1].apply_func) + count--; + thiz->digest.init (); for (auto& subtable : hb_iter (thiz->subtables, count)) thiz->digest.union_ (subtable.digest); + thiz->digest_second = c_accelerate_subtables.digest_second; thiz->count = count; @@ -4574,7 +6215,19 @@ struct hb_ot_layout_lookup_accelerator_t #endif bool apply (hb_ot_apply_context_t *c, bool use_cache) const { - c->lookup_accel = this; + if (count == 1) + { + /* The accelerator digest is the union of the subtable digests, so + * for a single subtable it equals that subtable's digest, which the + * caller has already tested; skip the redundant retest. Zeroed + * invalid entries were trimmed at create time, so the subtable is + * always valid here. */ +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + if (use_cache) + return subtables[0].apply_cached_no_digest (c); +#endif + return subtables[0].apply_no_digest (c); + } #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE if (use_cache) { @@ -4614,6 +6267,7 @@ struct hb_ot_layout_lookup_accelerator_t hb_set_digest_t digest; + hb_set_digest_t digest_second; private: unsigned count = 0; /* Number of subtables in the array. */ #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE @@ -4622,51 +6276,76 @@ struct hb_ot_layout_lookup_accelerator_t hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY]; }; -template -struct GSUBGPOSVersion1_2 +struct GSUBGPOS { - friend struct GSUBGPOS; - - protected: - FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set - * to 0x00010000u */ - typename Types:: template OffsetTo - scriptList; /* ScriptList table */ - typename Types::template OffsetTo - featureList; /* FeatureList table */ - typename Types::template OffsetTo> - lookupList; /* LookupList table */ - Offset32To - featureVars; /* Offset to Feature Variations - table--from beginning of table - * (may be NULL). Introduced - * in version 0x00010001. */ - public: - DEFINE_SIZE_MIN (4 + 3 * Types::size); + using LookupListT = LookupList; + using LookupList2T = LookupList; + template + using TLookupList = List16OfOffsetTo; + template + using TLookupList2 = List16OfOffsetTo; + template + using TLookupOffsetList = LookupOffsetList; + template + using TLookupOffsetList2 = LookupOffsetList; size_t get_size () const { + if (version.major != 1) return version.static_size; + return min_size + - (version.to_int () >= 0x00010001u ? featureVars.static_size : 0); + (version.to_int () >= 0x00010001u ? featureVars.static_size : 0) + +#ifndef HB_NO_BEYOND_64K + (version.to_int () >= 0x00010002u ? 3 * Offset32::static_size : 0) +#else + 0 +#endif + ; } - const typename Types::template OffsetTo>* get_lookup_list_offset () const + const ScriptList &get_script_list () const { - return &lookupList; +#ifndef HB_NO_BEYOND_64K + if (version.to_int () >= 0x00010002u && scriptList2) return this + scriptList2; +#endif + return this + scriptList; + } + const FeatureList &get_feature_list () const + { +#ifndef HB_NO_BEYOND_64K + if (version.to_int () >= 0x00010002u && featureList2) return this + featureList2; +#endif + return this + featureList; } - template bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - typedef List16OfOffsetTo TLookupList; - if (unlikely (!(scriptList.sanitize (c, this) && - featureList.sanitize (c, this) && - reinterpret_cast &> (lookupList).sanitize (c, this)))) + if (unlikely (!version.sanitize (c) || + version.major != 1 || + !c->check_range (this, get_size ()))) + return_trace (false); + hb_barrier (); + + bool script_list_ok = scriptList.sanitize (c, this); + bool feature_list_ok = featureList.sanitize (c, this); + bool lookup_list_ok = typed_lookup_list_offset ().sanitize (c, this); + +#ifndef HB_NO_BEYOND_64K + if (version.to_int () >= 0x00010002u) + { + if (scriptList2) script_list_ok = scriptList2.sanitize (c, this); + if (featureList2) feature_list_ok = featureList2.sanitize (c, this); + if (lookupList2) lookup_list_ok = typed_lookup_list2_offset ().sanitize (c, this); + } +#endif + + if (unlikely (!(script_list_ok && feature_list_ok && lookup_list_ok))) return_trace (false); #ifndef HB_NO_VAR - if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this)))) + if (unlikely (!(version.to_int () < 0x00010001u || + featureVars.sanitize (c, this, &get_feature_list ())))) return_trace (false); #endif @@ -4677,145 +6356,116 @@ struct GSUBGPOSVersion1_2 bool subset (hb_subset_layout_context_t *c) const { TRACE_SUBSET (this); + if (version.major != 1) return_trace (false); auto *out = c->subset_context->serializer->start_embed (this); if (unlikely (!c->subset_context->serializer->extend_min (out))) return_trace (false); out->version = version; - typedef LookupOffsetList TLookupList; - reinterpret_cast &> (out->lookupList) - .serialize_subset (c->subset_context, - reinterpret_cast &> (lookupList), - this, - c); +#ifndef HB_NO_BEYOND_64K + if (version.to_int () >= 0x00010002u) + { + if (unlikely (!c->subset_context->serializer->extend_size (out, get_size ()))) + return_trace (false); - reinterpret_cast &> (out->featureList) - .serialize_subset (c->subset_context, - reinterpret_cast &> (featureList), - this, - c); + out->scriptList = 0; + out->featureList = 0; + out->lookupList = 0; - out->scriptList.serialize_subset (c->subset_context, - scriptList, - this, - c); + if (lookupList2) + serialize_subset_offset (c->subset_context, out->lookupList2, + subset_lookup_list2_offset (), + this, c); + else + serialize_subset_offset (c->subset_context, out->lookupList2, + subset_lookup_list_offset (), + this, c); + + if (featureList2) + serialize_subset_offset (c->subset_context, out->featureList2, + subset_feature_list2_offset (), + this, c); + else + serialize_subset_offset (c->subset_context, out->featureList2, + subset_feature_list_offset (), + this, c); + + if (scriptList2) + serialize_subset_offset (c->subset_context, out->scriptList2, scriptList2, this, c); + else + serialize_subset_offset (c->subset_context, out->scriptList2, scriptList, this, c); + } + else +#endif + { + out->subset_lookup_list_offset () + .serialize_subset (c->subset_context, + subset_lookup_list_offset (), + this, + c); + + out->subset_feature_list_offset () + .serialize_subset (c->subset_context, + subset_feature_list_offset (), + this, + c); + + out->scriptList.serialize_subset (c->subset_context, + scriptList, + this, + c); + } #ifndef HB_NO_VAR if (version.to_int () >= 0x00010001u) { auto snapshot = c->subset_context->serializer->snapshot (); - if (!c->subset_context->serializer->extend_min (&out->featureVars)) + if (version.to_int () < 0x00010002u && + !c->subset_context->serializer->extend_min (&out->featureVars)) return_trace (false); // if all axes are pinned all feature vars are dropped. bool ret = !c->subset_context->plan->all_axes_pinned && out->featureVars.serialize_subset (c->subset_context, featureVars, this, c); - if (!ret && version.major == 1) + if (!ret) { - c->subset_context->serializer->revert (snapshot); - out->version.major = 1; - out->version.minor = 0; + out->featureVars = 0; + if (version.to_int () < 0x00010002u) + { + c->subset_context->serializer->revert (snapshot); + out->version.major = 1; + out->version.minor = 0; + } } } #endif return_trace (true); } -}; - -struct GSUBGPOS -{ - size_t get_size () const - { - switch (u.version.major) { - case 1: hb_barrier (); return u.version1.get_size (); -#ifndef HB_NO_BEYOND_64K - case 2: hb_barrier (); return u.version2.get_size (); -#endif - default: return u.version.static_size; - } - } - - template - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!u.version.sanitize (c))) return_trace (false); - hb_barrier (); - switch (u.version.major) { - case 1: hb_barrier (); return_trace (u.version1.sanitize (c)); -#ifndef HB_NO_BEYOND_64K - case 2: hb_barrier (); return_trace (u.version2.sanitize (c)); -#endif - default: return_trace (true); - } - } - - template - bool subset (hb_subset_layout_context_t *c) const - { - switch (u.version.major) { - case 1: hb_barrier (); return u.version1.subset (c); -#ifndef HB_NO_BEYOND_64K - case 2: hb_barrier (); return u.version2.subset (c); -#endif - default: return false; - } - } - const ScriptList &get_script_list () const - { - switch (u.version.major) { - case 1: hb_barrier (); return this+u.version1.scriptList; -#ifndef HB_NO_BEYOND_64K - case 2: hb_barrier (); return this+u.version2.scriptList; -#endif - default: return Null (ScriptList); - } - } - const FeatureList &get_feature_list () const - { - switch (u.version.major) { - case 1: hb_barrier (); return this+u.version1.featureList; -#ifndef HB_NO_BEYOND_64K - case 2: hb_barrier (); return this+u.version2.featureList; -#endif - default: return Null (FeatureList); - } - } unsigned int get_lookup_count () const { - switch (u.version.major) { - case 1: hb_barrier (); return (this+u.version1.lookupList).len; #ifndef HB_NO_BEYOND_64K - case 2: hb_barrier (); return (this+u.version2.lookupList).len; + if (version.to_int () >= 0x00010002u && lookupList2) + return (this + lookupList2).len; #endif - default: return 0; - } + return (this + lookupList).len; } const Lookup& get_lookup (unsigned int i) const { - switch (u.version.major) { - case 1: hb_barrier (); return (this+u.version1.lookupList)[i]; #ifndef HB_NO_BEYOND_64K - case 2: hb_barrier (); return (this+u.version2.lookupList)[i]; + if (version.to_int () >= 0x00010002u && lookupList2) + return (this + lookupList2)[i]; #endif - default: return Null (Lookup); - } + return (this + lookupList)[i]; } const FeatureVariations &get_feature_variations () const { - switch (u.version.major) { - case 1: hb_barrier (); return (u.version.to_int () >= 0x00010001u && hb_barrier () ? this+u.version1.featureVars : Null (FeatureVariations)); -#ifndef HB_NO_BEYOND_64K - case 2: hb_barrier (); return this+u.version2.featureVars; -#endif - default: return Null (FeatureVariations); - } + return (version.to_int () >= 0x00010001u && hb_barrier ()) ? this+featureVars : Null (FeatureVariations); } - bool has_data () const { return u.version.to_int (); } + bool has_data () const { return version.to_int (); } unsigned int get_script_count () const { return get_script_list ().len; } const Tag& get_script_tag (unsigned int i) const @@ -4852,12 +6502,44 @@ struct GSUBGPOS #endif return get_feature_variations ().find_index (coords, num_coords, index, instancer); } + bool get_feature_variations_state (const int *coords, + unsigned int num_coords, + unsigned int *index, + ItemVarStoreInstancer *instancer, + hb_vector_t *lookup_conditions) const + { + lookup_conditions->reset (); +#ifdef HB_NO_VAR + *index = FeatureVariations::NOT_FOUND_INDEX; + return true; +#else + find_variations_index (coords, num_coords, index, instancer); + return get_feature_variations ().collect_lookup_conditions ( + coords, + num_coords, + instancer, + lookup_conditions); +#endif + } + bool get_lookup_variations (unsigned feature_index, + unsigned variations_index, + hb_sorted_array_t conditions, + hb_set_t *lookup_indexes) const + { +#ifdef HB_NO_VAR + return false; +#else + return get_feature_variations ().get_lookup_variations ( + feature_index, get_feature_variation (feature_index, variations_index), + conditions, lookup_indexes); +#endif + } const Feature& get_feature_variation (unsigned int feature_index, unsigned int variations_index) const { #ifndef HB_NO_VAR if (FeatureVariations::NOT_FOUND_INDEX != variations_index && - u.version.to_int () >= 0x00010001u) + version.to_int () >= 0x00010001u) { const Feature *feature = get_feature_variations ().find_substitute (variations_index, feature_index); @@ -4877,6 +6559,13 @@ struct GSUBGPOS #endif } + void collect_feature_variation_indices (hb_collect_variation_indices_context_t *c) const + { +#ifndef HB_NO_VAR + get_feature_variations ().collect_variation_indices (c); +#endif + } + #ifndef HB_NO_VAR void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const { get_feature_variations ().collect_feature_substitutes_with_variations (c); } @@ -4964,15 +6653,33 @@ struct GSUBGPOS } void collect_name_ids (const hb_map_t *feature_index_map, - hb_set_t *nameids_to_retain /* OUT */) const + hb_set_t *nameids_to_retain, /* OUT */ + const hb_hashmap_t *feature_substitutes_map, + const hb_hashmap_t> *feature_record_cond_idx_map HB_UNUSED, + const hb_set_t *catch_all_features, + bool all_axes_pinned HB_UNUSED) const { unsigned count = get_feature_count (); for (unsigned i = 0 ; i < count; i++) { if (!feature_index_map->has (i)) continue; hb_tag_t tag = get_feature_tag (i); - get_feature (i).collect_name_ids (tag, nameids_to_retain); + const Feature *feature = &get_feature (i); + const Feature **substitute; + if (feature_substitutes_map->has (i, &substitute)) + { + feature = *substitute; + if (catch_all_features->has (i)) + get_feature (i).collect_name_ids (tag, nameids_to_retain); + } + feature->collect_name_ids (tag, nameids_to_retain); } +#ifndef HB_NO_VAR + if (!all_axes_pinned) + get_feature_variations ().collect_name_ids (feature_index_map, feature_record_cond_idx_map, + [this] (unsigned i) { return get_feature_tag (i); }, + nameids_to_retain); +#endif } template @@ -5044,15 +6751,90 @@ struct GSUBGPOS }; protected: - union { - FixedVersion<> version; /* Version identifier */ - GSUBGPOSVersion1_2 version1; + template + const Offset16To>& typed_lookup_list_offset () const + { return reinterpret_cast>&> (lookupList); } + #ifndef HB_NO_BEYOND_64K - GSUBGPOSVersion1_2 version2; + template + const Offset32To>& typed_lookup_list2_offset () const + { return reinterpret_cast>&> (lookupList2); } +#endif + + template + const Offset16To>& subset_lookup_list_offset () const + { return reinterpret_cast>&> (lookupList); } + template + Offset16To>& subset_lookup_list_offset () + { return reinterpret_cast>&> (lookupList); } + +#ifndef HB_NO_BEYOND_64K + template + const Offset32To>& subset_lookup_list2_offset () const + { return reinterpret_cast>&> (lookupList2); } +#endif + + const Offset16To& subset_feature_list_offset () const + { return reinterpret_cast&> (featureList); } + Offset16To& subset_feature_list_offset () + { return reinterpret_cast&> (featureList); } + +#ifndef HB_NO_BEYOND_64K + const Offset32To& subset_feature_list2_offset () const + { return reinterpret_cast&> (featureList2); } +#endif + + const void* get_lookup_list_field_offset () const + { +#ifndef HB_NO_BEYOND_64K + if (version.to_int () >= 0x00010002u && lookupList2) return &lookupList2; +#endif + return &lookupList; + } + + template + static bool serialize_subset_offset (hb_subset_context_t *c, + OffsetOut& out, + const OffsetIn& in, + const Base *base, + Ts&&... ds) + { + out = 0; + if (in.is_null ()) return false; + + auto *s = c->serializer; + s->push (); + bool ret = c->dispatch (base+in, std::forward (ds)...); + if (ret) s->add_link (out, s->pop_pack ()); + else s->pop_discard (); + return ret; + } + + FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set + * to 0x00010000u */ + Offset16To + scriptList; /* Offset to ScriptList table */ + Offset16To + featureList; /* Offset to FeatureList table */ + Offset16To + lookupList; /* Offset to LookupList table */ + Offset32To + featureVars; /* Offset to Feature Variations table--from + * beginning of table (may be NULL). + * Introduced in version 0x00010001. */ +#ifndef HB_NO_BEYOND_64K + Offset32To + scriptList2; /* 32-bit offset to ScriptList table. + * Introduced in version 0x00010002. */ + Offset32To + featureList2; /* 32-bit offset to FeatureList table. + * Introduced in version 0x00010002. */ + Offset32To + lookupList2; /* 32-bit offset to LookupList2 table. + * Introduced in version 0x00010002. */ #endif - } u; public: - DEFINE_SIZE_MIN (4); + DEFINE_SIZE_MIN (10); }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh index 823520f7483..40886ebb5be 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh @@ -136,13 +136,15 @@ struct JstfLangSys : List16OfOffset16To * ExtenderGlyphs -- Extender Glyph Table */ -typedef SortedArray16Of ExtenderGlyphs; +template +using ExtenderGlyphs = SortedArray16Of; /* * JstfScript -- The Justification Table */ +template struct JstfScript { unsigned int get_lang_sys_count () const @@ -174,17 +176,63 @@ struct JstfScript } protected: - Offset16To + typename Types::template LOffsetTo> extenderGlyphs; /* Offset to ExtenderGlyph table--from beginning * of JstfScript table-may be NULL */ - Offset16To + typename Types::template LOffsetTo defaultLangSys; /* Offset to DefaultJstfLangSys table--from * beginning of JstfScript table--may be Null */ RecordArrayOf langSys; /* Array of JstfLangSysRecords--listed * alphabetically by LangSysTag */ public: - DEFINE_SIZE_ARRAY (6, langSys); + DEFINE_SIZE_ARRAY (2 * Types::LOffset::static_size + 2, langSys); +}; + +template +struct JstfScriptRecord +{ + int cmp (hb_tag_t a) const { return tag.cmp (a); } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + const Record_sanitize_closure_t closure = {tag, base}; + return_trace (c->check_struct (this) && + offset.sanitize (c, base, &closure)); + } + + Tag tag; /* 4-byte JstfScript identification tag */ + typename Types::template LOffsetTo> + offset; /* Offset from beginning of JSTF header */ + public: + DEFINE_SIZE_STATIC (4 + Types::LOffset::static_size); +}; + +template +struct JstfScriptList : SortedArray16Of> +{ + const Tag& get_tag (unsigned int i) const + { return (*this)[i].tag; } + unsigned int get_tags (unsigned int start_offset, + unsigned int *script_count /* IN/OUT */, + hb_tag_t *script_tags /* OUT */) const + { + if (script_count) + { + + this->as_array ().sub_array (start_offset, script_count) + | hb_map (&JstfScriptRecord::tag) + | hb_sink (hb_array (script_tags, *script_count)) + ; + } + return this->len; + } + const JstfScript& get_script (const void *base, unsigned int i) const + { return base+(*this)[i].offset; } + bool find_index (hb_tag_t tag, unsigned int *index) const + { + return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); + } }; @@ -198,37 +246,90 @@ struct JSTF static constexpr hb_tag_t tableTag = HB_OT_TAG_JSTF; unsigned int get_script_count () const - { return scriptList.len; } + { +#ifndef HB_NO_BEYOND_64K + if (has_script_list2 ()) return get_script_list2 ().len; +#endif + return scriptList.len; + } const Tag& get_script_tag (unsigned int i) const - { return scriptList.get_tag (i); } + { +#ifndef HB_NO_BEYOND_64K + if (has_script_list2 ()) return get_script_list2 ().get_tag (i); +#endif + return scriptList.get_tag (i); + } unsigned int get_script_tags (unsigned int start_offset, unsigned int *script_count /* IN/OUT */, hb_tag_t *script_tags /* OUT */) const - { return scriptList.get_tags (start_offset, script_count, script_tags); } - const JstfScript& get_script (unsigned int i) const - { return this+scriptList[i].offset; } + { +#ifndef HB_NO_BEYOND_64K + if (has_script_list2 ()) + return get_script_list2 ().get_tags (start_offset, script_count, script_tags); +#endif + return scriptList.get_tags (start_offset, script_count, script_tags); + } + template + const JstfScript& get_script (unsigned int i) const; bool find_script_index (hb_tag_t tag, unsigned int *index) const - { return scriptList.find_index (tag, index); } + { +#ifndef HB_NO_BEYOND_64K + if (has_script_list2 ()) return get_script_list2 ().find_index (tag, index); +#endif + return scriptList.find_index (tag, index); + } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (version.sanitize (c) && - hb_barrier () && - likely (version.major == 1) && - scriptList.sanitize (c, this)); + if (unlikely (!version.sanitize (c) || + !hb_barrier () || + version.major != 1 || + !scriptList.sanitize (c, this))) + return_trace (false); +#ifndef HB_NO_BEYOND_64K + if (unlikely (version.minor >= 1 && !get_script_list2 ().sanitize (c, this))) + return_trace (false); +#endif + return_trace (true); } + private: +#ifndef HB_NO_BEYOND_64K + bool has_script_list2 () const + { return version.minor >= 1 && get_script_list2 ().len; } + const JstfScriptList& get_script_list2 () const + { return StructAfter> (scriptList); } +#endif + protected: FixedVersion<>version; /* Version of the JSTF table--initially set * to 0x00010000u */ - RecordArrayOf + JstfScriptList scriptList; /* Array of JstfScripts--listed * alphabetically by ScriptTag */ +#ifndef HB_NO_BEYOND_64K +/*JstfScriptList + scriptList2;*//* Array of JstfScript2s--listed + * alphabetically by ScriptTag. + * Present only if minorVersion is 1 or greater. */ +#endif public: DEFINE_SIZE_ARRAY (6, scriptList); }; +template <> +inline const JstfScript& +JSTF::get_script (unsigned int i) const +{ return scriptList.get_script (this, i); } + +#ifndef HB_NO_BEYOND_64K +template <> +inline const JstfScript& +JSTF::get_script (unsigned int i) const +{ return get_script_list2 ().get_script (this, i); } +#endif + } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc index 5f0bd1bce84..1d5dacfd058 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc @@ -265,6 +265,7 @@ OT::GDEF::is_blocklisted (hb_blob_t *blob, return false; } +template static void _hb_ot_layout_set_glyph_props (hb_font_t *font, hb_buffer_t *buffer) @@ -276,6 +277,8 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font, hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) { + if (SetDigest) + buffer->digest.add (info[i].codepoint); _hb_glyph_info_set_glyph_props (&info[i], gdef.get_glyph_props (info[i].codepoint)); _hb_glyph_info_clear_lig_props (&info[i]); } @@ -345,7 +348,7 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face, * @start_offset: offset of the first attachment point to retrieve * @point_count: (inout) (nullable): Input = the maximum number of attachment points to return; * Output = the actual number of attachment points returned (may be zero) - * @point_array: (out) (array length=point_count): The array of attachment points found for the query + * @point_array: (out) (array length=point_count) (nullable): The array of attachment points found for the query * * Fetches a list of all attachment points for the specified glyph in the GDEF * table of the face. The list returned will begin at the offset provided. @@ -375,7 +378,7 @@ hb_ot_layout_get_attach_points (hb_face_t *face, * @start_offset: offset of the first caret position to retrieve * @caret_count: (inout) (nullable): Input = the maximum number of caret positions to return; * Output = the actual number of caret positions returned (may be zero) - * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query + * @caret_array: (out) (array length=caret_count) (nullable): The array of caret positions found for the query * * Fetches a list of the caret positions defined for a ligature glyph in the GDEF * table of the font. The list returned will begin at the offset provided. @@ -446,7 +449,7 @@ get_gsubgpos_table (hb_face_t *face, * @start_offset: offset of the first script tag to retrieve * @script_count: (inout) (nullable): Input = the maximum number of script tags to return; * Output = the actual number of script tags returned (may be zero) - * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query + * @script_tags: (out) (array length=script_count) (nullable): The array of #hb_tag_t script tags found for the query * * Fetches a list of all scripts enumerated in the specified face's GSUB table * or GPOS table. The list returned will begin at the offset provided. @@ -615,7 +618,7 @@ hb_ot_layout_table_select_script (hb_face_t *face, * @start_offset: offset of the first feature tag to retrieve * @feature_count: (inout) (nullable): Input = the maximum number of feature tags to return; * Output = the actual number of feature tags returned (may be zero) - * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table + * @feature_tags: (out) (array length=feature_count) (nullable): Array of feature tags found in the table * * Fetches a list of all feature tags in the given face's GSUB or GPOS table. * Note that there might be duplicate feature tags, belonging to different @@ -685,7 +688,7 @@ hb_ot_layout_table_find_feature (hb_face_t *face, * @start_offset: offset of the first language tag to retrieve * @language_count: (inout) (nullable): Input = the maximum number of language tags to return; * Output = the actual number of language tags returned (may be zero) - * @language_tags: (out) (array length=language_count): Array of language tags found in the table + * @language_tags: (out) (array length=language_count) (nullable): Array of language tags found in the table * * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath * the specified script index. The list returned will begin at the offset provided. @@ -913,7 +916,7 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face, * @start_offset: offset of the first feature tag to retrieve * @feature_count: (inout) (nullable): Input = the maximum number of feature tags to return; * Output: the actual number of feature tags returned (may be zero) - * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query + * @feature_indexes: (out) (array length=feature_count) (nullable): The array of feature indexes found for the query * * Fetches a list of all features in the specified face's GSUB table * or GPOS table, underneath the specified script and language. The list @@ -949,7 +952,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face, * @start_offset: offset of the first feature tag to retrieve * @feature_count: (inout) (nullable): Input = the maximum number of feature tags to return; * Output = the actual number of feature tags returned (may be zero) - * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query + * @feature_tags: (out) (array length=feature_count) (nullable): The array of #hb_tag_t feature tags found for the query * * Fetches a list of all features in the specified face's GSUB table * or GPOS table, underneath the specified script and language. The list @@ -975,7 +978,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face, static_assert ((sizeof (unsigned int) == sizeof (hb_tag_t)), ""); unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags); - if (feature_tags) { + if (feature_count && feature_tags) { unsigned int count = *feature_count; for (unsigned int i = 0; i < count; i++) feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]); @@ -1037,7 +1040,7 @@ hb_ot_layout_language_find_feature (hb_face_t *face, * @start_offset: offset of the first lookup to retrieve * @lookup_count: (inout) (nullable): Input = the maximum number of lookups to return; * Output = the actual number of lookups returned (may be zero) - * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query + * @lookup_indexes: (out) (array length=lookup_count) (nullable): The array of lookup indexes found for the query * * Fetches a list of all lookups enumerated for the specified feature, in * the specified face's GSUB table or GPOS table. The list returned will @@ -1432,6 +1435,39 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, /* Variations support */ +bool +_hb_ot_layout_table_get_feature_variations_state (hb_face_t *face, + hb_tag_t table_tag, + const int *coords, + unsigned int num_coords, + unsigned int *variations_index, + hb_vector_t *lookup_conditions) +{ + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + const OT::GDEF &gdef = *face->table.GDEF->table; + + auto instancer = OT::ItemVarStoreInstancer (&gdef.get_var_store (), nullptr, + hb_array (coords, num_coords)); + + return g.get_feature_variations_state (coords, + num_coords, + variations_index, + &instancer, + lookup_conditions); +} + +bool +_hb_ot_layout_feature_get_lookup_variations (hb_face_t *face, + hb_tag_t table_tag, + unsigned feature_index, + unsigned variations_index, + hb_sorted_array_t conditions, + hb_set_t *lookup_indexes) +{ + return get_gsubgpos_table (face, table_tag).get_lookup_variations ( + feature_index, variations_index, conditions, lookup_indexes); +} + /** * hb_ot_layout_table_find_feature_variations: @@ -1475,7 +1511,7 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face, * @start_offset: offset of the first lookup to retrieve * @lookup_count: (inout) (nullable): Input = the maximum number of lookups to return; * Output = the actual number of lookups returned (may be zero) - * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query + * @lookup_indexes: (out) (array length=lookup_count) (nullable): The array of lookups found for the query * * Fetches a list of all lookups enumerated for the specified feature, in * the specified face's GSUB table or GPOS table, enabled at the specified @@ -1573,7 +1609,15 @@ void hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer) { - _hb_ot_layout_set_glyph_props (font, buffer); + _hb_ot_layout_set_glyph_props (font, buffer); +} + +void +hb_ot_layout_substitute_start_with_digest (hb_font_t *font, + hb_buffer_t *buffer) +{ + buffer->digest = hb_set_digest_t (); + _hb_ot_layout_set_glyph_props (font, buffer); } /** @@ -1854,7 +1898,7 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face, * @start_offset: offset of the first character to retrieve * @char_count: (inout) (nullable): Input = the maximum number of characters to return; * Output = the actual number of characters returned (may be zero) - * @characters: (out caller-allocates) (array length=char_count): A buffer pointer. + * @characters: (out caller-allocates) (array length=char_count) (nullable): A buffer pointer. * The Unicode codepoints of the characters for which this feature provides * glyph variants. * @@ -2037,7 +2081,9 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, !buffer->message (font, "start lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue; /* Only try applying the lookup if there is any overlap. */ - if (accel->digest.may_intersect (buffer->digest)) + if (accel->digest.may_intersect (buffer->digest) && + ((buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) || + accel->digest_second.may_intersect (buffer->digest))) { c.set_lookup_index (lookup_index); c.set_lookup_mask (lookup.mask, false); @@ -2272,6 +2318,9 @@ hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script) case HB_SCRIPT_NUSHU: /* Unicode-13.0 additions */ case HB_SCRIPT_KHITAN_SMALL_SCRIPT: + /* Unicode-18.0 additions */ + case HB_SCRIPT_JURCHEN: + case HB_SCRIPT_SEAL: return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT; default: @@ -2288,7 +2337,7 @@ hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script) * @language_tag: language tag, currently unused. * @coord: (out) (nullable): baseline value if found. * - * Fetches a baseline value from the face. + * Fetches a baseline value from the font. * * Return value: `true` if found baseline value in the font. * @@ -2314,7 +2363,7 @@ hb_ot_layout_get_baseline (hb_font_t *font, * @language: (nullable): language, currently unused. * @coord: (out) (nullable): baseline value if found. * - * Fetches a baseline value from the face. + * Fetches a baseline value from the font. * * This function is like hb_ot_layout_get_baseline() but takes * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t. @@ -2350,7 +2399,7 @@ hb_ot_layout_get_baseline2 (hb_font_t *font, * @language_tag: language tag, currently unused. * @coord: (out): baseline value if found. * - * Fetches a baseline value from the face, and synthesizes + * Fetches a baseline value from the font, and synthesizes * it if the font does not have it. * * Since: 4.0.0 @@ -2389,7 +2438,7 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, hb_font_get_nominal_glyph (font, '-', &glyph)) && hb_font_get_glyph_extents (font, glyph, &extents)) { - *coord = extents.y_bearing + extents.height / 2; + *coord = hb_saturate_add (extents.y_bearing, extents.height / 2); } else { @@ -2421,9 +2470,11 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, &embox_bottom); if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT) - *coord = embox_top + (embox_bottom - embox_top) / 10; + *coord = hb_saturate_add (embox_top, + hb_clamp_to (((int64_t) embox_bottom - embox_top) / 10)); else - *coord = embox_bottom + (embox_top - embox_bottom) / 10; + *coord = hb_saturate_add (embox_bottom, + hb_clamp_to (((int64_t) embox_top - embox_bottom) / 10)); } break; @@ -2434,7 +2485,8 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, script_tag, language_tag, coord)) - *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale; + *coord = hb_saturate_add (*coord, + HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale); else { hb_font_extents_t font_extents; @@ -2450,7 +2502,8 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, script_tag, language_tag, coord)) - *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale; + *coord = hb_saturate_sub (*coord, + HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale); else { hb_font_extents_t font_extents; @@ -2510,10 +2563,10 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, hb_font_get_glyph_extents (font, glyph, &extents)) *coord = extents.y_bearing; else - *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin + *coord = hb_clamp_to ((int64_t) font->y_scale * 6 / 10); // FIXME makes assumptions about origin } else - *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin + *coord = hb_clamp_to ((int64_t) font->x_scale * 6 / 10); // FIXME makes assumptions about origin break; case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: @@ -2531,7 +2584,7 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, script_tag, language_tag, &bottom); - *coord = (top + bottom) / 2; + *coord = hb_clamp_to (((int64_t) top + bottom) / 2); } break; @@ -2551,7 +2604,7 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, script_tag, language_tag, &bottom); - *coord = (top + bottom) / 2; + *coord = hb_clamp_to (((int64_t) top + bottom) / 2); } break; @@ -2572,7 +2625,7 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, * @language: (nullable): language, currently unused. * @coord: (out): baseline value if found. * - * Fetches a baseline value from the face, and synthesizes + * Fetches a baseline value from the font, and synthesizes * it if the font does not have it. * * This function is like hb_ot_layout_get_baseline_with_fallback() but takes @@ -2629,7 +2682,7 @@ struct hb_get_glyph_alternates_dispatch_t : * @start_offset: starting offset. * @alternate_count: (inout) (nullable): Input = the maximum number of alternate glyphs to return; * Output = the actual number of alternate glyphs returned (may be zero). - * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer. + * @alternate_glyphs: (out caller-allocates) (array length=alternate_count) (nullable): A glyphs buffer. * Alternate glyphs associated with the glyph id. * * Fetches alternates of a glyph from a given GSUB lookup index. Note that for one-to-one GSUB @@ -2764,13 +2817,13 @@ hb_ot_layout_lookup_get_optical_bound (hb_font_t *font, ret = pos.x_offset; break; case HB_DIRECTION_RTL: - ret = pos.x_advance - pos.x_offset; + ret = hb_saturate_sub (pos.x_advance, pos.x_offset); break; case HB_DIRECTION_TTB: ret = pos.y_offset; break; case HB_DIRECTION_BTT: - ret = pos.y_advance - pos.y_offset; + ret = hb_saturate_sub (pos.y_advance, pos.y_offset); break; case HB_DIRECTION_INVALID: default: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh index f669ac7c46d..a32df83c83b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh @@ -102,6 +102,10 @@ HB_INTERNAL void hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer); +HB_INTERNAL void +hb_ot_layout_substitute_start_with_digest (hb_font_t *font, + hb_buffer_t *buffer); + namespace OT { struct hb_ot_apply_context_t; struct hb_ot_layout_lookup_accelerator_t; @@ -159,7 +163,8 @@ static inline unsigned int _hb_next_syllable (hb_buffer_t *buffer, unsigned int start) { hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; + unsigned int count = start + hb_min (buffer->len - start, + (unsigned) HB_MAX_SYLLABLE_LENGTH); unsigned int syllable = info[start].syllable(); while (++start < count && syllable == info[start].syllable()) @@ -567,6 +572,20 @@ _hb_glyph_info_multiplied (const hb_glyph_info_t *info) return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; } +static inline unsigned int +_hb_glyph_info_get_lig_num_comps_in_ligation (const hb_glyph_info_t *info) +{ + /* When a glyph is decomposed by a MultipleSubst and its pieces later become + * components of a ligature, the pieces belong to the same ligature component + * as the first piece, matching how MarkBasePos attaches marks only to the + * first piece. So the non-first pieces contribute no extra component. + * https://github.com/harfbuzz/harfbuzz/issues/4969 */ + if (_hb_glyph_info_multiplied (info) && + _hb_glyph_info_get_lig_comp (info)) + return 0; + return _hb_glyph_info_get_lig_num_comps (info); +} + static inline bool _hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc index a0cdfddfa63..94ae3e76bf2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc @@ -128,7 +128,7 @@ void hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m, unsigned int table_index, unsigned int feature_index, - unsigned int variations_index, + const hb_ot_shape_plan_key_t &key, hb_mask_t mask, bool auto_zwnj, bool auto_zwj, @@ -142,13 +142,37 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m, table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]); + hb_set_t varied_lookups; + if (key.get_lookup_variations (face, table_index, feature_index, &varied_lookups)) + { + if (unlikely (varied_lookups.in_error ())) + { + m.lookups[table_index].ensure_error (); + return; + } + for (unsigned int lookup_index : varied_lookups) + { + if (lookup_index >= table_lookup_count) + continue; + hb_ot_map_t::lookup_map_t *lookup = m.lookups[table_index].push (); + lookup->mask = mask; + lookup->index = lookup_index; + lookup->auto_zwnj = auto_zwnj; + lookup->auto_zwj = auto_zwj; + lookup->random = random; + lookup->per_syllable = per_syllable; + lookup->feature_tag = feature_tag; + } + return; + } + offset = 0; do { len = ARRAY_LENGTH (lookup_indices); hb_ot_layout_feature_with_variations_get_lookups (face, - table_tags[table_index], - feature_index, - variations_index, + table_tags[table_index], + feature_index, + key.variations_index[table_index], offset, &len, lookup_indices); @@ -342,7 +366,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, required_feature_stage[table_index] == stage) add_lookups (m, table_index, required_feature_index[table_index], - key.variations_index[table_index], + key, global_bit_mask); for (auto &feature : m.features) @@ -350,7 +374,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, if (feature.stage[table_index] == stage) add_lookups (m, table_index, feature.index[table_index], - key.variations_index[table_index], + key, feature.mask, feature.auto_zwnj, feature.auto_zwj, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh index 68af9792439..dcefdcb37e1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh @@ -247,7 +247,7 @@ struct hb_ot_map_builder_t HB_INTERNAL void add_lookups (hb_ot_map_t &m, unsigned int table_index, unsigned int feature_index, - unsigned int variations_index, + const hb_ot_shape_plan_key_t &key, hb_mask_t mask, bool auto_zwnj = true, bool auto_zwj = true, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh index ad9d7cb03e8..08aab5f6f59 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh @@ -29,7 +29,9 @@ #include "hb-open-type.hh" #include "hb-ot-layout-common.hh" +#include "hb-ot-layout-gdef-table.hh" #include "hb-ot-math.h" +#include "hb-depend-data.hh" namespace OT { @@ -37,20 +39,38 @@ namespace OT { struct MathValueRecord { hb_position_t get_x_value (hb_font_t *font, const void *base) const - { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); } + { return hb_saturate_add (font->em_scale_x (value), (base+deviceTable).get_x_delta (font, get_var_store (font, base))); } hb_position_t get_y_value (hb_font_t *font, const void *base) const - { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); } + { return hb_saturate_add (font->em_scale_y (value), (base+deviceTable).get_y_delta (font, get_var_store (font, base))); } - MathValueRecord* copy (hb_serialize_context_t *c, const void *base) const + const ItemVariationStore &get_var_store (hb_font_t *font, const void *base) const + { +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_LAYOUT) + if ((base+deviceTable).is_variation_device ()) + return font->face->table.GDEF->table->get_var_store (); +#endif + return Null (ItemVariationStore); + } + + MathValueRecord* copy (hb_serialize_context_t *c, const void *base, + const hb_hashmap_t> *variation_map) const { TRACE_SERIALIZE (this); auto *out = c->embed (this); if (unlikely (!out)) return_trace (nullptr); - out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head); + hb_pair_t *varidx_delta; + if (variation_map->has ((base+deviceTable).get_variation_index (), &varidx_delta) && + !c->check_assign (out->value, (int64_t) value + hb_second (*varidx_delta), + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (nullptr); + out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head, variation_map); return_trace (out); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, const void *base) const + { (base+deviceTable).collect_variation_indices (c); } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -71,7 +91,8 @@ struct MathConstants { friend struct MATH; - MathConstants* copy (hb_serialize_context_t *c) const + MathConstants* copy (hb_serialize_context_t *c, + const hb_hashmap_t> *variation_map) const { TRACE_SERIALIZE (this); auto *out = c->start_embed (this); @@ -86,13 +107,19 @@ struct MathConstants unsigned count = ARRAY_LENGTH (mathValueRecords); for (unsigned i = 0; i < count; i++) - if (!c->copy (mathValueRecords[i], this)) + if (!c->copy (mathValueRecords[i], this, variation_map)) return_trace (nullptr); if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr); return_trace (out); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const auto &record : mathValueRecords) + record.collect_variation_indices (c, this); + } + bool sanitize_math_value_records (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -211,7 +238,7 @@ struct MathItalicsCorrectionInfo hb_sorted_vector_t new_coverage; + hb_zip (this+coverage, italicsCorrection) | hb_filter (glyphset, hb_first) - | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second) + | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this, &c->plan->layout_variation_idx_delta_map), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) @@ -221,6 +248,13 @@ struct MathItalicsCorrectionInfo return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const auto &entry : hb_zip (this+coverage, italicsCorrection)) + if (c->glyph_set->has (hb_first (entry))) + hb_second (entry).collect_variation_indices (c, this); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -264,7 +298,7 @@ struct MathTopAccentAttachment hb_sorted_vector_t new_coverage; + hb_zip (this+topAccentCoverage, topAccentAttachment) | hb_filter (glyphset, hb_first) - | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second) + | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this, &c->plan->layout_variation_idx_delta_map), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) @@ -274,6 +308,13 @@ struct MathTopAccentAttachment return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const auto &entry : hb_zip (this+topAccentCoverage, topAccentAttachment)) + if (c->glyph_set->has (hb_first (entry))) + hb_second (entry).collect_variation_indices (c, this); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -307,7 +348,8 @@ struct MathTopAccentAttachment struct MathKern { - MathKern* copy (hb_serialize_context_t *c) const + MathKern* copy (hb_serialize_context_t *c, + const hb_hashmap_t> *variation_map) const { TRACE_SERIALIZE (this); auto *out = c->start_embed (this); @@ -316,12 +358,18 @@ struct MathKern unsigned count = 2 * heightCount + 1; for (unsigned i = 0; i < count; i++) - if (!c->copy (mathValueRecordsZ.arrayZ[i], this)) + if (!c->copy (mathValueRecordsZ.arrayZ[i], this, variation_map)) return_trace (nullptr); return_trace (out); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const auto &record : mathValueRecordsZ.as_array (2 * heightCount + 1)) + record.collect_variation_indices (c, this); + } + bool sanitize_math_value_records (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -355,7 +403,10 @@ struct MathKern unsigned int pos; auto cmp = +[](const void* key, const void* p, int sign, hb_font_t* font, const MathKern* mathKern) -> int { - return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern); + hb_position_t a = *(hb_position_t *) key; + hb_position_t b = ((MathValueRecord *) p)->get_y_value (font, mathKern); + if (a == b) return 0; + return sign > 0 ? (a < b ? -1 : +1) : (b < a ? -1 : +1); }; unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight, heightCount, MathValueRecord::static_size, @@ -372,7 +423,7 @@ struct MathKern const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; const unsigned int entriesCount = heightCount + 1; - if (entries_count) + if (entries_count && kern_entries) { unsigned int start = hb_min (start_offset, entriesCount); unsigned int end = hb_min (start + *entries_count, entriesCount); @@ -413,7 +464,8 @@ struct MathKern struct MathKernInfoRecord { - MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const + MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base, + const hb_hashmap_t> *variation_map) const { TRACE_SERIALIZE (this); auto *out = c->embed (this); @@ -421,11 +473,17 @@ struct MathKernInfoRecord unsigned count = ARRAY_LENGTH (mathKern); for (unsigned i = 0; i < count; i++) - out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head); + out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head, variation_map); return_trace (out); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, const void *base) const + { + for (const auto &offset : mathKern) + (base+offset).collect_variation_indices (c); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -489,7 +547,7 @@ struct MathKernInfo hb_sorted_vector_t new_coverage; + hb_zip (this+mathKernCoverage, mathKernInfoRecords) | hb_filter (glyphset, hb_first) - | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second) + | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this, &c->plan->layout_variation_idx_delta_map), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) @@ -499,6 +557,13 @@ struct MathKernInfo return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const auto &entry : hb_zip (this+mathKernCoverage, mathKernInfoRecords)) + if (c->glyph_set->has (hb_first (entry))) + hb_second (entry).collect_variation_indices (c, this); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -578,6 +643,13 @@ struct MathGlyphInfo return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + (this+mathItalicsCorrectionInfo).collect_variation_indices (c); + (this+mathTopAccentAttachment).collect_variation_indices (c); + (this+mathKernInfo).collect_variation_indices (c); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -662,6 +734,9 @@ struct MathGlyphVariantRecord return_trace (c->check_struct (this)); } + void depend (hb_depend_data_builder_t *depend_data, unsigned source) const + { depend_data->add_depend(source, HB_OT_TAG_MATH, variantGlyph); } + void closure_glyphs (hb_set_t *variant_glyphs) const { variant_glyphs->add (variantGlyph); } @@ -723,6 +798,9 @@ struct MathGlyphPartRecord (partFlags & PartFlags::Defined); } + void depend (hb_depend_data_builder_t *depend_data, unsigned source) const + { depend_data->add_depend(source, HB_OT_TAG_MATH, glyph); } + void closure_glyphs (hb_set_t *variant_glyphs) const { variant_glyphs->add (glyph); } @@ -753,7 +831,7 @@ struct MathGlyphAssembly { TRACE_SUBSET (this); - if (!c->serializer->copy (italicsCorrection, this)) return_trace (false); + if (!c->serializer->copy (italicsCorrection, this, &c->plan->layout_variation_idx_delta_map)) return_trace (false); if (!c->serializer->copy (partRecords.len)) return_trace (false); for (const auto& record : partRecords.iter ()) @@ -761,6 +839,11 @@ struct MathGlyphAssembly return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + italicsCorrection.collect_variation_indices (c, this); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -776,7 +859,7 @@ struct MathGlyphAssembly hb_ot_math_glyph_part_t *parts /* OUT */, hb_position_t *italics_correction /* OUT */) const { - if (parts_count) + if (parts_count && parts) { int64_t mult = font->dir_mult (direction); for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count), @@ -790,6 +873,12 @@ struct MathGlyphAssembly return partRecords.len; } + void depend (hb_depend_data_builder_t *depend_data, unsigned source) const + { + for (const auto& _ : partRecords.iter ()) + _.depend (depend_data, source); + } + void closure_glyphs (hb_set_t *variant_glyphs) const { for (const auto& _ : partRecords.iter ()) @@ -829,6 +918,11 @@ struct MathGlyphConstruction return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + (this+glyphAssembly).collect_variation_indices (c); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -845,7 +939,7 @@ struct MathGlyphConstruction unsigned int *variants_count, /* IN/OUT */ hb_ot_math_glyph_variant_t *variants /* OUT */) const { - if (variants_count) + if (variants_count && variants) { int64_t mult = font->dir_mult (direction); for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count), @@ -855,6 +949,14 @@ struct MathGlyphConstruction return mathGlyphVariantRecord.len; } + void depend (hb_depend_data_builder_t *depend_data, unsigned source) const + { + (this+glyphAssembly).depend (depend_data, source); + + for (const auto& _ : mathGlyphVariantRecord.iter ()) + _.depend (depend_data, source); + } + void closure_glyphs (hb_set_t *variant_glyphs) const { (this+glyphAssembly).closure_glyphs (variant_glyphs); @@ -877,6 +979,34 @@ struct MathGlyphConstruction struct MathVariants { + void depend (hb_depend_data_builder_t *depend_data) const + { + const hb_array_t> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount); + + if (vertGlyphCoverage) + { + const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount); + + hb_zip (this+vertGlyphCoverage, vert_offsets) + | hb_apply ([&] (const hb_pair_t&> &_) + { + const MathGlyphConstruction &mgc = this+_.second; + mgc.depend (depend_data, _.first); + }) + ; + } + if (horizGlyphCoverage) + { + const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount); + + hb_zip (this+horizGlyphCoverage, hori_offsets) + | hb_apply ([&] (const hb_pair_t&> &_) + { + const MathGlyphConstruction &mgc = this+_.second; + mgc.depend (depend_data, _.first); + }) + ; + } + } + void closure_glyphs (const hb_set_t *glyph_set, hb_set_t *variant_glyphs) const { @@ -931,7 +1061,7 @@ struct MathVariants bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = c->plan->_glyphset_mathed; + const hb_set_t &glyphset = c->plan->_glyphset_cmaped; const hb_map_t &glyph_map = *c->plan->glyph_map; auto *out = c->serializer->start_embed (*this); @@ -965,6 +1095,16 @@ struct MathVariants return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const auto &entry : hb_zip (this+vertGlyphCoverage, glyphConstruction.as_array (vertGlyphCount))) + if (c->glyph_set->has (hb_first (entry))) + (this+hb_second (entry)).collect_variation_indices (c); + for (const auto &entry : hb_zip (this+horizGlyphCoverage, glyphConstruction.as_array (vertGlyphCount + horizGlyphCount).sub_array (vertGlyphCount))) + if (c->glyph_set->has (hb_first (entry))) + (this+hb_second (entry)).collect_variation_indices (c); + } + bool sanitize_offsets (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1073,6 +1213,12 @@ struct MATH bool has_data () const { return version.to_int (); } + void depend (hb_depend_data_builder_t *depend_data) const + { + if (mathVariants) + (this+mathVariants).depend (depend_data); + } + void closure_glyphs (hb_set_t *glyph_set) const { if (mathVariants) @@ -1089,12 +1235,22 @@ struct MATH auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); - out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head); + out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this); out->mathVariants.serialize_subset (c, mathVariants, this); return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, const hb_set_t *variant_glyph_set) const + { + (this+mathConstants).collect_variation_indices (c); + (this+mathGlyphInfo).collect_variation_indices (c); + auto *glyph_set = c->glyph_set; + c->glyph_set = variant_glyph_set; + (this+mathVariants).collect_variation_indices (c); + c->glyph_set = glyph_set; + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc index ab1f50c8eb8..040fdd7a6b2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc @@ -206,7 +206,7 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, * @start_offset: offset of the first kern entry to retrieve * @entries_count: (inout) (optional): Input = the maximum number of kern entries to return; * Output = the actual number of kern entries returned - * @kern_entries: (out caller-allocates) (array length=entries_count): array of kern entries returned + * @kern_entries: (out caller-allocates) (array length=entries_count) (nullable): array of kern entries returned * * Fetches the raw MathKern (cut-in) data for the specified font, glyph index, * and @kern. The corresponding list of kern values and correction heights is @@ -251,7 +251,7 @@ hb_ot_math_get_glyph_kernings (hb_font_t *font, * @start_offset: offset of the first variant to retrieve * @variants_count: (inout): Input = the maximum number of variants to return; * Output = the actual number of variants returned - * @variants: (out) (array length=variants_count): array of variants returned + * @variants: (out) (array length=variants_count) (nullable): array of variants returned * * Fetches the MathGlyphConstruction for the specified font, glyph index, and * direction. The corresponding list of size variants is returned as a list of @@ -313,7 +313,7 @@ hb_ot_math_get_min_connector_overlap (hb_font_t *font, * @start_offset: offset of the first glyph part to retrieve * @parts_count: (inout): Input = maximum number of glyph parts to return; * Output = actual number of parts returned - * @parts: (out) (array length=parts_count): the glyph parts returned + * @parts: (out) (array length=parts_count) (nullable): the glyph parts returned * @italics_correction: (out): italics correction of the glyph assembly * * Fetches the GlyphAssembly for the specified font, glyph index, and direction. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh index f6eeda40ed6..72e34cb15d7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh @@ -28,6 +28,7 @@ #define HB_OT_MAXP_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-dual.hh" namespace OT { @@ -38,6 +39,7 @@ namespace OT { */ #define HB_OT_TAG_maxp HB_TAG('m','a','x','p') +#define HB_OT_TAG_MAXP HB_TAG('M','A','X','P') struct maxpV1Tail { @@ -69,10 +71,9 @@ struct maxpV1Tail }; -struct maxp +template +struct maxp_MAXP { - static constexpr hb_tag_t tableTag = HB_OT_TAG_maxp; - unsigned int get_num_glyphs () const { return numGlyphs; } void set_num_glyphs (unsigned int count) @@ -97,10 +98,11 @@ struct maxp bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - maxp *maxp_prime = c->serializer->embed (this); + maxp_MAXP *maxp_prime = c->serializer->embed (this); if (unlikely (!maxp_prime)) return_trace (false); - maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu); + maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), + (1u << (8 * Types::size)) - 1); if (maxp_prime->version.major == 1) { hb_barrier (); @@ -142,11 +144,66 @@ struct maxp protected: FixedVersion<>version;/* Version of the maxp table (0.5 or 1.0), * 0x00005000u or 0x00010000u. */ - HBUINT16 numGlyphs; + typename Types::HBUINT + numGlyphs; /* The number of glyphs in the font. */ /*maxpV1Tail v1Tail[HB_VAR_ARRAY]; */ public: - DEFINE_SIZE_STATIC (6); + DEFINE_SIZE_STATIC (4 + Types::HBUINT::static_size); +}; + +struct maxp : maxp_MAXP +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_maxp; +}; + +struct MAXP : maxp_MAXP +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_MAXP; +}; + +struct maxp_accelerator_t +{ + maxp_accelerator_t () + { + blob = hb_blob_get_empty (); + numGlyphs = 0; + } + + maxp_accelerator_t (hb_face_t *face) : maxp_accelerator_t () + { +#ifndef HB_NO_BEYOND_64K + if (init_table (face)) + return; +#endif + + init_table (face); + } + + ~maxp_accelerator_t () { hb_blob_destroy (blob); } + + unsigned int get_num_glyphs () const { return numGlyphs; } + hb_blob_t *get_blob () const { return blob; } + + private: + template + bool init_table (hb_face_t *face) + { + hb_sanitize_context_t c; + c.set_num_glyphs (0); + hb_blob_ptr_t
table = c.reference_table
(face); + bool ret = table.get_length (); + if (ret) + { + blob = hb_blob_reference (table.get_blob ()); + numGlyphs = table->get_num_glyphs (); + } + table.destroy (); + return ret; + } + + hb_blob_t *blob; + unsigned int numGlyphs; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh index 20c62b83edb..4e1f9637502 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh @@ -83,7 +83,7 @@ struct meta unsigned int *count, hb_ot_meta_tag_t *entries) const { - if (count) + if (count && entries) { + table->dataMaps.as_array ().sub_array (start_offset, count) | hb_map (&DataMap::get_tag) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc index 7ad29777714..e93588cda11 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc @@ -42,7 +42,7 @@ * @face: a face object * @start_offset: iteration's start offset * @entries_count:(inout) (optional): buffer size as input, filled size as output - * @entries: (out caller-allocates) (array length=entries_count): entries tags buffer + * @entries: (out caller-allocates) (array length=entries_count) (nullable): entries tags buffer * * Fetches all available feature types. * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc index 4253d5bb03d..cd01736b0a6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc @@ -69,33 +69,38 @@ _hb_ot_metrics_get_position_common (hb_font_t *font, #else #define GET_VAR .0f #endif -#define GET_METRIC_X(TABLE, ATTR) \ - (face->table.TABLE->has_data () && \ - ((void) (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \ - face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true)) #define GET_METRIC_Y(TABLE, ATTR) \ (face->table.TABLE->has_data () && \ ((void) (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \ face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true)) +#define GET_HEA_METRIC_X(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + ((void) (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \ + HB_DUAL_GET (*face->table.TABLE, table->ATTR) + GET_VAR, metrics_tag)))), true)) +#define GET_HEA_METRIC_Y(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + ((void) (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \ + HB_DUAL_GET (*face->table.TABLE, table->ATTR) + GET_VAR, metrics_tag)))), true)) case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) || - GET_METRIC_Y (hhea, ascender); + GET_HEA_METRIC_Y (hhea, ascender); case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER: return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoDescender)) || - GET_METRIC_Y (hhea, descender); + GET_HEA_METRIC_Y (hhea, descender); case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) || - GET_METRIC_Y (hhea, lineGap); + GET_HEA_METRIC_Y (hhea, lineGap); #ifndef HB_NO_VERTICAL - case HB_OT_METRICS_TAG_VERTICAL_ASCENDER: return GET_METRIC_X (vhea, ascender); - case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender); - case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: return GET_METRIC_X (vhea, lineGap); + case HB_OT_METRICS_TAG_VERTICAL_ASCENDER: return GET_HEA_METRIC_X (vhea, ascender); + case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_HEA_METRIC_X (vhea, descender); + case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: return GET_HEA_METRIC_X (vhea, lineGap); #endif +#undef GET_HEA_METRIC_Y +#undef GET_HEA_METRIC_X #undef GET_METRIC_Y -#undef GET_METRIC_X #undef GET_VAR default: assert (0); return false; } @@ -158,6 +163,12 @@ hb_ot_metrics_get_position (hb_font_t *font, #define GET_METRIC_Y(TABLE, ATTR) \ (face->table.TABLE->has_data () && \ ((void) (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR))), true)) +#define GET_HEA_METRIC_X(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + ((void) (position && (*position = font->em_scalef_x (HB_DUAL_GET (*face->table.TABLE, table->ATTR) + GET_VAR))), true)) +#define GET_HEA_METRIC_Y(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + ((void) (position && (*position = font->em_scalef_y (HB_DUAL_GET (*face->table.TABLE, table->ATTR) + GET_VAR))), true)) case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC_Y (OS2, usWinAscent); case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent); @@ -168,17 +179,17 @@ hb_ot_metrics_get_position (hb_font_t *font, if (font->slant) { - unsigned rise = face->table.hhea->caretSlopeRise; + unsigned rise = HB_DUAL_GET (*face->table.hhea, table->caretSlopeRise); unsigned upem = face->get_upem (); mult = (rise && rise < upem) ? hb_min (upem / rise, 256u) : 1u; } if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE) { - bool ret = GET_METRIC_Y (hhea, caretSlopeRise); + bool ret = GET_HEA_METRIC_Y (hhea, caretSlopeRise); if (position) - *position *= mult; + *position = hb_clamp_to ((int64_t) *position * mult); return ret; } @@ -186,28 +197,29 @@ hb_ot_metrics_get_position (hb_font_t *font, { hb_position_t rise = 0; - if (font->slant && position && GET_METRIC_Y (hhea, caretSlopeRise)) + if (font->slant && position && GET_HEA_METRIC_Y (hhea, caretSlopeRise)) rise = *position; - bool ret = GET_METRIC_X (hhea, caretSlopeRun); + bool ret = GET_HEA_METRIC_X (hhea, caretSlopeRun); if (position) { - *position *= mult; + *position = hb_clamp_to ((int64_t) *position * mult); if (font->slant) - *position += roundf (mult * font->slant_xy * rise); + *position = hb_saturate_add (*position, + hb_clamp_to (roundf (mult * font->slant_xy * rise))); } return ret; } } - case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: return GET_METRIC_X (hhea, caretOffset); + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: return GET_HEA_METRIC_X (hhea, caretOffset); #ifndef HB_NO_VERTICAL - case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: return GET_METRIC_X (vhea, caretSlopeRise); - case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: return GET_METRIC_Y (vhea, caretSlopeRun); - case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: return GET_METRIC_Y (vhea, caretOffset); + case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: return GET_HEA_METRIC_X (vhea, caretSlopeRise); + case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: return GET_HEA_METRIC_Y (vhea, caretSlopeRun); + case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: return GET_HEA_METRIC_Y (vhea, caretOffset); #endif case HB_OT_METRICS_TAG_X_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sxHeight); case HB_OT_METRICS_TAG_CAP_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sCapHeight); @@ -226,11 +238,13 @@ hb_ot_metrics_get_position (hb_font_t *font, /* Private tags */ case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2: return GET_METRIC_Y (OS2, sTypoAscender); - case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA: return GET_METRIC_Y (hhea, ascender); + case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA: return GET_HEA_METRIC_Y (hhea, ascender); case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2: return GET_METRIC_Y (OS2, sTypoDescender); - case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA: return GET_METRIC_Y (hhea, descender); + case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA: return GET_HEA_METRIC_Y (hhea, descender); case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2: return GET_METRIC_Y (OS2, sTypoLineGap); - case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA: return GET_METRIC_Y (hhea, lineGap); + case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA: return GET_HEA_METRIC_Y (hhea, lineGap); +#undef GET_HEA_METRIC_Y +#undef GET_HEA_METRIC_X #undef GET_METRIC_Y #undef GET_METRIC_X #undef GET_VAR @@ -326,9 +340,10 @@ hb_ot_metrics_get_position_with_fallback (hb_font_t *font, case HB_OT_METRICS_TAG_CAP_HEIGHT: if (hb_font_get_nominal_glyph (font, 'O', &glyph) && hb_font_get_glyph_extents (font, glyph, &extents)) - *position = extents.height + 2 * extents.y_bearing; + *position = hb_clamp_to ((int64_t) extents.height + + 2 * (int64_t) extents.y_bearing); else - *position = font->y_scale * 2 / 3; + *position = hb_clamp_to ((int64_t) font->y_scale * 2 / 3); break; case HB_OT_METRICS_TAG_STRIKEOUT_SIZE: @@ -347,17 +362,17 @@ hb_ot_metrics_get_position_with_fallback (hb_font_t *font, break; case HB_OT_METRICS_TAG_UNDERLINE_OFFSET: - *position = - font->y_scale / 18; + *position = hb_saturate_neg (font->y_scale) / 18; break; case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE: - *position = font->x_scale * 10 / 12; + *position = hb_clamp_to ((int64_t) font->x_scale * 10 / 12); break; case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE: case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE: - *position = font->y_scale * 10 / 12; + *position = hb_clamp_to ((int64_t) font->y_scale * 10 / 12); break; case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh index a044b7f9c0c..65ed98c96d9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh @@ -272,7 +272,7 @@ struct OS2 Triple *axis_range; if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range)) { - unsigned weight_class = static_cast (roundf (hb_clamp (axis_range->middle, 1.0, 1000.0))); + unsigned weight_class = static_cast (roundf (hb_clamp (axis_range->middle, 1.0f, 1000.0f))); if (os2_prime->usWeightClass != weight_class) os2_prime->usWeightClass = weight_class; } @@ -346,10 +346,10 @@ struct OS2 size_t get_size () const { - unsigned result = min_size; - if (version >= 1) result += v1X.get_size (); - if (version >= 2) result += v2X.get_size (); - if (version >= 5) result += v5X.get_size (); + size_t result = min_size; + if (version >= 1) result = hb_unsigned_add_saturate (result, v1X.get_size ()); + if (version >= 2) result = hb_unsigned_add_saturate (result, v2X.get_size ()); + if (version >= 5) result = hb_unsigned_add_saturate (result, v5X.get_size ()); return result; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh index 1de8864c488..fa6d4dad6c5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh @@ -116,7 +116,7 @@ struct post Triple *axis_range; if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t'), &axis_range)) { - float italic_angle = hb_max (-90.0, hb_min (axis_range->middle, 90.0)); + float italic_angle = hb_max (-90.f, hb_min (axis_range->middle, 90.f)); if (post_prime->italicAngle.to_float () != italic_angle) post_prime->italicAngle.set_float (italic_angle); } @@ -188,7 +188,7 @@ struct post if (unlikely (!gids)) { - gids = (uint16_t *) hb_malloc (count * sizeof (gids[0])); + gids = (uint16_t *) hb_malloc2 (count, sizeof (gids[0])); if (unlikely (!gids)) return false; /* Anything better?! */ @@ -197,7 +197,10 @@ struct post auto thiz = this; hb_array_t (gids, count) .qsort ([thiz] (const uint16_t &a, const uint16_t &b) { - return thiz->find_glyph_name (a).cmp (thiz->find_glyph_name (b)) > 0; + /* hb_array_t::cmp has reversed argument order, so + * x.cmp(y) returns sign of (y - x). Pass (b, a) to + * get standard "negative when a < b" ordering. */ + return thiz->find_glyph_name (b).cmp (thiz->find_glyph_name (a)); }); if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids))) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc index c17e7628975..364cc7c2e4e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc @@ -197,8 +197,10 @@ zero_mark_advances (hb_buffer_t *buffer, { if (adjust_offsets_when_zeroing) { - buffer->pos[i].x_offset -= buffer->pos[i].x_advance; - buffer->pos[i].y_offset -= buffer->pos[i].y_advance; + buffer->pos[i].x_offset = hb_saturate_sub (buffer->pos[i].x_offset, + buffer->pos[i].x_advance); + buffer->pos[i].y_offset = hb_saturate_sub (buffer->pos[i].y_offset, + buffer->pos[i].y_advance); } buffer->pos[i].x_advance = 0; buffer->pos[i].y_advance = 0; @@ -231,10 +233,12 @@ position_mark (const hb_ot_shape_plan_t *plan HB_UNUSED, case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW: case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE: if (buffer->props.direction == HB_DIRECTION_LTR) { - pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing; + pos.x_offset = hb_clamp_to ((int64_t) base_extents.x_bearing + base_extents.width - + mark_extents.width / 2 - mark_extents.x_bearing); break; } else if (buffer->props.direction == HB_DIRECTION_RTL) { - pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing; + pos.x_offset = hb_clamp_to ((int64_t) base_extents.x_bearing - + mark_extents.width / 2 - mark_extents.x_bearing); break; } HB_FALLTHROUGH; @@ -245,21 +249,24 @@ position_mark (const hb_ot_shape_plan_t *plan HB_UNUSED, case HB_UNICODE_COMBINING_CLASS_BELOW: case HB_UNICODE_COMBINING_CLASS_ABOVE: /* Center align. */ - pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing; + pos.x_offset = hb_clamp_to ((int64_t) base_extents.x_bearing + + ((int64_t) base_extents.width - mark_extents.width) / 2 - + mark_extents.x_bearing); break; case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT: case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT: /* Left align. */ - pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing; + pos.x_offset = hb_saturate_sub (base_extents.x_bearing, mark_extents.x_bearing); break; case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT: case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT: case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT: /* Right align. */ - pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing; + pos.x_offset = hb_clamp_to ((int64_t) base_extents.x_bearing + base_extents.width - + mark_extents.width - mark_extents.x_bearing); break; } @@ -271,19 +278,20 @@ position_mark (const hb_ot_shape_plan_t *plan HB_UNUSED, case HB_UNICODE_COMBINING_CLASS_BELOW: case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT: /* Add gap, fall-through. */ - base_extents.height -= y_gap; + base_extents.height = hb_saturate_sub (base_extents.height, y_gap); HB_FALLTHROUGH; case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: - pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing; + pos.y_offset = hb_clamp_to ((int64_t) base_extents.y_bearing + + base_extents.height - mark_extents.y_bearing); /* Never shift up "below" marks. */ if ((y_gap > 0) == (pos.y_offset > 0)) { - base_extents.height -= pos.y_offset; + base_extents.height = hb_saturate_sub (base_extents.height, pos.y_offset); pos.y_offset = 0; } - base_extents.height += mark_extents.height; + base_extents.height = hb_saturate_add (base_extents.height, mark_extents.height); break; case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE: @@ -291,23 +299,24 @@ position_mark (const hb_ot_shape_plan_t *plan HB_UNUSED, case HB_UNICODE_COMBINING_CLASS_ABOVE: case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT: /* Add gap, fall-through. */ - base_extents.y_bearing += y_gap; - base_extents.height -= y_gap; + base_extents.y_bearing = hb_saturate_add (base_extents.y_bearing, y_gap); + base_extents.height = hb_saturate_sub (base_extents.height, y_gap); HB_FALLTHROUGH; case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT: - pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height); + pos.y_offset = hb_clamp_to ((int64_t) base_extents.y_bearing - + mark_extents.y_bearing - mark_extents.height); /* Don't shift down "above" marks too much. */ if ((y_gap > 0) != (pos.y_offset > 0)) { - int correction = -pos.y_offset / 2; - base_extents.y_bearing += correction; - base_extents.height -= correction; - pos.y_offset += correction; + hb_position_t correction = -(pos.y_offset / 2); + base_extents.y_bearing = hb_saturate_add (base_extents.y_bearing, correction); + base_extents.height = hb_saturate_sub (base_extents.height, correction); + pos.y_offset = hb_saturate_add (pos.y_offset, correction); } - base_extents.y_bearing -= mark_extents.height; - base_extents.height += mark_extents.height; + base_extents.y_bearing = hb_saturate_sub (base_extents.y_bearing, mark_extents.height); + base_extents.height = hb_saturate_add (base_extents.height, mark_extents.height); break; } } @@ -332,7 +341,8 @@ position_around_base (const hb_ot_shape_plan_t *plan, zero_mark_advances (buffer, base + 1, end, adjust_offsets_when_zeroing); return; } - base_extents.y_bearing += buffer->pos[base].y_offset; + base_extents.y_bearing = hb_saturate_add (base_extents.y_bearing, + buffer->pos[base].y_offset); /* Use horizontal advance for horizontal positioning. * Generally a better idea. Also works for zero-ink glyphs. See: * https://github.com/harfbuzz/harfbuzz/issues/1532 */ @@ -346,8 +356,8 @@ position_around_base (const hb_ot_shape_plan_t *plan, hb_position_t x_offset = 0, y_offset = 0; if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { - x_offset -= buffer->pos[base].x_advance; - y_offset -= buffer->pos[base].y_advance; + x_offset = hb_saturate_neg (buffer->pos[base].x_advance); + y_offset = hb_saturate_neg (buffer->pos[base].y_advance); } hb_glyph_extents_t component_extents = base_extents; @@ -376,9 +386,13 @@ position_around_base (const hb_ot_shape_plan_t *plan, horiz_dir = hb_script_get_horizontal_direction (plan->props.script); } if (horiz_dir == HB_DIRECTION_LTR) - component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components; + component_extents.x_bearing = hb_clamp_to ( + (int64_t) component_extents.x_bearing + + (int64_t) this_lig_component * component_extents.width / num_lig_components); else - component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components; + component_extents.x_bearing = hb_clamp_to ( + (int64_t) component_extents.x_bearing + + (int64_t) (num_lig_components - 1 - this_lig_component) * component_extents.width / num_lig_components); component_extents.width /= num_lig_components; } } @@ -394,16 +408,16 @@ position_around_base (const hb_ot_shape_plan_t *plan, buffer->pos[i].x_advance = 0; buffer->pos[i].y_advance = 0; - buffer->pos[i].x_offset += x_offset; - buffer->pos[i].y_offset += y_offset; + buffer->pos[i].x_offset = hb_saturate_add (buffer->pos[i].x_offset, x_offset); + buffer->pos[i].y_offset = hb_saturate_add (buffer->pos[i].y_offset, y_offset); } else { if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { - x_offset -= buffer->pos[i].x_advance; - y_offset -= buffer->pos[i].y_advance; + x_offset = hb_saturate_sub (x_offset, buffer->pos[i].x_advance); + y_offset = hb_saturate_sub (y_offset, buffer->pos[i].y_advance); } else { - x_offset += buffer->pos[i].x_advance; - y_offset += buffer->pos[i].y_advance; + x_offset = hb_saturate_add (x_offset, buffer->pos[i].x_advance); + y_offset = hb_saturate_add (y_offset, buffer->pos[i].y_advance); } } } @@ -559,7 +573,7 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED, if (horizontal) pos[i].x_advance = +font->x_scale / 4; else - pos[i].y_advance = -font->y_scale / 4; + pos[i].y_advance = -(int64_t) font->y_scale / 4; } hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]); @@ -579,16 +593,16 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED, case t::SPACE_EM_6: case t::SPACE_EM_16: if (horizontal) - pos[i].x_advance = +(font->x_scale + ((int) space_type)/2) / (int) space_type; + pos[i].x_advance = ((int64_t) font->x_scale + ((int) space_type)/2) / (int) space_type; else - pos[i].y_advance = -(font->y_scale + ((int) space_type)/2) / (int) space_type; + pos[i].y_advance = -((int64_t) font->y_scale + ((int) space_type)/2) / (int) space_type; break; case t::SPACE_4_EM_18: if (horizontal) - pos[i].x_advance = (int64_t) +font->x_scale * 4 / 18; + pos[i].x_advance = (int64_t) font->x_scale * 4 / 18; else - pos[i].y_advance = (int64_t) -font->y_scale * 4 / 18; + pos[i].y_advance = -(int64_t) font->y_scale * 4 / 18; break; case t::SPACE_FIGURE: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc index 9d792cc7f11..9cbacf46662 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc @@ -468,7 +468,8 @@ struct hb_ot_shape_context_t /* Prepare */ static void -hb_set_unicode_props (hb_buffer_t *buffer) +hb_set_unicode_props (hb_buffer_t *buffer, + hb_mask_t global_mask) { /* Implement enough of Unicode Graphemes here that shaping * in reverse-direction wouldn't break graphemes. Namely, @@ -482,6 +483,7 @@ hb_set_unicode_props (hb_buffer_t *buffer) hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) { + info[i].mask = global_mask; _hb_glyph_info_set_unicode_props (&info[i], buffer); if (info[i].codepoint < 0x80) @@ -519,6 +521,7 @@ hb_set_unicode_props (hb_buffer_t *buffer) _hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint)) { i++; + info[i].mask = global_mask; _hb_glyph_info_set_unicode_props (&info[i], buffer); _hb_glyph_info_set_continuation (&info[i], buffer); } @@ -743,16 +746,6 @@ hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c) } } -static inline void -hb_ot_shape_initialize_masks (const hb_ot_shape_context_t *c) -{ - hb_ot_map_t *map = &c->plan->map; - hb_buffer_t *buffer = c->buffer; - - hb_mask_t global_mask = map->get_global_mask (); - buffer->reset_masks (global_mask); -} - static inline void hb_ot_shape_setup_masks (const hb_ot_shape_context_t *c) { @@ -912,22 +905,29 @@ hb_ot_substitute_plan (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; - hb_ot_layout_substitute_start (c->font, buffer); - - if (c->plan->fallback_glyph_classes) - hb_synthesize_glyph_classes (c->buffer); - #ifndef HB_NO_AAT_SHAPE if (unlikely (c->plan->apply_morx)) { + hb_ot_layout_substitute_start (c->font, buffer); + + if (c->plan->fallback_glyph_classes) + hb_synthesize_glyph_classes (buffer); + hb_aat_layout_substitute (c->plan, c->font, c->buffer, c->user_features, c->num_user_features); - c->buffer->update_digest (); + /* The buffer digest is only used by the OT lookup-apply loop; + * without GPOS ahead, nothing consumes it. */ + if (c->plan->apply_gpos) + c->buffer->update_digest (); } else #endif { - c->buffer->update_digest (); + hb_ot_layout_substitute_start_with_digest (c->font, buffer); + + if (c->plan->fallback_glyph_classes) + hb_synthesize_glyph_classes (buffer); + c->plan->substitute (c->font, buffer); } } @@ -973,8 +973,8 @@ hb_ot_substitute_post (const hb_ot_shape_context_t *c) static inline void adjust_mark_offsets (hb_glyph_position_t *pos) { - pos->x_offset -= pos->x_advance; - pos->y_offset -= pos->y_advance; + pos->x_offset = hb_saturate_sub (pos->x_offset, pos->x_advance); + pos->y_offset = hb_saturate_sub (pos->y_offset, pos->y_advance); } static inline void @@ -1175,8 +1175,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) _hb_buffer_allocate_unicode_vars (c->buffer); - hb_ot_shape_initialize_masks (c); - hb_set_unicode_props (c->buffer); + hb_set_unicode_props (c->buffer, c->plan->map.get_global_mask ()); hb_insert_dotted_circle (c->buffer, c->font); hb_form_clusters (c->buffer); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh index 649acddb414..e5b08b45277 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh @@ -33,26 +33,71 @@ #include "hb-aat-map.hh" +HB_INTERNAL bool +_hb_ot_layout_table_get_feature_variations_state (hb_face_t *face, + hb_tag_t table_tag, + const int *coords, + unsigned int num_coords, + unsigned int *variations_index, + hb_vector_t *lookup_conditions); + +HB_INTERNAL bool +_hb_ot_layout_feature_get_lookup_variations (hb_face_t *face, + hb_tag_t table_tag, + unsigned feature_index, + unsigned variations_index, + hb_sorted_array_t conditions, + hb_set_t *lookup_indexes); + struct hb_ot_shape_plan_key_t { unsigned int variations_index[2]; + /* Sorted offsets of distinct true conditions within FeatureVariations. + * Different outcomes may conservatively separate equivalent lookup sets. */ + hb_vector_t lookup_conditions[2]; - void init (hb_face_t *face, + bool init (hb_face_t *face, const int *coords, unsigned num_coords) { for (unsigned int table_index = 0; table_index < 2; table_index++) - hb_ot_layout_table_find_feature_variations (face, - table_tags[table_index], - coords, - num_coords, - &variations_index[table_index]); + if (unlikely (!_hb_ot_layout_table_get_feature_variations_state ( + face, + table_tags[table_index], + coords, + num_coords, + &variations_index[table_index], + &lookup_conditions[table_index]))) + { + for (auto &v : lookup_conditions) + v.fini (); + return false; + } + return true; + } + + void fini () + { + for (auto &v : lookup_conditions) + v.fini (); + } + + bool get_lookup_variations (hb_face_t *face, + unsigned int table_index, + unsigned int feature_index, + hb_set_t *lookups) const + { + return _hb_ot_layout_feature_get_lookup_variations ( + face, table_tags[table_index], feature_index, variations_index[table_index], + lookup_conditions[table_index].as_sorted_array (), lookups); } bool equal (const hb_ot_shape_plan_key_t *other) { return variations_index[0] == other->variations_index[0] && - variations_index[1] == other->variations_index[1]; + variations_index[1] == other->variations_index[1] && + lookup_conditions[0] == other->lookup_conditions[0] && + lookup_conditions[1] == other->lookup_conditions[1]; } }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-fallback.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-fallback.hh index ff0b2acede1..e428c63931d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-fallback.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-fallback.hh @@ -231,11 +231,7 @@ struct arabic_fallback_plan_t OT::hb_ot_layout_lookup_accelerator_t *accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; }; -#if defined(_WIN32) && !defined(HB_NO_WIN1256) -#define HB_WITH_WIN1256 -#endif - -#ifdef HB_WITH_WIN1256 +#ifndef HB_NO_WIN1256 #include "hb-ot-shaper-arabic-win1256.hh" #endif @@ -254,7 +250,7 @@ arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUS const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED) { -#ifdef HB_WITH_WIN1256 +#ifndef HB_NO_WIN1256 /* Does this font look like it's Windows-1256-encoded? */ hb_codepoint_t g; if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ && diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh index 79d3014d3e1..19aa3ce0fc5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-joining-list.hh @@ -6,10 +6,10 @@ * * on files with these headers: * - * # ArabicShaping-17.0.0.txt - * # Date: 2025-08-14 - * # Scripts-17.0.0.txt - * # Date: 2025-07-24, 13:28:55 GMT + * # ArabicShaping-18.0.0.txt + * # Date: 2026-08-18, 19:02:41 GMT + * # Scripts-18.0.0.txt + * # Date: 2026-06-29, 15:25:26 GMT */ #ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-pua.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-pua.hh index 7464e5d8a3b..dbbee473fcf 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-pua.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-pua.hh @@ -2,7 +2,7 @@ /* * The following table is generated by running: * - * ./gen-arabic-pua.py + * ./gen-arabic-pua.py ArabicPUASimplified.txt ArabicPUATraditional.txt * */ @@ -37,15 +37,15 @@ static const uint8_t _hb_arabic_pua_u8[453]= 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, + 48, 49, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 52, 53, 54, 55, + 56, 57, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 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, + 0, 64, 0, 0, 65, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 67, 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, }; -static const uint16_t _hb_arabic_pua_u16[717]= +static const uint16_t _hb_arabic_pua_u16[713]= { 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, @@ -77,21 +77,21 @@ static const uint16_t _hb_arabic_pua_u16[717]= 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, + 61970,61971,61972,61957,62101,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, + 0,61974, 0, 0,62099, 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 uint8_t _hb_arabic_pua_b4 (const uint8_t* a, unsigned i) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh index 81c84cf1962..ffc5ecd74a1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh @@ -6,10 +6,10 @@ * * on files with these headers: * - * # ArabicShaping-17.0.0.txt - * # Date: 2025-08-14 - * # Blocks-17.0.0.txt - * # Date: 2025-08-01 + * # ArabicShaping-18.0.0.txt + * # Date: 2026-08-18, 19:02:41 GMT + * # Blocks-18.0.0.txt + * # Date: 2026-07-08 * UnicodeData.txt does not have a header. */ @@ -20,7 +20,7 @@ #include -static const uint8_t _hb_arabic_joining_u8[737]= +static const uint8_t _hb_arabic_joining_u8[749]= { 0, 16, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -45,11 +45,11 @@ static const uint8_t _hb_arabic_joining_u8[737]= 0, 0, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48, 6, 0, 0, 1, 1, 1, 1, 1, 1, 49, 0, 50, 51, 52, 53, 54, 55, 0, 0, 56, 57, 58, 0, 0, 59, 0, 0, 60, 1, 1, 1, 61, 0, 0, - 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, - 1, 64, 0, 65, 0, 0, 0, 66, 1, 67, 0, 0, 0, 0, 0, 68, - 69, 70, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 62, 0, 0, 63, 64, 65, 0, 0, 0, 0, 0, 0, 0, 0, 66, + 1, 67, 0, 68, 0, 0, 0, 69, 1, 70, 0, 0, 0, 0, 0, 71, + 72, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 72, 73, 0, 0, 0, 0, 0, 0,119,119,119,119, 51, 51, 51, + 1, 75, 76, 0, 0, 0, 0, 0, 0,119,119,119,119, 51, 51, 51, 51, 34, 34, 34, 34,119,119, 7,119, 34, 51, 51, 51, 35, 51, 51, 51, 0,119,119,119,115,119,119,119, 0, 0, 0,119,112, 7,119, 119, 3, 34, 34, 35, 35, 51, 51, 35, 34, 50, 51, 51, 50,115,119, @@ -65,10 +65,10 @@ static const uint8_t _hb_arabic_joining_u8[737]= 119, 51, 51, 35, 32, 32, 2, 16, 34, 34, 50, 51, 19, 51, 51, 35, 51, 35, 0,114,119,119, 55, 51, 35, 35, 35, 34, 51, 35, 51, 50, 34, 35,119,119,119, 39, 34, 50, 3, 49, 51, 51, 51, 51, 50,119, - 119,119, 50,115, 51, 51, 35, 51, 51, 51, 51, 3,119, 55, 51,114, - 119, 51, 51, 34, 51, 51,119,119,119, 3, 51, 34, 2, 35, 50, 35, - 51, 48, 34, 3, 0, 32, 19,119,119, 51, 51,119,119,119,103,119, - 119, + 119,119, 50,115, 51, 23, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 113, 51, 35, 51, 51, 51, 51, 3,119, 55, 51,114,119, 51, 51, 34, + 51, 51,119,119,119, 3, 51, 34, 2, 35, 50, 35, 51, 48, 34, 3, + 0, 32, 19,119,119, 51, 51,119,119,119,103,119,119, }; static inline uint8_t _hb_arabic_joining_b4 (const uint8_t* a, unsigned i) @@ -280,7 +280,7 @@ static const struct ligature_set_t { struct ligature_pairs_t { uint16_t components[1]; uint16_t ligature; - } ligatures[14]; + } ligatures[15]; } ligature_table[] = { { 0xFE91u, { @@ -337,6 +337,7 @@ static const struct ligature_set_t { { {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 */ + { {0xFEF0u}, 0xFC43u }, /* ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED 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 */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc index 611aa262f40..1b1e6277f3c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc @@ -35,6 +35,9 @@ /* buffer var allocations */ #define arabic_shaping_action() ot_shaper_var_u8_auxiliary() /* arabic shaping action */ +/* buffer **position** var allocations, used after GPOS */ +#define stch_advance() var.i32 /* advance used for stretching */ + #define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_SHAPER0 /* See: @@ -492,6 +495,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, * First pass calculates the exact number of extra glyphs we need, * We then enlarge buffer to have that much room, * Second pass applies the stretch, copying things to the end of buffer. + * + * Cache glyph advances in the position scratch field during the first pass, + * for re-use these during the second pass. */ int sign = font->x_scale < 0 ? -1 : +1; @@ -531,15 +537,17 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_in_range (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING)) { i--; - hb_position_t width = font->get_glyph_h_advance (info[i].codepoint); + if (step == MEASURE) + pos[i].stch_advance() = font->get_glyph_h_advance (info[i].codepoint); + hb_position_t width = pos[i].stch_advance(); if (info[i].arabic_shaping_action() == STCH_FIXED) { - w_fixed += width; + w_fixed = hb_saturate_add (w_fixed, width); n_fixed++; } else { - w_repeating += width; + w_repeating = hb_saturate_add (w_repeating, width); n_repeating++; } } @@ -551,7 +559,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1])))) { context--; - w_total += pos[context].x_advance; + w_total = hb_saturate_add (w_total, pos[context].x_advance); } i++; // Don't touch i again. @@ -573,7 +581,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, w_remaining_signed = -w_remaining_signed; w_repeating_signed = -w_repeating_signed; } - hb_position_t w_remaining = (hb_position_t) (w_total - w_fixed); + hb_position_t w_remaining = hb_saturate_sub (w_total, w_fixed); if (w_remaining_signed > w_repeating_signed && w_repeating_signed > 0) n_copies = w_remaining_signed / w_repeating_signed - 1; @@ -586,7 +594,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, int64_t excess = (n_copies + 1) * w_repeating_signed - w_remaining_signed; if (excess > 0) { - extra_repeat_overlap = excess / (n_copies * n_repeating); + extra_repeat_overlap = hb_clamp_to (excess / ((int64_t) n_copies * (int64_t) n_repeating)); w_remaining = 0; } } @@ -617,7 +625,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_position_t x_offset = w_remaining / 2; for (unsigned int k = end; k > start; k--) { - hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint); + hb_position_t width = pos[k - 1].stch_advance(); unsigned int repeat = 1; if (info[k - 1].arabic_shaping_action() == STCH_REPEATING) @@ -630,9 +638,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, { if (rtl) { - x_offset -= width; + x_offset = hb_saturate_sub (x_offset, width); if (n > 0) - x_offset += extra_repeat_overlap; + x_offset = hb_saturate_add (x_offset, extra_repeat_overlap); } pos[k - 1].x_offset = x_offset; /* Append copy. */ @@ -642,9 +650,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, if (!rtl) { - x_offset += width; + x_offset = hb_saturate_add (x_offset, width); if (n > 0) - x_offset -= extra_repeat_overlap; + x_offset = hb_saturate_sub (x_offset, extra_repeat_overlap); } } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc index 1430d142d14..dbd7ff2b14e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc @@ -67,14 +67,23 @@ static void override_features_hangul (hb_ot_shape_planner_t *plan) { /* Uniscribe does not apply 'calt' for Hangul, and certain fonts - * (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups - * in calt, which is not desirable. */ - plan->map.disable_feature (HB_TAG('c','a','l','t')); + * (Noto Sans CJK, Source Han Sans, etc) apply all of jamo lookups + * in calt, which is not desirable. + * + * Rather than disabling 'calt' for the entire run, which also turns + * it off for any other characters in the run, allocate a mask for it + * and clear that mask on jamo only (in setup_masks_hangul). That + * keeps jamo out of reach of such lookups while letting the rest of + * the run shape with 'calt' as usual. + * + * https://github.com/harfbuzz/harfbuzz/discussions/4853 */ + plan->map.add_feature (HB_TAG('c','a','l','t')); } struct hangul_shape_plan_t { hb_mask_t mask_array[HANGUL_FEATURE_COUNT]; + hb_mask_t calt_mask; }; static void * @@ -87,6 +96,8 @@ data_create_hangul (const hb_ot_shape_plan_t *plan) for (unsigned int i = 0; i < HANGUL_FEATURE_COUNT; i++) hangul_plan->mask_array[i] = plan->map.get_1_mask (hangul_features[i]); + hangul_plan->calt_mask = plan->map.get_1_mask (HB_TAG('c','a','l','t')); + return hangul_plan; } @@ -405,7 +416,14 @@ setup_masks_hangul (const hb_ot_shape_plan_t *plan, unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++, info++) + { info->mask |= hangul_plan->mask_array[info->hangul_shaping_feature()]; + + /* Keep 'calt' away from jamo; see override_features_hangul(). */ + hb_codepoint_t u = info->codepoint; + if (isL (u) || isV (u) || isT (u)) + info->mask &= ~hangul_plan->calt_mask; + } } HB_BUFFER_DEALLOCATE_VAR (buffer, hangul_shaping_feature); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc index 74fe5efa3b7..10ca0db6c56 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc @@ -6,12 +6,12 @@ * * on files with these headers: * - * # IndicSyllabicCategory-17.0.0.txt - * # Date: 2025-08-01, 04:02:23 GMT - * # IndicPositionalCategory-17.0.0.txt - * # Date: 2025-07-29, 13:35:52 GMT - * # Blocks-17.0.0.txt - * # Date: 2025-08-01 + * # IndicSyllabicCategory-18.0.0.txt + * # Date: 2026-07-02, 18:58:37 GMT + * # IndicPositionalCategory-18.0.0.txt + * # Date: 2026-06-24, 13:39:21 GMT + * # Blocks-18.0.0.txt + * # Date: 2026-07-08 */ #include "hb.hh" @@ -82,7 +82,7 @@ static_assert (OT_VPst == M_Cat(VPst), ""); #define _OT_CS OT_CS /* 4 chars; CS */ #define _OT_DC OT_DOTTEDCIRCLE /* 1 chars; DOTTEDCIRCLE */ #define _OT_H OT_H /* 11 chars; H */ -#define _OT_M OT_M /* 142 chars; M */ +#define _OT_M OT_M /* 144 chars; M */ #define _OT_MH OT_MH /* 1 chars; MH */ #define _OT_ML OT_ML /* 1 chars; ML */ #define _OT_MP OT_MPst /* 1 chars; MPst */ @@ -111,7 +111,7 @@ static_assert (OT_VPst == M_Cat(VPst), ""); #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_A POS_AFTER_MAIN /* 5 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 /* 853 chars; BASE_C */ @@ -141,7 +141,7 @@ static const uint16_t _hb_indic_values[42]= _(VA,T), _(VB,B), _(VL,L), _(VR,R), _(VS,X), _(X,X), _(Xg,X), _(Yg,X), _(ZWJ,X),_(ZWNJ,X), }; -static const uint8_t _hb_indic_u8[1220]= +static const uint8_t _hb_indic_u8[1224]= { 1, 0, 50, 4, 5, 96, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -181,45 +181,45 @@ static const uint8_t _hb_indic_u8[1220]= 56, 12, 14, 6, 0, 0, 0, 4, 44, 2, 16, 2, 6, 22, 0, 4, 2, 0, 36, 28, 6, 28, 0, 4, 30, 30, 30, 30, 0, 0, 42, 0, 34, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 42, 12, 12, 6, 6, - 6, 6, 24, 2, 2, 18, 36,112, 18, 18, 18, 18, 18, 18,114,116, - 118,120,122, 18, 0, 6, 6, 6, 44, 10, 0, 2, 54, 32, 46, 10, + 6, 6, 24, 2, 2, 18, 36,110, 18, 18, 18, 18, 18, 18,112,114, + 116,118,120, 18, 0, 6, 6, 6, 44, 10, 0, 2, 54, 32, 46, 10, 26, 0, 0, 0, 0, 0, 34, 70, 6, 20, 0, 14, 44, 2, 16, 10, - 2, 0, 72, 50,124, 48, 0, 32, 48, 32, 46, 0,126, 0, 0, 0, - 16, 2, 10, 10, 12, 2,128, 0, 6, 6, 6, 14, 6, 14, 24, 2, - 22, 22, 52, 74, 76, 32, 46, 0, 16, 58, 58, 78,130, 12, 14, 6, - 2, 0, 36,132,134, 32, 46, 0, 0, 0, 80,136, 16, 0, 0, 0, + 2, 0, 72, 50,122, 48, 0, 32, 48, 32, 46, 0,124, 0, 0, 0, + 16, 2, 10, 10, 12, 2,126, 0, 6, 6, 6, 14, 6, 14, 24, 2, + 22, 22, 52, 74, 76, 32, 46, 0, 16, 58, 58, 78,128, 12, 14, 6, + 2, 0, 36,130,132, 32, 46, 0, 0,134,136,138, 16, 0, 0, 0, 0, 70, 14, 6, 6, 20, 0, 6, 20, 6, 24, 0, 16, 10, 10, 2, - 0, 16, 10, 0, 2, 10, 0, 2, 2, 0, 0, 22, 76, 48, 0, 82, - 54, 22, 84, 0, 12, 12,138, 6, 28, 60, 38, 28, 86, 28, 88, 0, - 0, 0,140, 86, 2, 10, 16, 0, 26, 2, 16, 2, 28, 60, 38, 60, - 38, 18, 88, 0, 0, 0, 74, 38, 0, 0, 16, 10,142,144, 0, 0, - 12, 12,146, 6, 2,148,150, 22, 22, 22, 48, 82, 54, 22, 84,152, - 0, 0, 2,154, 0, 0, 0, 14, 0, 2, 2, 2, 2, 2, 26, 2, - 2,156, 2, 2, 90, 6, 6, 6, 6,158, 92, 94,160,162, 62, 58, - 164,166,168,170, 4, 4, 0, 10, 2, 6, 6, 96, 98, 26, 2,172, - 174,100,176,178,100,102,102, 2,104, 62,180, 2, 2,182,184,186, - 12, 12, 12,188, 4, 12,190, 0, 2, 26, 2, 2, 2, 90, 6, 6, - 6, 6, 0, 92, 62, 94, 98,192,194,196, 96,198,200,106,106,108, - 108,202, 0, 0, 42, 0,204, 0, 8,206, 8, 8,208, 40,210, 40, - 40, 2,212,214, 8, 34, 0, 0, 0, 0,216, 0, 4, 4, 4, 0, - 0, 34, 0, 0, 0, 0,110, 0, 0, 64,110, 0, 0, 0,218, 0, - 0, 42, 4, 34, 8, 40, 40, 40, 0, 0, 0,220, 2, 2,104, 16, - 4, 2, 2, 10, 16, 2, 4, 34, 0,222, 78, 2, 56, 12, 0, 0, - 0, 80, 72, 0, 37, 37, 2, 2, 6, 6, 31, 31, 0, 0, 2, 37, + 0, 16, 10, 0, 2, 10, 0, 2, 2, 0, 0, 22, 76, 48, 0, 80, + 54, 22, 82, 0, 12, 12,140, 6, 28, 60, 38, 28, 84, 28, 86, 0, + 0, 0,142, 84, 2, 10, 16, 0, 26, 2, 16, 2, 28, 60, 38, 60, + 38, 18, 86, 0, 0, 0, 74, 38, 0, 0, 16, 10,144,146, 0, 0, + 12, 12,148, 6, 2,150,152, 22, 22, 22, 48, 80, 54, 22, 82,154, + 0, 0, 2,156, 0, 0, 0, 14, 0, 2, 2, 2, 2, 2, 26, 2, + 2,158, 2, 2, 88, 6, 6, 6, 6,160, 90, 92,162,164, 62, 58, + 166,168,170,172, 4, 4, 0, 10, 2, 6, 6, 94, 96, 26, 2,174, + 176, 98,178,180, 98,100,100, 2,102, 62,182, 2, 2,184,186,188, + 12, 12, 12,190, 4, 12,192, 0, 2, 26, 2, 2, 2, 88, 6, 6, + 6, 6, 0, 90, 62, 92, 96,194,196,198, 94,200,202,104,104,106, + 106,204, 0, 0, 42, 0,206, 0, 8,208, 8, 8,210, 40,212, 40, + 40, 2,214,216, 8, 34, 0, 0, 0, 0,218, 0, 4, 4, 4, 0, + 0, 34, 0, 0, 0, 0,108, 0, 0, 64,108, 0, 0, 0,220, 0, + 0, 42, 4, 34, 8, 40, 40, 40, 0, 0, 0,222, 2, 2,102, 16, + 4, 2, 2, 10, 16, 2, 4, 34, 0,224, 78, 2, 56, 12, 0, 0, + 0,226, 72, 0, 37, 37, 2, 2, 6, 6, 31, 31, 0, 0, 2, 37, 29, 29, 37, 31, 37, 2, 12, 12, 31, 37, 11, 11, 31, 2, 24, 2, 14, 14, 36, 36, 37, 11, 6, 37, 22, 27, 12, 37, 27, 27, 37, 6, 24, 37, 11, 7, 11, 37, 11, 15, 11, 12, 15, 37, 37, 29, 0, 22, 14, 12, 32, 32, 30, 30, 6, 29, 37, 15, 29, 37, 22, 37, 37, 12, - 12, 11, 22, 22, 37, 22, 15, 15, 11, 8, 14, 37, 14, 8, 2, 31, - 35, 32, 32, 33, 35, 35, 33, 33, 35, 23, 23, 23, 2, 32, 26, 38, - 38, 38, 30, 37, 12, 15, 12, 7, 15, 12, 37, 0, 0, 29, 29, 12, - 18, 11, 37, 13, 37, 3, 37, 28, 11, 10, 10, 37, 10, 11, 29, 31, - 37, 14, 37, 4, 4, 29, 6, 31, 2, 12, 12, 27, 25, 37, 2, 11, - 2, 24, 31, 35, 33, 34, 0, 32, 29, 9, 1, 21, 19, 20, 16, 2, - 21, 21, 17, 2, 23, 2, 2, 35, 32, 2, 20, 35, 34, 32, 32, 29, - 2, 29, 29, 32, 32, 35, 35, 34, 34, 34, 38, 39, 39, 26, 9, 39, - 27, 39, 0, 37, 0, 27, 27, 0, 0, 4, 4, 0, 41, 40, 5, 37, - 31, 12, 2, 23, + 12, 11, 22, 22, 15, 15, 11, 8, 14, 37, 14, 8, 2, 31, 35, 32, + 32, 33, 35, 35, 33, 33, 35, 23, 23, 23, 2, 32, 26, 38, 38, 38, + 30, 37, 12, 15, 12, 7, 15, 12, 37, 0, 0, 29, 29, 12, 18, 11, + 37, 13, 37, 3, 37, 28, 11, 10, 10, 37, 37, 10, 10, 22, 10, 11, + 29, 31, 37, 14, 37, 4, 4, 29, 6, 31, 2, 12, 12, 27, 25, 37, + 2, 11, 2, 24, 31, 35, 33, 34, 0, 32, 29, 9, 1, 21, 19, 20, + 16, 2, 21, 21, 17, 2, 23, 2, 2, 35, 32, 2, 20, 35, 34, 32, + 32, 29, 2, 29, 29, 32, 32, 35, 35, 34, 34, 34, 38, 39, 39, 26, + 9, 39, 27, 39, 0, 37, 0, 27, 27, 0, 0, 4, 4, 0, 41, 40, + 5, 37, 31, 12, 2, 23, 37, 22, }; static inline uint8_t _hb_indic_b4 (const uint8_t* a, unsigned i) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh index 0b038ba2201..9e8675e2d6d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh @@ -6,18 +6,18 @@ * * on files with these headers: * - * # IndicSyllabicCategory-17.0.0.txt - * # Date: 2025-08-01, 04:02:23 GMT - * # IndicPositionalCategory-17.0.0.txt - * # Date: 2025-07-29, 13:35:52 GMT - * # ArabicShaping-17.0.0.txt - * # Date: 2025-08-14 + * # IndicSyllabicCategory-18.0.0.txt + * # Date: 2026-07-02, 18:58:37 GMT + * # IndicPositionalCategory-18.0.0.txt + * # Date: 2026-06-24, 13:39:21 GMT + * # ArabicShaping-18.0.0.txt + * # Date: 2026-08-18, 19:02:41 GMT * # DerivedCoreProperties-17.0.0.txt * # Date: 2025-07-30, 23:55:08 GMT - * # Blocks-17.0.0.txt - * # Date: 2025-08-01 - * # Scripts-17.0.0.txt - * # Date: 2025-07-24, 13:28:55 GMT + * # Blocks-18.0.0.txt + * # Date: 2026-07-08 + * # Scripts-18.0.0.txt + * # Date: 2026-06-29, 15:25:26 GMT * # Override values For Indic_Syllabic_Category * # Not derivable * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17 @@ -28,6 +28,8 @@ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16 * # Updated for Unicode 15.1 by Andrew Glass 2023-09-14 * # Updated for Unicode 16.0 by Andrew Glass 2024-09-11 + * # Updated for Unicode 17.0 by Andrew Glass 2025-09-15 + * # Updated for Unicode 18.0 by Andrew Glass 2026-09-04 * # Override values For Indic_Positional_Category * # Not derivable * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17 @@ -40,6 +42,8 @@ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16 * # Updated for Unicode 15.1 by Andrew Glass 2023-09-14 * # Updated for Unicode 16.0 by Andrew Glass 2024-09-11 + * # Updated for Unicode 17.0 by Andrew Glass 2025-09-15 + * # Updated for Unicode 18.0 by Andrew Glass 2026-09-04 * UnicodeData.txt does not have a header. */ @@ -103,7 +107,7 @@ #include -static const uint8_t hb_use_u8[3343]= +static const uint8_t hb_use_u8[3359]= { 33, 3, 0, 0, 0, 4, 0, 80, 118, 128, 9, 10, 11, 192, 208, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -161,24 +165,24 @@ static const uint8_t hb_use_u8[3343]= 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 9, 41, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 6, 6, 6, 6, 6, 6, 6, - 6, 0, 0, 0, 0, 0, 0, 48, 0, 44, 0, 0, 0, 0, 0, 49, - 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 49, 0, 44, 0, 0, 0, 0, 0, 50, + 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 2, 2, 2, 2, 2, 36, 9, - 9, 9, 9, 0, 0, 0, 5, 31, 0, 2, 2, 2, 2, 50, 51, 0, + 9, 9, 9, 0, 0, 0, 5, 31, 0, 2, 2, 2, 2, 51, 52, 0, 0, 9, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 32, - 19, 17, 6, 18, 7, 15, 11, 67, 22, 31, 52, 25, 6, 2, 2, 2, + 19, 17, 6, 18, 7, 15, 11, 67, 22, 31, 53, 25, 6, 2, 2, 2, 2, 104, 14, 8, 2, 2, 2, 5, 8, 5, 5, 0, 2, 2, 0, 32, 19, 0, 0, 0, 34, 0, 0, 2, 8, 2, 0, 0, 0, 0, 0, 5, 105, 31, 24, 8, 2, 2, 5, 0, 8, 5, 2, 8, 5, 2, 0, 35, - 19, 17, 13, 0, 25, 38, 25, 68, 0, 53, 0, 0, 0, 8, 2, 5, - 5, 54, 39, 77, 0, 0, 0, 0, 0, 31, 24, 8, 2, 2, 2, 2, + 19, 17, 13, 0, 25, 38, 25, 68, 0, 54, 0, 0, 0, 8, 2, 5, + 5, 55, 39, 77, 0, 0, 0, 0, 0, 31, 24, 8, 2, 2, 2, 2, 8, 5, 2, 8, 2, 2, 0, 32, 19, 17, 6, 18, 25, 7, 34, 67, - 0, 0, 0, 0, 0, 8, 54, 54, 46, 31, 14, 8, 2, 2, 2, 5, - 8, 5, 2, 8, 2, 2, 0, 32, 20, 0, 0, 25, 7, 0, 0, 2, + 0, 0, 0, 0, 0, 8, 55, 55, 46, 31, 14, 8, 2, 2, 2, 5, + 8, 5, 2, 8, 2, 2, 0, 32, 20, 0, 25, 7, 7, 0, 0, 2, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 26, 8, 2, 2, 5, 0, 2, 5, 2, 2, 0, 8, 5, 5, 2, 0, 8, 5, 0, 2, 5, 0, 2, 2, 2, 2, 2, 2, 0, 0, 11, 15, 27, 0, 12, 33, 12, 45, - 0, 0, 0, 0, 34, 0, 0, 0, 0, 24, 14, 55, 2, 2, 2, 5, + 0, 0, 0, 0, 34, 0, 0, 0, 0, 24, 14, 47, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 0, 32, 7, 0, 0, 25, 13, 2, 5, 0, 0, 36, 14, 8, 2, 2, 2, 5, 2, 2, 2, 8, 2, 2, 0, 32, 20, 0, 0, 34, 27, 0, 0, 0, 5, 106, 78, 0, 0, 0, 0, 0, @@ -192,7 +196,7 @@ static const uint8_t hb_use_u8[3343]= 26, 18, 9, 13, 9, 2, 2, 79, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 81, 0, 0, 0, 0, 110, 0, 0, 0, 0, 2, 2, 2, 2, 2, 23, 20, 21, 57, 7, 7, 111, 82, 112, 113, - 83, 2, 2, 2, 2, 2, 48, 0, 44, 2, 2, 2, 11, 6, 2, 2, + 83, 2, 2, 2, 2, 2, 49, 0, 44, 2, 2, 2, 11, 6, 2, 2, 114, 83, 84, 41, 23, 84, 14, 14, 2, 30, 7, 40, 2, 2, 2, 2, 2, 2, 115, 58, 116, 14, 14, 117, 85, 2, 2, 2, 2, 2, 14, 20, 0, 2, 21, 59, 0, 0, 0, 0, 8, 2, 21, 27, 0, 0, 0, 0, @@ -200,19 +204,19 @@ static const uint8_t hb_use_u8[3343]= 2, 5, 21, 0, 0, 0, 0, 0, 0, 2, 2, 4, 20, 7, 21, 6, 12, 12, 12, 12, 24, 60, 118, 119, 120, 121, 122, 0, 0, 0, 0, 123, 0, 5, 0, 0, 8, 0, 124, 4, 125, 39, 39, 126, 86, 2, 2, 2, - 2, 2, 2, 2, 2, 50, 5, 0, 0, 7, 59, 20, 7, 127, 10, 0, + 2, 2, 2, 2, 2, 51, 5, 0, 0, 7, 59, 20, 7, 127, 10, 0, 0, 70, 128, 70, 70, 129, 130, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 14, 0, 0, 0, 2, 2, 2, 30, 71, 20, 0, 0, 2, 2, 131, 132, 42, 133, 10, 81, 134, 15, 20, 7, 21, 18, 59, - 12, 12, 58, 9, 9, 9, 87, 26, 53, 9, 88, 41, 2, 2, 2, 2, + 12, 12, 58, 9, 9, 9, 87, 26, 54, 9, 88, 41, 2, 2, 2, 2, 2, 2, 2, 89, 7, 6, 6, 7, 12, 12, 7, 61, 2, 2, 2, 5, 0, 0, 0, 0, 0, 0, 135, 62, 62, 62, 62, 0, 0, 0, 0, 0, 0, 88, 41, 2, 2, 2, 2, 2, 2, 79, 10, 21, 22, 7, 136, 10, 2, 2, 2, 2, 89, 7, 11, 20, 20, 42, 137, 0, 0, 0, 0, 0, 0, 2, 2, 10, 19, 12, 11, 90, 42, 42, 42, 138, 139, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 8, 2, 9, 26, 16, 16, 16, 9, 16, - 16, 24, 16, 16, 16, 52, 0, 53, 0, 0, 0, 140, 78, 9, 44, 0, - 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 49, 142, + 16, 24, 16, 16, 16, 53, 0, 54, 0, 0, 0, 140, 78, 9, 44, 0, + 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 50, 142, 3, 39, 39, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 72, 0, 0, 91, 0, 0, 0, 0, 0, 0, 76, 91, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, @@ -222,31 +226,31 @@ static const uint8_t hb_use_u8[3343]= 0, 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 144, 11, 11, 11, 11, 11, 11, 11, 92, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 30, 2, 2, 2, 7, 7, 145, 16, - 0, 2, 2, 2, 47, 6, 21, 6, 90, 42, 146, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 48, 6, 21, 6, 90, 42, 146, 0, 0, 0, 0, 0, 0, 9, 147, 2, 2, 2, 2, 2, 2, 2, 148, 11, 7, 6, 12, 149, 150, 93, 0, 0, 0, 0, 0, 0, 0, 2, 2, 30, 8, 2, 2, 2, 2, 2, 2, 2, 2, 36, 7, 21, 71, 58, 151, 94, 152, 0, 0, 0, 0, 2, 153, 2, 2, 2, 2, 154, 0, 8, 2, 39, 44, 0, 85, 24, - 2, 73, 6, 40, 47, 73, 2, 2, 95, 36, 5, 0, 0, 0, 0, 0, + 2, 73, 6, 40, 48, 73, 2, 2, 95, 36, 5, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 155, 18, 22, 0, 0, 156, 96, 0, 0, 0, 0, 2, 23, 20, 11, 59, 27, 157, 0, 0, 0, 0, 0, 0, 0, 0, - 49, 3, 3, 3, 3, 72, 0, 0, 0, 2, 5, 2, 8, 2, 2, 2, - 2, 2, 8, 2, 2, 2, 8, 5, 0, 47, 6, 25, 13, 0, 0, 158, - 159, 2, 2, 8, 2, 8, 2, 2, 2, 2, 2, 2, 0, 51, 35, 0, - 97, 2, 2, 50, 35, 0, 8, 2, 2, 0, 0, 0, 0, 8, 2, 2, - 5, 2, 2, 9, 54, 0, 0, 0, 0, 2, 2, 2, 0, 25, 7, 7, + 50, 3, 3, 3, 3, 72, 0, 0, 0, 2, 5, 2, 8, 2, 2, 2, + 2, 2, 8, 2, 2, 2, 8, 5, 0, 48, 6, 25, 13, 0, 0, 158, + 159, 2, 2, 8, 2, 8, 2, 2, 2, 2, 2, 2, 0, 52, 35, 0, + 97, 2, 2, 51, 35, 0, 8, 2, 2, 0, 0, 0, 0, 8, 2, 2, + 5, 2, 2, 9, 55, 0, 0, 0, 0, 2, 2, 2, 0, 25, 7, 7, 8, 2, 2, 2, 2, 2, 25, 38, 0, 2, 2, 2, 16, 16, 16, 16, - 16, 160, 2, 5, 0, 0, 0, 0, 0, 2, 51, 51, 0, 0, 0, 0, + 16, 160, 2, 5, 0, 0, 0, 0, 0, 2, 52, 52, 0, 0, 0, 0, 0, 5, 2, 2, 5, 2, 2, 2, 2, 8, 2, 5, 0, 8, 2, 0, 0, 161, 162, 163, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 6, 6, 6, 7, 7, 93, 0, 0, 0, 0, 0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 40, 30, 40, 0, 0, 0, 0, 164, 19, 17, 18, 15, 67, 35, 0, 0, 0, 13, 0, 0, 0, 0, 0, - 0, 9, 55, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 6, 7, 165, + 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 6, 7, 165, 7, 18, 166, 98, 2, 2, 2, 2, 2, 0, 0, 23, 167, 0, 0, 0, - 0, 2, 50, 0, 0, 0, 0, 0, 0, 2, 23, 22, 6, 6, 6, 7, + 0, 2, 51, 0, 0, 0, 0, 0, 0, 2, 23, 22, 6, 6, 6, 7, 7, 61, 64, 0, 0, 69, 99, 13, 100, 2, 2, 2, 2, 2, 2, 11, - 17, 7, 7, 168, 46, 0, 0, 0, 55, 47, 0, 0, 0, 0, 0, 0, + 17, 7, 7, 168, 46, 0, 0, 0, 47, 48, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 5, 5, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 36, 19, 17, 18, 7, 169, 13, 0, 0, 9, 9, 8, 2, 2, 2, 5, 8, 5, 2, 8, 2, 2, 56, 32, @@ -254,7 +258,7 @@ static const uint8_t hb_use_u8[3343]= 2, 2, 11, 0, 9, 9, 9, 26, 0, 9, 9, 26, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 0, 5, 2, 2, 2, 8, 20, 21, 6, 6, 13, 33, 29, 29, 22, 170, 14, 171, 101, 35, 0, 0, 0, 0, 0, - 0, 31, 52, 0, 0, 0, 0, 0, 0, 2, 2, 23, 22, 6, 6, 6, + 0, 31, 53, 0, 0, 0, 0, 0, 0, 2, 2, 23, 22, 6, 6, 6, 7, 11, 92, 24, 32, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 172, 173, 0, 0, 0, 0, 0, 0, 0, 19, 17, 6, 6, 57, 71, 22, 100, 9, 102, 5, 0, 0, 0, 0, 0, 22, 6, 6, 0, 12, 12, 9, @@ -268,13 +272,14 @@ static const uint8_t hb_use_u8[3343]= 101, 176, 177, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, 2, 23, 22, 6, 6, 0, 7, 11, 14, 61, 0, 33, 0, 0, 0, 0, 0, 30, 6, 7, 7, 7, 73, 2, 2, 2, 178, 95, 9, 24, 179, 10, - 180, 0, 0, 48, 97, 0, 0, 0, 0, 30, 6, 7, 15, 17, 6, 2, + 180, 0, 0, 49, 97, 0, 0, 0, 0, 30, 6, 7, 15, 17, 6, 2, 2, 2, 2, 64, 64, 64, 43, 43, 43, 43, 43, 43, 24, 181, 0, 8, - 0, 15, 6, 15, 15, 0, 0, 0, 0, 7, 6, 6, 13, 7, 7, 9, - 65, 0, 10, 10, 10, 10, 10, 10, 10, 57, 18, 60, 26, 0, 0, 0, - 0, 2, 2, 2, 5, 2, 8, 2, 2, 30, 7, 7, 13, 0, 38, 7, - 25, 9, 99, 182, 183, 0, 0, 0, 0, 2, 2, 2, 8, 5, 2, 2, - 2, 2, 2, 2, 2, 2, 11, 11, 27, 7, 34, 60, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 0, 0, 15, 6, 15, 15, 0, 0, 0, + 0, 7, 6, 6, 13, 7, 7, 9, 65, 0, 10, 10, 10, 10, 10, 10, + 10, 57, 18, 60, 26, 0, 0, 0, 0, 2, 2, 2, 5, 2, 8, 2, + 2, 30, 7, 7, 13, 0, 38, 7, 25, 9, 99, 182, 183, 0, 0, 0, + 0, 2, 2, 2, 8, 5, 2, 2, 2, 2, 2, 2, 2, 2, 11, 11, + 27, 7, 34, 60, 82, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 2, 184, 57, 27, 0, 0, 0, 0, 9, 185, 2, 2, 2, 2, 2, 2, 2, 2, 11, 7, 6, 13, 0, 12, 15, 96, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 98, 0, 0, 66, 66, 66, 186, 187, 66, 1, @@ -283,10 +288,10 @@ static const uint8_t hb_use_u8[3343]= 7, 7, 7, 7, 7, 7, 191, 192, 193, 9, 9, 9, 26, 0, 0, 0, 0, 14, 41, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 27, 0, 2, 2, 2, 2, 2, 5, 0, 56, 194, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 0, 0, 0, 53, 16, 52, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 0, 0, 0, 54, 16, 53, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 2, 2, 2, 2, 2, 0, 56, 35, 0, 49, 3, 3, 3, 72, 0, - 0, 9, 9, 9, 55, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, + 8, 2, 2, 2, 2, 2, 0, 56, 35, 0, 50, 3, 3, 3, 72, 0, + 0, 9, 9, 9, 47, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 46, 46, 46, 86, 0, 0, O, O, G, G, B, B, WJ, @@ -295,8 +300,8 @@ static const uint8_t hb_use_u8[3343]= VPre, VPst, VAbv, VAbv, VBlw, VPre, VPst, B, VPst,VMAbv,VMPst, O, VAbv,VMAbv, O, VPst, O, N, N, O, VPre, B, VAbv, O,VMAbv,CMBlw, B, VPre, O, O, VPst,CMBlw, O, B,VMAbv, HM, HM, VAbv, O, GB, GB, VAbv, B,VMPst, B, FAbv, FAbv, FBlw, - FBlw, GB, O, VPre, H,CMAbv,CMAbv, B, VBlw, O, GB, O, WJ, B,CMBlw,CMBlw, - CMBlw,VMBlw, O, O,VMBlw,VMAbv,CMAbv,VMAbv, B, O,CMBlw, VBlw, VPre, VPre, VAbv, VBlw, + FBlw, GB, O, VPre, H,CMAbv,CMAbv,VMAbv, B, B, VBlw, O, GB, O, WJ, B, + CMBlw,CMBlw,CMBlw,VMBlw, O, O,VMBlw,VMAbv,CMAbv, O,CMBlw, VBlw, VPre, VPre, VAbv, VBlw, VPst, VPst,VMAbv, H, B,SMAbv,SMAbv, SB, SE, R, R,VMPst, H, J, J, VPst, H, VAbv, H, O,FMBlw, FPst, FPst, VAbv, VPre, WJ, O, VBlw, B, O, SB, O, SE,FMPst,FMPst, O, MBlw, CS,VMPst, B, SUB, O, SUB, SUB, O,VMPst, IS, MBlw, @@ -358,18 +363,18 @@ static const uint16_t hb_use_u16[864]= 24,1872,1880, 200,1888, 0, 0, 0, 24, 24,1896,1904, 0, 0, 0, 0, 1912,1920, 24,1928,1936, 32, 0, 0, 0, 0,1944, 24, 24,1952,1960, 0, 1968, 24, 24,1976,1984,1992, 24, 24,2000,2008, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,2016, 0, 48, 24, 256,2024, 128, 24, 88, 144, - 24,2032, 176,2040, 0, 0, 0, 0,2048, 24, 24,2056,2064, 32,2072, 24, - 2080,2088, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24,2096, - 2104, 80, 24,2112,2120,2128, 0, 0, 8, 8, 8,2136,2144,2152, 8, 8, - 8, 8, 8, 8, 8, 8, 8,2160, 24,2168,2176, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 32, 0, 0, 0, 24, 24, 24,2184, 0, 0, 0, 0, - 0, 0, 0, 0,2192, 24,2200, 32, 24, 24, 24, 24,2208,2216, 264, 264, - 2224,2232, 0, 0, 0, 0,2240, 0, 24, 24, 24, 24, 24, 232, 0,2248, - 24, 24, 24, 24, 24, 24, 104, 88, 96,2256, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,2264, 24, 24, 88,2272,2280, 0, 0, 0, - 0, 24,2288, 0, 24, 24,2296, 32, 0, 0, 0, 0, 0, 24,2304, 32, - 0, 0, 0, 0, 0, 24,2312, 104, 24, 24, 24, 24,2320, 32, 0, 0, + 2016, 0, 0, 0, 0, 0,2024, 0, 48, 24, 256,2032, 128, 24, 88, 144, + 24,2040, 176,2048, 0, 0, 0, 0,2056, 24, 24,2064,2072, 32,2080, 24, + 2088,2096, 32, 0, 0, 0, 0,2104, 0, 0, 0, 0, 0, 0, 24,2112, + 2120, 80, 24,2128,2136,2144, 0, 0, 8, 8, 8,2152,2160,2168, 8, 8, + 8, 8, 8, 8, 8, 8, 8,2176, 24,2184,2192, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 0, 0, 0, 24, 24, 24,2200, 0, 0, 0, 0, + 0, 0, 0, 0,2208, 24,2216, 32, 24, 24, 24, 24,2224,2232, 264, 264, + 2240,2248, 0, 0, 0, 0,2256, 0, 24, 24, 24, 24, 24, 232, 0,2264, + 24, 24, 24, 24, 24, 24, 104, 88, 96,2272, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,2280, 24, 24, 88,2288,2296, 0, 0, 0, + 0, 24,2304, 0, 24, 24,2312, 32, 0, 0, 0, 0, 0, 24,2320, 32, + 0, 0, 0, 0, 0, 24,2328, 104, 24, 24, 24, 24,2336, 32, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 16, }; @@ -380,7 +385,7 @@ static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) static inline uint8_t hb_use_get_category (unsigned u) { /* packtab: [2^4,2^5,2^3,2^3,2^1] */ - return u<921600u ? (uint8_t)(hb_use_u8[2953u+((hb_use_u8[625u+hb_use_u16[((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((u)>>1))>>3))>>3))>>5)))<<5)+((((((((u)>>1))>>3))>>3))&31)])<<3)+((((((u)>>1))>>3))&7)]+((((u)>>1))&7)])<<1)+((u)&1)]) : O; + return u<921600u ? (uint8_t)(hb_use_u8[2969u+((hb_use_u8[625u+hb_use_u16[((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((u)>>1))>>3))>>3))>>5)))<<5)+((((((((u)>>1))>>3))>>3))&31)])<<3)+((((((u)>>1))>>3))&7)]+((((u)>>1))&7)])<<1)+((u)&1)]) : O; } @@ -388,7 +393,7 @@ static inline uint8_t hb_use_get_category (unsigned u) #include -static const uint8_t hb_use_u8[3663]= +static const uint8_t hb_use_u8[3679]= { 33, 3, 0, 0, 0, 4, 0, 80, 118, 128, 9, 10, 11, 192, 208, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -438,18 +443,18 @@ static const uint8_t hb_use_u8[3663]= 0, 0, 0, 0, 0, 3, 182, 183, 0, 3, 184, 185, 0, 3, 186, 187, 188, 189, 190, 191, 0, 0, 0, 0, 0, 3, 192, 0, 0, 0, 0, 0, 0, 193, 194, 195, 0, 0, 196, 197, 198, 199, 200, 201, 3, 202, 0, 0, - 0, 0, 0, 0, 203, 0, 0, 0, 0, 204, 205, 206, 207, 208, 209, 0, - 0, 210, 211, 212, 213, 214, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 215, 216, 217, 218, 0, 0, 0, 0, 0, 1, 219, 220, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 221, 222, 223, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 224, 0, 0, 0, 0, 0, - 0, 0, 0, 225, 226, 0, 0, 0, 0, 3, 3, 227, 228, 229, 0, 0, - 230, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 231, - 232, 3, 3, 3, 233, 234, 0, 0, 0, 0, 0, 0, 235, 0, 0, 0, - 0, 3, 236, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 238, 3, - 239, 0, 0, 0, 0, 0, 0, 5, 240, 0, 0, 0, 0, 0, 0, 5, - 241, 3, 3, 242, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, - 243, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 0, 203, 0, 0, 204, 0, 0, 0, 0, 205, 206, 207, 208, 209, 210, 0, + 0, 211, 212, 213, 214, 215, 6, 0, 216, 0, 0, 0, 0, 0, 0, 0, + 217, 218, 219, 220, 0, 0, 0, 0, 0, 1, 221, 222, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 223, 224, 225, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 226, 0, 0, 0, 0, 0, + 0, 0, 0, 227, 228, 0, 0, 0, 0, 3, 3, 229, 230, 231, 0, 0, + 232, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 233, + 234, 3, 3, 3, 235, 236, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, + 0, 3, 238, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 240, 3, + 241, 0, 0, 0, 0, 0, 0, 5, 242, 0, 0, 0, 0, 0, 0, 5, + 243, 3, 3, 244, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, + 245, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 5, 2, 2, 2, 2, 6, 0, 2, 2, 2, 2, @@ -466,24 +471,24 @@ static const uint8_t hb_use_u8[3663]= 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 9, 41, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 6, 6, 6, 6, 6, 6, 6, - 6, 0, 0, 0, 0, 0, 0, 48, 0, 44, 0, 0, 0, 0, 0, 49, - 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 49, 0, 44, 0, 0, 0, 0, 0, 50, + 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 2, 2, 2, 2, 2, 36, 9, - 9, 9, 9, 0, 0, 0, 5, 31, 0, 2, 2, 2, 2, 50, 51, 0, + 9, 9, 9, 0, 0, 0, 5, 31, 0, 2, 2, 2, 2, 51, 52, 0, 0, 9, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 32, - 19, 17, 6, 18, 7, 15, 11, 67, 22, 31, 52, 25, 6, 2, 2, 2, + 19, 17, 6, 18, 7, 15, 11, 67, 22, 31, 53, 25, 6, 2, 2, 2, 2, 104, 14, 8, 2, 2, 2, 5, 8, 5, 5, 0, 2, 2, 0, 32, 19, 0, 0, 0, 34, 0, 0, 2, 8, 2, 0, 0, 0, 0, 0, 5, 105, 31, 24, 8, 2, 2, 5, 0, 8, 5, 2, 8, 5, 2, 0, 35, - 19, 17, 13, 0, 25, 38, 25, 68, 0, 53, 0, 0, 0, 8, 2, 5, - 5, 54, 39, 77, 0, 0, 0, 0, 0, 31, 24, 8, 2, 2, 2, 2, + 19, 17, 13, 0, 25, 38, 25, 68, 0, 54, 0, 0, 0, 8, 2, 5, + 5, 55, 39, 77, 0, 0, 0, 0, 0, 31, 24, 8, 2, 2, 2, 2, 8, 5, 2, 8, 2, 2, 0, 32, 19, 17, 6, 18, 25, 7, 34, 67, - 0, 0, 0, 0, 0, 8, 54, 54, 46, 31, 14, 8, 2, 2, 2, 5, - 8, 5, 2, 8, 2, 2, 0, 32, 20, 0, 0, 25, 7, 0, 0, 2, + 0, 0, 0, 0, 0, 8, 55, 55, 46, 31, 14, 8, 2, 2, 2, 5, + 8, 5, 2, 8, 2, 2, 0, 32, 20, 0, 25, 7, 7, 0, 0, 2, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 26, 8, 2, 2, 5, 0, 2, 5, 2, 2, 0, 8, 5, 5, 2, 0, 8, 5, 0, 2, 5, 0, 2, 2, 2, 2, 2, 2, 0, 0, 11, 15, 27, 0, 12, 33, 12, 45, - 0, 0, 0, 0, 34, 0, 0, 0, 0, 24, 14, 55, 2, 2, 2, 5, + 0, 0, 0, 0, 34, 0, 0, 0, 0, 24, 14, 47, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 0, 32, 7, 0, 0, 25, 13, 2, 5, 0, 0, 36, 14, 8, 2, 2, 2, 5, 2, 2, 2, 8, 2, 2, 0, 32, 20, 0, 0, 34, 27, 0, 0, 0, 5, 106, 78, 0, 0, 0, 0, 0, @@ -497,7 +502,7 @@ static const uint8_t hb_use_u8[3663]= 26, 18, 9, 13, 9, 2, 2, 79, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 81, 0, 0, 0, 0, 110, 0, 0, 0, 0, 2, 2, 2, 2, 2, 23, 20, 21, 57, 7, 7, 111, 82, 112, 113, - 83, 2, 2, 2, 2, 2, 48, 0, 44, 2, 2, 2, 11, 6, 2, 2, + 83, 2, 2, 2, 2, 2, 49, 0, 44, 2, 2, 2, 11, 6, 2, 2, 114, 83, 84, 41, 23, 84, 14, 14, 2, 30, 7, 40, 2, 2, 2, 2, 2, 2, 115, 58, 116, 14, 14, 117, 85, 2, 2, 2, 2, 2, 14, 20, 0, 2, 21, 59, 0, 0, 0, 0, 8, 2, 21, 27, 0, 0, 0, 0, @@ -505,19 +510,19 @@ static const uint8_t hb_use_u8[3663]= 2, 5, 21, 0, 0, 0, 0, 0, 0, 2, 2, 4, 20, 7, 21, 6, 12, 12, 12, 12, 24, 60, 118, 119, 120, 121, 122, 0, 0, 0, 0, 123, 0, 5, 0, 0, 8, 0, 124, 4, 125, 39, 39, 126, 86, 2, 2, 2, - 2, 2, 2, 2, 2, 50, 5, 0, 0, 7, 59, 20, 7, 127, 10, 0, + 2, 2, 2, 2, 2, 51, 5, 0, 0, 7, 59, 20, 7, 127, 10, 0, 0, 70, 128, 70, 70, 129, 130, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 14, 0, 0, 0, 2, 2, 2, 30, 71, 20, 0, 0, 2, 2, 131, 132, 42, 133, 10, 81, 134, 15, 20, 7, 21, 18, 59, - 12, 12, 58, 9, 9, 9, 87, 26, 53, 9, 88, 41, 2, 2, 2, 2, + 12, 12, 58, 9, 9, 9, 87, 26, 54, 9, 88, 41, 2, 2, 2, 2, 2, 2, 2, 89, 7, 6, 6, 7, 12, 12, 7, 61, 2, 2, 2, 5, 0, 0, 0, 0, 0, 0, 135, 62, 62, 62, 62, 0, 0, 0, 0, 0, 0, 88, 41, 2, 2, 2, 2, 2, 2, 79, 10, 21, 22, 7, 136, 10, 2, 2, 2, 2, 89, 7, 11, 20, 20, 42, 137, 0, 0, 0, 0, 0, 0, 2, 2, 10, 19, 12, 11, 90, 42, 42, 42, 138, 139, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 8, 2, 9, 26, 16, 16, 16, 9, 16, - 16, 24, 16, 16, 16, 52, 0, 53, 0, 0, 0, 140, 78, 9, 44, 0, - 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 49, 142, + 16, 24, 16, 16, 16, 53, 0, 54, 0, 0, 0, 140, 78, 9, 44, 0, + 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 50, 142, 3, 39, 39, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 72, 0, 0, 91, 0, 0, 0, 0, 0, 0, 76, 91, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, @@ -527,31 +532,31 @@ static const uint8_t hb_use_u8[3663]= 0, 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 144, 11, 11, 11, 11, 11, 11, 11, 92, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 30, 2, 2, 2, 7, 7, 145, 16, - 0, 2, 2, 2, 47, 6, 21, 6, 90, 42, 146, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 48, 6, 21, 6, 90, 42, 146, 0, 0, 0, 0, 0, 0, 9, 147, 2, 2, 2, 2, 2, 2, 2, 148, 11, 7, 6, 12, 149, 150, 93, 0, 0, 0, 0, 0, 0, 0, 2, 2, 30, 8, 2, 2, 2, 2, 2, 2, 2, 2, 36, 7, 21, 71, 58, 151, 94, 152, 0, 0, 0, 0, 2, 153, 2, 2, 2, 2, 154, 0, 8, 2, 39, 44, 0, 85, 24, - 2, 73, 6, 40, 47, 73, 2, 2, 95, 36, 5, 0, 0, 0, 0, 0, + 2, 73, 6, 40, 48, 73, 2, 2, 95, 36, 5, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 155, 18, 22, 0, 0, 156, 96, 0, 0, 0, 0, 2, 23, 20, 11, 59, 27, 157, 0, 0, 0, 0, 0, 0, 0, 0, - 49, 3, 3, 3, 3, 72, 0, 0, 0, 2, 5, 2, 8, 2, 2, 2, - 2, 2, 8, 2, 2, 2, 8, 5, 0, 47, 6, 25, 13, 0, 0, 158, - 159, 2, 2, 8, 2, 8, 2, 2, 2, 2, 2, 2, 0, 51, 35, 0, - 97, 2, 2, 50, 35, 0, 8, 2, 2, 0, 0, 0, 0, 8, 2, 2, - 5, 2, 2, 9, 54, 0, 0, 0, 0, 2, 2, 2, 0, 25, 7, 7, + 50, 3, 3, 3, 3, 72, 0, 0, 0, 2, 5, 2, 8, 2, 2, 2, + 2, 2, 8, 2, 2, 2, 8, 5, 0, 48, 6, 25, 13, 0, 0, 158, + 159, 2, 2, 8, 2, 8, 2, 2, 2, 2, 2, 2, 0, 52, 35, 0, + 97, 2, 2, 51, 35, 0, 8, 2, 2, 0, 0, 0, 0, 8, 2, 2, + 5, 2, 2, 9, 55, 0, 0, 0, 0, 2, 2, 2, 0, 25, 7, 7, 8, 2, 2, 2, 2, 2, 25, 38, 0, 2, 2, 2, 16, 16, 16, 16, - 16, 160, 2, 5, 0, 0, 0, 0, 0, 2, 51, 51, 0, 0, 0, 0, + 16, 160, 2, 5, 0, 0, 0, 0, 0, 2, 52, 52, 0, 0, 0, 0, 0, 5, 2, 2, 5, 2, 2, 2, 2, 8, 2, 5, 0, 8, 2, 0, 0, 161, 162, 163, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 6, 6, 6, 7, 7, 93, 0, 0, 0, 0, 0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 40, 30, 40, 0, 0, 0, 0, 164, 19, 17, 18, 15, 67, 35, 0, 0, 0, 13, 0, 0, 0, 0, 0, - 0, 9, 55, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 6, 7, 165, + 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 6, 7, 165, 7, 18, 166, 98, 2, 2, 2, 2, 2, 0, 0, 23, 167, 0, 0, 0, - 0, 2, 50, 0, 0, 0, 0, 0, 0, 2, 23, 22, 6, 6, 6, 7, + 0, 2, 51, 0, 0, 0, 0, 0, 0, 2, 23, 22, 6, 6, 6, 7, 7, 61, 64, 0, 0, 69, 99, 13, 100, 2, 2, 2, 2, 2, 2, 11, - 17, 7, 7, 168, 46, 0, 0, 0, 55, 47, 0, 0, 0, 0, 0, 0, + 17, 7, 7, 168, 46, 0, 0, 0, 47, 48, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 5, 5, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 36, 19, 17, 18, 7, 169, 13, 0, 0, 9, 9, 8, 2, 2, 2, 5, 8, 5, 2, 8, 2, 2, 56, 32, @@ -559,7 +564,7 @@ static const uint8_t hb_use_u8[3663]= 2, 2, 11, 0, 9, 9, 9, 26, 0, 9, 9, 26, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 0, 5, 2, 2, 2, 8, 20, 21, 6, 6, 13, 33, 29, 29, 22, 170, 14, 171, 101, 35, 0, 0, 0, 0, 0, - 0, 31, 52, 0, 0, 0, 0, 0, 0, 2, 2, 23, 22, 6, 6, 6, + 0, 31, 53, 0, 0, 0, 0, 0, 0, 2, 2, 23, 22, 6, 6, 6, 7, 11, 92, 24, 32, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 172, 173, 0, 0, 0, 0, 0, 0, 0, 19, 17, 6, 6, 57, 71, 22, 100, 9, 102, 5, 0, 0, 0, 0, 0, 22, 6, 6, 0, 12, 12, 9, @@ -573,13 +578,14 @@ static const uint8_t hb_use_u8[3663]= 101, 176, 177, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, 2, 23, 22, 6, 6, 0, 7, 11, 14, 61, 0, 33, 0, 0, 0, 0, 0, 30, 6, 7, 7, 7, 73, 2, 2, 2, 178, 95, 9, 24, 179, 10, - 180, 0, 0, 48, 97, 0, 0, 0, 0, 30, 6, 7, 15, 17, 6, 2, + 180, 0, 0, 49, 97, 0, 0, 0, 0, 30, 6, 7, 15, 17, 6, 2, 2, 2, 2, 64, 64, 64, 43, 43, 43, 43, 43, 43, 24, 181, 0, 8, - 0, 15, 6, 15, 15, 0, 0, 0, 0, 7, 6, 6, 13, 7, 7, 9, - 65, 0, 10, 10, 10, 10, 10, 10, 10, 57, 18, 60, 26, 0, 0, 0, - 0, 2, 2, 2, 5, 2, 8, 2, 2, 30, 7, 7, 13, 0, 38, 7, - 25, 9, 99, 182, 183, 0, 0, 0, 0, 2, 2, 2, 8, 5, 2, 2, - 2, 2, 2, 2, 2, 2, 11, 11, 27, 7, 34, 60, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 0, 0, 15, 6, 15, 15, 0, 0, 0, + 0, 7, 6, 6, 13, 7, 7, 9, 65, 0, 10, 10, 10, 10, 10, 10, + 10, 57, 18, 60, 26, 0, 0, 0, 0, 2, 2, 2, 5, 2, 8, 2, + 2, 30, 7, 7, 13, 0, 38, 7, 25, 9, 99, 182, 183, 0, 0, 0, + 0, 2, 2, 2, 8, 5, 2, 2, 2, 2, 2, 2, 2, 2, 11, 11, + 27, 7, 34, 60, 82, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 2, 184, 57, 27, 0, 0, 0, 0, 9, 185, 2, 2, 2, 2, 2, 2, 2, 2, 11, 7, 6, 13, 0, 12, 15, 96, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 98, 0, 0, 66, 66, 66, 186, 187, 66, 1, @@ -588,10 +594,10 @@ static const uint8_t hb_use_u8[3663]= 7, 7, 7, 7, 7, 7, 191, 192, 193, 9, 9, 9, 26, 0, 0, 0, 0, 14, 41, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 27, 0, 2, 2, 2, 2, 2, 5, 0, 56, 194, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 0, 0, 0, 53, 16, 52, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 0, 0, 0, 54, 16, 53, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 2, 2, 2, 2, 2, 0, 56, 35, 0, 49, 3, 3, 3, 72, 0, - 0, 9, 9, 9, 55, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, + 8, 2, 2, 2, 2, 2, 0, 56, 35, 0, 50, 3, 3, 3, 72, 0, + 0, 9, 9, 9, 47, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 46, 46, 46, 86, 0, 0, O, O, G, G, B, B, WJ, @@ -600,8 +606,8 @@ static const uint8_t hb_use_u8[3663]= VPre, VPst, VAbv, VAbv, VBlw, VPre, VPst, B, VPst,VMAbv,VMPst, O, VAbv,VMAbv, O, VPst, O, N, N, O, VPre, B, VAbv, O,VMAbv,CMBlw, B, VPre, O, O, VPst,CMBlw, O, B,VMAbv, HM, HM, VAbv, O, GB, GB, VAbv, B,VMPst, B, FAbv, FAbv, FBlw, - FBlw, GB, O, VPre, H,CMAbv,CMAbv, B, VBlw, O, GB, O, WJ, B,CMBlw,CMBlw, - CMBlw,VMBlw, O, O,VMBlw,VMAbv,CMAbv,VMAbv, B, O,CMBlw, VBlw, VPre, VPre, VAbv, VBlw, + FBlw, GB, O, VPre, H,CMAbv,CMAbv,VMAbv, B, B, VBlw, O, GB, O, WJ, B, + CMBlw,CMBlw,CMBlw,VMBlw, O, O,VMBlw,VMAbv,CMAbv, O,CMBlw, VBlw, VPre, VPre, VAbv, VBlw, VPst, VPst,VMAbv, H, B,SMAbv,SMAbv, SB, SE, R, R,VMPst, H, J, J, VPst, H, VAbv, H, O,FMBlw, FPst, FPst, VAbv, VPre, WJ, O, VBlw, B, O, SB, O, SE,FMPst,FMPst, O, MBlw, CS,VMPst, B, SUB, O, SUB, SUB, O,VMPst, IS, MBlw, @@ -620,7 +626,7 @@ static const uint8_t hb_use_u8[3663]= SUB, SUB, GB,CMAbv, IS, VBlw, IS, R, MBlw, GB, VAbv, R,VMPst, J, SB, SE, J, HR, G, G, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw, }; -static const uint16_t hb_use_u16[488]= +static const uint16_t hb_use_u16[492]= { 0, 0, 8, 8, 16, 16, 24, 24, 40, 40, 0, 24, 32, 0, 0, 120, 136, 24, 56, 0, 168, 24, 240, 24, 272, 32, 280, 288, 0, 296, 304, 0, @@ -647,12 +653,12 @@ static const uint16_t hb_use_u16[488]= 24,1768,1776,1784,1792, 0, 248, 24, 24,1800,1808, 32, 256,1816,1824,1832, 24,1840,1848, 32,1856,1864, 32, 24, 208, 0, 24,1872,1880, 200,1888, 0, 1896,1904,1912,1920, 24,1928,1936, 32,1944, 24, 24,1952,1960, 0,1968, 24, - 24,1976,1984,1992,2000,2008,2016, 0, 48, 24, 256,2024, 128, 24, 88, 144, - 24,2032, 176,2040,2048, 24, 24,2056,2064, 32,2072, 24,2080,2088, 24,2096, - 2104, 80, 24,2112,2120,2128, 8,2136,2144,2152, 8,2160, 24,2168,2176, 32, - 24,2184,2192, 24,2200, 32,2208,2216, 264, 264,2224,2232,2240, 0, 24, 232, - 0,2248, 104, 88, 96,2256, 0,2264, 88,2272,2280, 0,2288, 0,2296, 32, - 2304, 32,2312, 104,2320, 32, 40, 16, + 24,1976,1984,1992,2000,2008,2016, 0,2024, 0, 48, 24, 256,2032, 128, 24, + 88, 144, 24,2040, 176,2048,2056, 24, 24,2064,2072, 32,2080, 24,2088,2096, + 0,2104, 24,2112,2120, 80, 24,2128,2136,2144, 8,2152,2160,2168, 8,2176, + 24,2184,2192, 32, 24,2200,2208, 24,2216, 32,2224,2232, 264, 264,2240,2248, + 2256, 0, 24, 232, 0,2264, 104, 88, 96,2272, 0,2280, 88,2288,2296, 0, + 2304, 0,2312, 32,2320, 32,2328, 104,2336, 32, 40, 16, }; static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) @@ -662,7 +668,7 @@ static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) static inline uint8_t hb_use_get_category (unsigned u) { /* packtab: [2^4,2^4,2^3,2^1,2^3,2^1] */ - return u<921600u ? (uint8_t)(hb_use_u8[3273u+((hb_use_u8[945u+hb_use_u16[((hb_use_u8[369u+((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((((u)>>1))>>3))>>1))>>3))>>4)))<<4)+((((((((((u)>>1))>>3))>>1))>>3))&15)])<<3)+((((((((u)>>1))>>3))>>1))&7)])<<1)+((((((u)>>1))>>3))&1)]+((((u)>>1))&7)])<<1)+((u)&1)]) : O; + return u<921600u ? (uint8_t)(hb_use_u8[3289u+((hb_use_u8[945u+hb_use_u16[((hb_use_u8[369u+((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((((u)>>1))>>3))>>1))>>3))>>4)))<<4)+((((((((((u)>>1))>>3))>>1))>>3))&15)])<<3)+((((((((u)>>1))>>3))>>1))&7)])<<1)+((((((u)>>1))>>3))&1)]+((((u)>>1))&7)])<<1)+((u)&1)]) : O; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc index f834752c51a..1a5137e28fa 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc @@ -10,8 +10,8 @@ * # Date: 2015-03-12, 21:17:00 GMT [AG] * # Date: 2019-11-08, 23:22:00 GMT [AG] * - * # Scripts-17.0.0.txt - * # Date: 2025-07-24, 13:28:55 GMT + * # Scripts-18.0.0.txt + * # Date: 2026-06-29, 15:25:26 GMT */ #include "hb.hh" diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh index 9993507e360..d5ed30fdde1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper.hh @@ -402,6 +402,11 @@ hb_ot_shaper_categorize (hb_script_t script, case HB_SCRIPT_TAI_YO: case HB_SCRIPT_TOLONG_SIKI: + /* Unicode-18.0 additions */ + case HB_SCRIPT_JURCHEN: + case HB_SCRIPT_PROTO_CUNEIFORM: + case HB_SCRIPT_SEAL: + /* 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. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh index 28bc23d8f01..5b3a55b4b1c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh @@ -63,9 +63,8 @@ static bool axis_value_is_outside_axis_range (hb_tag_t axis_tag, float axis_valu if (!user_axes_location->has (axis_tag)) return false; - double axis_value_double = static_cast(axis_value); Triple axis_range = user_axes_location->get (axis_tag); - return (axis_value_double < axis_range.minimum || axis_value_double > axis_range.maximum); + return (axis_value < axis_range.minimum || axis_value > axis_range.maximum); } struct StatAxisRecord diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh index 30e106554d6..c0131d07150 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh @@ -7,7 +7,7 @@ * on files with these headers: * * - * File-Date: 2025-08-25 + * File-Date: 2026-09-17 */ #ifndef HB_OT_TAG_TABLE_HH @@ -82,7 +82,7 @@ static const LangTag ot_languages2[] = { {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','a',' ',' '), HB_TAG('I','N','A',' ')}, /* Interlingua (IALA) */ {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 */ @@ -516,7 +516,7 @@ static const LangTag ot_languages3[] = { {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','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','e','y',' '), HB_TAG('Q','I','N',' ')}, /* Laoktu Chin -> Chin */ {HB_TAG('c','h','f',' '), HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ {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 */ @@ -834,7 +834,7 @@ static const LangTag ot_languages3[] = { {HB_TAG('m','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ {HB_TAG('m','c','t',' '), HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ {HB_TAG('m','d','f',' '), HB_TAG('M','O','K',' ')}, /* Moksha */ - {HB_TAG('m','d','y',' '), HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ + {HB_TAG('m','d','y',' '), HB_TAG('M','L','E',' ')}, /* Male */ {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','f','b',' '), HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ @@ -854,7 +854,7 @@ static const LangTag ot_languages3[] = { {HB_TAG('m','o','p',' '), HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ {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','h',' '), HB_TAG('Q','I','N',' ')}, /* Mara -> 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 */ @@ -1016,7 +1016,7 @@ static const LangTag ot_languages3[] = { {HB_TAG('s','e','z',' '), HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ {HB_TAG('s','g','c',' '), HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ {HB_TAG('s','g','w',' '), HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ - {HB_TAG('s','h','l',' '), HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ + {HB_TAG('s','h','l',' '), HB_TAG('Q','I','N',' ')}, /* Shendu (retired code) -> Chin */ {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','z',' '), HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ @@ -1040,7 +1040,7 @@ static const LangTag ot_languages3[] = { {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','s',' '), HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ + {HB_TAG('s','r','s',' '), HB_TAG('A','T','H',' ')}, /* Tsuut'ina -> Athapaskan */ {HB_TAG('s','s','h',' '), HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ {HB_TAG('s','t','a',' '), HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ {HB_TAG('s','t','v',' '), HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ @@ -1236,8 +1236,8 @@ static const hb_tag_t ot_languages3_multi_values[] = { HB_TAG('D','C','R',' '), /* Woods Cree */ HB_TAG('T','C','R',' '), /* Woods Cree -> TH-Cree */ HB_TAG('C','R','E',' '), /* Woods Cree -> Cree */ - HB_TAG('S','L','A',' '), /* Slave (Athapascan) [macrolanguage] -> Slavey */ - HB_TAG('A','T','H',' '), /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ + HB_TAG('S','L','A',' '), /* Slavey [macrolanguage] */ + HB_TAG('A','T','H',' '), /* Slavey [macrolanguage] -> Athapaskan */ HB_TAG('D','G','O',' '), /* Dogri (individual language) */ HB_TAG('D','G','R',' '), /* Dogri (macrolanguage) */ HB_TAG('D','I','Q',' '), /* Dimli */ @@ -1490,7 +1490,7 @@ static const LangTagRange ot_languages3_multi[] = { {HB_TAG('c','r','x',' '), 59, 2}, /* Carrier */ {HB_TAG('c','s','w',' '), 61, 3}, /* Swampy Cree -> N-Cree */ {HB_TAG('c','w','d',' '), 64, 3}, /* Woods Cree */ - {HB_TAG('d','e','n',' '), 67, 2}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ + {HB_TAG('d','e','n',' '), 67, 2}, /* Slavey [macrolanguage] */ {HB_TAG('d','g','o',' '), 69, 2}, /* Dogri (individual language) */ {HB_TAG('d','i','q',' '), 71, 2}, /* Dimli */ {HB_TAG('d','r','w',' '), 73, 2}, /* Darwazi (retired code) -> Dari */ @@ -1659,6 +1659,13 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (subtag_matches (p, limit, "-fonupa", 7)) + { + /* Undetermined; Uralic Phonetic Alphabet */ + tags[0] = HB_TAG('U','P','P','H'); /* Uralic Phonetic Alphabet */ + *count = 1; + return true; + } if (subtag_matches (p, limit, "-geok", 5)) { /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ @@ -3110,6 +3117,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("tmh", -1); /* Tamashek [macrolanguage] */ case HB_TAG('T','O','D',' '): /* Todo */ return hb_language_from_string ("xwo", -1); /* Written Oirat */ + case HB_TAG('U','P','P','H'): /* Uralic Phonetic Alphabet */ + return hb_language_from_string ("und-fonupa", -1); /* Undetermined; Uralic Phonetic Alphabet */ case HB_TAG('W','D','T',' '): /* Wendat */ return hb_language_from_string ("wdt", -1); /* Wendat */ case HB_TAG('W','Y','N',' '): /* Wyandot */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc index 79407dd6661..dd9079d0a5b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc @@ -43,8 +43,10 @@ hb_ot_old_tag_from_script (hb_script_t script) case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT; case HB_SCRIPT_MATH: return HB_OT_TAG_MATH_SCRIPT; - /* KATAKANA and HIRAGANA both map to 'kana' */ + /* Hiragana, Katakana, and their collective ISO 15924 script all map to 'kana'. */ case HB_SCRIPT_HIRAGANA: return HB_TAG('k','a','n','a'); + case HB_TAG('H','r','k','t'): + return HB_TAG('k','a','n','a'); /* Spaces at the end are preserved, unlike ISO 15924 */ case HB_SCRIPT_LAO: return HB_TAG('l','a','o',' '); @@ -350,7 +352,7 @@ hb_ot_tags_from_language (const char *lang_str, if (first_len == 2) { - static hb_atomic_t last_tag_idx_2 = 0; /* Poor man's cache. */ + static hb_atomic_t last_tag_idx_2 {0}; /* Poor man's cache. */ unsigned tag_idx = last_tag_idx_2; if (likely (tag_idx < ARRAY_LENGTH (ot_languages2) && @@ -376,7 +378,7 @@ hb_ot_tags_from_language (const char *lang_str, #ifndef HB_NO_LANGUAGE_LONG else if (first_len == 3) { - static hb_atomic_t last_tag_idx_3 = 0; /* Poor man's cache. */ + static hb_atomic_t last_tag_idx_3 {0}; /* Poor man's cache. */ unsigned tag_idx = last_tag_idx_3; if (likely (tag_idx < ARRAY_LENGTH (ot_languages3) && @@ -394,7 +396,7 @@ hb_ot_tags_from_language (const char *lang_str, return; } - static hb_atomic_t last_tag_idx_3_multi = 0; /* Poor man's cache. */ + static hb_atomic_t last_tag_idx_3_multi {0}; /* Poor man's cache. */ unsigned multi_tag_idx = last_tag_idx_3_multi; if (likely (multi_tag_idx < ARRAY_LENGTH (ot_languages3_multi) && @@ -666,10 +668,10 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, primary_script_tag, nullptr, nullptr); *language = hb_ot_tag_to_language (language_tag); - if (script_count == 0 || primary_script_tag[0] != script_tag) + const char *lang_str = *language ? hb_language_to_string (*language) : nullptr; + if (lang_str && (script_count == 0 || primary_script_tag[0] != script_tag)) { unsigned char *buf; - const char *lang_str = hb_language_to_string (*language); size_t len = strlen (lang_str); buf = (unsigned char *) hb_malloc (len + 16); if (unlikely (!buf)) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh index 8a9307d6933..054d22aaab0 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh @@ -29,6 +29,7 @@ #include "hb-open-type.hh" #include "hb-ot-var-common.hh" +#include "hb-ot-var-fvar-table.hh" /* @@ -103,6 +104,11 @@ struct AxisValueMap from_coord = renormalizeValue ((double) from_coord, unmapped_range, triple_distances); to_coord = renormalizeValue ((double) to_coord, axis_range, triple_distances); + /* Malformed input can renormalize outside [-1,1], which would + * overflow F2DOT14. */ + from_coord = hb_clamp (from_coord, -1.f, 1.f); + to_coord = hb_clamp (to_coord, -1.f, 1.f); + coords[0].set_float (from_coord); coords[1].set_float (to_coord); } @@ -220,10 +226,10 @@ struct SegmentMaps : Array16Of if (value < map[i].fromCoord) break; - if (i == 0) + if (i == start) { // Value before all segments; Shift. - return value - map[0].fromCoord + map[0].toCoord; + return value - map[start].fromCoord + map[start].toCoord; } if (i == end) { @@ -251,10 +257,11 @@ struct SegmentMaps : Array16Of float unmapped_middle = unmap_float (axis_range.middle); float unmapped_max = unmap_float (axis_range.maximum); - return Triple{(double) unmapped_min, (double) unmapped_middle, (double) unmapped_max}; + return Triple{unmapped_min, unmapped_middle, unmapped_max}; } - bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const + bool subset (hb_subset_context_t *c, hb_tag_t axis_tag, + hb_vector_t *out_mappings = nullptr) const { TRACE_SUBSET (this); @@ -262,9 +269,14 @@ struct SegmentMaps : Array16Of * We should instead keep the design coords in the shape plan and use * those. unmap_axis_range needs to be killed. */ - /* avar mapped normalized axis range*/ + /* avar mapped normalized axis range. Under avar2, axes_location holds + * only the self-contained pins for the other tables; avar itself uses + * the intermediate-space ranges of all restricted axes. */ + const auto &axes_location = c->plan->has_avar2 + ? c->plan->old_intermediates + : c->plan->axes_location; Triple *axis_range; - if (!c->plan->axes_location.has (axis_tag, &axis_range)) + if (!axes_location.has (axis_tag, &axis_range)) return c->serializer->embed (*this); TripleDistances *axis_triple_distances; @@ -304,18 +316,185 @@ struct SegmentMaps : Array16Of value_mappings.qsort (); + if (unlikely (value_mappings.in_error ())) + return_trace (false); + for (const auto& _ : value_mappings) { if (!_.serialize (c->serializer)) return_trace (false); } - return_trace (c->serializer->check_assign (out->len, value_mappings.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + if (!c->serializer->check_assign (out->len, value_mappings.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + /* Hand the instantiated mappings to the caller; avar2 offset + * compensation needs them to locate the new mapping's kinks. */ + if (out_mappings) + *out_mappings = std::move (value_mappings); + return_trace (true); } public: DEFINE_SIZE_ARRAY (2, *this); }; +/* One knot of the avar2 offset-compensation function + * offset(z) = inv_renorm(z) - z, in new intermediate space. */ +struct avar2_offset_knot_t +{ + double z; + double offset; +}; + +/* Insert a knot keeping the vector sorted by z; first insertion wins on + * duplicate z. */ +static inline void +_avar2_add_knot (hb_vector_t &knots, double z, double offset) +{ + unsigned i = 0; + while (i < knots.length && knots.arrayZ[i].z < z) i++; + if (i < knots.length && knots.arrayZ[i].z == z) return; + knots.push (avar2_offset_knot_t {0.0, 0.0}); + if (unlikely (knots.in_error ())) return; + for (unsigned j = knots.length - 1; j > i; j--) + knots.arrayZ[j] = knots.arrayZ[j - 1]; + knots.arrayZ[i] = avar2_offset_knot_t {z, offset}; +} + +/* Piecewise-linear evaluation over the sorted knots. Inputs are always + * within [-1, +1] and anchor knots at -1/0/+1 always exist. */ +static inline double +_avar2_eval_offset (const hb_vector_t &knots, double z) +{ + unsigned len = knots.length; + for (unsigned i = 0; i < len; i++) + { + if (z == knots.arrayZ[i].z) return knots.arrayZ[i].offset; + if (z < knots.arrayZ[i].z) + { + if (!i) return knots.arrayZ[0].offset; + const auto &before = knots.arrayZ[i - 1]; + const auto &after = knots.arrayZ[i]; + double denom = after.z - before.z; + return before.offset + (after.offset - before.offset) * (z - before.z) / denom; + } + } + return len ? knots.arrayZ[len - 1].offset : 0.0; +} + +/* Piecewise-linear evaluation over instantiated avar v1 mappings, as + * produced by SegmentMaps::subset (sorted, with -1/0/+1 anchors). + * Matches SegmentMaps::map_float for such well-formed mappings. */ +static inline double +_avar2_map_new_mapping (const hb_vector_t &mappings, double v, + unsigned from_offset = 0, unsigned to_offset = 1) +{ + unsigned len = mappings.length; + if (!len) return v; + + for (unsigned i = 0; i < len; i++) + { + double from = (double) mappings.arrayZ[i].coords[from_offset].to_float (); + if (v == from) + return (double) mappings.arrayZ[i].coords[to_offset].to_float (); + if (v < from) + { + double to = (double) mappings.arrayZ[i].coords[to_offset].to_float (); + if (!i) return v - from + to; + double prev_from = (double) mappings.arrayZ[i - 1].coords[from_offset].to_float (); + double prev_to = (double) mappings.arrayZ[i - 1].coords[to_offset].to_float (); + double denom = from - prev_from; + if (denom == 0.0) return prev_to; + return prev_to + (to - prev_to) * (v - prev_from) / denom; + } + } + return v - (double) mappings.arrayZ[len - 1].coords[from_offset].to_float () + + (double) mappings.arrayZ[len - 1].coords[to_offset].to_float (); +} + +/* Inverse of _avar2_map_new_mapping: pull an output coordinate back to a + * preimage input coordinate. For a non-strictly-monotone mapping this picks + * one preimage, which is fine for its only use (augmenting the error + * estimator's sample set). */ +static inline double +_avar2_unmap_new_mapping (const hb_vector_t &mappings, double v) +{ + return _avar2_map_new_mapping (mappings, v, 1, 0); +} + +/* Plain (non-avar) fvar-style normalization of a user value against a + * user-space (min, default, max) triple. */ +static inline double +_avar2_normalize_value (double v, double min, double def, double max) +{ + v = hb_clamp (v, min, max); + if (v == def) return 0.0; + if (v < def) return def == min ? 0.0 : (v - def) / (def - min); + return def == max ? 0.0 : (v - def) / (max - def); +} + +/* Inverse of the above: map a normalized value back to user space. */ +static inline double +_avar2_denormalize_value (double v, double min, double def, double max) +{ + if (v == 0.0) return def; + return v < 0.0 ? def + v * (def - min) : def + v * (max - def); +} + +/* Estimate the residual offset-compensation error for one restricted axis: + * the max |old-avar1-final - (new-avar1 + offset)| over the retained user + * range, in F2Dot14 units. offset(z) is the piecewise-linear function + * through the knots. The residual is dominated by F2Dot14 requantization of + * a steep retained avar v1 segment (e.g. a moved default compressing part + * of the axis into a narrow z band); offset compensation cannot remove it. + * Used only to pick the better knot set and decide whether to warn. + * + * Sampled on a uniform grid augmented with the user-space preimages of + * every kink of the residual (old/new avar v1 breakpoints and offset(z) + * knots), so the worst kink cannot fall between uniform samples. The + * pointwise F2Dot14 rounding makes this an estimate rather than an exact + * bound, but every piecewise-linear extremum is visited. */ +static inline unsigned +_avar2_estimate_offset_error (const SegmentMaps &old_seg, + const hb_vector_t &new_mapping, + double old_min, double old_def, double old_max, + double new_min, double new_def, double new_max, + const hb_vector_t &knots) +{ + constexpr unsigned samples = 257; + hb_vector_t us; + if (unlikely (!us.alloc (samples + old_seg.as_array ().length + + new_mapping.length + knots.length))) + return UINT_MAX; /* estimator only; fail towards "worse" */ + for (unsigned i = 0; i < samples; i++) + us.push (new_min + (new_max - new_min) * i / (samples - 1)); + for (const auto &_ : old_seg.as_array ()) + us.push (_avar2_denormalize_value ((double) _.coords[0].to_float (), + old_min, old_def, old_max)); + for (const auto &_ : new_mapping) + us.push (_avar2_denormalize_value ((double) _.coords[0].to_float (), + new_min, new_def, new_max)); + for (const auto &knot : knots) + us.push (_avar2_denormalize_value ( + _avar2_unmap_new_mapping (new_mapping, knot.z), + new_min, new_def, new_max)); + if (unlikely (us.in_error ())) return UINT_MAX; + + unsigned max_err = 0; + for (double u : us) + { + if (u < new_min || u > new_max) continue; + double n_old = _avar2_normalize_value (u, old_min, old_def, old_max); + double old_final = (double) old_seg.map_float ((float) n_old); + double n_new = _avar2_normalize_value (u, new_min, new_def, new_max); + double z = _avar2_map_new_mapping (new_mapping, n_new); + double new_final = z + _avar2_eval_offset (knots, z); + int err = abs ((int) roundf ((float) (old_final * 16384.0)) - + (int) roundf ((float) (new_final * 16384.0))); + if ((unsigned) err > max_err) max_err = err; + } + return max_err; +} + struct avar { static constexpr hb_tag_t tableTag = HB_OT_TAG_avar; @@ -400,7 +579,12 @@ struct avar int v = coords[i]; uint32_t varidx = varidx_map.map (i); float delta = var_store.get_delta (varidx, coords_2_14.arrayZ, coords_2_14.length, var_store_cache); - v += roundf (delta * 4); // 2.14 -> 16.16 + /* Apply the delta unclamped and clamp only the result to [-1, +1], + * matching fontTools. Since inputs and results are in [-1, +1], + * deltas beyond ±2 are equivalent to ±2; clamp to that range only + * to keep the float->int conversion safe. */ + float d = hb_clamp (delta * 4, -(float) (1<<17), +(float) (1<<17)); // 2.14 -> 16.16 + v += (int) roundf (d); v = hb_clamp (v, -(1<<16), +(1<<16)); out.push (v); } @@ -411,25 +595,53 @@ struct avar #endif } + /* An avar version 2 font is never downgraded to v1: even with a NULL + * varStore offset (legal; maps like plain v1) the avar2 subsetting path + * applies, with "no variation" semantics for rows that don't resolve — + * offset compensation then creates delta rows on demand. */ bool has_v2_data () const { return version.major > 1; } + /* Resolve the avar2 VarStore and VarIdxMap, for the subset planner. + * Either pointer may be to the Null object (nullable offsets). */ + bool get_v2_store_and_map (const ItemVariationStore **store, + const DeltaSetIndexMap **varidx_map) const + { +#ifndef HB_NO_AVAR2 + if (version.major < 2) return false; + const SegmentMaps *map = &firstAxisSegmentMaps; + for (unsigned i = 0; i < axisCount; i++) + map = &StructAfter (*map); + const auto &v2 = * (const avarV2Tail *) map; + *store = &(this+v2.varStore); + *varidx_map = &(this+v2.varIdxMap); + return true; +#else + return false; +#endif + } + // axis normalization is done in 2.14 here // TODO: deprecate this API once fonttools is updated to use 16.16 normalization - bool map_coords_2_14 (float *coords, unsigned int coords_length) const + bool map_coords_2_14 (float *coords, unsigned int coords_length, + bool v1_only = false) const { hb_vector_t coords_2_14; - if (!coords_2_14.resize (coords_length)) return false; + if (!v1_only && !coords_2_14.resize (coords_length)) return false; unsigned int count = hb_min (coords_length, axisCount); const SegmentMaps *map = &firstAxisSegmentMaps; for (unsigned int i = 0; i < count; i++) { int v = roundf (map->map_float (coords[i]) * 16384.f); - coords_2_14[i] = v; + if (!v1_only) + coords_2_14[i] = v; coords[i] = v / 16384.f; map = &StructAfter (*map); } + if (v1_only) + return true; + #ifndef HB_NO_AVAR2 if (version.major < 2) return true; @@ -449,8 +661,10 @@ struct avar int v = coords_2_14[i]; uint32_t varidx = varidx_map.map (i); float delta = var_store.get_delta (varidx, coords_2_14.arrayZ, coords_2_14.length, var_store_cache); - v += roundf (delta); - v = hb_clamp (v, -(1<<16), +(1<<16)); + /* As above: apply the delta unclamped (±2 covers every useful case) + * and clamp the result to [-1, +1], matching fontTools. */ + v += (int) hb_clamp (roundf (delta), -(float) (1<<15), +(float) (1<<15)); + v = hb_clamp (v, -(1<<14), +(1<<14)); coords[i] = v / 16384.f; } @@ -471,11 +685,17 @@ struct avar avar *out = c->serializer->allocate_min (); if (unlikely (!out)) return_trace (false); - out->version.major = 1; + out->version.major = c->plan->has_avar2 ? 2 : 1; out->version.minor = 0; if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); + /* For avar2, keep the instantiated v1 mappings around; offset + * compensation needs them to locate the new mappings' kinks. */ + hb_vector_t> new_mappings; + if (c->plan->has_avar2 && !new_mappings.resize (axisCount)) + return_trace (false); + const hb_map_t& axes_index_map = c->plan->axes_index_map; const SegmentMaps *map = &firstAxisSegmentMaps; unsigned count = axisCount; @@ -486,14 +706,495 @@ struct avar hb_tag_t *axis_tag; if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) return_trace (false); - if (!map->subset (c, *axis_tag)) - return_trace (false); + + Triple *axis_location; + if (c->plan->has_avar2 && + c->plan->user_axes_location.has (*axis_tag, &axis_location) && + axis_location->is_point ()) + { + /* Pinned axis in avar2 mode: serialize identity segment map + * {-1->-1, 0->0, 1->1}. The axis is kept in fvar as hidden, + * so avar needs a segment map entry for it. */ + auto *identity_map = c->serializer->start_embed (); + if (unlikely (!c->serializer->extend_min (identity_map))) + return_trace (false); + AxisValueMap m; + m.set_mapping (-1.f, -1.f); + if (!m.serialize (c->serializer)) return_trace (false); + m.set_mapping (0.f, 0.f); + if (!m.serialize (c->serializer)) return_trace (false); + m.set_mapping (1.f, 1.f); + if (!m.serialize (c->serializer)) return_trace (false); + if (!c->serializer->check_assign (identity_map->len, 3u, + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + else + { + /* Restricted or free axis: use standard SegmentMaps::subset() */ + if (!map->subset (c, *axis_tag, + c->plan->has_avar2 ? &new_mappings[i] : nullptr)) + return_trace (false); + } } map = &StructAfter (*map); } + + if (c->plan->has_avar2) + return_trace (_subset_avar2 (c, new_mappings)); + return_trace (true); } + private: + struct avar2_index_map_plan_t + { + bool init (const hb_vector_t &varidx_mapping, + const hb_map_t &axes_index_map, + unsigned axis_count) + { + if (!output_map.alloc (axes_index_map.get_population ())) + return false; + + bool has_no_variation = false; + unsigned max_outer = 0, max_inner = 0; + for (unsigned i = 0; i < axis_count; i++) + { + if (!axes_index_map.has (i)) continue; + uint32_t varidx = varidx_mapping[i]; + output_map.push (varidx); + if (varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + { + has_no_variation = true; + continue; + } + max_outer = hb_max (max_outer, varidx >> 16); + max_inner = hb_max (max_inner, varidx & 0xFFFF); + } + if (output_map.in_error () || + output_map.length != axes_index_map.get_population ()) + return false; + + if (has_no_variation) + { + width = 4; + inner_bit_count = 16; + } + else + { + inner_bit_count = hb_max (1u, hb_bit_storage (max_inner)); + unsigned outer_bit_count = hb_max (1u, hb_bit_storage (max_outer)); + width = hb_clamp ((inner_bit_count + outer_bit_count + 7) / 8, 1u, 4u); + if (inner_bit_count + outer_bit_count > width * 8) + inner_bit_count = width * 8 - outer_bit_count; + } + return true; + } + + unsigned get_inner_bit_count () const { return inner_bit_count; } + unsigned get_width () const { return width; } + hb_array_t get_output_map () const { return output_map.as_array (); } + + unsigned inner_bit_count = 1; + unsigned width = 1; + hb_vector_t output_map; + }; + + bool _subset_avar2 (hb_subset_context_t *c, + const hb_vector_t> &new_mappings) const + { +#if defined (HB_NO_VAR) || defined (HB_NO_AVAR2) + /* Not reachable: the plan never sets has_avar2 in these configurations. */ + return false; +#else + + /* 1. Locate original avar2 data, keeping per-axis old segment maps */ + hb_vector_t old_seg_maps; + if (!old_seg_maps.alloc (axisCount)) return false; + const SegmentMaps *map = &firstAxisSegmentMaps; + for (unsigned i = 0; i < axisCount; i++) + { + old_seg_maps.push (map); + map = &StructAfter (*map); + } + + const auto &v2 = * (const avarV2Tail *) map; + const auto &varidx_map = this+v2.varIdxMap; + const auto &var_store = this+v2.varStore; + + auto fvar_axes = c->plan->source->table.fvar->get_axes (); + + /* 2. Compute default deltas by evaluating VarStore at old defaults */ + hb_vector_t default_coords; + if (!default_coords.resize (axisCount)) return false; + for (unsigned i = 0; i < axisCount; i++) + { + hb_tag_t *axis_tag; + if (c->plan->axes_old_index_tag_map.has (i, &axis_tag) && + c->plan->old_intermediates.has (*axis_tag)) + { + float d_i = (float) c->plan->old_intermediates.get (*axis_tag).middle; + default_coords[i] = roundf (d_i * 16384.f); + } + else + default_coords[i] = 0; + } + + auto *store_cache = var_store.create_cache (); + hb_vector_t default_deltas; + if (!default_deltas.resize (axisCount)) { + ItemVariationStore::destroy_cache (store_cache); + return false; + } + for (unsigned i = 0; i < axisCount; i++) + { + uint32_t varidx = varidx_map.map (i); + if (varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + default_deltas[i] = 0.f; + else + default_deltas[i] = var_store.get_delta (varidx, default_coords.arrayZ, + default_coords.length, store_cache); + } + ItemVariationStore::destroy_cache (store_cache); + + /* 3. Rebase IVS regions */ + item_variations_t item_vars; + if (!item_vars.create_from_item_varstore (var_store, c->plan->axes_old_index_tag_map)) + return false; + if (!item_vars.instantiate_tuple_vars (c->plan->old_intermediates, + c->plan->axes_triple_distances, + false)) + return false; + + /* 4. Self-contained pinned axes (whose final coordinate is constant over + * the retained box) were detected at plan time + * (_compute_avar2_reachable_ranges) and removed from axes_index_map. + * They are skipped below; their constant contribution is baked into the + * other variation tables by standard instancing at the plan's + * axes_location/normalized_coords. */ + + /* 5. Build per-axis varIdx mapping (may create new VarDatas). + * Entries (or the implicit identity mapping) that don't resolve to a + * real store row behave as "no variation" at runtime; normalize them to + * NO_VARIATIONS_INDEX so the offset loop creates fresh rows instead of + * writing into nonexistent ones. This also covers a NULL VarStore + * (never downgraded: rows are created on demand). */ + hb_vector_t new_varidx_mapping; + if (!new_varidx_mapping.resize (axisCount)) return false; + for (unsigned i = 0; i < axisCount; i++) + { + uint32_t varidx = varidx_map.map (i); + if (varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX && + !var_store.has_delta_set (varidx)) + varidx = HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + new_varidx_mapping[i] = varidx; + } + + /* 5.5. Privatize shared varIdx delta rows before adding offset + * compensation. avar2's VarIdxMap may map several fvar axes to the SAME + * IVS delta row. Writing one axis's offset-compensation deltas into a + * shared row would corrupt every other axis that reads that row. So give + * each offset-receiving axis whose row is shared its own private copy of + * the row (identical contents, preserving the rebased deltas), then + * repoint its varIdx. Sharers keep the clean row; the varstore + * optimization pass re-merges identical rows afterwards. */ + hb_hashmap_t varidx_ref_count; + for (unsigned i = 0; i < axisCount; i++) + { + if (!c->plan->axes_index_map.has (i)) continue; /* self-contained: dropped */ + uint32_t varidx = new_varidx_mapping[i]; + if (varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) continue; + unsigned *count; + if (varidx_ref_count.has (varidx, &count)) + (*count)++; + else if (!varidx_ref_count.set (varidx, 1)) + return false; + } + for (unsigned i = 0; i < axisCount; i++) + { + hb_tag_t *axis_tag_ptr; + if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag_ptr)) + return false; + /* Only axes that will receive offset compensation (restricted or + * pinned) can contaminate a shared row. */ + if (!c->plan->axes_index_map.has (i) || + !c->plan->user_axes_location.has (*axis_tag_ptr)) + continue; + uint32_t varidx = new_varidx_mapping[i]; + if (varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + continue; /* gets a fresh, private VarData in the offset loop below */ + unsigned *count; + if (!varidx_ref_count.has (varidx, &count) || *count <= 1) + continue; /* sole owner: safe to write offsets in place */ + unsigned outer = varidx >> 16; + unsigned new_inner = item_vars.duplicate_row (outer, varidx & 0xFFFF); + if (unlikely (new_inner == (unsigned) -1)) return false; + new_varidx_mapping[i] = (outer << 16) | new_inner; + (*count)--; + } + + /* 6. Add offset compensation tuples. + * Track processed (outer,inner) pairs to avoid adding duplicate biases + * when multiple axes share the same varIdx. */ + hb_set_t processed_varidxes; + for (unsigned i = 0; i < axisCount; i++) + { + hb_tag_t *axis_tag_ptr; + if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag_ptr)) + return false; + hb_tag_t axis_tag = *axis_tag_ptr; + + /* Self-contained pinned axes are removed from fvar/avar; their + * contribution is baked into the variation tables instead. */ + if (!c->plan->axes_index_map.has (i)) + continue; + + Triple *new_user; + if (c->plan->user_axes_location.has (axis_tag, &new_user)) + { + /* This axis is being restricted or pinned */ + Triple *old_int; + if (!c->plan->old_intermediates.has (axis_tag, &old_int)) + return false; + + float a_i = (float) old_int->minimum; + float d_i = (float) old_int->middle; + float b_i = (float) old_int->maximum; + + int d_int = roundf (d_i * 16384.f); + + bool is_pinned = new_user->is_point (); + + uint32_t varidx = new_varidx_mapping[i]; + unsigned outer, inner, item_count; + + if (varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + { + /* No existing avar2 mapping. Create new VarData. */ + outer = item_vars.add_vardata (1); + inner = 0; + item_count = 1; + new_varidx_mapping[i] = (outer << 16) | inner; + default_deltas[i] = 0.f; /* no prior default delta */ + } + else + { + outer = varidx >> 16; + inner = varidx & 0xFFFF; + item_count = item_vars.get_item_count (outer); + } + + /* Empty-region bias: d_int + round(defaultDelta) */ + int bias = d_int + (int) roundf (default_deltas[i]); + if (bias != 0) + { + hb_hashmap_t empty_region; + item_vars.add_tuple (outer, std::move (empty_region), + inner, bias, item_count); + } + + if (!is_pinned) + { + /* Offset compensation encodes, as avar2 deltas on this axis, the + * piecewise-linear function offset(z) = inv_renorm(z) - z, where + * inv_renorm maps a new intermediate coordinate z back to the old + * intermediate coordinate. It is known at these knots in the new + * intermediate space: + * z = -1 -> a_i + 1 (new minimum) + * z = 0 -> d_i (new default) + * z = +1 -> b_i - 1 (new maximum) + */ + hb_vector_t knots; + _avar2_add_knot (knots, -1.0, (double) a_i + 1.0); + _avar2_add_knot (knots, 0.0, (double) d_i); + _avar2_add_knot (knots, 1.0, (double) b_i - 1.0); + + const hb_vector_t &new_mapping = new_mappings[i]; + + float min_f = 0.f, def_f = 0.f, max_f = 0.f; + if (likely (i < fvar_axes.length)) + fvar_axes[i].get_coordinates (min_f, def_f, max_f); + double old_min = (double) min_f; + double old_def = (double) def_f; + double old_max = (double) max_f; + + /* If the axis default MOVED, inv_renorm also kinks where the OLD + * default lands in the new space (the old intermediate coordinate + * crosses 0 there), at + * z = z_old -> -z_old + * Omitting that knot (as a plain two-tent encoding would) makes + * interior coordinates wrong. */ + double z_old = _avar2_normalize_value ((double) old_def, + (double) new_user->minimum, + (double) new_user->middle, + (double) new_user->maximum); + z_old = _avar2_map_new_mapping (new_mapping, z_old); + z_old = (double) roundf ((float) (z_old * 16384.0)) / 16384.0; + if (-1.0 < z_old && z_old < 1.0) + _avar2_add_knot (knots, z_old, -z_old); + + /* Interior avar v1 breakpoints inside the retained range each put + * a kink in offset(z). Sampling only {-1, 0, +1, z_old} would + * linearly interpolate across those kinks. The instantiated + * mapping keeps exactly the in-range old breakpoints, and the new + * mapping kinks at each one's output coordinate; add that z with + * its old intermediate value so offset(z) is reproduced at every + * kink. */ + hb_vector_t with_breakpoints (knots); + for (const auto &m : new_mapping) + { + double from = (double) m.coords[0].to_float (); + if (from == -1.0 || from == 0.0 || from == 1.0) + continue; /* anchors already seeded */ + double z = (double) m.coords[1].to_float (); + if (!(-1.0 < z && z < 1.0)) + continue; + double user = _avar2_denormalize_value (from, + (double) new_user->minimum, + (double) new_user->middle, + (double) new_user->maximum); + double n_old = _avar2_normalize_value (user, old_min, old_def, old_max); + double x_old = (double) old_seg_maps[i]->map_float ((float) n_old); + x_old = (double) roundf ((float) (x_old * 16384.0)) / 16384.0; + _avar2_add_knot (with_breakpoints, z, x_old - z); + } + + if (unlikely (knots.in_error () || with_breakpoints.in_error ())) + return false; + + /* Extra tents cost F2Dot14 rounding, so for a steep segment they + * can add more quantization noise than the structural error they + * remove. Keep the interior breakpoints only when they do not + * increase the estimated residual; this makes the collection a + * strict (never-worse) improvement over the {-1, 0, +1, z_old} + * anchors. Warn when even the better choice is not bit-exact (a + * steep retained segment that cannot be reproduced in F2Dot14). */ + unsigned err = _avar2_estimate_offset_error (*old_seg_maps[i], new_mapping, + old_min, old_def, old_max, + (double) new_user->minimum, + (double) new_user->middle, + (double) new_user->maximum, + knots); + if (with_breakpoints.length != knots.length) + { + unsigned err_with = _avar2_estimate_offset_error (*old_seg_maps[i], new_mapping, + old_min, old_def, old_max, + (double) new_user->minimum, + (double) new_user->middle, + (double) new_user->maximum, + with_breakpoints); + if (err_with <= err) + { + knots = std::move (with_breakpoints); + err = err_with; + } + } + if (err > 8) + DEBUG_MSG (SUBSET, nullptr, + "avar2 offset compensation is approximate for axis %c%c%c%c: " + "max residual %u F2Dot14 units", + HB_UNTAG (axis_tag), err); + + /* Synthesize tents. Adjacent tents evaluate to zero at each + * other's peaks, so each knot's delta is offset(z) - offset(0); + * the base value offset(0) = d_i is carried by the empty-region + * bias above. This reduces to the classic pair of tents + * (-1,-1,0) / (0,+1,+1) when the default is unchanged and there + * are no interior knots. */ + for (unsigned k = 0; k < knots.length; k++) + { + double z = knots.arrayZ[k].z; + if (z == 0.0) continue; + int delta = (int) roundf ((float) ((knots.arrayZ[k].offset - (double) d_i) * 16384.0)); + if (!delta) continue; + double lower, upper; + if (z > 0.0) + { + lower = knots.arrayZ[k - 1].z; + upper = k + 1 < knots.length ? knots.arrayZ[k + 1].z : z; + } + else + { + upper = knots.arrayZ[k + 1].z; + lower = k > 0 ? knots.arrayZ[k - 1].z : z; + } + hb_hashmap_t region; + if (unlikely (!region.set (axis_tag, Triple (lower, z, upper)))) + return false; + item_vars.add_tuple (outer, std::move (region), + inner, delta, item_count); + } + } + } + else + { + /* Free or private axis — not being restricted. + * If it has a non-zero default delta, add it back as a bias. + * Skip if this (outer,inner) was already processed (shared varIdx). */ + uint32_t varidx = new_varidx_mapping[i]; + if (varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + continue; + + if (processed_varidxes.has (varidx)) + continue; + processed_varidxes.add (varidx); + + unsigned outer = varidx >> 16; + unsigned inner = varidx & 0xFFFF; + int dd = (int) roundf (default_deltas[i]); + if (dd != 0) + { + unsigned item_count = item_vars.get_item_count (outer); + hb_hashmap_t empty_region; + item_vars.add_tuple (outer, std::move (empty_region), + inner, dd, item_count); + } + } + } + + /* 7. Finalize: build region list + convert to varstore */ + if (!item_vars.build_region_list ()) return false; + if (!item_vars.as_item_varstore (true /* optimize */, + false /* use_no_variation_idx */)) + return false; + + /* 8. Apply varidx_map optimization remapping */ + const auto &opt_varidx_map = item_vars.get_varidx_map (); + for (unsigned i = 0; i < axisCount; i++) + { + uint32_t varidx = new_varidx_mapping[i]; + if (varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + continue; + uint32_t *new_idx; + if (opt_varidx_map.has (varidx, &new_idx)) + new_varidx_mapping[i] = *new_idx; + } + + /* 9. Serialize avarV2Tail. Entries cover the retained axes only; + * self-contained pinned axes are removed from fvar. */ + avar2_index_map_plan_t index_map_plan; + if (!index_map_plan.init (new_varidx_mapping, + c->plan->axes_index_map, + axisCount)) + return false; + + auto *tail = c->serializer->allocate_size (avarV2Tail::static_size); + if (unlikely (!tail)) return false; + if (!tail->varIdxMap.serialize_serialize (c->serializer, index_map_plan)) + return false; + if (!tail->varStore.serialize_serialize (c->serializer, + item_vars.has_long_word (), + c->plan->axis_tags, + item_vars.get_region_list (), + item_vars.get_vardata_encodings ())) + return false; + + return true; +#endif + } + + public: + protected: FixedVersion<>version; /* Version of the avar table * initially set to 0x00010000u */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh index 26c4d6cfec9..70aba42a295 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh @@ -47,7 +47,7 @@ struct TupleVariationHeader if (unlikely ((ti & (TupleIndex::EmbeddedPeakTuple | TupleIndex::IntermediateRegion)))) { unsigned count = ((ti & TupleIndex::EmbeddedPeakTuple) != 0) + ((ti & TupleIndex::IntermediateRegion) != 0) * 2; - return min_size + count * axis_count_times_2; + return hb_unsigned_mul_add_saturate (count, axis_count_times_2, min_size); } return min_size; } @@ -103,18 +103,31 @@ struct TupleVariationHeader start = hb_min (peak, 0.f); end = hb_max (peak, 0.f); } - axis_tuples.set (*axis_tag, Triple ((double) start, (double) peak, (double) end)); + axis_tuples.set (*axis_tag, Triple (start, peak, end)); } return true; } HB_ALWAYS_INLINE - double calculate_scalar (hb_array_t coords, unsigned int coord_count, + float calculate_scalar (hb_array_t coords, unsigned int coord_count, const hb_array_t shared_tuples, - hb_scalar_cache_t *shared_tuple_scalar_cache = nullptr) const + hb_scalar_cache_t *shared_tuple_scalar_cache = (hb_scalar_cache_t *) &Null(hb_scalar_cache_t)) const { unsigned tuple_index = tupleIndex; + unsigned int index = tuple_index & TupleIndex::TupleIndexMask; + + /* The gvar shared-tuple cache is clamped to the 12-bit tuple-index range. + * Only PrivatePointNumbers may accompany a cached shared-tuple index; any + * other flag sets a bit at or above 0x1000, making this range test fail. + */ + bool plain_shared_tuple = (tuple_index & ~TupleIndex::PrivatePointNumbers) < shared_tuple_scalar_cache->length; + if (likely (plain_shared_tuple)) + { + float scalar; + if (likely (shared_tuple_scalar_cache->get (index, &scalar))) + return scalar; + } const F2DOT14 *peak_tuple; @@ -127,20 +140,19 @@ struct TupleVariationHeader } else { - unsigned int index = tuple_index & TupleIndex::TupleIndexMask; // Inlined for performance - float scalar; - if (shared_tuple_scalar_cache && + if (!plain_shared_tuple && + shared_tuple_scalar_cache->length && shared_tuple_scalar_cache->get (index, &scalar)) { if (has_interm && (scalar != 0 && scalar != 1.f)) shared_tuple_scalar_cache = nullptr; else - return (double) scalar; + return scalar; } if (unlikely ((index + 1) * coord_count > shared_tuples.length)) - return 0.0; + return 0.f; peak_tuple = shared_tuples.arrayZ + (coord_count * index); } @@ -154,7 +166,7 @@ struct TupleVariationHeader end_tuple = get_end_tuple (coord_count); } - double scalar = 1.0; + float scalar = 1.f; #ifndef HB_OPTIMIZE_SIZE #if HB_FAST_NUM_ACCESS bool skip = coord_count >= 16; @@ -180,7 +192,7 @@ struct TupleVariationHeader if (!peak) continue; int v = coords[i]; - if (!v) { scalar = 0.0; break; } + if (!v) { scalar = 0.f; break; } if (v == peak) continue; if (has_interm) @@ -190,18 +202,18 @@ struct TupleVariationHeader int end = end_tuple[i].to_int (); if (unlikely (start > peak || peak > end || (start < 0 && end > 0 && peak))) continue; - if (v < start || v > end) { scalar = 0.0; break; } + if (v < start || v > end) { scalar = 0.f; break; } if (v < peak) - { if (peak != start) scalar *= (double) (v - start) / (peak - start); } + { if (peak != start) scalar *= (float) (v - start) / (peak - start); } else - { if (peak != end) scalar *= (double) (end - v) / (end - peak); } + { if (peak != end) scalar *= (float) (end - v) / (end - peak); } } - else if (v < hb_min (0, peak) || v > hb_max (0, peak)) { scalar = 0.0; break; } + else if (v < hb_min (0, peak) || v > hb_max (0, peak)) { scalar = 0.f; break; } else - scalar *= (double) v / peak; + scalar *= (float) v / peak; } if (shared_tuple_scalar_cache) - shared_tuple_scalar_cache->set (get_index (), scalar); + shared_tuple_scalar_cache->set (index, scalar); return scalar; } @@ -209,6 +221,7 @@ struct TupleVariationHeader bool has_intermediate () const { return tupleIndex & TupleIndex::IntermediateRegion; } bool has_private_points () const { return tupleIndex & TupleIndex::PrivatePointNumbers; } unsigned get_index () const { return tupleIndex & TupleIndex::TupleIndexMask; } + static constexpr unsigned max_shared_tuple_count = 0x1000u; protected: struct TupleIndex : HBUINT16 @@ -399,21 +412,21 @@ struct tuple_delta_t return; } - if ((tent->minimum < 0.0 && tent->maximum > 0.0) || + if ((tent->minimum < 0.f && tent->maximum > 0.f) || !(tent->minimum <= tent->middle && tent->middle <= tent->maximum)) return; - if (tent->middle == 0.0) + if (tent->middle == 0.f) { out.push (std::move (*this)); return; } if (!axis_limit.is_point () && - !(-1.0 <= axis_limit.minimum && + !(-1.f <= axis_limit.minimum && axis_limit.minimum <= axis_limit.middle && axis_limit.middle <= axis_limit.maximum && - axis_limit.maximum <= +1.0)) + axis_limit.maximum <= +1.f)) return; rebase_tent_result_t &solutions = scratch.first; @@ -604,7 +617,7 @@ struct tuple_delta_t for (unsigned i = 0; i < point_indices.length; i++) { if (!point_indices[i]) continue; - rounded_deltas.arrayZ[j++] = (int) roundf (x_deltas.arrayZ[i]); + rounded_deltas.arrayZ[j++] = hb_clamp_to (roundf ((double) x_deltas.arrayZ[i])); } rounded_deltas.resize (j); @@ -629,7 +642,7 @@ struct tuple_delta_t for (unsigned idx = 0; idx < point_indices.length; idx++) { if (!point_indices[idx]) continue; - int rounded_delta = (int) roundf (y_deltas.arrayZ[idx]); + int rounded_delta = hb_clamp_to (roundf ((double) y_deltas.arrayZ[idx])); if (j >= rounded_deltas.length) return false; @@ -710,14 +723,14 @@ struct tuple_delta_t { i = next_index (i, start_point, end_point); if (i == next) break; - deltas_x.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].x, - (double) orig_points.arrayZ[prev].x, - (double) orig_points.arrayZ[next].x, - (double) deltas_x.arrayZ[prev], (double) deltas_x.arrayZ[next]); - deltas_y.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].y, - (double) orig_points.arrayZ[prev].y, - (double) orig_points.arrayZ[next].y, - (double) deltas_y.arrayZ[prev], (double) deltas_y.arrayZ[next]); + deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, + orig_points.arrayZ[prev].x, + orig_points.arrayZ[next].x, + deltas_x.arrayZ[prev], deltas_x.arrayZ[next]); + deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, + orig_points.arrayZ[prev].y, + orig_points.arrayZ[next].y, + deltas_y.arrayZ[prev], deltas_y.arrayZ[next]); inferred_idxes.add (i); if (--unref_count == 0) goto no_more_gaps; } @@ -734,8 +747,8 @@ struct tuple_delta_t { if (!inferred_idxes.has (i)) { - deltas_x.arrayZ[i] = 0.0; - deltas_y.arrayZ[i] = 0.0; + deltas_x.arrayZ[i] = 0.f; + deltas_y.arrayZ[i] = 0.f; } indices[i] = true; } @@ -763,8 +776,8 @@ struct tuple_delta_t for (unsigned i = 0; i < count; i++) { - rounded_x_deltas.arrayZ[i] = (int) roundf (deltas_x.arrayZ[i]); - rounded_y_deltas.arrayZ[i] = (int) roundf (deltas_y.arrayZ[i]); + rounded_x_deltas.arrayZ[i] = hb_clamp_to (roundf ((double) deltas_x.arrayZ[i])); + rounded_y_deltas.arrayZ[i] = hb_clamp_to (roundf ((double) deltas_y.arrayZ[i])); } if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, scratch.iup, tolerance)) @@ -906,16 +919,16 @@ struct tuple_delta_t return compiled_points.resize_dirty (pos); } - static double infer_delta (double target_val, double prev_val, double next_val, double prev_delta, double next_delta) + static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta) { if (prev_val == next_val) - return (prev_delta == next_delta) ? prev_delta : 0.0; + return (prev_delta == next_delta) ? prev_delta : 0.f; else if (target_val <= hb_min (prev_val, next_val)) return (prev_val < next_val) ? prev_delta : next_delta; else if (target_val >= hb_max (prev_val, next_val)) return (prev_val > next_val) ? prev_delta : next_delta; - double r = (target_val - prev_val) / (next_val - prev_val); + float r = (target_val - prev_val) / (next_val - prev_val); return prev_delta + r * (next_delta - prev_delta); } @@ -936,12 +949,14 @@ struct TupleVariationData size_t get_size (unsigned axis_count_times_2) const { - unsigned total_size = min_size; + size_t total_size = min_size; unsigned count = tupleVarCount.get_count (); const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header()); for (unsigned i = 0; i < count; i++) { - total_size += tuple_var_header->get_size (axis_count_times_2) + tuple_var_header->get_data_size (); + total_size = hb_unsigned_add_saturate (total_size, + tuple_var_header->get_size (axis_count_times_2), + (size_t) tuple_var_header->get_data_size ()); tuple_var_header = &tuple_var_header->get_next (axis_count_times_2); } @@ -1144,7 +1159,7 @@ struct TupleVariationData Triple *axis_limit; if (!normalized_axes_location.has (axis_tag, &axis_limit)) return false; - TripleDistances axis_triple_distances{1.0, 1.0}; + TripleDistances axis_triple_distances{1.f, 1.f}; if (axes_triple_distances.has (axis_tag)) axis_triple_distances = axes_triple_distances.get (axis_tag); @@ -1290,6 +1305,22 @@ struct TupleVariationData } public: + /* avar2 partial-instancing culling: drop tuples whose region a partial + * instance can never reach (hb_subset_plan_t::avar2_reachable_ranges). */ + void cull_unreachable (const hb_hashmap_t &reachable_ranges) + { + unsigned j = 0; + for (unsigned i = 0; i < tuple_vars.length; i++) + { + if (_hb_avar2_region_is_dead (tuple_vars.arrayZ[i].axis_tuples, reachable_ranges)) + continue; + if (i != j) + tuple_vars.arrayZ[j] = std::move (tuple_vars.arrayZ[i]); + j++; + } + tuple_vars.shrink (j); + } + bool instantiate (const hb_hashmap_t& normalized_axes_location, const hb_hashmap_t& axes_triple_distances, optimize_scratch_t &scratch, @@ -1511,6 +1542,105 @@ struct TupleVariationData bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); } + /* avar2 partial-instancing culling: rewrite this tuple variation data, + * dropping TupleVariations whose region a partial instance can never + * reach (see hb_subset_plan_t::avar2_reachable_ranges). On success with + * *changed set, out contains the rewritten data — possibly empty, when + * every tuple died. Keeps the original data (*changed stays false) when + * nothing is culled or the data is malformed. Returns false only on + * allocation failure. */ + bool cull_tuple_variations (hb_bytes_t var_data_bytes, + unsigned axis_count, + hb_array_t shared_tuples, + const hb_map_t *axes_old_index_tag_map, + const hb_hashmap_t &reachable_ranges, + hb_vector_t &out /* OUT */, + bool *changed /* OUT */) const + { + *changed = false; + + hb_vector_t shared_indices; + tuple_iterator_t iterator; + if (!get_tuple_iterator (var_data_bytes, axis_count, this, + shared_indices, &iterator)) + return true; /* no tuples or malformed: keep original */ + + const char *bytes_start = var_data_bytes.arrayZ; + const char *bytes_end = bytes_start + var_data_bytes.length; + const char *serialized_base = (const char *) &(this+data); + const char *shared_points_end = (const char *) iterator.get_serialized_data (); + if (unlikely (serialized_base < bytes_start || serialized_base > bytes_end || + shared_points_end < serialized_base || shared_points_end > bytes_end)) + return true; + + struct kept_tuple_t + { + const char *header; + unsigned header_size; + const char *data; + unsigned data_size; + }; + hb_vector_t kept; + unsigned total = 0; + unsigned kept_headers_size = 0, kept_data_size = 0; + do + { + const TupleVariationHeader *header = iterator.current_tuple; + unsigned header_size = header->get_size (axis_count * 2); + unsigned data_size = header->get_data_size (); + const char *tuple_data = (const char *) iterator.get_serialized_data (); + if (unlikely (tuple_data < serialized_base || + data_size > (unsigned) (bytes_end - tuple_data))) + return true; /* malformed: keep original */ + + hb_hashmap_t axis_tuples; + if (!header->unpack_axis_tuples (axis_count, shared_tuples, + axes_old_index_tag_map, axis_tuples)) + return true; + + total++; + if (!_hb_avar2_region_is_dead (axis_tuples, reachable_ranges)) + { + kept.push (kept_tuple_t {(const char *) header, header_size, + tuple_data, data_size}); + kept_headers_size += header_size; + kept_data_size += data_size; + } + } while (iterator.move_to_next ()); + + if (unlikely (kept.in_error ())) return false; + if (kept.length == total) return true; /* nothing to cull */ + + *changed = true; + if (!kept.length) return true; /* everything culled: no variation data */ + + unsigned shared_points_size = shared_points_end - serialized_base; + unsigned data_offset = min_size + kept_headers_size; + unsigned new_size = data_offset + shared_points_size + kept_data_size; + if (unlikely (!out.resize (new_size))) + return false; + + TupleVariationData *out_data = (TupleVariationData *) out.arrayZ; + out_data->tupleVarCount = (uint16_t) (kept.length | + (has_shared_point_numbers () ? 0x8000u : 0u)); + out_data->data = data_offset; + + char *p = out.arrayZ + min_size; + for (const auto &t : kept) + { + hb_memcpy (p, t.header, t.header_size); + p += t.header_size; + } + hb_memcpy (p, serialized_base, shared_points_size); + p += shared_points_size; + for (const auto &t : kept) + { + hb_memcpy (p, t.data, t.data_size); + p += t.data_size; + } + return true; + } + static bool decompile_points (const HBUINT8 *&p /* IN/OUT */, hb_vector_t &points /* OUT */, const HBUINT8 *end) @@ -1721,15 +1851,145 @@ struct item_variations_t const hb_subset_plan_t *plan, bool optimize=true, bool use_no_variation_idx=true, - const hb_array_t inner_maps = hb_array_t ()) + const hb_array_t inner_maps = hb_array_t (), + bool layout_conditions = false) { if (!create_from_item_varstore (varStore, plan->axes_old_index_tag_map, inner_maps)) return false; - if (!instantiate_tuple_vars (plan->axes_location, plan->axes_triple_distances)) + /* avar2 partial instancing: cull unreachable regions. */ + if (plan->has_avar2 && plan->avar2_reachable_ranges.get_population ()) + for (tuple_variations_t& tuple_vars : vars) + tuple_vars.cull_unreachable (plan->avar2_reachable_ranges); + if (!instantiate_tuple_vars (plan->axes_location, plan->axes_triple_distances, + !layout_conditions)) + return false; + if (layout_conditions && + (!instantiate_condition_values (plan, varStore) || !build_region_list ())) return false; return as_item_varstore (optimize, use_no_variation_idx); } + bool instantiate_condition_values (const hb_subset_plan_t *plan, + const ItemVariationStore &varStore) + { + // GDEF serialization can be retried; always start from the source values. + auto &condition_map = plan->layout_condition_idx_value_map; + condition_map.clear (); + if (!plan->layout_condition_values) return true; + using condition_value_t = hb_pair_t>; + hb_vector_t conditions; + for (auto condition : plan->layout_condition_values.iter ()) + conditions.push (condition); + if (unlikely (conditions.in_error ())) return false; + // Row order must not depend on the addresses of the source conditions. + conditions.qsort ([] (const condition_value_t &a, const condition_value_t &b) { + if (a.second.first != b.second.first) + return a.second.first < b.second.first ? -1 : 1; + return a.second.second < b.second.second ? -1 : + a.second.second > b.second.second ? 1 : 0; + }); + hb_map_t outer_map; + unsigned new_outer = 0; + for (unsigned i = 0; i < plan->gdef_varstore_inner_maps.length; i++) + if (plan->gdef_varstore_inner_maps[i].get_population ()) + if (!outer_map.set (i, new_outer++)) return false; + for (auto condition : conditions) + { + unsigned old_idx = condition.second.first; + double value = condition.second.second + + varStore.get_delta (old_idx, plan->normalized_coords.as_array ()); + unsigned old_outer = old_idx >> 16; + if (!outer_map.has (old_outer)) + continue; + unsigned outer = outer_map.get (old_outer); + unsigned inner = plan->gdef_varstore_inner_maps[old_outer].get (old_idx & 0xFFFF); + unsigned idx = (outer << 16) | inner; + if (outer >= vars.length || inner >= var_data_num_rows[outer]) + continue; + + double maximum = fabs ((double) value); + bool variable = false; + for (const tuple_delta_t &tuple : vars[outer].tuple_vars) + { + if (unlikely (inner >= tuple.deltas_x.length)) return false; + float delta = tuple.deltas_x[inner]; + variable |= delta != 0.f; + maximum = hb_max (maximum, fabs ((double) delta)); + } + if (!variable) + { + if (!condition_map.set (condition.first, + hb_pair (unsigned (VarIdx::NO_VARIATION), int (value > 0)))) + return false; + continue; + } + + double scale = 1.; + while (maximum * scale > INT_MAX) + scale *= .5; + // Positive rescaling preserves the Boolean boundary. Prefer exact + // integers, otherwise use the available 32-bit precision. + while (maximum * scale * 2 <= INT_MAX) + { + bool integral = (double) value * scale == round ((double) value * scale); + for (const tuple_delta_t &tuple : vars[outer].tuple_vars) + integral &= (double) tuple.deltas_x[inner] * scale == + round ((double) tuple.deltas_x[inner] * scale); + if (integral) break; + scale *= 2; + } + int default_value = (int) round ((double) value * scale); + if (scale != 1. || default_value < -32768 || default_value > 32767) + { + // A condition may share its row with a positioning value. Give it a + // private copy before integer rounding discards fractional deltas. + tuple_variations_t private_row; + for (const tuple_delta_t &tuple : vars[outer].tuple_vars) + { + if (!tuple.deltas_x[inner]) continue; + tuple_delta_t copy; + copy.axis_tuples = tuple.axis_tuples; + copy.indices.push (true); + copy.deltas_x.push ((float) round ((double) tuple.deltas_x[inner] * scale)); + if (unlikely (copy.axis_tuples.in_error () || copy.indices.in_error () || + copy.deltas_x.in_error ())) return false; + private_row.tuple_vars.push (std::move (copy)); + } + if (unlikely (vars.length >= 0xFFFFu)) return false; + if (unlikely (private_row.tuple_vars.in_error ())) return false; + idx = vars.length << 16; + vars.push (std::move (private_row)); + var_data_num_rows.push (1); + if (unlikely (vars.in_error () || var_data_num_rows.in_error ())) return false; + if (default_value < -32768 || default_value > 32767) + { + // Keep the Boolean result in the int16 default: no deltas apply + // at the default instance. A neutral region carries the excess. + // Each part is exact in float; integer row assembly adds them + // before serialization, preserving all 32 bits of the bias. + int bias = default_value - hb_clamp (default_value, -32768, 32767); + default_value -= bias; + int high = bias / 65536 * 65536; + int parts[] = {high, bias - high}; + for (int part : parts) + { + if (!part) continue; + unsigned count = vars[idx >> 16].tuple_vars.length; + add_tuple (idx >> 16, hb_hashmap_t (), + 0, part, 1); + const auto &tuples = vars[idx >> 16].tuple_vars; + if (unlikely (tuples.in_error () || tuples.length != count + 1 || + tuples.tail ().indices.in_error () || + tuples.tail ().deltas_x.in_error ())) return false; + } + } + } + if (!condition_map.set (condition.first, hb_pair (idx, default_value))) + return false; + } + return !condition_map.in_error (); + } + /* keep below APIs public only for unit test: test-item-varstore */ bool create_from_item_varstore (const ItemVariationStore& varStore, const hb_map_t& axes_old_index_tag_map, @@ -1764,15 +2024,75 @@ struct item_variations_t } bool instantiate_tuple_vars (const hb_hashmap_t& normalized_axes_location, - const hb_hashmap_t& axes_triple_distances) + const hb_hashmap_t& axes_triple_distances, + bool build_regions = true) { optimize_scratch_t scratch; for (tuple_variations_t& tuple_vars : vars) if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances, scratch)) return false; - if (!build_region_list ()) return false; - return true; + return !build_regions || build_region_list (); + } + + /* Add a new VarData subtable. Returns outer index. */ + unsigned add_vardata (unsigned item_count) + { + vars.push (tuple_variations_t ()); + var_data_num_rows.push (item_count); + return vars.length - 1; + } + + /* Get item count for a VarData subtable. */ + unsigned get_item_count (unsigned outer) const + { return outer < var_data_num_rows.length ? var_data_num_rows[outer] : 0; } + + /* Duplicate the delta row at position inner within VarData subtable outer, + * appending the copy as a new item. Used to give an axis a private copy of + * a delta row that avar2's VarIdxMap shares between several axes, before + * per-axis offset-compensation deltas are written into it. Returns the new + * inner index, or (unsigned) -1 on failure. */ + unsigned duplicate_row (unsigned outer, unsigned inner) + { + if (unlikely (outer >= vars.length || + inner >= var_data_num_rows[outer] || + var_data_num_rows[outer] >= 0xFFFFu)) + return (unsigned) -1; + for (tuple_delta_t& tuple : vars[outer].tuple_vars) + { + if (unlikely (inner >= tuple.deltas_x.length || + inner >= tuple.indices.length)) + return (unsigned) -1; + tuple.indices.push (tuple.indices.arrayZ[inner]); + tuple.deltas_x.push (tuple.deltas_x.arrayZ[inner]); + if (inner < tuple.deltas_y.length) + tuple.deltas_y.push (tuple.deltas_y.arrayZ[inner]); + if (unlikely (tuple.indices.in_error () || + tuple.deltas_x.in_error () || + tuple.deltas_y.in_error ())) + return (unsigned) -1; + } + return var_data_num_rows[outer]++; + } + + /* Add a tuple with a single non-zero delta at position inner. + * axis_tuples defines the region (empty map = constant/bias tuple). */ + void add_tuple (unsigned outer, + hb_hashmap_t&& axis_tuples, + unsigned inner, int delta, unsigned item_count) + { + if (outer >= vars.length) return; + tuple_delta_t tuple; + tuple.axis_tuples = std::move (axis_tuples); + if (!tuple.indices.resize (item_count) || + !tuple.deltas_x.resize (item_count)) return; + for (unsigned i = 0; i < item_count; i++) + { + tuple.indices.arrayZ[i] = true; + tuple.deltas_x.arrayZ[i] = 0.f; + } + tuple.deltas_x[inner] = (float) delta; + vars[outer].tuple_vars.push (std::move (tuple)); } bool build_region_list () @@ -1793,7 +2113,7 @@ struct item_variations_t bool all_zeros = true; for (float d : tuple.deltas_x) { - int delta = (int) roundf (d); + int delta = hb_clamp_to (roundf ((double) d)); if (delta != 0) { all_zeros = false; @@ -1921,9 +2241,12 @@ struct item_variations_t for (unsigned i = 0; i < num_rows; i++) { - int rounded_delta = roundf (tuple.deltas_x[i]); - delta_rows[start_row + i][*col_idx] += rounded_delta; - has_long |= rounded_delta < -65536 || rounded_delta > 65535; + int rounded_delta = hb_clamp_to (roundf ((double) tuple.deltas_x[i])); + int &delta = delta_rows[start_row + i][*col_idx]; + int64_t sum = (int64_t) delta + rounded_delta; + if (unlikely (sum < INT_MIN || sum > INT_MAX)) return false; + delta = (int) sum; + has_long |= delta < -32768 || delta > 32767; } } @@ -1949,16 +2272,28 @@ struct item_variations_t if (!front_mapping.set ((major<<16) + minor, &row)) return false; - if (delta_rows_map.has (&row)) - continue; + /* Duplicate rows may only be dropped when optimizing: without a + * varidx_map the caller relies on original VariationIndex values + * staying valid (e.g. HVAR/VVAR with an implicit advance mapping). */ + if (optimize) + { + if (delta_rows_map.has (&row)) + continue; - delta_rows_map.set (&row, 1); + delta_rows_map.set (&row, 1); + } major_rows.push (&row); } + if (unlikely (major_rows.in_error () || delta_rows_map.in_error ())) + return false; if (major_rows) - encoding_objs.push (delta_row_encoding_t (std::move (major_rows), num_cols)); + { + auto *encoding = encoding_objs.push (std::move (major_rows), num_cols); + if (unlikely (encoding_objs.in_error () || encoding->in_error ())) + return false; + } start_row += num_rows; } @@ -2011,8 +2346,10 @@ struct item_variations_t removed_todo_idxes.add (i); removed_todo_idxes.add (j); + if (unlikely (removed_todo_idxes.in_error ())) return false; encoding.merge (other_encoding); + if (unlikely (encoding.in_error ())) return false; for (unsigned idx = 0; idx < encoding_objs.length; idx++) { @@ -2030,8 +2367,10 @@ struct item_variations_t for (const auto& row : obj.items) encoding.add_row (row); + if (unlikely (encoding.in_error ())) return false; removed_todo_idxes.add (idx); + if (unlikely (removed_todo_idxes.in_error ())) return false; continue; } @@ -2041,7 +2380,8 @@ struct item_variations_t } auto moved_encoding = std::move (encoding); - encoding_objs.push (moved_encoding); + encoding_objs.push (std::move (moved_encoding)); + if (unlikely (encoding_objs.in_error ())) return false; } int num_final_encodings = (int) encoding_objs.length - (int) removed_todo_idxes.get_population (); @@ -2069,7 +2409,7 @@ struct item_variations_t { delta_row_encoding_t& encoding = encodings[i]; /* just sanity check, this shouldn't happen */ - if (encoding.is_empty ()) + if (encoding.is_empty () || encoding.in_error ()) return false; unsigned num_rows = encoding.items.length; @@ -2095,7 +2435,9 @@ struct item_variations_t return false; } - split_encodings.push (delta_row_encoding_t (std::move (rows), num_cols)); + auto *split = split_encodings.push (std::move (rows), num_cols); + if (unlikely (split_encodings.in_error () || split->in_error ())) + return false; } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh index d8f497d5346..d33326d73cf 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-cvar-table.hh @@ -79,12 +79,12 @@ struct cvar unsigned num_cvt_item, const TupleVariationData<> *tuple_var_data, const void *base, + unsigned var_data_length, hb_vector_t& cvt_deltas /* OUT */) { if (!coords) return true; hb_vector_t shared_indices; TupleVariationData<>::tuple_iterator_t iterator; - unsigned var_data_length = tuple_var_data->get_size (axis_count * 2); hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast (tuple_var_data), var_data_length); if (!TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, base, shared_indices, &iterator)) @@ -191,8 +191,17 @@ struct cvar return false; } + /* Bound the tuple variation data by the actual cvar table length rather + * than trusting tupleVarCount to walk the headers; an inflated count would + * otherwise run get_size() off the end of the table. */ + hb_blob_t *cvar_blob = hb_face_reference_table (plan->source, cvar::tableTag); + unsigned cvar_length = hb_blob_get_length (cvar_blob); + hb_blob_destroy (cvar_blob); + unsigned var_data_offset = (unsigned) ((const char *) tuple_var_data - (const char *) base); + unsigned var_data_length = var_data_offset < cvar_length ? cvar_length - var_data_offset : 0; + if (!calculate_cvt_deltas (plan->normalized_coords.length, plan->normalized_coords.as_array (), - num_cvt_item, tuple_var_data, base, cvt_deltas)) + num_cvt_item, tuple_var_data, base, var_data_length, cvt_deltas)) { hb_blob_destroy (cvt_prime_blob); return false; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh index 74d392de9b7..cd7f7fdb84f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh @@ -43,7 +43,7 @@ static bool axis_coord_pinned_or_within_axis_range (const hb_array_t(coords[axis_index].to_float ()); + float axis_coord = coords[axis_index].to_float (); if (axis_limit.is_point ()) { if (axis_limit.minimum != axis_coord) @@ -107,8 +107,9 @@ struct InstanceRecord if (!axis_coord_pinned_or_within_axis_range (coords, i, *axis_limit)) return_trace (false); - //skip pinned axis - if (axis_limit->is_point ()) + //skip axes dropped from fvar (pinned; or self-contained under avar2, + //where other pinned axes stay in fvar as hidden) + if (axis_limit->is_point () && !c->plan->axes_index_map.has (i)) continue; } @@ -179,6 +180,8 @@ struct AxisRecord hb_tag_t get_axis_tag () const { return axisTag; } + bool is_hidden () const { return flags & AXIS_FLAG_HIDDEN; } + float normalize_axis_value (float v) const { float min_value, default_value, max_value; @@ -219,10 +222,7 @@ struct AxisRecord { float min, default_, max; get_coordinates (min, default_, max); - return TripleDistances ( - static_cast(min), - static_cast(default_), - static_cast(max)); + return TripleDistances (min, default_, max); } bool subset (hb_subset_context_t *c) const @@ -235,9 +235,21 @@ struct AxisRecord Triple *axis_limit; if (user_axes_location.has (axisTag, &axis_limit)) { - out->minValue.set_float (axis_limit->minimum); - out->defaultValue.set_float (axis_limit->middle); - out->maxValue.set_float (axis_limit->maximum); + if (c->plan->has_avar2 && axis_limit->is_point ()) + { + /* Pinned axis in avar2 mode: keep in fvar as hidden with + * min=default=max=pinned_value. */ + out->minValue.set_float (axis_limit->middle); + out->defaultValue.set_float (axis_limit->middle); + out->maxValue.set_float (axis_limit->middle); + out->flags = out->flags | (HBUINT16) AXIS_FLAG_HIDDEN; + } + else + { + out->minValue.set_float (axis_limit->minimum); + out->defaultValue.set_float (axis_limit->middle); + out->maxValue.set_float (axis_limit->maximum); + } } return_trace (true); } @@ -285,7 +297,7 @@ struct fvar unsigned int *axes_count /* IN/OUT */, hb_ot_var_axis_t *axes_array /* OUT */) const { - if (axes_count) + if (axes_count && axes_array) { hb_array_t arr = get_axes ().sub_array (start_offset, axes_count); for (unsigned i = 0; i < arr.length; ++i) @@ -299,7 +311,7 @@ struct fvar unsigned int *axes_count /* IN/OUT */, hb_ot_var_axis_info_t *axes_array /* OUT */) const { - if (axes_count) + if (axes_count && axes_array) { hb_array_t arr = get_axes ().sub_array (start_offset, axes_count); for (unsigned i = 0; i < arr.length; ++i) @@ -360,7 +372,7 @@ struct fvar return 0; } - if (coords_length && *coords_length) + if (coords_length && *coords_length && coords) { hb_array_t instanceCoords = instance->get_coordinates (axisCount) .sub_array (0, coords_length); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh index ec24253b429..512a0176c71 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh @@ -30,6 +30,7 @@ #include "hb-decycler.hh" #include "hb-open-type.hh" +#include "hb-ot-dual.hh" #include "hb-ot-var-common.hh" /* @@ -150,6 +151,18 @@ struct glyph_variations_t contour_point_vector_t *all_points; if (!plan->new_gid_contour_points_map.has (new_gid, &all_points)) return false; + /* IUP adds rebased constant deltas to the contour coordinates. Keep + * the plan's original points intact across serialization retries. */ + contour_point_vector_t points; + if (iup_optimize) + { + points = *all_points; + if (unlikely (points.in_error ())) return false; + all_points = &points; + } + /* avar2 partial instancing: cull unreachable tuples. */ + if (plan->has_avar2 && plan->avar2_reachable_ranges.get_population ()) + glyph_variations[i].cull_unreachable (plan->avar2_reachable_ranges); if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, scratch, &pool, all_points, iup_optimize)) return false; } @@ -301,12 +314,14 @@ struct glyph_variations_t } }; -template +template struct gvar_GVAR { - static constexpr hb_tag_t tableTag = TableTag; + using GlyphCountType = typename Types::HBUINT; - using GlyphVariationData = TupleVariationData; + using GlyphVariationData = TupleVariationData; + static constexpr unsigned glyph_count_max () + { return (1u << (8 * GlyphCountType::static_size)) - 1; } bool has_data () const { return version.to_int () != 0; } @@ -327,7 +342,7 @@ struct gvar_GVAR { return sanitize_shallow (c); } bool decompile_glyph_variations (hb_subset_context_t *c, - glyph_variations_t& glyph_vars /* OUT */) const + glyph_variations_t& glyph_vars /* OUT */) const { hb_hashmap_t new_gid_var_data_map; auto it = hb_iter (c->plan->new_to_old_gid_list); @@ -354,7 +369,7 @@ struct gvar_GVAR template bool serialize (hb_serialize_context_t *c, - const glyph_variations_t& glyph_vars, + const glyph_variations_t& glyph_vars, Iterator it, unsigned axis_count, unsigned num_glyphs, @@ -367,7 +382,7 @@ struct gvar_GVAR out->version.major = 1; out->version.minor = 0; out->axisCount = axis_count; - out->glyphCountX = hb_min (0xFFFFu, num_glyphs); + out->glyphCountX = hb_min (glyph_count_max (), num_glyphs); unsigned glyph_var_data_size = glyph_vars.compiled_byte_size (); /* According to the spec: If the short format (Offset16) is used for offsets, @@ -376,7 +391,8 @@ struct gvar_GVAR bool long_offset = glyph_var_data_size > 0x1FFFEu || force_long_offsets; out->flags = long_offset ? 1 : 0; - HBUINT8 *glyph_var_data_offsets = c->allocate_size ((long_offset ? 4 : 2) * (num_glyphs + 1), false); + unsigned glyph_var_data_offsets_size = (long_offset ? 4 : 2) * (num_glyphs + 1); + HBUINT8 *glyph_var_data_offsets = c->allocate_size (glyph_var_data_offsets_size, false); if (!glyph_var_data_offsets) return_trace (false); /* shared tuples */ @@ -384,7 +400,7 @@ struct gvar_GVAR out->sharedTupleCount = shared_tuple_count; if (!shared_tuple_count) - out->sharedTuples = 0; + out->sharedTuples = (char *) glyph_var_data_offsets + glyph_var_data_offsets_size - (char *) out; else { hb_array_t shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c); @@ -403,7 +419,7 @@ struct gvar_GVAR bool instantiate (hb_subset_context_t *c) const { TRACE_SUBSET (this); - glyph_variations_t glyph_vars; + glyph_variations_t glyph_vars; if (!decompile_glyph_variations (c, glyph_vars)) return_trace (false); @@ -442,24 +458,57 @@ struct gvar_GVAR out->sharedTupleCount = sharedTupleCount; unsigned int num_glyphs = c->plan->num_output_glyphs (); - out->glyphCountX = hb_min (0xFFFFu, num_glyphs); + out->glyphCountX = hb_min (glyph_count_max (), num_glyphs); + + /* avar2 partial instancing: cull tuple variations whose region falls + * outside the reachable old-space final-coord ranges. Rewritten glyph + * data is cached per new gid; untouched glyphs are copied verbatim. */ + hb_vector_t> culled_vars; + hb_set_t culled_gids; + if (c->plan->has_avar2 && c->plan->avar2_reachable_ranges.get_population ()) + { + hb_array_t shared_tuples_array = + (this+sharedTuples).as_array ((unsigned) sharedTupleCount * (unsigned) axisCount); + if (unlikely (!culled_vars.resize (num_glyphs))) return_trace (false); + auto cull_it = hb_iter (c->plan->new_to_old_gid_list); + if (cull_it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + cull_it++; + for (auto &_ : cull_it) + { + hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob, glyph_count, _.second); + if (var_data_bytes.length < GlyphVariationData::min_size) continue; + bool changed = false; + if (unlikely (!var_data_bytes.as () + ->cull_tuple_variations (var_data_bytes, axisCount, + shared_tuples_array, + &c->plan->axes_old_index_tag_map, + c->plan->avar2_reachable_ranges, + culled_vars[_.first], &changed))) + return_trace (false); + if (changed) culled_gids.add (_.first); + } + if (unlikely (culled_gids.in_error ())) return_trace (false); + } auto it = hb_iter (c->plan->new_to_old_gid_list); if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) it++; - size_t subset_data_size = 0; + unsigned subset_data_size = 0; unsigned padding_size = 0; for (auto &_ : it) { hb_codepoint_t old_gid = _.second; - unsigned glyph_data_size = get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length; + unsigned glyph_data_size = culled_gids.has (_.first) + ? culled_vars[_.first].length + : get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length; if (glyph_data_size % 2) { glyph_data_size++; padding_size++; } - subset_data_size += glyph_data_size; + if (unlikely (hb_unsigned_add_overflows (subset_data_size, glyph_data_size, &subset_data_size))) + return_trace (false); } /* According to the spec: If the short format (Offset16) is used for offsets, @@ -471,12 +520,13 @@ struct gvar_GVAR #endif out->flags = long_offset ? 1 : 0; - HBUINT8 *subset_offsets = c->serializer->allocate_size ((long_offset ? 4 : 2) * (num_glyphs + 1), false); + unsigned subset_offsets_size = (long_offset ? 4 : 2) * (num_glyphs + 1); + HBUINT8 *subset_offsets = c->serializer->allocate_size (subset_offsets_size, false); if (!subset_offsets) return_trace (false); /* shared tuples */ if (!sharedTupleCount || !sharedTuples) - out->sharedTuples = 0; + out->sharedTuples = (char *) subset_offsets + subset_offsets_size - (char *) out; else { unsigned int shared_tuple_size = F2DOT14::static_size * axisCount * sharedTupleCount; @@ -523,9 +573,12 @@ struct gvar_GVAR for (; last < gid; last++) ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2; - hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob, - glyph_count, - old_gid); + hb_bytes_t var_data_bytes = culled_gids.has (gid) + ? hb_bytes_t (culled_vars[gid].arrayZ, + culled_vars[gid].length) + : get_glyph_var_data_bytes (c->source_blob, + glyph_count, + old_gid); hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length); unsigned glyph_data_size = var_data_bytes.length; @@ -588,7 +641,8 @@ struct gvar_GVAR hb_scalar_cache_t *create_cache () const { - return hb_scalar_cache_t::create (table->sharedTupleCount); + return hb_scalar_cache_t::create (hb_min ((unsigned) table->sharedTupleCount, + +TupleVariationHeader::max_shared_tuple_count)); } static void destroy_cache (hb_scalar_cache_t *cache) @@ -600,7 +654,7 @@ struct gvar_GVAR accelerator_t (hb_face_t *face) { - table = hb_sanitize_context_t ().reference_table (face); + table = hb_sanitize_context_t ().reference_table (face, T::tableTag); /* If sanitize failed, set glyphCount to 0. */ glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0; } @@ -717,9 +771,13 @@ struct gvar_GVAR const hb_array_t points, hb_glyf_scratch_t &scratch, hb_scalar_cache_t *gvar_cache = nullptr, - bool phantom_only = false) const + bool phantom_only = false, + int64_t *budget = nullptr) const { if (unlikely (glyph >= glyphCount)) return true; + hb_scalar_cache_t *scalar_cache = gvar_cache ? + gvar_cache : + (hb_scalar_cache_t *) &Null(hb_scalar_cache_t); hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph); if (!var_data_bytes.as ()->has_data ()) return true; @@ -759,10 +817,15 @@ struct gvar_GVAR do { float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples, - gvar_cache); + scalar_cache); if (scalar == 0.f) continue; + if (budget && + unlikely (!hb_budget_spend (*budget, HB_BUDGET_1, + phantom_only && count >= 4 ? 4 : count))) + return false; + if (!private_points_checked) { auto scan = iterator; @@ -992,7 +1055,8 @@ struct gvar_GVAR NNOffset32To> sharedTuples; /* Offset from the start of this table to the shared tuple records. * Array of tuple records shared across all glyph variation data tables. */ - GidOffsetType glyphCountX; /* The number of glyphs in this font. This must match the number of + GlyphCountType + glyphCountX; /* The number of glyphs in this font. This must match the number of * glyphs stored elsewhere in the font. */ HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows. * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the @@ -1004,17 +1068,54 @@ struct gvar_GVAR offsetZ; /* Offsets from the start of the GlyphVariationData array * to each GlyphVariationData table. */ public: - DEFINE_SIZE_ARRAY (20, offsetZ); + DEFINE_SIZE_ARRAY (18 + GlyphCountType::static_size, offsetZ); }; -using gvar = gvar_GVAR; -using GVAR = gvar_GVAR; +struct gvar : gvar_GVAR +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar; +}; -struct gvar_accelerator_t : gvar::accelerator_t { - gvar_accelerator_t (hb_face_t *face) : gvar::accelerator_t (face) {} +struct GVAR : gvar_GVAR +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_GVAR; }; -struct GVAR_accelerator_t : GVAR::accelerator_t { - GVAR_accelerator_t (hb_face_t *face) : GVAR::accelerator_t (face) {} + +struct gvar_accelerator_t : hb_dual_accelerator_t +{ + gvar_accelerator_t (hb_face_t *face) : + hb_dual_accelerator_t (face) {} + + hb_scalar_cache_t *create_cache () const + { + if (has_data ()) return HB_DUAL_GET (*this, create_cache ()); + return nullptr; + } + + static void destroy_cache (hb_scalar_cache_t *cache) + { + hb_scalar_cache_t::destroy (cache); + } + + bool apply_deltas_to_points (hb_codepoint_t glyph, + hb_array_t coords, + const hb_array_t points, + hb_glyf_scratch_t &scratch, + hb_scalar_cache_t *gvar_cache = nullptr, + bool phantom_only = false, + int64_t *budget = nullptr) const + { + return HB_DUAL_GET (*this, apply_deltas_to_points (glyph, coords, points, + scratch, gvar_cache, + phantom_only, budget)); + } + + unsigned int get_axis_count () const + { + if (has_data ()) return HB_DUAL_GET (*this, get_axis_count ()); + return 0; + } }; } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh index 5c0b415f4aa..95cb772be9d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh @@ -49,6 +49,12 @@ struct index_map_subset_plan_t bool bypass_empty = true) { map_count = 0; + full_map_count = plan->new_to_old_gid_list.length ? + plan->new_to_old_gid_list.tail ().first + 1 : 0; + /* Only the advance mapping may be dropped in favor of implicit + * glyph-id indexing (for the others a null offset means no deltas), + * and only when the source was map-less too, preserving its form. */ + can_drop_to_implicit = !bypass_empty && !index_map; max_inners.init (); output_map.init (); @@ -181,13 +187,30 @@ struct index_map_subset_plan_t unsigned int get_map_count () const { return map_count; } size_t get_size () const - { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); } + { + if (!map_count) return 0; + return hb_unsigned_mul_add_saturate (get_width (), map_count, + DeltaSetIndexMap::min_size); + } - bool is_identity () const { return get_output_map ().length == 0; } + bool is_identity () const + { + if (!output_map) return true; + /* An advance map whose entries are the identity over every output + * glyph is equivalent to implicit glyph-id indexing; drop it. A + * truncated map doesn't qualify: glyphs past its end share its last + * value, not their own ids. */ + if (!can_drop_to_implicit || map_count != full_map_count) return false; + for (unsigned i = 0; i < map_count; i++) + if (output_map.arrayZ[i] != i) return false; + return true; + } hb_array_t get_output_map () const { return output_map.as_array (); } protected: unsigned int map_count; + unsigned int full_map_count; + bool can_drop_to_implicit; hb_vector_t max_inners; unsigned int outer_bit_count; unsigned int inner_bit_count; @@ -390,10 +413,18 @@ struct HVARVVAR } else { + /* avar2 partial instancing: cull unreachable regions. */ + hb_set_t dead_regions; + if (c->plan->has_avar2) + hvar_plan.var_store->collect_dead_regions (c->plan->axes_old_index_tag_map, + c->plan->avar2_reachable_ranges, + dead_regions); + if (unlikely (!out->varStore .serialize_serialize (c->serializer, hvar_plan.var_store, - hvar_plan.inner_maps.as_array ()))) + hvar_plan.inner_maps.as_array (), + dead_regions.get_population () ? &dead_regions : nullptr))) return_trace (false); } @@ -406,6 +437,9 @@ struct HVARVVAR const int *coords, unsigned int coord_count, hb_scalar_cache_t *store_cache = nullptr) const { + /* Implicit mapping uses outer index zero and the glyph id as the + * inner index. An oversized glyph id must not select another table. */ + if (!advMap && glyph > 0xFFFFu) return 0.f; uint32_t varidx = (this+advMap).map (glyph); return (this+varStore).get_delta (varidx, coords, coord_count, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc index 4d594d587d8..538e2b2f43b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc @@ -89,7 +89,7 @@ hb_ot_var_get_axis_count (hb_face_t *face) * @start_offset: offset of the first lookup to retrieve * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return; * Output = the actual number of variation axes returned (may be zero) - * @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found + * @axes_array: (out caller-allocates) (array length=axes_count) (nullable): The array of variation axes found * * Fetches a list of all variation axes in the specified face. The list returned will begin * at the offset provided. @@ -135,7 +135,7 @@ hb_ot_var_find_axis (hb_face_t *face, * @start_offset: offset of the first lookup to retrieve * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return; * Output = the actual number of variation axes returned (may be zero) - * @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found + * @axes_array: (out caller-allocates) (array length=axes_count) (nullable): The array of variation axes found * * Fetches a list of all variation axes in the specified face. The list returned will begin * at the offset provided. @@ -239,7 +239,7 @@ hb_ot_var_named_instance_get_postscript_name_id (hb_face_t *face, * @instance_index: The index of the named instance to query * @coords_length: (inout) (optional): Input = the maximum number of coordinates to return; * Output = the actual number of coordinates returned (may be zero) - * @coords: (out) (array length=coords_length): The array of coordinates found for the query + * @coords: (out) (array length=coords_length) (nullable): The array of coordinates found for the query * * Fetches the design-space coordinates corresponding to the given * named instance in the face. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh index ff7ce678e4e..51be3c04acf 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh @@ -28,6 +28,7 @@ #define HB_OT_VORG_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-dual.hh" /* * VORG -- Vertical Origin Table @@ -37,6 +38,7 @@ namespace OT { +template struct VertOriginMetric { int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } @@ -48,14 +50,16 @@ struct VertOriginMetric } public: - HBGlyphID16 glyph; + typename Types::HBGlyphID + glyph; FWORD vertOriginY; public: - DEFINE_SIZE_STATIC (4); + DEFINE_SIZE_STATIC (Types::HBGlyphID::static_size + FWORD::static_size); }; -struct VORG +template +struct VORGFormat1_2 { static constexpr hb_tag_t tableTag = HB_OT_TAG_VORG; @@ -79,7 +83,7 @@ struct VORG if (unlikely (!c->extend_min ((*this)))) return; - this->version.major = 1; + this->version.major = Types::size == 2 ? 1 : 2; this->version.minor = 0; this->defaultVertOriginY = defaultVertOriginY; @@ -91,18 +95,18 @@ struct VORG bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - auto *vorg_prime = c->serializer->start_embed (); + auto *vorg_prime = c->serializer->start_embed (); if (unlikely (!c->serializer->check_success (vorg_prime))) return_trace (false); auto it = + vertYOrigins.as_array () - | hb_filter (c->plan->glyphset (), &VertOriginMetric::glyph) - | hb_map ([&] (const VertOriginMetric& _) + | hb_filter (c->plan->glyphset (), &VertOriginMetric::glyph) + | hb_map ([&] (const VertOriginMetric& _) { hb_codepoint_t new_glyph = HB_SET_VALUE_INVALID; c->plan->new_gid_for_old_gid (_.glyph, &new_glyph); - VertOriginMetric metric; + VertOriginMetric metric; metric.glyph = new_glyph; metric.vertOriginY = _.vertOriginY; return metric; @@ -119,19 +123,78 @@ struct VORG TRACE_SANITIZE (this); return_trace (c->check_struct (this) && hb_barrier () && - version.major == 1 && + version.major == (Types::size == 2 ? 1 : 2) && vertYOrigins.sanitize (c)); } protected: - FixedVersion<>version; /* Version of VORG table. Set to 0x00010000u. */ + FixedVersion<>version; /* Version of VORG table. */ FWORD defaultVertOriginY; /* The default vertical origin. */ - SortedArray16Of + typename Types::template SortedArrayOf> vertYOrigins; /* The array of vertical origins. */ public: - DEFINE_SIZE_ARRAY(8, vertYOrigins); + DEFINE_SIZE_ARRAY(6 + Types::HBUINT::static_size, vertYOrigins); +}; + +struct VORG +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_VORG; + + bool has_data () const { return u.version.v.to_int (); } + + HB_ALWAYS_INLINE + int get_y_origin (hb_codepoint_t glyph) const + { + switch (u.version.v.major) { + case 1: return u.version1.get_y_origin (glyph); +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.get_y_origin (glyph); +#endif + default: return 0; + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + switch (u.version.v.major) { + case 1: return_trace (u.version1.subset (c)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (u.version2.subset (c)); +#endif + default: return_trace (false); + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!u.version.v.sanitize (c))) return_trace (false); + hb_barrier (); + switch (u.version.v.major) { + case 1: hb_barrier (); return_trace (u.version1.sanitize (c)); +#ifndef HB_NO_BEYOND_64K + case 2: hb_barrier (); return_trace (u.version2.sanitize (c)); +#endif + default: return_trace (false); + } + } + + protected: + union { + struct { + FixedVersion<>v; /* Version of VORG table. */ + } version; + VORGFormat1_2version1; +#ifndef HB_NO_BEYOND_64K + VORGFormat1_2version2; +#endif + } u; + + public: + DEFINE_SIZE_UNION (4, version.v); }; } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot.h b/src/java.desktop/share/native/libharfbuzz/hb-ot.h index f2dbaa1b317..f0d3521a893 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot.h @@ -30,6 +30,7 @@ #include "hb.h" +#include "hb-ot-fetch.h" #include "hb-ot-color.h" #include "hb-ot-deprecated.h" #include "hb-ot-font.h" diff --git a/src/java.desktop/share/native/libharfbuzz/hb-outline.cc b/src/java.desktop/share/native/libharfbuzz/hb-outline.cc index 12963fe46e3..88190403d7b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-outline.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-outline.cc @@ -298,6 +298,16 @@ hb_outline_recording_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, c->contours.push (c->points.length); } +static int64_t * +hb_outline_recording_pen_get_budget_remaining (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + void *user_data HB_UNUSED) +{ + hb_outline_t *c = (hb_outline_t *) data; + + return c->budget_remaining; +} + static inline void free_static_outline_recording_pen_funcs (); static struct hb_outline_recording_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t @@ -311,6 +321,7 @@ static struct hb_outline_recording_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_ hb_draw_funcs_set_quadratic_to_func (funcs, hb_outline_recording_pen_quadratic_to, nullptr, nullptr); hb_draw_funcs_set_cubic_to_func (funcs, hb_outline_recording_pen_cubic_to, nullptr, nullptr); hb_draw_funcs_set_close_path_func (funcs, hb_outline_recording_pen_close_path, nullptr, nullptr); + hb_draw_funcs_set_get_budget_remaining_func (funcs, hb_outline_recording_pen_get_budget_remaining, nullptr, nullptr); hb_draw_funcs_make_immutable (funcs); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-outline.hh b/src/java.desktop/share/native/libharfbuzz/hb-outline.hh index e23f5afa0a8..306e1d36579 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-outline.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-outline.hh @@ -76,6 +76,7 @@ struct hb_outline_t hb_vector_t points; hb_vector_t contours; + int64_t *budget_remaining = nullptr; }; HB_INTERNAL hb_draw_funcs_t * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc index e867f37f3c5..46cea29effa 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc @@ -62,6 +62,103 @@ hb_paint_extents_pop_transform (hb_paint_funcs_t *funcs HB_UNUSED, c->pop_transform (); } +/* Like the hb_draw_extents_get_funcs() sink, but tied to the paint + * session's live work budget. */ +struct hb_paint_extents_sink_t +{ + hb_extents_t<> extents; + int64_t *budget_remaining; + + bool consume_segment () + { + return hb_budget_spend (*budget_remaining, HB_BUDGET_1); + } +}; + +static void +hb_paint_extents_count_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, void *data, + hb_draw_state_t *st HB_UNUSED, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_paint_extents_sink_t *sink = (hb_paint_extents_sink_t *) data; + if (unlikely (!sink->consume_segment ())) return; + sink->extents.add_point (to_x, to_y); +} + +static void +hb_paint_extents_count_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, void *data, + hb_draw_state_t *st HB_UNUSED, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_paint_extents_sink_t *sink = (hb_paint_extents_sink_t *) data; + if (unlikely (!sink->consume_segment ())) return; + sink->extents.add_point (to_x, to_y); +} + +static void +hb_paint_extents_count_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, void *data, + hb_draw_state_t *st HB_UNUSED, + float control_x, float control_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_paint_extents_sink_t *sink = (hb_paint_extents_sink_t *) data; + if (unlikely (!sink->consume_segment ())) return; + sink->extents.add_point (control_x, control_y); + sink->extents.add_point (to_x, to_y); +} + +static void +hb_paint_extents_count_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, void *data, + hb_draw_state_t *st HB_UNUSED, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_paint_extents_sink_t *sink = (hb_paint_extents_sink_t *) data; + if (unlikely (!sink->consume_segment ())) return; + sink->extents.add_point (control1_x, control1_y); + sink->extents.add_point (control2_x, control2_y); + sink->extents.add_point (to_x, to_y); +} + +static int64_t * +hb_paint_extents_get_budget_remaining (hb_draw_funcs_t *, void *draw_data, void *) +{ + return ((hb_paint_extents_sink_t *) draw_data)->budget_remaining; +} + +static inline void free_static_paint_extents_draw_funcs (); + +static struct hb_paint_extents_draw_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t +{ + static hb_draw_funcs_t *create () + { + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + + hb_draw_funcs_set_move_to_func (funcs, hb_paint_extents_count_move_to, nullptr, nullptr); + hb_draw_funcs_set_line_to_func (funcs, hb_paint_extents_count_line_to, nullptr, nullptr); + hb_draw_funcs_set_quadratic_to_func (funcs, hb_paint_extents_count_quadratic_to, nullptr, nullptr); + hb_draw_funcs_set_cubic_to_func (funcs, hb_paint_extents_count_cubic_to, nullptr, nullptr); + hb_draw_funcs_set_get_budget_remaining_func (funcs, hb_paint_extents_get_budget_remaining, nullptr, nullptr); + + hb_draw_funcs_make_immutable (funcs); + + hb_atexit (free_static_paint_extents_draw_funcs); + + return funcs; + } +} static_paint_extents_draw_funcs; + +static inline +void free_static_paint_extents_draw_funcs () +{ + static_paint_extents_draw_funcs.free_instance (); +} + static void hb_paint_extents_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED, void *paint_data, @@ -71,10 +168,12 @@ hb_paint_extents_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED, { hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data; - hb_extents_t<> extents; - hb_draw_funcs_t *draw_extent_funcs = hb_draw_extents_get_funcs (); - hb_font_draw_glyph (font, glyph, draw_extent_funcs, &extents); - c->push_clip (extents); + hb_paint_extents_sink_t sink {{}, &c->budget_remaining}; + /* Skip the outline extraction when the session work budget is + * spent; an empty clip clips everything out. */ + if (likely (c->budget_remaining >= 0)) + hb_font_draw_glyph (font, glyph, static_paint_extents_draw_funcs.get_unconst (), &sink); + c->push_clip (sink.extents); } static void @@ -200,6 +299,29 @@ hb_paint_extents_paint_sweep_gradient (hb_paint_funcs_t *funcs HB_UNUSED, c->paint (); } +static hb_bool_t +hb_paint_extents_set_budget (hb_paint_funcs_t *, void *paint_data, + int64_t budget, void *) +{ + auto *context = (hb_paint_extents_context_t *) paint_data; + context->budget = budget; + context->budget_initialized = true; + context->recharge_budget (); + return true; +} + +static int64_t +hb_paint_extents_get_budget (hb_paint_funcs_t *, void *paint_data, void *) +{ + return ((hb_paint_extents_context_t *) paint_data)->budget; +} + +static int64_t * +hb_paint_extents_get_budget_remaining (hb_paint_funcs_t *, void *paint_data, void *) +{ + return &((hb_paint_extents_context_t *) paint_data)->budget_remaining; +} + static inline void free_static_paint_extents_funcs (); static struct hb_paint_extents_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t @@ -220,6 +342,9 @@ static struct hb_paint_extents_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_ hb_paint_funcs_set_linear_gradient_func (funcs, hb_paint_extents_paint_linear_gradient, nullptr, nullptr); hb_paint_funcs_set_radial_gradient_func (funcs, hb_paint_extents_paint_radial_gradient, nullptr, nullptr); hb_paint_funcs_set_sweep_gradient_func (funcs, hb_paint_extents_paint_sweep_gradient, nullptr, nullptr); + hb_paint_funcs_set_set_budget_func (funcs, hb_paint_extents_set_budget, nullptr, nullptr); + hb_paint_funcs_set_get_budget_func (funcs, hb_paint_extents_get_budget, nullptr, nullptr); + hb_paint_funcs_set_get_budget_remaining_func (funcs, hb_paint_extents_get_budget_remaining, nullptr, nullptr); hb_paint_funcs_make_immutable (funcs); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh index 531eb3c7c52..cd77d555570 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh @@ -40,6 +40,15 @@ struct hb_paint_extents_context_t transforms.clear (); clips.clear (); groups.clear (); + /* COLR scratch storage is zero-allocated and reused without running + * constructors. Distinguish that state from an explicitly requested + * zero budget. */ + if (unlikely (!budget_initialized)) + { + budget = HB_BUDGET_DEFAULT; + budget_initialized = true; + } + recharge_budget (); transforms.push (hb_transform_t<>{}); clips.push (hb_bounds_t<>{hb_bounds_t<>::UNBOUNDED}); @@ -131,6 +140,19 @@ struct hb_paint_extents_context_t group.union_ (clip); } + /* Cumulative work budget for the current session; reset by clear(). + * Outline traversal and consumed segments charge the same live + * counter. */ + int64_t budget = HB_BUDGET_DEFAULT; + bool budget_initialized = true; + int64_t budget_remaining = HB_BUDGET_GLYPH; + + void recharge_budget () + { + budget_remaining = budget == HB_BUDGET_DEFAULT ? + HB_BUDGET_GLYPH : budget; + } + protected: hb_vector_t> transforms; hb_vector_t> clips; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint.cc b/src/java.desktop/share/native/libharfbuzz/hb-paint.cc index 56e9c0901f1..d18369c92c6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint.cc @@ -60,6 +60,20 @@ hb_paint_color_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data, hb_font_t *font, void *user_data) { return false; } +static void +hb_paint_fill_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + hb_bool_t is_foreground, + hb_color_t color, + void *user_data) +{ + /* Decompose into the equivalent general sequence. */ + funcs->push_clip_glyph (paint_data, glyph, font); + funcs->color (paint_data, is_foreground, color); + funcs->pop_clip (paint_data); +} + static void hb_paint_push_clip_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, @@ -146,6 +160,19 @@ hb_paint_custom_palette_color_nil (hb_paint_funcs_t *funcs, void *paint_data, hb_color_t *color, void *user_data) { return false; } +static hb_bool_t +hb_paint_set_budget_nil (hb_paint_funcs_t *funcs HB_UNUSED, void *paint_data HB_UNUSED, + int64_t budget HB_UNUSED, + void *user_data HB_UNUSED) { return false; } + +static int64_t +hb_paint_get_budget_nil (hb_paint_funcs_t *funcs HB_UNUSED, void *paint_data HB_UNUSED, + void *user_data HB_UNUSED) { return HB_BUDGET_DEFAULT; } + +static int64_t * +hb_paint_get_budget_remaining_nil (hb_paint_funcs_t *funcs HB_UNUSED, void *paint_data HB_UNUSED, + void *user_data HB_UNUSED) { return nullptr; } + static bool _hb_paint_funcs_set_preamble (hb_paint_funcs_t *funcs, bool func_is_null, @@ -406,6 +433,67 @@ hb_paint_funcs_is_immutable (hb_paint_funcs_t *funcs) return hb_object_is_immutable (funcs); } +/** + * hb_paint_set_budget: + * @funcs: paint functions object + * @paint_data: associated paint data + * @budget: the new work-budget policy + * + * Sets the work-budget policy and recharges the live work budget. Negative + * values other than #HB_BUDGET_DEFAULT are clamped to zero. + * + * Return value: `true` if the paint functions support work budgets + * + * Since: 14.5.0 + **/ +hb_bool_t +hb_paint_set_budget (hb_paint_funcs_t *funcs, void *paint_data, int64_t budget) +{ + return funcs->set_budget (paint_data, budget); +} + +/** + * hb_paint_get_budget: + * @funcs: paint functions object + * @paint_data: associated paint data + * + * Fetches the configured work-budget policy. + * + * Return value: the configured policy, or #HB_BUDGET_DEFAULT if unsupported + * + * Since: 14.5.0 + **/ +int64_t +hb_paint_get_budget (hb_paint_funcs_t *funcs, void *paint_data) +{ + return funcs->get_budget (paint_data); +} + +/** + * hb_paint_get_budget_remaining: + * @funcs: paint functions object + * @paint_data: associated paint data + * + * Fetches the live work budget. A negative value means the budget was + * exhausted. Zero means the preceding work fit exactly, but no positive-cost + * work can start. + * + * Return value: the live work budget; if it is not tracked, the concrete + * configured policy or #HB_BUDGET_UNLIMITED + * + * Since: 14.5.0 + **/ +int64_t +hb_paint_get_budget_remaining (hb_paint_funcs_t *funcs, void *paint_data) +{ + int64_t *remaining = funcs->get_budget_remaining_ptr (paint_data); + if (remaining) + return *remaining; + + int64_t budget = funcs->get_budget (paint_data); + return budget == HB_BUDGET_DEFAULT ? HB_BUDGET_UNLIMITED : budget; +} + /** * hb_color_line_get_color_stops: @@ -551,6 +639,30 @@ hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data, return funcs->color_glyph (paint_data, glyph, font); } +/** + * hb_paint_fill_glyph: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * @glyph: the glyph ID + * @font: the font + * @is_foreground: whether the color is the foreground + * @color: The color to use + * + * Perform a "fill-glyph" paint operation: fill the glyph's shape + * with a solid color. + * + * Since: 14.3.0 + */ +void +hb_paint_fill_glyph (hb_paint_funcs_t *funcs, void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + hb_bool_t is_foreground, + hb_color_t color) +{ + funcs->fill_glyph (paint_data, glyph, font, is_foreground, color); +} + /** * hb_paint_push_clip_glyph: * @funcs: paint functions @@ -939,7 +1051,7 @@ hb_paint_normalize_color_line (hb_color_stop_t *stops, hb_array_t (stops, len) .qsort ([] (const hb_color_stop_t &a, const hb_color_stop_t &b) { - return a.offset < b.offset; + return (a.offset > b.offset) - (a.offset < b.offset); }); float mn = stops[0].offset, mx = stops[0].offset; @@ -1082,34 +1194,53 @@ hb_paint_sweep_gradient_tiles (hb_color_stop_t *stops, else { float span = angles[n_stops - 1] - angles[0]; - if (fabsf (span) < 1e-6f) + if (!(fabsf (span) >= 1e-6f)) /* Reversed to catch NaN. */ goto done; - int k = 0; - if (angles[0] >= 0) - { - float ss = angles[0]; - while (ss > 0) - { - if (span > 0) { ss -= span; k--; } - else { ss += span; k++; } - } - } - else + span = fabsf (span); + + if (span < HB_2_PI / HB_PAINT_MAX_SWEEP_TILES) { - float ee = angles[n_stops - 1]; - while (ee < 0) + /* The pattern repeats faster than the tile resolution; tiling + * it would cost unbounded work for sub-visual detail. Fill + * the whole circle with the period-average color instead. */ + float r = 0.f, g = 0.f, b = 0.f, a = 0.f; + for (unsigned i = 1; i < n_stops; i++) { - if (span > 0) { ee += span; k++; } - else { ee -= span; k--; } + float w = (angles[i] - angles[i - 1]) / span * 0.5f; + r += w * (hb_color_get_red (colors[i - 1]) + hb_color_get_red (colors[i])); + g += w * (hb_color_get_green (colors[i - 1]) + hb_color_get_green (colors[i])); + b += w * (hb_color_get_blue (colors[i - 1]) + hb_color_get_blue (colors[i])); + a += w * (hb_color_get_alpha (colors[i - 1]) + hb_color_get_alpha (colors[i])); } + hb_color_t avg = HB_COLOR (hb_clamp_to ((double) b + 0.5), + hb_clamp_to ((double) g + 0.5), + hb_clamp_to ((double) r + 0.5), + hb_clamp_to ((double) a + 0.5)); + emit_patch (0.f, avg, HB_2_PI, avg, user_data); + goto done; } - span = fabsf (span); - for (int l = k; l < 1000; l++) + /* First repeat that can reach angle 0, computed by division; + * counting there one span at a time can take effectively forever, + * or fail to terminate outright once the span drops below the + * float ulp of the angles. One repeat of slack absorbs rounding + * differences; earlier repeats are fully clipped anyway. */ + double dk = floor (-(double) hb_max (angles[0], angles[n_stops - 1]) / (double) span) - 1.; + if (!(dk >= -1.e18 && dk <= 1.e18)) /* Non-finite angles. */ + goto done; + + unsigned iterations = 0, tiles = 0; + for (int64_t l = (int64_t) dk; ; l++) { for (unsigned i = 1; i < n_stops; i++) { + /* Bounds clipped-away segments too; those stay negligible for + * sorted stops but are unbounded if the sort contract is + * violated. */ + if (unlikely (iterations++ >= 256 * HB_PAINT_MAX_SWEEP_TILES)) + goto done; + float a0_l, a1_l; hb_color_t col0, col1; if ((l % 2 != 0) && (extend == HB_PAINT_EXTEND_REFLECT)) @@ -1128,6 +1259,8 @@ hb_paint_sweep_gradient_tiles (hb_color_stop_t *stops, } if (a1_l < 0.f) continue; + if (unlikely (tiles++ >= HB_PAINT_MAX_SWEEP_TILES)) + goto done; if (a0_l < 0.f) { float f = (0.f - a0_l) / (a1_l - a0_l); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint.h b/src/java.desktop/share/native/libharfbuzz/hb-paint.h index e00d9b18732..a6e58961f82 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint.h @@ -63,6 +63,109 @@ HB_BEGIN_DECLS **/ typedef struct hb_paint_funcs_t hb_paint_funcs_t; +/** + * hb_paint_set_budget_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions + * @budget: the new work-budget policy + * @user_data: User data pointer passed to hb_paint_funcs_set_set_budget_func() + * + * Sets the work-budget policy and recharges the live work budget. @budget is + * #HB_BUDGET_DEFAULT, #HB_BUDGET_UNLIMITED, or a non-negative concrete value. + * + * Return value: `true` if the budget was set, `false` if unsupported + * + * Since: 14.5.0 + **/ +typedef hb_bool_t (*hb_paint_set_budget_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + int64_t budget, + void *user_data); + +/** + * hb_paint_get_budget_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions + * @user_data: User data pointer passed to hb_paint_funcs_set_get_budget_func() + * + * Fetches the configured work-budget policy. + * + * Return value: the configured work-budget policy + * + * Since: 14.5.0 + **/ +typedef int64_t (*hb_paint_get_budget_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + void *user_data); + +/** + * hb_paint_get_budget_remaining_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions + * @user_data: User data pointer passed to + * hb_paint_funcs_set_get_budget_remaining_func() + * + * Fetches the address of the live work budget. The returned address must stay + * valid while @paint_data is used with @funcs. The live value must be concrete; + * it must not contain #HB_BUDGET_DEFAULT. + * + * Return value: (nullable) (transfer none): the live work budget, or `NULL` if + * live budget accounting is unsupported + * + * Since: 14.5.0 + **/ +typedef int64_t *(*hb_paint_get_budget_remaining_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + void *user_data); + +/** + * hb_paint_funcs_set_set_budget_func: + * @funcs: paint functions object + * @func: (closure user_data) (destroy destroy) (scope notified): budget setter + * @user_data: Data to pass to @func + * @destroy: (nullable): callback to destroy @user_data + * + * Sets the budget setter callback. + * + * Since: 14.5.0 + **/ +HB_EXTERN void +hb_paint_funcs_set_set_budget_func (hb_paint_funcs_t *funcs, + hb_paint_set_budget_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_paint_funcs_set_get_budget_func: + * @funcs: paint functions object + * @func: (closure user_data) (destroy destroy) (scope notified): budget getter + * @user_data: Data to pass to @func + * @destroy: (nullable): callback to destroy @user_data + * + * Sets the budget-policy getter callback. + * + * Since: 14.5.0 + **/ +HB_EXTERN void +hb_paint_funcs_set_get_budget_func (hb_paint_funcs_t *funcs, + hb_paint_get_budget_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_paint_funcs_set_get_budget_remaining_func: + * @funcs: paint functions object + * @func: (closure user_data) (destroy destroy) (scope notified): live-budget getter + * @user_data: Data to pass to @func + * @destroy: (nullable): callback to destroy @user_data + * + * Sets the live-budget getter callback. + * + * Since: 14.5.0 + **/ +HB_EXTERN void +hb_paint_funcs_set_get_budget_remaining_func (hb_paint_funcs_t *funcs, + hb_paint_get_budget_remaining_func_t func, + void *user_data, hb_destroy_func_t destroy); + HB_EXTERN hb_paint_funcs_t * hb_paint_funcs_create (void); @@ -93,6 +196,16 @@ hb_paint_funcs_make_immutable (hb_paint_funcs_t *funcs); HB_EXTERN hb_bool_t hb_paint_funcs_is_immutable (hb_paint_funcs_t *funcs); +HB_EXTERN hb_bool_t +hb_paint_set_budget (hb_paint_funcs_t *funcs, void *paint_data, + int64_t budget); + +HB_EXTERN int64_t +hb_paint_get_budget (hb_paint_funcs_t *funcs, void *paint_data); + +HB_EXTERN int64_t +hb_paint_get_budget_remaining (hb_paint_funcs_t *funcs, void *paint_data); + /** * hb_paint_push_transform_func_t: * @funcs: paint functions object @@ -157,6 +270,31 @@ typedef hb_bool_t (*hb_paint_color_glyph_func_t) (hb_paint_funcs_t *funcs, hb_font_t *font, void *user_data); +/** + * hb_paint_fill_glyph_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() + * @glyph: the glyph ID + * @font: the font + * @is_foreground: whether the color is the foreground + * @color: The color to use, unpremultiplied + * @user_data: User data pointer passed to hb_paint_funcs_set_fill_glyph_func() + * + * A virtual method for the #hb_paint_funcs_t to fill a glyph's shape with + * a solid color. If not implemented, a sequence of "push-clip-glyph", + * "color", "pop-clip" paint operations, in that order, will be emitted + * instead. + * + * Since: 14.3.0 + */ +typedef void (*hb_paint_fill_glyph_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + hb_bool_t is_foreground, + hb_color_t color, + void *user_data); + /** * hb_paint_push_clip_glyph_func_t: * @funcs: paint functions object @@ -854,6 +992,23 @@ hb_paint_funcs_set_color_glyph_func (hb_paint_funcs_t *funcs, void *user_data, hb_destroy_func_t destroy); +/** + * hb_paint_funcs_set_fill_glyph_func: + * @funcs: A paint functions struct + * @func: (closure user_data) (destroy destroy) (scope notified): The fill-glyph callback + * @user_data: Data to pass to @func + * @destroy: (nullable): Function to call when @user_data is no longer needed + * + * Sets the fill-glyph callback on the paint functions struct. + * + * Since: 14.3.0 + */ +HB_EXTERN void +hb_paint_funcs_set_fill_glyph_func (hb_paint_funcs_t *funcs, + hb_paint_fill_glyph_func_t func, + void *user_data, + hb_destroy_func_t destroy); + /** * hb_paint_funcs_set_push_clip_glyph_func: * @funcs: A paint functions struct @@ -1117,6 +1272,13 @@ hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, hb_font_t *font); +HB_EXTERN void +hb_paint_fill_glyph (hb_paint_funcs_t *funcs, void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + hb_bool_t is_foreground, + hb_color_t color); + HB_EXTERN void hb_paint_push_clip_glyph (hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint.hh b/src/java.desktop/share/native/libharfbuzz/hb-paint.hh index df37e8bf6e9..d4ab0a3413b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint.hh @@ -48,6 +48,10 @@ HB_PAINT_FUNC_IMPLEMENT (push_group_for) \ HB_PAINT_FUNC_IMPLEMENT (pop_group) \ HB_PAINT_FUNC_IMPLEMENT (custom_palette_color) \ + HB_PAINT_FUNC_IMPLEMENT (fill_glyph) \ + HB_PAINT_FUNC_IMPLEMENT (set_budget) \ + HB_PAINT_FUNC_IMPLEMENT (get_budget) \ + HB_PAINT_FUNC_IMPLEMENT (get_budget_remaining) \ /* ^--- Add new callbacks here */ struct hb_paint_funcs_t @@ -92,7 +96,7 @@ struct hb_paint_funcs_t { return func.color_glyph (this, paint_data, glyph, font, - !user_data ? nullptr : user_data->push_clip_glyph); } + !user_data ? nullptr : user_data->color_glyph); } void push_clip_glyph (void *paint_data, hb_codepoint_t glyph, hb_font_t *font) @@ -121,6 +125,15 @@ struct hb_paint_funcs_t { func.color (this, paint_data, is_foreground, color, !user_data ? nullptr : user_data->color); } + void fill_glyph (void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + hb_bool_t is_foreground, + hb_color_t color) + { func.fill_glyph (this, paint_data, + glyph, font, + is_foreground, color, + !user_data ? nullptr : user_data->fill_glyph); } bool image (void *paint_data, hb_blob_t *image, unsigned width, unsigned height, @@ -173,6 +186,19 @@ struct hb_paint_funcs_t color_index, color, !user_data ? nullptr : user_data->custom_palette_color); } + bool set_budget (void *paint_data, int64_t budget) + { + if (budget < 0 && budget != HB_BUDGET_DEFAULT) + budget = 0; + return func.set_budget (this, paint_data, budget, + !user_data ? nullptr : user_data->set_budget); + } + int64_t get_budget (void *paint_data) + { return func.get_budget (this, paint_data, + !user_data ? nullptr : user_data->get_budget); } + int64_t *get_budget_remaining_ptr (void *paint_data) + { return func.get_budget_remaining (this, paint_data, + !user_data ? nullptr : user_data->get_budget_remaining); } /* Internal specializations. */ @@ -268,7 +294,12 @@ hb_color_lerp (hb_color_t c0, hb_color_t c1, float t) auto lerp = [&] (unsigned shift) -> unsigned { unsigned v0 = (c0 >> shift) & 0xFF; unsigned v1 = (c1 >> shift) & 0xFF; - return (unsigned) (v0 + t * ((float) v1 - (float) v0) + 0.5f); + float v = v0 + t * ((float) v1 - (float) v0) + 0.5f; + /* t may be outside [0,1] (or NaN) for malformed gradients; + * keep the float-to-unsigned conversion defined. */ + if (!(v > 0.f)) return 0; + if (v > 255.f) return 255; + return (unsigned) v; }; return HB_COLOR (lerp (0), lerp (8), lerp (16), lerp (24)); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh b/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh index b5dfae19960..d7903a89714 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh @@ -35,6 +35,7 @@ #include "graph/serialize.hh" using graph::graph_t; +using graph::graph_result_t; /* * For a detailed writeup on the overflow resolution algorithm see: @@ -69,7 +70,7 @@ struct lookup_size_t }; static inline -bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context) +graph_result_t _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context) { // For each lookup this will check the size of subtables and split them as needed // so that no subtable is at risk of overflowing. (where we support splitting for @@ -87,11 +88,10 @@ bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context for (unsigned lookup_index : lookup_indices) { graph::Lookup* lookup = ext_context.lookups.get(lookup_index); - if (!lookup->split_subtables_if_needed (ext_context, lookup_index)) - return false; + TRY (lookup->split_subtables_if_needed (ext_context, lookup_index)); } - return true; + return Ok(); } /* @@ -99,7 +99,7 @@ bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context * to extension lookups. */ static inline -bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context) +graph_result_t _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context) { // Simple Algorithm (v1, current): // 1. Calculate how many bytes each non-extension lookup consumes. @@ -117,7 +117,7 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context // TODO(garretrieger): also support extension promotion during iterative resolution phase, then // we can use a less conservative threshold here. // TODO(grieger): skip this for the 24 bit case. - if (!ext_context.lookups) return true; + if (!ext_context.lookups) return Ok(); unsigned total_lookup_table_sizes = 0; hb_vector_t lookup_sizes; @@ -132,7 +132,7 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context hb_set_t visited; lookup_sizes.push (lookup_size_t { lookup_index, - ext_context.graph.find_subgraph_size (lookup_index, visited), + ext_context.graph.find_subgraph_size (lookup_index, visited).value_or (0), lookup->number_of_subtables (), }); } @@ -167,7 +167,7 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context { size_t lookup_size = ext_context.graph.vertices_[p.lookup_index].table_size (); hb_set_t visited; - size_t subtables_size = ext_context.graph.find_subgraph_size (p.lookup_index, visited, 1) - lookup_size; + size_t subtables_size = ext_context.graph.find_subgraph_size (p.lookup_index, visited, 1).value_or (0) - lookup_size; size_t remaining_size = p.size - subtables_size - lookup_size; l3_l4_size += subtables_size; @@ -181,16 +181,15 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context layers_full = true; } - if (!ext_context.lookups.get(p.lookup_index)->make_extension (ext_context, p.lookup_index)) - return false; + TRY (ext_context.lookups.get(p.lookup_index)->make_extension (ext_context, p.lookup_index)); } - return true; + return Ok(); } static inline -bool _try_isolating_subgraphs (const hb_vector_t& overflows, - graph_t& sorted_graph) +graph_result_t _try_isolating_subgraphs (const hb_vector_t& overflows, + graph_t& sorted_graph) { unsigned space = 0; hb_set_t roots_to_isolate; @@ -212,7 +211,7 @@ bool _try_isolating_subgraphs (const hb_vector_t& over roots_to_isolate.add(root); } - if (!roots_to_isolate) return false; + if (!roots_to_isolate) return Ok(false); unsigned maximum_to_move = hb_max ((sorted_graph.num_roots_for_space (space) / 2u), 1u); if (roots_to_isolate.get_population () > maximum_to_move) { @@ -237,17 +236,16 @@ bool _try_isolating_subgraphs (const hb_vector_t& over sorted_graph.num_roots_for_space (space), roots_to_isolate.get_population (), sorted_graph.next_space ()); + TRY (sorted_graph.isolate_subgraph (roots_to_isolate)); + TRY (sorted_graph.move_to_new_space (roots_to_isolate)); - sorted_graph.isolate_subgraph (roots_to_isolate); - sorted_graph.move_to_new_space (roots_to_isolate); - - return true; + return Ok(true); } static inline -bool _resolve_shared_overflow(const hb_vector_t& overflows, - int overflow_index, - graph_t& sorted_graph) +graph_result_t _resolve_shared_overflow(const hb_vector_t& overflows, + int overflow_index, + graph_t& sorted_graph) { const graph::overflow_record_t& r = overflows[overflow_index]; @@ -263,8 +261,8 @@ bool _resolve_shared_overflow(const hb_vector_t& overf } } - unsigned result = sorted_graph.duplicate(&parents, r.child); - if (result == (unsigned) -1 && parents.get_population() > 2) { + auto result = sorted_graph.duplicate(&parents, r.child); + if (!result.is_ok () && parents.get_population() > 2) { // All links to the child are overflowing, so we can't include all // in the duplication. Remove one parent from the duplication. // Remove the lowest index parent, which will be the closest to the child. @@ -272,7 +270,7 @@ bool _resolve_shared_overflow(const hb_vector_t& overf result = sorted_graph.duplicate(&parents, r.child); } - if (result == (unsigned) -1) return false; + if (!result.is_ok ()) return Ok(false); if (parents.get_population() > 1) { // If the duplicated node has more than one parent pre-emptively raise it's priority to the maximum. @@ -286,16 +284,16 @@ bool _resolve_shared_overflow(const hb_vector_t& overf // to move nodes closer, but only for non-shared nodes. Since this node is shared, it will simply be given // further duplication which defeats the attempt to duplicate with multiple parents. To fix this we // pre-emptively raise priority now which allows the duplicated node to pack into the same layer as it's parents. - sorted_graph.vertices_[result].give_max_priority(); + sorted_graph.vertices_[*result].give_max_priority(); } - return true; + return Ok(true); } static inline -bool _process_overflows (const hb_vector_t& overflows, - hb_set_t& priority_bumped_parents, - graph_t& sorted_graph) +graph_result_t _process_overflows (const hb_vector_t& overflows, + hb_set_t& priority_bumped_parents, + graph_t& sorted_graph) { bool resolution_attempted = false; @@ -303,19 +301,19 @@ bool _process_overflows (const hb_vector_t& overflows, for (int i = overflows.length - 1; i >= 0; i--) { const graph::overflow_record_t& r = overflows[i]; - const auto& child = sorted_graph.vertices_[r.child]; - if (child.is_shared ()) + if (sorted_graph.vertices_[r.child].is_shared ()) { // The child object is shared, we may be able to eliminate the overflow // by duplicating it. - if (_resolve_shared_overflow(overflows, i, sorted_graph)) - return true; + TRY_ASSIGN (bool resolved, _resolve_shared_overflow(overflows, i, sorted_graph)); + if (resolved) + return Ok(true); // Sometimes we can't duplicate a node which looks shared because it's not actually shared // (eg. all links from the same parent) in this case continue on to other resolution options. } - if (child.is_leaf () && !priority_bumped_parents.has (r.parent)) + if (sorted_graph.vertices_[r.child].is_leaf () && !priority_bumped_parents.has (r.parent)) { // This object is too far from it's parent, attempt to move it closer. // @@ -328,7 +326,8 @@ bool _process_overflows (const hb_vector_t& overflows, // is < then the total size of the children (and the parent can be moved). // Since in that case moving the parent will cause a smaller increase in // the length of other offsets. - if (sorted_graph.raise_childrens_priority (r.parent)) { + TRY_ASSIGN (bool raised, sorted_graph.raise_childrens_priority (r.parent)); + if (raised) { priority_bumped_parents.add (r.parent); resolution_attempted = true; } @@ -340,88 +339,106 @@ bool _process_overflows (const hb_vector_t& overflows, // - Table splitting. } - return resolution_attempted; + return Ok(resolution_attempted); } -inline bool +inline graph_result_t +_assign_spaces_and_sort (graph_t& sorted_graph /* IN/OUT */) +{ + DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs."); + TRY_ASSIGN (bool assigned, sorted_graph.assign_spaces ()); + if (assigned) + return sorted_graph.sort_shortest_distance (); + else + return sorted_graph.sort_shortest_distance_if_needed (); +} + +inline graph_result_t +_gsub_gpos_specialization (hb_tag_t table_tag, + bool always_recalculate_extensions, + graph_t& sorted_graph /* IN/OUT */) +{ + DEBUG_MSG (SUBSET_REPACK, nullptr, "Applying GSUB/GPOS repacking specializations."); + if (!always_recalculate_extensions) return _assign_spaces_and_sort (sorted_graph); + + auto context_res = graph::gsubgpos_graph_context_t::create (table_tag, sorted_graph); + + if (unlikely (context_res.is_err())) { + if (context_res.error() == graph::SANITIZE_FAILURE) + // Sanitize failures are ignored, and we just skip splitting/extension promotion which needs a valid + // GSUB/GPOS + return _assign_spaces_and_sort (sorted_graph); + else + // All other errors are propagated. + return Err(context_res.error()); + } + + // Otherwise we have a valid GSUB/GPOS table and can try extension promotion and splitting + auto& ext_context = *context_res; + DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed."); + TRY (_presplit_subtables_if_needed (ext_context)); + + DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed."); + TRY (_promote_extensions_if_needed (ext_context)); + + // an additional sorting is needed before assign_spaces () which requires + // correct topological ordering to find space roots + TRY (sorted_graph.sort_shortest_distance_if_needed ()); + + TRY_ASSIGN (bool will_overflow, graph::will_overflow (sorted_graph)); + if (!will_overflow) return Ok(); + return _assign_spaces_and_sort (sorted_graph); +} + +inline graph_result_t hb_resolve_graph_overflows (hb_tag_t table_tag, unsigned max_rounds , bool always_recalculate_extensions, graph_t& sorted_graph /* IN/OUT */) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Repacking %c%c%c%c.", HB_UNTAG(table_tag)); - sorted_graph.sort_shortest_distance (); - if (sorted_graph.in_error ()) - { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state after initial sort."); - return false; - } + TRY (sorted_graph.sort_shortest_distance ()); - bool will_overflow = graph::will_overflow (sorted_graph); + TRY_ASSIGN (bool will_overflow, graph::will_overflow (sorted_graph)); if (!will_overflow) - return true; + return Ok(); bool is_gsub_or_gpos = (table_tag == HB_OT_TAG_GPOS || table_tag == HB_OT_TAG_GSUB); - graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph); - if (is_gsub_or_gpos && will_overflow) - { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Applying GSUB/GPOS repacking specializations."); - if (always_recalculate_extensions) - { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed."); - if (!_presplit_subtables_if_needed (ext_context)) { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed."); - return false; - } - - DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed."); - if (!_promote_extensions_if_needed (ext_context)) { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed."); - return false; - } - } - - DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs."); - if (sorted_graph.assign_spaces ()) - sorted_graph.sort_shortest_distance (); - else - sorted_graph.sort_shortest_distance_if_needed (); - } + if (is_gsub_or_gpos) + TRY(_gsub_gpos_specialization (table_tag, always_recalculate_extensions, sorted_graph)); unsigned round = 0; unsigned total_iterations = 0; hb_vector_t overflows; // TODO(garretrieger): select a good limit for max rounds. - while (!sorted_graph.in_error () - && graph::will_overflow (sorted_graph, &overflows) - && round < max_rounds - && total_iterations < HB_REPACKER_MAX_ITERATIONS) { + while (round < max_rounds && total_iterations < HB_REPACKER_MAX_ITERATIONS) { + TRY_ASSIGN (bool overflows_exist, graph::will_overflow (sorted_graph, &overflows)); + if (!overflows_exist) + break; + DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %u ===", round); print_overflows (sorted_graph, overflows); total_iterations++; hb_set_t priority_bumped_parents; - if (!_try_isolating_subgraphs (overflows, sorted_graph)) + TRY_ASSIGN (bool isolated, _try_isolating_subgraphs (overflows, sorted_graph)); + if (!isolated) { round++; - if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph)) + TRY_ASSIGN (bool processed, _process_overflows (overflows, priority_bumped_parents, sorted_graph)); + if (!processed) { DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :("); break; } } - sorted_graph.sort_shortest_distance (); - } - - if (sorted_graph.in_error ()) - { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state."); - return false; + TRY (sorted_graph.sort_shortest_distance ()); } - if (graph::will_overflow (sorted_graph)) + TRY_ASSIGN (bool has_overflow, graph::will_overflow (sorted_graph)); + if (unlikely (has_overflow)) { if (is_gsub_or_gpos && !always_recalculate_extensions) { // If this a GSUB/GPOS table and we didn't try to extension promotion and table splitting then @@ -431,10 +448,10 @@ hb_resolve_graph_overflows (hb_tag_t table_tag, } DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed."); - return false; + return Err(graph::OVERFLOW_RESOLUTION_FAILED); } - return true; + return Ok(); } /* @@ -456,31 +473,32 @@ hb_resolve_overflows (const T& packed, hb_tag_t table_tag, unsigned max_rounds = 32, bool recalculate_extensions = false) { - graph_t sorted_graph (packed); - if (sorted_graph.in_error ()) + auto graph_res = graph_t::create (packed); + if (!graph_res.is_ok ()) { - // Invalid graph definition. + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Graph creation failed, cause: %s", graph::to_string(graph_res.error())); return nullptr; } + graph_t sorted_graph = std::move (*graph_res); - if (!sorted_graph.is_fully_connected ()) + auto resolve_res = hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph); + if (resolve_res.is_err ()) { - sorted_graph.print_orphaned_nodes (); + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Overflow resolution failed, cause: %s", graph::to_string(resolve_res.error())); return nullptr; } - if (sorted_graph.in_error ()) + auto serialize_res = graph::serialize (sorted_graph); + if (serialize_res.is_err ()) { - // Allocations failed somewhere DEBUG_MSG (SUBSET_REPACK, nullptr, - "Graph is in error, likely due to a memory allocation error."); + "Serialization failed, cause: %s", graph::to_string(serialize_res.error())); return nullptr; } - if (!hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph)) - return nullptr; - - return graph::serialize (sorted_graph); + return *serialize_res; } #endif /* HB_REPACKER_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-script-list.h b/src/java.desktop/share/native/libharfbuzz/hb-script-list.h index 16347b9d84e..4e1e298c0da 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-script-list.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-script-list.h @@ -227,6 +227,9 @@ HB_END_DECLS * @HB_SCRIPT_SIDETIC: `Sidt`, Since: 11.5.0 * @HB_SCRIPT_TAI_YO: `Tayo`, Since: 11.5.0 * @HB_SCRIPT_TOLONG_SIKI: `Tols`, Since: 11.5.0 + * @HB_SCRIPT_JURCHEN: `Jurc`, Since: 14.5.0 + * @HB_SCRIPT_PROTO_CUNEIFORM: `Pcun`, Since: 14.5.0 + * @HB_SCRIPT_SEAL: `Seal`, Since: 14.5.0 * @HB_SCRIPT_INVALID: No script set * * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding @@ -473,6 +476,13 @@ typedef enum HB_SCRIPT_TAI_YO = HB_TAG ('T','a','y','o'), /*17.0*/ HB_SCRIPT_TOLONG_SIKI = HB_TAG ('T','o','l','s'), /*17.0*/ + /* + * Since: 14.5.0 + */ + HB_SCRIPT_JURCHEN = HB_TAG ('J','u','r','c'), /*18.0*/ + HB_SCRIPT_PROTO_CUNEIFORM = HB_TAG ('P','c','u','n'), /*18.0*/ + HB_SCRIPT_SEAL = HB_TAG ('S','e','a','l'), /*18.0*/ + /* No script set. */ HB_SCRIPT_INVALID = HB_TAG_NONE, @@ -492,5 +502,4 @@ typedef enum } hb_script_t; - #endif /* HB_SCRIPT_LIST_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh index 9fe99c85ea7..7af87053879 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh @@ -87,6 +87,11 @@ struct hb_serialize_context_t virtual_links.push (o.virtual_links[i]); } + bool in_error () const + { + return real_links.in_error() || virtual_links.in_error(); + } + bool add_virtual_link (objidx_t objidx) { if (!objidx) @@ -195,7 +200,7 @@ struct hb_serialize_context_t }; } - hb_serialize_context_t (void *start_, unsigned int size) : + hb_serialize_context_t (void *start_, size_t size) : start ((char *) start_), end (start + size), current (nullptr) @@ -230,7 +235,7 @@ struct hb_serialize_context_t || errors == HB_SERIALIZE_ERROR_ARRAY_OVERFLOW; } - void reset (void *start_, unsigned int size) + void reset (void *start_, size_t size) { start = (char*) start_; end = start + size; @@ -680,7 +685,7 @@ struct hb_serialize_context_t HB_NODISCARD Type *embed (const Type *obj) { - unsigned int size = obj->get_size (); + size_t size = obj->get_size (); Type *ret = this->allocate_size (size, false); if (unlikely (!ret)) return nullptr; hb_memcpy (ret, obj, size); @@ -733,6 +738,7 @@ struct hb_serialize_context_t Type *extend_size (Type *obj, size_t size, bool clear = true) { if (unlikely (in_error ())) return nullptr; + if (unlikely (size >= INT_MAX)) { err (HB_SERIALIZE_ERROR_OTHER); return nullptr; } assert (this->start <= (char *) obj); assert ((char *) obj <= this->head); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set.cc b/src/java.desktop/share/native/libharfbuzz/hb-set.cc index 6d45840cdf1..4da1dbb5b46 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-set.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-set.cc @@ -357,6 +357,24 @@ hb_set_is_equal (const hb_set_t *set, return set->is_equal (*other); } +/** + * hb_set_intersects: + * @set: A set + * @other: Another set + * + * Tests whether @set and @other have any elements in common. + * + * Return value: `true` if the two sets intersect, `false` otherwise. + * + * Since: 14.4.0 + **/ +hb_bool_t +hb_set_intersects (const hb_set_t *set, + const hb_set_t *other) +{ + return set->intersects (*other); +} + /** * hb_set_hash: * @set: A set diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set.h b/src/java.desktop/share/native/libharfbuzz/hb-set.h index 25ea1ca34a5..97e6de29b7f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-set.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-set.h @@ -131,6 +131,10 @@ HB_EXTERN hb_bool_t hb_set_is_equal (const hb_set_t *set, const hb_set_t *other); +HB_EXTERN hb_bool_t +hb_set_intersects (const hb_set_t *set, + const hb_set_t *other); + HB_EXTERN unsigned int hb_set_hash (const hb_set_t *set); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-set.hh index c5df9b8aec4..b09b22ce1ab 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-set.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-set.hh @@ -87,6 +87,7 @@ struct hb_sparseset_t uint32_t hash () const { return s.hash (); } void add (hb_codepoint_t g) { s.add (g); } + void add_bits (hb_codepoint_t g, uint64_t bits) { s.add_bits (g, bits); } bool add_range (hb_codepoint_t first, hb_codepoint_t last) { return s.add_range (first, last); } template @@ -125,6 +126,9 @@ struct hb_sparseset_t bool may_intersect (const hb_sparseset_t &other) const { return s.may_intersect (other.s); } + bool intersects (const hb_sparseset_t &other) const + { return s.intersects (other.s); } + bool intersects (hb_codepoint_t first, hb_codepoint_t last) const { return s.intersects (first, last); } @@ -137,11 +141,15 @@ struct hb_sparseset_t bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); } void union_ (const hb_sparseset_t &other) { s.union_ (other.s); } - void intersect (const hb_sparseset_t &other) { s.intersect (other.s); } + void intersect (const hb_sparseset_t &other, + hb_vector_t *workspace = nullptr) + { s.intersect (other.s, workspace); } void subtract (const hb_sparseset_t &other) { s.subtract (other.s); } void symmetric_difference (const hb_sparseset_t &other) { s.symmetric_difference (other.s); } bool next (hb_codepoint_t *codepoint) const { return s.next (codepoint); } + bool next_bits (hb_codepoint_t *codepoint, uint64_t *bits) const + { return s.next_bits (codepoint, bits); } bool previous (hb_codepoint_t *codepoint) const { return s.previous (codepoint); } bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const { return s.next_range (first, last); } @@ -151,6 +159,7 @@ struct hb_sparseset_t { return s.next_many (codepoint, out, size); } unsigned int get_population () const { return s.get_population (); } + bool get_singleton (hb_codepoint_t *codepoint) const { return s.get_singleton (codepoint); } hb_codepoint_t get_min () const { return s.get_min (); } hb_codepoint_t get_max () const { return s.get_max (); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc index 19188f8006a..97e2030d3a9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc @@ -52,6 +52,20 @@ * Most client programs will not need to deal with shape plans directly. **/ +#ifdef HAVE_HARFRUST +extern "C" void _hb_harfrust_shape_plan_destroy_rs (void *data); +#endif + +hb_shape_plan_t::~hb_shape_plan_t () +{ +#ifdef HAVE_HARFRUST + void *data = harfrust_data.get_relaxed (); + if (data) + _hb_harfrust_shape_plan_destroy_rs (data); +#endif + key.fini (); +} + /* * hb_shape_plan_key_t @@ -89,7 +103,8 @@ hb_shape_plan_key_t::init (bool copy, this->shaper_func = nullptr; this->shaper_name = nullptr; #ifndef HB_NO_OT_SHAPE - this->ot.init (face, coords, num_coords); + if (unlikely (!this->ot.init (face, coords, num_coords))) + goto bail; #endif /* @@ -115,6 +130,7 @@ hb_shape_plan_key_t::init (bool copy, else if (0 == strcmp (*shaper_list, #shaper)) \ HB_SHAPER_PLAN (shaper); #include "hb-shaper-list.hh" + #undef HB_SHAPER_IMPLEMENT } else @@ -132,6 +148,9 @@ hb_shape_plan_key_t::init (bool copy, #undef HB_SHAPER_PLAN bail: +#ifndef HB_NO_OT_SHAPE + this->ot.fini (); +#endif ::hb_free (features); return false; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh index 1cf47784ff6..46cb6b139ff 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh @@ -31,7 +31,6 @@ #include "hb-shaper.hh" #include "hb-ot-shape.hh" - struct hb_shape_plan_key_t { hb_segment_properties_t props; @@ -55,7 +54,14 @@ struct hb_shape_plan_key_t unsigned int num_coords, const char * const *shaper_list); - HB_INTERNAL void fini () { hb_free ((void *) user_features); user_features = nullptr; } + HB_INTERNAL void fini () + { + hb_free ((void *) user_features); + user_features = nullptr; +#ifndef HB_NO_OT_SHAPE + ot.fini (); +#endif + } HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other); @@ -64,13 +70,16 @@ struct hb_shape_plan_key_t struct hb_shape_plan_t { - ~hb_shape_plan_t () { key.fini (); } + HB_INTERNAL ~hb_shape_plan_t (); hb_object_header_t header; hb_face_t *face_unsafe; /* We don't carry a reference to face. */ hb_shape_plan_key_t key; #ifndef HB_NO_OT_SHAPE hb_ot_shape_plan_t ot; #endif +#ifdef HAVE_HARFRUST + hb_atomic_t harfrust_data; +#endif }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc index a36fa14fb28..2589af3fd5b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc @@ -144,7 +144,7 @@ hb_shape_full (hb_font_t *font, hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props, features, num_features, - font->coords, font->num_coords, + font->coords, font->has_nonzero_coords ? font->num_coords : 0, shaper_list); hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); @@ -316,9 +316,10 @@ hb_shape_justify (hb_font_t *font, /* Copy buffer text as we need it so we can shape multiple times. */ unsigned text_len = buffer->len; - auto *text_info = (hb_glyph_info_t *) hb_malloc (text_len * sizeof (buffer->info[0])); + auto *text_info = (hb_glyph_info_t *) hb_malloc2 (text_len, sizeof (buffer->info[0])); if (unlikely (text_len && !text_info)) return false; + HB_SCOPE_GUARD (hb_free (text_info)); hb_memcpy (text_info, buffer->info, text_len * sizeof (buffer->info[0])); auto text = hb_array (text_info, text_len); @@ -428,8 +429,6 @@ hb_shape_justify (hb_font_t *font, (double) min_target_advance, (double) max_target_advance, ya, yb, y); - hb_free (text_info); - if (failed) return false; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-static.cc b/src/java.desktop/share/native/libharfbuzz/hb-static.cc index 78713b22049..9867d340750 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-static.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-static.cc @@ -69,25 +69,6 @@ const unsigned char *endchar_str = static_endchar_str; /* hb_face_t */ -#ifndef HB_NO_BEYOND_64K -static inline unsigned -load_num_glyphs_from_loca (const hb_face_t *face) -{ - unsigned ret = 0; - - unsigned indexToLocFormat = face->table.head->indexToLocFormat; - - if (indexToLocFormat <= 1) - { - bool short_offset = 0 == indexToLocFormat; - hb_blob_t *loca_blob = face->table.loca.get_blob (); - ret = hb_max (1u, loca_blob->length / (short_offset ? 2 : 4)) - 1; - } - - return ret; -} -#endif - static inline unsigned load_num_glyphs_from_maxp (const hb_face_t *face) { @@ -97,16 +78,8 @@ load_num_glyphs_from_maxp (const hb_face_t *face) unsigned int hb_face_t::load_num_glyphs () const { - unsigned ret = 0; - -#ifndef HB_NO_BEYOND_64K - ret = hb_max (ret, load_num_glyphs_from_loca (this)); -#endif - - ret = hb_max (ret, load_num_glyphs_from_maxp (this)); - - num_glyphs = ret; - return ret; + num_glyphs = load_num_glyphs_from_maxp (this); + return num_glyphs; } unsigned int diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc index e6d3ecccdbe..14c90297870 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc @@ -49,6 +49,7 @@ bool hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, unsigned int fdCount, const FDSelect &src, /* IN */ + unsigned int src_num_glyphs, unsigned int &subset_fd_count /* OUT */, unsigned int &subset_fdselect_size /* OUT */, unsigned int &subset_fdselect_format /* OUT */, @@ -83,7 +84,13 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */ old_glyph = gid; } - auto fd_range = src.get_fd_range (old_glyph); + /* FDSelect may only cover the CharStrings glyphs; see subset_get_fd (). */ + hb_pair_t fd_range = + likely (old_glyph < src_num_glyphs) ? + src.get_fd_range (old_glyph) : + hb_pair_t {0, HB_CODEPOINT_INVALID}; + if (old_glyph < src_num_glyphs) + fd_range.second = hb_min (fd_range.second, src_num_glyphs); unsigned fd = fd_range.first; if (fd != prev_fd) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh index 518b35466ff..68b7433ec98 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh @@ -34,6 +34,16 @@ namespace CFF { +/* CFF2 CharStrings may omit a tail of glyphs provided by VARC, in which + * case FDSelect only covers the CharStrings glyphs. Use FD 0 for glyphs + * beyond that. */ +template +static inline unsigned +subset_get_fd (const ACC &acc, hb_codepoint_t glyph) +{ + return likely (glyph < acc.num_glyphs) ? acc.fdSelect->get_fd (glyph) : 0; +} + /* Used for writing a temporary charstring */ struct str_encoder_t { @@ -334,6 +344,9 @@ struct cs_command_t typedef hb_vector_t *cs_command_vec_t; +struct cff2_instancing_plan_t; +struct cff2_cs_rounding_t; + struct flatten_param_t { flatten_param_t (str_buff_t &flatStr_, @@ -346,6 +359,12 @@ struct flatten_param_t bool drop_hints; const hb_subset_plan_t *plan; cs_command_vec_t commands; /* Optional: capture parsed commands for specialization */ + + /* CFF2 partial instancing: when set, blends are rewritten against the + * instanced variation store instead of being copied or flattened. */ + const cff2_instancing_plan_t *instancer = nullptr; + cff2_cs_rounding_t *rounding = nullptr; + bool emitted_blend = false; }; template @@ -371,7 +390,7 @@ struct subr_flattener_t continue; } const hb_ubytes_t str = (*acc.charStrings)[glyph]; - unsigned int fd = acc.fdSelect->get_fd (glyph); + unsigned int fd = subset_get_fd (acc, glyph); if (unlikely (fd >= acc.fdCount)) return false; @@ -422,8 +441,7 @@ struct parsed_cs_op_t : op_str_t bool is_hinting () const { return hinting_flag; } void set_hinting () { hinting_flag = true; } - /* The layout of this struct is designed to fit within the - * padding of op_str_t! */ + /* Metadata for retained charstring tokens. */ protected: bool hinting_flag = false; @@ -438,30 +456,93 @@ struct parsed_cs_str_t : parsed_values_t parsed (false), hint_dropped (false), has_prefix_ (false), - has_calls_ (false) + has_calls_ (false), + coalescing_ (false) { SUPER::init (); } + HB_ALWAYS_INLINE void add_op (op_code_t op, const byte_str_ref_t& str_ref) { - if (!is_parsed ()) - SUPER::add_op (op, str_ref); + if (is_parsed ()) return; + last_op_ = op; + if (coalescing_) + { + /* Do not record individual tokens; only note their boundaries. + * Bytes are flushed as verbatim segments at call sites and at + * the end of the string. Only enabled when per-op granularity + * is not needed later for hint analysis. */ + penultimate_end_ = last_end_; + last_end_ = str_ref.get_offset (); + if (unlikely (op == OpCode_return || op == OpCode_endchar)) + flush_segment (str_ref, last_end_); + return; + } + SUPER::add_op (op, str_ref); + } + + bool has_immediate_subr_number () const + { + if (is_parsed ()) return true; + op_code_t op = coalescing_ ? last_op_ : + values.length ? values.tail ().op : OpCode_Invalid; + return op == OpCode_shortint || op == OpCode_fixedcs || + (OpCode_OneByteIntFirst <= op && op <= OpCode_TwoByteNegInt3); } void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num) { - if (!is_parsed ()) + if (is_parsed ()) return; + has_calls_ = true; + last_op_ = op; + + if (coalescing_) { - has_calls_ = true; + /* Flush bytes preceding the subroutine-number token, then skip + * over the number: it is re-encoded with the new bias. */ + flush_segment (str_ref, penultimate_end_); + opStart = last_end_; + SUPER::add_op (op, str_ref, {subr_num}); + penultimate_end_ = last_end_ = str_ref.get_offset (); + return; + } - /* Pop the subroutine number. */ - values.pop (); + /* Pop the subroutine number. */ + values.pop (); - SUPER::add_op (op, str_ref, {subr_num}); + SUPER::add_op (op, str_ref, {subr_num}); + } + + /* Flush pending bytes [opStart, end) as verbatim segment entries. */ + void flush_segment (const byte_str_ref_t& str_ref, unsigned end) + { + unsigned start = opStart; + if (end <= start) return; + while (start < end) + { + auto arr = str_ref.sub_array (start, hb_min (end - start, 255u)); + if (unlikely (!arr.length)) break; + parsed_cs_op_t *val = values.push (); + val->ptr = arr.arrayZ; + val->length = arr.length; + start += arr.length; } + opStart = end; } + /* For coalescing mode: flush any pending bytes through the current + * position; used where the string ends without an explicit + * return/endchar op (CFF2). */ + void flush_coalesced (const byte_str_ref_t& str_ref) + { + if (coalescing_ && !is_parsed ()) + flush_segment (str_ref, str_ref.get_offset ()); + } + + void enable_coalescing () { coalescing_ = true; } + bool is_coalescing () const { return coalescing_; } + void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid) { has_prefix_ = true; @@ -525,6 +606,14 @@ struct parsed_cs_str_t : parsed_values_t bool vsindex_dropped : 1; bool has_prefix_ : 1; bool has_calls_ : 1; + /* Record verbatim byte segments instead of individual tokens, + * making a separate compact() pass unnecessary; incompatible with + * hint analysis. */ + bool coalescing_ : 1; + /* End offsets of the last two tokens seen (coalescing mode). */ + op_code_t last_op_ = OpCode_Invalid; + unsigned penultimate_end_ = 0; + unsigned last_end_ = 0; op_code_t prefix_op_; number_t prefix_num_; @@ -605,14 +694,19 @@ struct subr_subset_param_t parsed_cs_str_vec_t *parsed_local_subrs_, hb_set_t *global_closure_, hb_set_t *local_closure_, - bool drop_hints_) : + bool drop_hints_, + bool coalesce_ = false) : 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_) {} + drop_hints (drop_hints_), + coalesce (coalesce_) + { + if (coalesce) parsed_charstring->enable_coalescing (); + } parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context) { @@ -651,7 +745,10 @@ struct subr_subset_param_t else { if (!parsed_str->is_parsed ()) + { parsed_str->alloc (env.str_ref.total_size ()); + if (coalesce) parsed_str->enable_coalescing (); + } current_parsed_str = parsed_str; } } @@ -664,6 +761,7 @@ struct subr_subset_param_t hb_set_t *global_closure; hb_set_t *local_closure; bool drop_hints; + bool coalesce; }; struct subr_remap_t : hb_inc_bimap_t @@ -738,8 +836,9 @@ struct subr_subsetter_t * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required), * because we can't tell if a number belongs to a hint op until we see the first moveto. * - * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number - * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine. + * Retained calls require an immediately preceding subroutine-number token + * within the same program. Caller-supplied operands are rejected; use + * desubroutinization for those programs. */ bool subset (void) { @@ -781,6 +880,12 @@ struct subr_subsetter_t return false; } + /* When hints are not analyzed (not dropping hints, not populating + * the accelerator), coalesce parsed tokens as they are added, + * instead of a separate compact() pass. */ + bool coalesce = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING) && + !plan->inprogress_accelerator; + /* phase 1 & 2 */ for (auto _ : plan->new_to_old_gid_list) { @@ -788,7 +893,7 @@ struct subr_subsetter_t hb_codepoint_t old_glyph = _.second; const hb_ubytes_t str = (*acc.charStrings)[old_glyph]; - unsigned int fd = acc.fdSelect->get_fd (old_glyph); + unsigned int fd = subset_get_fd (acc, old_glyph); if (unlikely (fd >= acc.fdCount)) return false; @@ -813,7 +918,8 @@ struct subr_subsetter_t &parsed_local_subrs_storage[fd], &closures.global_closure, &closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + plan->flags & HB_SUBSET_FLAGS_NO_HINTING, + coalesce); if (unlikely (!interp.interpret (param))) return false; @@ -845,8 +951,11 @@ struct subr_subsetter_t * * The compacting both saves memory and makes further operations * faster. + * + * Not needed when tokens were coalesced during parsing. */ - parsed_charstrings[new_glyph].compact (); + if (!coalesce) + parsed_charstrings[new_glyph].compact (); } /* Since parsed strings were loaded from accelerator, we still need @@ -887,7 +996,7 @@ struct subr_subsetter_t } last++; // Skip over gid - unsigned int fd = acc.fdSelect->get_fd (old_glyph); + unsigned int fd = subset_get_fd (acc, old_glyph); if (unlikely (fd >= acc.fdCount)) return false; if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix))) @@ -1071,7 +1180,7 @@ struct subr_subsetter_t { hb_codepoint_t new_glyph = _.first; hb_codepoint_t old_glyph = _.second; - unsigned int fd = acc.fdSelect->get_fd (old_glyph); + unsigned int fd = subset_get_fd (acc, old_glyph); if (unlikely (fd >= acc.fdCount)) return false; @@ -1230,6 +1339,7 @@ HB_INTERNAL bool hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, unsigned int fdCount, const CFF::FDSelect &src, /* IN */ + unsigned int src_num_glyphs, unsigned int &subset_fd_count /* OUT */, unsigned int &subset_fdselect_size /* OUT */, unsigned int &subset_fdselect_format /* OUT */, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc index 558b61121a7..9446e99e627 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc @@ -348,6 +348,11 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_thas_immediate_subr_number ())) + { + env.set_error (); + return; + } byte_str_ref_t str_ref = env.str_ref; env.call_subr (subrs, type); param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num); @@ -518,6 +523,7 @@ struct cff1_subset_plan glyph_to_sid_map_t *glyph_to_sid_map = acc.cff_accelerator ? acc.cff_accelerator->glyph_to_sid_map.get_acquire () : nullptr; + bool created_map = false; if (!glyph_to_sid_map && acc.cff_accelerator) { @@ -525,11 +531,17 @@ struct cff1_subset_plan glyph_to_sid_map = acc.create_glyph_to_sid_map (); } + if (!glyph_to_sid_map || glyph_to_sid_map->in_error ()) + { + glyph_to_sid_map = nullptr; + created_map = false; + } + auto it = hb_iter (plan->new_to_old_gid_list); if (it->first == 0) it++; auto _ = *it; bool not_is_cid = !acc.is_CID (); - bool skip = !not_is_cid && glyph_to_sid_map; + bool skip = !not_is_cid && glyph_to_sid_map && !identity_charset; if (not_is_cid) sidmap.alloc (num_glyphs); for (hb_codepoint_t glyph = 1; glyph < num_glyphs; glyph++) @@ -545,12 +557,18 @@ struct cff1_subset_plan /* Retain the SID for the old missing glyph ID */ old_glyph = glyph; } - unsigned sid = glyph_to_sid_map ? - glyph_to_sid_map->arrayZ[old_glyph].code : - acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache); + unsigned sid; + if (identity_charset) + sid = glyph; + else + { + sid = glyph_to_sid_map ? + glyph_to_sid_map->arrayZ[old_glyph].code : + acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache); - if (not_is_cid) - sid = sidmap.add (sid); + if (not_is_cid) + sid = sidmap.add (sid); + } if (sid != last_sid + 1) subset_charset_ranges.push (code_pair_t {sid, glyph}); @@ -621,6 +639,7 @@ struct cff1_subset_plan orig_fdcount = acc.fdCount; drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING; desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE; + identity_charset = (plan->flags & HB_SUBSET_FLAGS_CFF_IDENTITY_CHARSET) && acc.is_CID (); #ifdef HB_EXPERIMENTAL_API min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0; @@ -628,7 +647,7 @@ struct cff1_subset_plan min_charstrings_off_size = 0; #endif - subset_charset = !acc.is_predef_charset (); + subset_charset = !acc.is_predef_charset () || identity_charset; if (!subset_charset) /* check whether the subset renumbers any glyph IDs */ for (const auto &_ : plan->new_to_old_gid_list) @@ -663,6 +682,7 @@ struct cff1_subset_plan if (unlikely (!hb_plan_subset_cff_fdselect (plan, orig_fdcount, *acc.fdSelect, + acc.num_glyphs, subset_fdcount, info.fd_select.size, subset_fdselect_format, @@ -786,6 +806,7 @@ struct cff1_subset_plan unsigned int topDictModSIDs[name_dict_values_t::ValCount]; bool desubroutinize = false; + bool identity_charset = false; unsigned min_charstrings_off_size = 0; }; @@ -993,6 +1014,7 @@ OT::cff1::accelerator_subset_t::subset (hb_subset_context_t *c) const if (unlikely (!cff_plan.create (*this, c->plan))) { DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan."); + c->serializer->err (HB_SERIALIZE_ERROR_OTHER); return false; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc index cce15bafe90..9f33256b3f2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc @@ -30,14 +30,368 @@ #include "hb-open-type.hh" #include "hb-ot-cff2-table.hh" +#include "hb-ot-var-common.hh" #include "hb-set.h" #include "hb-subset-plan.hh" #include "hb-subset-cff-common.hh" #include "hb-cff2-interp-cs.hh" +#include "hb-subset-cff2-round.hh" #include "hb-subset-cff2-to-cff1.hh" using namespace CFF; +namespace CFF { + +/* + * Partial instancing (some axes pinned or limited, others kept). + * + * This is a port of fontTools' instantiateCFF2 (fonttools/fonttools#3506), + * with one simplification: the variation-store instancing solver acts on + * regions independently of the per-blend delta values, so instead of lifting + * every blend's deltas into the store, instancing it, and reading the rows + * back, we instance each VarData once with identity delta rows. The + * instantiated tuples then give, per VarData, a fixed linear map from old + * per-region deltas to new per-region deltas. The contribution that folds + * into each blend's default value is the old store's region scalars + * evaluated at the new default location (plan->normalized_coords); the + * surviving rebased regions all evaluate to zero there. + * + * Use: create (), then note_use () for every blend the retained charstrings + * and private dicts hold, then finalize (); only VarDatas that are both + * still variable and actually used survive into the new store. + */ +struct cff2_instancing_plan_t +{ + struct vardata_transform_t + { + /* new_deltas[j] = Σ_i matrix[j][i] * old_deltas[i] */ + hb_vector_t> matrix; + /* Default-value fold-in scalars, one per old region: the old store's + * region scalars at the new default location. */ + hb_vector_t gains; + /* Surviving regions, parallel to matrix rows. */ + hb_vector_t> regions; + /* Index into the new global region list, per new region (finalize). */ + hb_vector_t region_indices; + unsigned new_major = 0; + bool alive_ = false; + bool alive () const { return alive_; } + + /* One value's delta for new region j, from its old per-region deltas. */ + double transform_delta (unsigned j, hb_array_t deltas) const + { + const hb_vector_t &col = matrix.arrayZ[j]; + double d = 0.; + unsigned count = hb_min (col.length, deltas.length); + for (unsigned c = 0; c < count; c++) + d += (double) col.arrayZ[c] * deltas.arrayZ[c].to_real (); + return d; + } + }; + + hb_vector_t transforms; /* per old VarData (vsindex) */ + hb_vector_t> new_regions; /* global region list */ + hb_set_t used_majors; + unsigned new_major_count = 0; + + bool has_variations () const { return new_major_count; } + + const vardata_transform_t *get_transform (unsigned major) const + { return major < transforms.length ? &transforms.arrayZ[major] : nullptr; } + + /* Record that a retained blend references this VarData. */ + void note_use (unsigned major) { used_majors.add (major); } + + /* The new vsindex a private dict's (or charstring's) old ivs maps to; + * dead VarDatas fall back to 0, their blends having become static. */ + unsigned remap_ivs (unsigned old_ivs) const + { + const vardata_transform_t *t = get_transform (old_ivs); + return (t && t->alive ()) ? t->new_major : 0; + } + + double fold_deltas (unsigned old_ivs, hb_array_t deltas) const + { + const vardata_transform_t *t = get_transform (old_ivs); + if (unlikely (!t || t->gains.length != deltas.length)) return 0.; + double v = 0.; + for (unsigned i = 0; i < deltas.length; i++) + v += (double) t->gains.arrayZ[i] * deltas.arrayZ[i].to_real (); + return v; + } + + bool create (const CFF2ItemVariationStore *cff2VarStore, + const hb_subset_plan_t *plan) + { + const OT::ItemVariationStore &varStore = cff2VarStore->varStore; + unsigned major_count = varStore.get_sub_table_count (); + if (!transforms.resize (major_count)) return false; + + if (!varStore.get_region_list ().get_var_regions (plan->axes_old_index_tag_map, orig_regions)) + return false; + + /* Instance each VarData with identity delta rows; the surviving tuples' + * delta columns are the old-region → new-region transform. */ + OT::optimize_scratch_t scratch; + for (unsigned m = 0; m < major_count; m++) + { + const OT::VarData &var_data = varStore.get_sub_table (m); + unsigned k = var_data.get_region_index_count (); + vardata_transform_t &t = transforms.arrayZ[m]; + + if (!t.gains.resize_exact (k)) return false; + varStore.get_region_scalars (m, plan->normalized_coords.arrayZ, + plan->normalized_coords.length, + t.gains.arrayZ, k); + + OT::tuple_variations_t tuples; + for (unsigned r = 0; r < k; r++) + { + OT::tuple_delta_t tuple; + if (!tuple.deltas_x.resize (k) || + !tuple.indices.resize (k)) + return false; + for (unsigned i = 0; i < k; i++) + tuple.indices.arrayZ[i] = true; + tuple.deltas_x.arrayZ[r] = 1.f; + unsigned region_index = var_data.get_region_index (r); + if (unlikely (region_index >= orig_regions.length)) return false; + tuple.axis_tuples = orig_regions.arrayZ[region_index]; + if (unlikely (tuple.axis_tuples.in_error ())) return false; + tuples.tuple_vars.push (std::move (tuple)); + } + if (unlikely (tuples.tuple_vars.in_error ())) return false; + + if (!tuples.instantiate (plan->axes_location, plan->axes_triple_distances, scratch)) + return false; + + for (auto &tuple : tuples.tuple_vars) + { + if (unlikely (tuple.deltas_x.length != k)) return false; + hb_vector_t col; + if (unlikely (!col.resize_exact (k))) return false; + for (unsigned i = 0; i < k; i++) + col.arrayZ[i] = tuple.deltas_x.arrayZ[i]; + t.matrix.push (std::move (col)); + t.regions.push (std::move (tuple.axis_tuples)); + } + if (unlikely (t.matrix.in_error () || t.regions.in_error ())) return false; + } + + return true; + } + + /* Decide which VarDatas survive, number them, and build the new global + * region list: surviving original regions first, in their original order, + * then solver-split new regions in order of appearance (fontTools' + * rebuildRegions + prune_regions). */ + bool finalize () + { + for (unsigned m = 0; m < transforms.length; m++) + { + vardata_transform_t &t = transforms.arrayZ[m]; + t.alive_ = t.matrix.length && used_majors.has (m); + if (t.alive_) + t.new_major = new_major_count++; + } + + /* Keys hash by content, so pointers into different owners compare fine. */ + hb_hashmap_t*, unsigned> region_idx_map; + hb_vector_t*> region_ptrs; + for (const vardata_transform_t &t : transforms) + { + if (!t.alive ()) continue; + for (const auto ®ion : t.regions) + if (!region_idx_map.has (®ion)) + if (unlikely (!region_idx_map.set (®ion, (unsigned) -1))) + return false; + } + for (const auto &r : orig_regions) + { + unsigned *idx; + if (region_idx_map.has (&r, &idx) && *idx == (unsigned) -1) + { + if (unlikely (!region_idx_map.set (&r, region_ptrs.length))) return false; + region_ptrs.push (&r); + } + } + for (const vardata_transform_t &t : transforms) + { + if (!t.alive ()) continue; + for (const auto ®ion : t.regions) + { + unsigned *idx; + if (region_idx_map.has (®ion, &idx) && *idx == (unsigned) -1) + { + if (unlikely (!region_idx_map.set (®ion, region_ptrs.length))) return false; + region_ptrs.push (®ion); + } + } + } + if (unlikely (region_ptrs.in_error ())) return false; + + for (vardata_transform_t &t : transforms) + { + if (!t.alive ()) continue; + for (const auto ®ion : t.regions) + { + unsigned *idx; + if (unlikely (!region_idx_map.has (®ion, &idx))) return false; + t.region_indices.push (*idx); + } + if (unlikely (t.region_indices.in_error ())) return false; + } + + if (!new_regions.resize (region_ptrs.length)) return false; + for (unsigned i = 0; i < region_ptrs.length; i++) + { + new_regions.arrayZ[i] = *region_ptrs.arrayZ[i]; + if (unlikely (new_regions.arrayZ[i].in_error ())) return false; + } + + return true; + } + + /* Serialize the instanced store: a CFF2ItemVariationStore whose VarDatas + * carry no items, just region indexes (blend deltas live in charstrings). + * Laid out manually since all sizes are known up front. */ + bool serialize_var_store (hb_serialize_context_t *c, + const hb_vector_t &axis_tags) const + { + unsigned data_count = new_major_count; + unsigned header_size = 2 + 4 + 2 + 4 * data_count; + + uint64_t offset = header_size; + hb_vector_t data_offsets; + for (const vardata_transform_t &t : transforms) + { + if (!t.alive ()) continue; + data_offsets.push ((unsigned) offset); + offset += 6 + 2 * (uint64_t) t.region_indices.length; + } + if (unlikely (data_offsets.in_error () || data_offsets.length != data_count)) + return false; + unsigned regions_offset = (unsigned) offset; + uint64_t total = offset + 4 + (uint64_t) new_regions.length * axis_tags.length * 6; + if (unlikely (total > 0xFFFFFFFFu)) return false; + + HBUINT16 *size_field = c->allocate_size (HBUINT16::static_size); + if (unlikely (!size_field)) return false; + /* OFF 2026 5.3.3.11.2 permits larger stores with length=65535. */ + *size_field = hb_min (total, (uint64_t) 0xFFFFu); + + char *header = c->allocate_size (header_size); + if (unlikely (!header)) return false; + * (HBUINT16 *) (header + 0) = 1; /* format */ + * (HBUINT32 *) (header + 2) = regions_offset; + * (HBUINT16 *) (header + 6) = data_count; + for (unsigned i = 0; i < data_count; i++) + * (HBUINT32 *) (header + 8 + 4 * i) = data_offsets.arrayZ[i]; + + for (const vardata_transform_t &t : transforms) + { + if (!t.alive ()) continue; + unsigned k = t.region_indices.length; + HBUINT16 *v = (HBUINT16 *) c->allocate_size (6 + 2 * k); + if (unlikely (!v)) return false; + v[0] = 0; /* itemCount */ + v[1] = 0; /* wordSizeCount */ + v[2] = k; /* regionIndices.len */ + for (unsigned j = 0; j < k; j++) + v[3 + j] = t.region_indices.arrayZ[j]; + } + + hb_vector_t*> region_ptrs; + if (unlikely (!region_ptrs.alloc_exact (new_regions.length))) return false; + for (const auto &r : new_regions) + region_ptrs.push (&r); + auto *region_list = c->start_embed (); + return region_list->serialize (c, axis_tags, region_ptrs); + } + + private: + hb_vector_t> orig_regions; +}; + +/* Usage-collection pass for partial instancing: record which VarDatas the + * retained charstrings' and private dicts' blends reference. Mirrors the + * emission pass: blends consumed by dropped hint ops don't count. */ +struct cff2_usage_param_t +{ + void init () {} + + cff2_instancing_plan_t *instancing = nullptr; + bool drop_hints = false; + bool has_blend = false; + bool has_flex1 = false; + unsigned ivs = 0; /* dict-side current vsindex */ +}; + +struct cff2_cs_opset_usage_t : cff2_cs_opset_t +{ + static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, cff2_usage_param_t& param) + { + param.has_flex1 |= op == OpCode_flex1; + bool counts = true; + switch (op) + { + case OpCode_return: + case OpCode_endchar: + counts = false; + break; + + case OpCode_hstem: + case OpCode_hstemhm: + case OpCode_vstem: + case OpCode_vstemhm: + case OpCode_hintmask: + case OpCode_cntrmask: + if (param.drop_hints) + counts = false; + break; + + default: + break; + } + + if (counts) + for (unsigned int i = 0; i < env.argStack.get_count (); i++) + if (env.argStack[i].blending ()) + { + param.has_blend = true; + if (param.instancing) param.instancing->note_use (env.get_ivs ()); + break; + } + + env.clear_args (); + } +}; + +struct cff2_private_dict_usage_opset_t : dict_opset_t +{ + static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_usage_param_t& param) + { + switch (op) { + case OpCode_vsindexdict: + env.process_vsindex (); + param.ivs = env.get_ivs (); + env.clear_args (); + return; + case OpCode_blenddict: + param.instancing->note_use (param.ivs); + env.clear_args (); + return; + default: + dict_opset_t::process_op (op, env); + if (!env.argStack.is_empty ()) return; + env.clear_args (); + return; + } + } +}; + +} /* namespace CFF */ + struct cff2_sub_table_info_t : cff_sub_table_info_t { cff2_sub_table_info_t () @@ -74,54 +428,52 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) { - /* Optionally capture command for specialization (before flushing, to preserve args) */ - if (param.commands) + bool skip_command = false; + switch (op) { - bool skip_command = false; + case OpCode_return: + case OpCode_endchar: + skip_command = true; + break; - switch (op) - { - case OpCode_return: - case OpCode_endchar: - skip_command = true; - break; + case OpCode_hstem: + case OpCode_hstemhm: + case OpCode_vstem: + case OpCode_vstemhm: + case OpCode_hintmask: + case OpCode_cntrmask: + skip_command = param.drop_hints; + break; - case OpCode_hstem: - case OpCode_hstemhm: - case OpCode_vstem: - case OpCode_vstemhm: - case OpCode_hintmask: - case OpCode_cntrmask: - if (param.drop_hints) - skip_command = true; - break; + default: + break; + } - default: - break; - } + if (!skip_command && param.rounding && unlikely (!round_args (op, env, param))) + { + env.set_error (); + return; + } - if (!skip_command) + /* Capture resolved commands for CFF2-to-CFF1 specialization. */ + if (param.commands && !skip_command) + { + cs_command_t cmd (op); + for (unsigned int i = 0; i < env.argStack.get_count ();) { - cs_command_t cmd (op); - /* Capture resolved blend values */ - for (unsigned int i = 0; i < env.argStack.get_count ();) + const blend_arg_t &arg = env.argStack[i]; + if (arg.blending ()) { - const blend_arg_t &arg = env.argStack[i]; - if (arg.blending ()) - { - /* For blend args, capture only the resolved default value */ - cmd.args.push (arg); - /* Skip over the multiple blend values */ - i += arg.numValues; - } - else - { - cmd.args.push (arg); - i++; - } + cmd.args.push (arg); + i += arg.numValues; + } + else + { + cmd.args.push (arg); + i++; } - param.commands->push (cmd); } + param.commands->push (cmd); } switch (op) @@ -129,6 +481,8 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) { + if (param.rounding) + { + encode_rounded_args (env, param); + SUPER::flush_args (env, param); + return; + } for (unsigned int i = 0; i < env.argStack.get_count ();) { const blend_arg_t &arg = env.argStack[i]; @@ -162,7 +522,10 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) + { + unsigned k = 0; + if (param.instancer) + { + unsigned ivs = env.get_ivs (); + const auto *t = param.instancer->get_transform (ivs); + k = t && t->alive () ? t->matrix.length : 0; + for (unsigned i = 0; i < env.argStack.get_count (); i++) + { + auto &arg = env.argStack[i]; + if (!arg.blending ()) continue; + if (unlikely (!t || arg.deltas.length != t->gains.length)) return false; + double value = arg.to_real () + param.instancer->fold_deltas (ivs, arg.deltas.as_array ()); + hb_vector_t deltas = std::move (arg.deltas); + arg.set_real (value); + if (unlikely (!arg.deltas.resize (k))) return false; + for (unsigned r = 0; r < k; r++) + arg.deltas.arrayZ[r].set_real (t->transform_delta (r, deltas.as_array ())); + } + } + return param.rounding->round (op, hb_array (env.argStack.arrayZ, env.argStack.get_count ()), k); + } + + static void encode_rounded_args (cff2_cs_interp_env_t &env, flatten_param_t& param) + { + str_encoder_t encoder (param.flatStr); + unsigned count = env.argStack.get_count (); + for (unsigned i = 0; i < count;) + { + const auto &arg = env.argStack[i]; + if (!arg.blending ()) + { + encoder.encode_num_cs (arg); + i++; + continue; + } + unsigned k = arg.deltas.length; + unsigned n = 1; + while (i + n < count && env.argStack[i + n].deltas.length == k) n++; + /* Previously emitted operands remain on the stack during each blend. */ + unsigned chunk = hb_min (n, (512 - i) / (k + 1)); + if (unlikely (!chunk)) + { + env.set_error (); + return; + } + for (unsigned j = 0; j < chunk; j++) + encoder.encode_num_cs (env.argStack[i + j]); + for (unsigned j = 0; j < chunk; j++) + for (const auto &d : env.argStack[i + j].deltas) + encoder.encode_num_cs (d); + encoder.encode_int (chunk); + encoder.encode_op (OpCode_blendcs); + param.emitted_blend = true; + i += chunk; + } + } + static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param) { /* flatten the default values */ @@ -202,6 +624,113 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) + { + const cff2_instancing_plan_t &instancer = *param.instancer; + unsigned ivs = env.get_ivs (); + const cff2_instancing_plan_t::vardata_transform_t *t = instancer.get_transform (ivs); + if (unlikely (!t)) + { + env.set_error (); + return; + } + + unsigned n = arg.numValues; + for (unsigned int j = 0; j < n; j++) + { + const blend_arg_t &arg1 = env.argStack[i + j]; + if (unlikely (!(arg1.blending () && (arg1.numValues == n) && (arg1.valueIndex == j) && + (arg1.deltas.length == env.get_region_count ()) && + (arg1.deltas.length == t->gains.length)))) + { + env.set_error (); + return; + } + } + + str_encoder_t encoder (param.flatStr); + unsigned k_new = t->alive () ? t->matrix.length : 0; + + if (!k_new) + { + /* All of this VarData's regions died; blends dissolve into statics. */ + for (unsigned int j = 0; j < n; j++) + { + const blend_arg_t &arg1 = env.argStack[i + j]; + number_t v; + v.set_real (arg1.to_real () + round (instancer.fold_deltas (ivs, arg1.deltas.as_array ()))); + encoder.encode_num_cs (v); + } + return; + } + + /* Emit in chunks so the output charstring stays within the argument + * stack limit: values already emitted for this op, plus this chunk's + * defaults, deltas and count, must not exceed 513. */ + unsigned done = 0; + while (done < n) + { + unsigned avail = 512 > (i + done) ? 512 - (i + done) : 0; + unsigned chunk = hb_min (avail / (k_new + 1), n - done); + if (unlikely (!chunk)) + { + env.set_error (); + return; + } + + for (unsigned int j = done; j < done + chunk; j++) + { + const blend_arg_t &arg1 = env.argStack[i + j]; + number_t v; + v.set_real (arg1.to_real () + round (instancer.fold_deltas (ivs, arg1.deltas.as_array ()))); + encoder.encode_num_cs (v); + } + for (unsigned int j = done; j < done + chunk; j++) + { + const blend_arg_t &arg1 = env.argStack[i + j]; + for (unsigned r = 0; r < k_new; r++) + { + number_t v; + v.set_int (hb_clamp_to (round (t->transform_delta (r, arg1.deltas.as_array ())))); + encoder.encode_num_cs (v); + } + } + encoder.encode_int (chunk); + encoder.encode_op (OpCode_blendcs); + done += chunk; + } + param.emitted_blend = true; + } + + /* Partial instancing: prepend a vsindex op when the charstring's + * (remapped) ivs differs from its FD's (remapped) private-dict ivs. */ + static void emit_vsindex_prefix (cff2_cs_interp_env_t &env, flatten_param_t& param) + { + if (!param.emitted_blend) return; + const cff2_instancing_plan_t &instancer = *param.instancer; + unsigned new_ivs = instancer.remap_ivs (env.get_ivs ()); + unsigned fd_ivs = instancer.remap_ivs (env.get_orig_ivs ()); + if (new_ivs == fd_ivs) return; + + str_buff_t prefix; + str_encoder_t enc (prefix); + enc.encode_int ((int) new_ivs); + enc.encode_op (OpCode_vsindexcs); + + str_buff_t &buf = param.flatStr; + unsigned old_len = buf.length; + if (unlikely (prefix.in_error () || !buf.resize (old_len + prefix.length))) + { + env.set_error (); + return; + } + memmove (buf.arrayZ + prefix.length, buf.arrayZ, old_len); + hb_memcpy (buf.arrayZ, prefix.arrayZ, prefix.length); + } + static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) { switch (op) @@ -254,12 +783,14 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_tflush_coalesced (env.str_ref); param.current_parsed_str->set_parsed (); env.return_from_subr (); param.set_current_str (env, false); break; case OpCode_endchar: + param.current_parsed_str->flush_coalesced (env.str_ref); param.current_parsed_str->set_parsed (); SUPER::process_op (op, env, param); break; @@ -284,6 +815,11 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t &env, subr_subset_param_t& param, cff2_biased_subrs_t& subrs, hb_set_t *closure) { + if (unlikely (!param.current_parsed_str->has_immediate_subr_number ())) + { + env.set_error (); + return; + } byte_str_ref_t str_ref = env.str_ref; env.call_subr (subrs, type); param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num); @@ -326,7 +862,12 @@ struct cff2_private_blend_encoder_param_t if (!seen_blend) { region_count = varStore->varStore.get_region_index_count (ivs); - scalars.resize_exact (region_count); + if (unlikely (!scalars.resize_exact (region_count))) + { + if (c) c->err (HB_SERIALIZE_ERROR_OTHER); + seen_blend = true; + return; + } varStore->varStore.get_region_scalars (ivs, normalized_coords.arrayZ, normalized_coords.length, &scalars[0], region_count); seen_blend = true; @@ -353,6 +894,13 @@ struct cff2_private_blend_encoder_param_t hb_vector_t scalars; const CFF2ItemVariationStore *varStore = nullptr; hb_array_t normalized_coords; + + /* CFF2 partial instancing: when set, blends are rewritten against the + * instanced variation store instead of being flattened. */ + const cff2_instancing_plan_t *instancer = nullptr; + /* Error-compensated fold rounding state, per dict operator. */ + double fold_exact = 0.; + double fold_emitted = 0.; }; struct cff2_private_dict_blend_opset_t : dict_opset_t @@ -365,6 +913,98 @@ struct cff2_private_dict_blend_opset_t : dict_opset_t arg.set_int (round (arg.to_real () + param.blend_deltas (blends))); } + /* The fold added to a value, error-compensated across the operator: most + * blended private-dict values (BlueValues, StemSnap*, ...) are + * delta-encoded, so independently rounded folds would accumulate in the + * decoded absolutes; keeping the emitted cumulative fold equal to the + * rounded exact cumulative fold bounds every absolute within ±0.5. */ + static double fold (cff2_private_blend_encoder_param_t& param, + const hb_array_t blends) + { + double f = param.blend_deltas (blends); + double emit = round (param.fold_exact + f) - param.fold_emitted; + param.fold_exact += f; + param.fold_emitted += emit; + return emit; + } + + /* Partial instancing: emit the args preceding this blend group, then the + * group itself rewritten against the instanced store, and clear the + * stack. The op's remaining args are flushed at process_op time. */ + static void rewrite_blends (cff2_priv_dict_interp_env_t& env, + cff2_private_blend_encoder_param_t& param, + unsigned start, unsigned n, unsigned k) + { + const cff2_instancing_plan_t &instancer = *param.instancer; + const cff2_instancing_plan_t::vardata_transform_t *t = instancer.get_transform (param.ivs); + if (unlikely (!t || t->gains.length != k)) + { + env.set_error (); + return; + } + + str_buff_t str; + str_encoder_t encoder (str); + + for (unsigned idx = 0; idx < start; idx++) + encoder.encode_num_tp (env.argStack[idx]); + + unsigned k_new = t->alive () ? t->matrix.length : 0; + if (!k_new) + { + /* This VarData died (or is unused by any retained charstring, which + * can happen for FDs kept only for retain-gids holes); blends + * dissolve into statics. */ + for (unsigned j = 0; j < n; j++) + { + const hb_array_t blends = env.argStack.sub_array (start + n + (j * k), k); + number_t v; + v.set_real (env.argStack[start + j].to_real () + fold (param, blends)); + encoder.encode_num_tp (v); + } + } + else + { + unsigned done = 0; + while (done < n) + { + unsigned avail = 512 > (start + done) ? 512 - (start + done) : 0; + unsigned chunk = hb_min (avail / (k_new + 1), n - done); + if (unlikely (!chunk)) + { + env.set_error (); + return; + } + + for (unsigned j = done; j < done + chunk; j++) + { + const hb_array_t blends = env.argStack.sub_array (start + n + (j * k), k); + number_t v; + v.set_real (env.argStack[start + j].to_real () + fold (param, blends)); + encoder.encode_num_tp (v); + } + for (unsigned j = done; j < done + chunk; j++) + { + const hb_array_t blends = env.argStack.sub_array (start + n + (j * k), k); + for (unsigned r = 0; r < k_new; r++) + { + number_t v; + v.set_int (hb_clamp_to (round (t->transform_delta (r, blends)))); + encoder.encode_num_tp (v); + } + } + encoder.encode_int (chunk); + encoder.encode_op (OpCode_blenddict); + done += chunk; + } + } + + auto bytes = str.as_bytes (); + param.c->embed (&bytes, bytes.length); + + env.clear_args (); + } + static void process_blend (cff2_priv_dict_interp_env_t& env, cff2_private_blend_encoder_param_t& param) { unsigned int n, k; @@ -372,14 +1012,30 @@ struct cff2_private_dict_blend_opset_t : dict_opset_t param.process_blend (); k = param.region_count; n = env.argStack.pop_uint (); + + unsigned count = env.argStack.get_count (); + unsigned int total; + if (unlikely (hb_unsigned_mul_overflows (k + 1, n, &total) || total > count)) + { + env.set_error (); + return; + } + /* copy the blend values into blend array of the default values */ - unsigned int start = env.argStack.get_count () - ((k+1) * n); + unsigned int start = count - total; /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */ - if (unlikely (start > env.argStack.get_count ())) + if (unlikely (start > count)) { env.set_error (); return; } + + if (param.instancer && k) + { + rewrite_blends (env, param, start, n, k); + return; + } + for (unsigned int i = 0; i < n; i++) { const hb_array_t blends = env.argStack.sub_array (start + n + (i * k), k); @@ -410,6 +1066,20 @@ struct cff2_private_dict_blend_opset_t : dict_opset_t case OpCode_vsindexdict: env.process_vsindex (); param.ivs = env.get_ivs (); + if (param.instancer) + { + /* Re-emit with the remapped vsindex; 0 is the dict default. */ + unsigned new_ivs = param.instancer->remap_ivs (param.ivs); + if (new_ivs) + { + str_buff_t str; + str_encoder_t encoder (str); + encoder.encode_int ((int) new_ivs); + encoder.encode_op (OpCode_vsindexdict); + auto bytes = str.as_bytes (); + param.c->embed (&bytes, bytes.length); + } + } env.clear_args (); return; case OpCode_blenddict: @@ -439,6 +1109,7 @@ struct cff2_private_dict_blend_opset_t : dict_opset_t param.c->embed (&bytes, bytes.length); env.clear_args (); + param.fold_exact = param.fold_emitted = 0.; } }; @@ -446,9 +1117,11 @@ struct cff2_private_dict_op_serializer_t : op_serializer_t { cff2_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_, bool pinned_, const CFF::CFF2ItemVariationStore* varStore_, - hb_array_t normalized_coords_) + hb_array_t normalized_coords_, + const cff2_instancing_plan_t *instancer_ = nullptr) : desubroutinize (desubroutinize_), drop_hints (drop_hints_), pinned (pinned_), - varStore (varStore_), normalized_coords (normalized_coords_) {} + param (nullptr, varStore_, normalized_coords_) + { param.instancer = instancer_; } bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, @@ -467,11 +1140,13 @@ struct cff2_private_dict_op_serializer_t : op_serializer_t return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link)); } - if (pinned) + if (pinned || param.instancer) { - // Reinterpret opstr and process blends. + /* Reinterpret opstr and process blends. The param persists across + * this dict's opstrs, so that an ivs set by a vsindexdict opstr is + * still in effect when a later opstr's blends are processed. */ cff2_priv_dict_interp_env_t env {hb_ubytes_t (opstr.ptr, opstr.length)}; - cff2_private_blend_encoder_param_t param (c, varStore, normalized_coords); + param.c = c; dict_interpreter_t interp (env); return_trace (interp.interpret (param)); } @@ -483,11 +1158,11 @@ struct cff2_private_dict_op_serializer_t : op_serializer_t const bool desubroutinize; const bool drop_hints; const bool pinned; - const CFF::CFF2ItemVariationStore* varStore; - hb_array_t normalized_coords; + mutable cff2_private_blend_encoder_param_t param; }; + namespace OT { struct cff2_subset_plan { @@ -502,12 +1177,21 @@ struct cff2_subset_plan orig_fdcount = acc.fdArray->count; drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING; - pinned = (bool) plan->normalized_coords; + bool instancing_requested = (bool) plan->normalized_coords; + pinned = instancing_requested && plan->all_axes_pinned; normalized_coords = plan->normalized_coords; head_maxp_info = plan->head_maxp_info; hmtx_map = &plan->hmtx_map; desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE || - pinned; // For instancing we need this path + instancing_requested; // For instancing we need this path + + /* Partial instancing: some axes pinned or limited, others kept. */ + partial_instancing = instancing_requested && !pinned && + acc.varStore != &Null (CFF2ItemVariationStore); + if (partial_instancing && + unlikely (!instancing.create (acc.varStore, plan))) + return false; + axis_tags = &plan->axis_tags; /* Enable command capture for CFF2→CFF1 conversion (for specialization) */ capture_commands = pinned; @@ -520,6 +1204,92 @@ struct cff2_subset_plan if (desubroutinize) { + if (instancing_requested) + { + /* Identify charstrings that can round absolute coordinates. Conservatively + * keep relative rounding for flex1, whose implicit direction can vary. + * Also collect the VarDatas referenced by partial instances. */ + hb_vector_t round_charstrings; + if (unlikely (!round_charstrings.resize (num_glyphs))) return false; + hb_set_t used_fds; + for (unsigned int i = 0; i < num_glyphs; i++) + { + hb_codepoint_t glyph; + if (!plan->old_gid_for_new_gid (i, &glyph)) + continue; + const hb_ubytes_t str = (*acc.charStrings)[glyph]; + unsigned int fd = CFF::subset_get_fd (acc, glyph); + if (unlikely (fd >= acc.fdCount)) + return false; + used_fds.add (fd); + + cff2_cs_interp_env_t env (str, acc, fd); + cs_interpreter_t, cff2_cs_opset_usage_t, cff2_usage_param_t> interp (env); + cff2_usage_param_t param; + param.instancing = partial_instancing ? &instancing : nullptr; + param.drop_hints = drop_hints; + if (unlikely (!interp.interpret (param))) + return false; + round_charstrings.arrayZ[i] = param.has_blend && !param.has_flex1; + } + if (partial_instancing) + { + for (unsigned fd : used_fds) + { + cff2_usage_param_t param; + param.instancing = &instancing; + unsigned count = acc.privateDicts[fd].get_count (); + for (unsigned j = 0; j < count; j++) + { + const op_str_t &opstr = acc.privateDicts[fd][j]; + if (drop_hints && dict_opset_t::is_hint_op (opstr.op)) + continue; + cff2_priv_dict_interp_env_t env {hb_ubytes_t (opstr.ptr, opstr.length)}; + dict_interpreter_t interp (env); + if (unlikely (!interp.interpret (param))) + return false; + } + } + if (unlikely (!instancing.finalize ())) + return false; + } + + /* Keep full-instance blends unrounded until their absolute positions + * are known; partial-instance blends stay symbolic for rewriting. */ + if (!subset_charstrings.resize_exact (num_glyphs)) + return false; + if (capture_commands && !charstring_commands.resize_exact (num_glyphs)) + return false; + for (unsigned int i = 0; i < num_glyphs; i++) + { + hb_codepoint_t glyph; + if (!plan->old_gid_for_new_gid (i, &glyph)) + continue; + const hb_ubytes_t str = (*acc.charStrings)[glyph]; + unsigned int fd = CFF::subset_get_fd (acc, glyph); + if (unlikely (fd >= acc.fdCount)) + return false; + + cff2_cs_interp_env_t env (str, acc, fd, + pinned ? plan->normalized_coords.arrayZ : nullptr, + pinned ? plan->normalized_coords.length : 0); + env.round_blends = !round_charstrings.arrayZ[i]; + cs_interpreter_t, cff2_cs_opset_flatten_t, flatten_param_t> interp (env); + flatten_param_t param = { + subset_charstrings.arrayZ[i], + (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING), + plan, + capture_commands ? &charstring_commands.arrayZ[i] : nullptr + }; + cff2_cs_rounding_t rounding; + if (round_charstrings.arrayZ[i]) param.rounding = &rounding; + param.instancer = partial_instancing ? &instancing : nullptr; + if (unlikely (!interp.interpret (param))) + return false; + } + } + else + { /* Flatten global & local subrs */ subr_flattener_t, cff2_cs_opset_flatten_t> flattener(acc, plan); @@ -538,6 +1308,7 @@ struct cff2_subset_plan if (!flattener.flatten (subset_charstrings)) return false; } + } } else { @@ -571,6 +1342,7 @@ struct cff2_subset_plan if (unlikely (!hb_plan_subset_cff_fdselect (plan, orig_fdcount, *(const FDSelect *)acc.fdSelect, + acc.num_glyphs, subset_fdcount, subset_fdselect_size, subset_fdselect_format, @@ -603,6 +1375,10 @@ struct cff2_subset_plan bool drop_hints = false; bool desubroutinize = false; + bool partial_instancing = false; + cff2_instancing_plan_t instancing; + const hb_vector_t *axis_tags = nullptr; + unsigned min_charstrings_off_size = 0; hb_array_t normalized_coords; // For instantiation @@ -695,7 +1471,7 @@ _serialize_cff1_charstrings (hb_serialize_context_t *c, } unsigned data_size = 0; - unsigned total_size = CFF1CharStrings::total_size (cff1_charstrings, &data_size); + unsigned total_size = CFF1CharStrings::total_size (cff1_charstrings, &data_size, plan.min_charstrings_off_size); if (unlikely (!c->start_zerocopy (total_size))) { c->pop_discard (); @@ -703,7 +1479,7 @@ _serialize_cff1_charstrings (hb_serialize_context_t *c, } auto *cs = c->start_embed (); - if (unlikely (!cs->serialize (c, cff1_charstrings))) + if (unlikely (!cs->serialize (c, cff1_charstrings, &data_size, plan.min_charstrings_off_size))) { c->pop_discard (); return false; @@ -1138,7 +1914,8 @@ OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c, } auto *pd = c->push (); cff2_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints, plan.pinned, - varStore, normalized_coords); + varStore, normalized_coords, + plan.partial_instancing ? &plan.instancing : nullptr); if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link))) { unsigned fd = plan.fdmap[i]; @@ -1191,13 +1968,30 @@ OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c, if (varStore != &Null (CFF2ItemVariationStore) && !plan.pinned) { - auto *dest = c->push (); - if (unlikely (!dest->serialize (c, varStore))) + if (plan.partial_instancing) { - c->pop_discard (); - return false; + if (plan.instancing.has_variations ()) + { + c->push (); + if (unlikely (!plan.instancing.serialize_var_store (c, *plan.axis_tags))) + { + c->pop_discard (); + return false; + } + plan.info.var_store_link = c->pop_pack (false); + } + /* else: the store emptied; the vstore op gets dropped along with it. */ + } + else + { + auto *dest = c->push (); + if (unlikely (!dest->serialize (c, varStore))) + { + c->pop_discard (); + return false; + } + plan.info.var_store_link = c->pop_pack (false); } - plan.info.var_store_link = c->pop_pack (false); } OT::cff2 *cff2 = c->allocate_min (); @@ -1228,7 +2022,11 @@ OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const { cff2_subset_plan cff2_plan; - if (unlikely (!cff2_plan.create (*this, c->plan))) return false; + if (unlikely (!cff2_plan.create (*this, c->plan))) + { + c->serializer->err (HB_SERIALIZE_ERROR_OTHER); + return false; + } // If instantiating (pinned) and downgrade flag is set, convert to CFF1 if (cff2_plan.pinned && (c->plan->flags & HB_SUBSET_FLAGS_DOWNGRADE_CFF2)) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-depend.h b/src/java.desktop/share/native/libharfbuzz/hb-subset-depend.h new file mode 100644 index 00000000000..9d784fc6258 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-depend.h @@ -0,0 +1,133 @@ +/* + * Copyright © 2024 Adobe, 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. + * + * Adobe Author(s): Skef Iterum + */ + +#ifndef HB_SUBSET_DEPEND_H +#define HB_SUBSET_DEPEND_H + +#if !defined(HB_SUBSET_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) +#error "Include instead." +#endif + +#include "hb.h" + +HB_BEGIN_DECLS + +/** + * hb_subset_depend_edge_flags_t: + * @HB_SUBSET_DEPEND_EDGE_FLAG_NONE: No flags set. + * @HB_SUBSET_DEPEND_EDGE_FLAG_FROM_CONTEXT_POSITION: Edge from a multi-position + * contextual rule (Context or ChainContext with inputCount > 1). Depend + * extraction records edges based on what glyphs could statically be at each + * position according to input coverage or class. However, at runtime lookups + * within the rule are applied sequentially: a lookup at an earlier position + * may transform the glyph at a later position, and two lookups at the same + * position may interact such that one produces a glyph that another + * immediately consumes as an "intermediate". A glyph that matches the static + * coverage may therefore not persist at that position when the rule actually + * fires, so this edge may not trigger during closure. + * @HB_SUBSET_DEPEND_EDGE_FLAG_FROM_NESTED_CONTEXT: Edge from a lookup invoked + * within another contextual lookup. The outer context's requirements are not + * propagated to this edge, so the edge may fire even when those requirements + * are not met. + * + * Flags on dependency edges returned by hb_subset_depend_lookup_glyph() that + * mark edges which may produce expected over-approximation when computing + * closure via the depend graph, relative to + * hb_ot_layout_lookups_substitute_closure(). These flags help distinguish + * known limitations of static dependency analysis (expected over-approximation) + * from bugs (unexpected over-approximation). + * + * Since: 14.3.0 + */ +typedef enum { /*< flags >*/ + HB_SUBSET_DEPEND_EDGE_FLAG_NONE = 0x00u, + HB_SUBSET_DEPEND_EDGE_FLAG_FROM_CONTEXT_POSITION = 0x01u, + HB_SUBSET_DEPEND_EDGE_FLAG_FROM_NESTED_CONTEXT = 0x02u, +} hb_subset_depend_edge_flags_t; +#define HB_SUBSET_DEPEND_EDGE_FLAGS_T_DEFINED +/* HB_MARK_AS_FLAG_T is applied in hb-depend-data.hh (internal header only) */ + +#ifndef HB_NO_SUBSET_DEPEND + +/** + * hb_subset_depend_t: + * + * Data type for holding glyph dependency graphs. + * + * Highly experimental API. Subject to change. + * + * Since: 14.3.0 + */ +typedef struct hb_subset_depend_t hb_subset_depend_t; + +/** + * hb_subset_depend_entry_t: + * @table_tag: Source table (e.g. GSUB, glyf, CFF, COLR, MATH). + * @dependent: Target glyph ID. + * @layout_tag: Feature tag for GSUB edges; 0 otherwise. + * @ligature_set_index: Index into the sets array for ligature component + * glyphs, or #HB_CODEPOINT_INVALID if not a ligature edge. + * @context_set_index: Index into the sets array for context requirement + * glyphs, or #HB_CODEPOINT_INVALID if none. Use hb_subset_depend_lookup_set() + * to retrieve the set. + * @flags: Edge flags (#hb_subset_depend_edge_flags_t). + * + * A single dependency edge returned by hb_subset_depend_lookup_glyph(). + * + * Since: 14.3.0 + */ +typedef struct { + hb_tag_t table_tag; + hb_codepoint_t dependent; + hb_tag_t layout_tag; + hb_codepoint_t ligature_set_index; + hb_codepoint_t context_set_index; + hb_subset_depend_edge_flags_t flags; +} hb_subset_depend_entry_t; + +HB_EXTERN hb_subset_depend_t * +hb_subset_depend_from_face_or_fail (hb_face_t *face); + +HB_EXTERN unsigned int +hb_subset_depend_lookup_glyph (hb_subset_depend_t *depend, + hb_codepoint_t gid, + unsigned int start_offset, + unsigned int *entry_count, /* IN/OUT */ + hb_subset_depend_entry_t *entries /* OUT */); + +HB_EXTERN hb_bool_t +hb_subset_depend_lookup_set (hb_subset_depend_t *depend, + hb_codepoint_t index, + hb_set_t *out /* OUT */); + +HB_EXTERN void +hb_subset_depend_destroy (hb_subset_depend_t *depend); + +#endif + +HB_END_DECLS + +#endif /* HB_SUBSET_DEPEND_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc index 5de29081cc1..47d8e63ab34 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc @@ -128,6 +128,7 @@ hb_subset_input_t::hb_subset_input_t () HB_TAG ('v', 'c', 'h', 'w'), HB_TAG ('h', 'a', 'l', 't'), HB_TAG ('v', 'h', 'a', 'l'), + HB_TAG ('p', 'a', 'l', 't'), //private HB_TAG ('H', 'a', 'r', 'f'), @@ -425,8 +426,7 @@ hb_subset_input_keep_everything (hb_subset_input_t *input) * * Pin all axes to default locations in the given subset input object. * - * All axes in a font must be pinned. Additionally, `CFF2` table, if present, - * will be de-subroutinized. + * The `CFF2` table, if present, will be de-subroutinized. * * Return value: `true` if success, `false` otherwise * @@ -466,8 +466,7 @@ hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input, * * Pin an axis to its default location in the given subset input object. * - * All axes in a font must be pinned. Additionally, `CFF2` table, if present, - * will be de-subroutinized. + * The `CFF2` table, if present, will be de-subroutinized. * * Return value: `true` if success, `false` otherwise * @@ -495,8 +494,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, * * Pin an axis to a fixed location in the given subset input object. * - * All axes in a font must be pinned. Additionally, `CFF2` table, if present, - * will be de-subroutinized. + * The `CFF2` table, if present, will be de-subroutinized. * * Return value: `true` if success, `false` otherwise * @@ -665,7 +663,8 @@ hb_subset_axis_range_from_string (const char *str, int len, } double v; - if (!hb_parse_double (&str, part, &v)) return false; + const char *piece_end = part ? part : end; + if (!hb_parse_double (&str, piece_end, &v)) return false; values[i] = v; if (part == NULL) break; @@ -736,6 +735,374 @@ hb_subset_axis_range_to_string (hb_subset_input_t *input, } #endif +#ifdef HB_EXPERIMENTAL_API +static void +_append_arg (hb_vector_t &sb, const char *arg) +{ + if (sb.in_error ()) return; + if (sb.length) + sb.push (' '); + unsigned len = strlen (arg); + sb.extend (hb_bytes_t (arg, len)); +} +static void +_format_number_set (const hb_set_t *set, hb_vector_t &out, unsigned base = 10) +{ + assert (base == 10 || base == 16); + if (unlikely (base != 10 && base != 16)) return; + + hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID; + bool first_range = true; + while (hb_set_next_range (set, &first, &last)) + { + if (!first_range) + out.push (','); + first_range = false; + + char buf[64]; + int len; + if (first == last) + { + if (base == 16) + len = snprintf (buf, sizeof (buf), "%X", first); + else + len = snprintf (buf, sizeof (buf), "%u", first); + } + else + { + if (base == 16) + len = snprintf (buf, sizeof (buf), "%X-%X", first, last); + else + len = snprintf (buf, sizeof (buf), "%u-%u", first, last); + } + if (unlikely (len < 0 || (size_t) len >= sizeof (buf))) return; + out.extend (hb_bytes_t (buf, len)); + } +} + +static void +_format_tag (hb_tag_t tag, hb_vector_t &out) +{ + char buf[4]; + hb_tag_to_string (tag, buf); + + unsigned len = 4; + while (len > 0 && buf[len - 1] == ' ') + len--; + + for (unsigned i = 0; i < len; i++) + { + char c = buf[i]; + if (!((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || c == '_')) + { + c = '_'; + } + out.push (c); + } +} + +static void +_format_tag_set (const hb_set_t *set, hb_vector_t &out) +{ + bool first_tag = true; + for (hb_codepoint_t tag : *set) + { + if (!first_tag) + out.push (','); + first_tag = false; + + _format_tag (tag, out); + } +} + +static bool +_is_set_default (const hb_set_t *set, const hb_set_t *default_set) +{ + return hb_set_is_inverted (set) == hb_set_is_inverted (default_set) && + hb_set_is_equal (set, default_set); +} + +template +static void +_format_set_arg (const hb_set_t *set, + const char *opt_name, + Formatter &&formatter, + hb_vector_t &sb) +{ + if (hb_set_is_inverted (set)) + { + hb_set_t *excluded = hb_set_copy (set); + hb_set_invert (excluded); + + hb_vector_t opt; + opt.extend (hb_bytes_t ("--", 2)); + opt.extend (hb_bytes_t (opt_name, strlen (opt_name))); + opt.extend (hb_bytes_t ("=*", 2)); + opt.push ('\0'); + if (opt.arrayZ) _append_arg (sb, opt.arrayZ); + + if (!hb_set_is_empty (excluded)) + { + hb_vector_t formatted; + formatter (excluded, formatted); + if (formatted.length) + { + hb_vector_t opt2; + opt2.extend (hb_bytes_t ("--", 2)); + opt2.extend (hb_bytes_t (opt_name, strlen (opt_name))); + opt2.extend (hb_bytes_t ("-=", 2)); + opt2.extend (formatted.as_array ()); + opt2.push ('\0'); + if (opt2.arrayZ) _append_arg (sb, opt2.arrayZ); + } + } + hb_set_destroy (excluded); + } + else if (hb_set_is_empty (set)) + { + hb_vector_t opt; + opt.extend (hb_bytes_t ("--", 2)); + opt.extend (hb_bytes_t (opt_name, strlen (opt_name))); + opt.extend (hb_bytes_t ("-=*", 3)); + opt.push ('\0'); + if (opt.arrayZ) _append_arg (sb, opt.arrayZ); + } + else + { + hb_vector_t formatted; + formatter (set, formatted); + if (formatted.length) + { + hb_vector_t opt; + opt.extend (hb_bytes_t ("--", 2)); + opt.extend (hb_bytes_t (opt_name, strlen (opt_name))); + opt.extend (hb_bytes_t ("=", 1)); + opt.extend (formatted.as_array ()); + opt.push ('\0'); + if (opt.arrayZ) _append_arg (sb, opt.arrayZ); + } + } +} + +static void +_format_number_set_arg (const hb_set_t *set, + const char *opt_name, + hb_vector_t &sb, + unsigned base = 10) +{ + _format_set_arg (set, opt_name, [base] (const hb_set_t *s, hb_vector_t &out) { + _format_number_set (s, out, base); + }, sb); +} + +static void +_format_tag_set_arg (const hb_set_t *set, + const char *opt_name, + hb_vector_t &sb) +{ + _format_set_arg (set, opt_name, _format_tag_set, sb); +} + +static bool +_format_glyph_map_arg (const hb_map_t &glyph_map, + hb_vector_t &sb) +{ + if (glyph_map.is_empty ()) + return true; + + hb_set_t keys; + hb_map_keys (&glyph_map, &keys); + hb_vector_t pairs; + bool first = true; + for (hb_codepoint_t key : keys) + { + if (!first) + pairs.push (','); + first = false; + hb_codepoint_t val = hb_map_get (&glyph_map, key); + char buf[64]; + int len = snprintf (buf, sizeof (buf), "%u:%u", key, val); + if (unlikely (len < 0 || (size_t) len >= sizeof (buf))) return false; + pairs.extend (hb_bytes_t (buf, len)); + } + if (pairs.length) + { + hb_vector_t opt; + opt.extend (hb_bytes_t ("--gid-map=", 10)); + opt.extend (pairs.as_array ()); + opt.push ('\0'); + if (opt.arrayZ) _append_arg (sb, opt.arrayZ); + } + return true; +} + +static bool +_format_axes_location_arg (const hb_hashmap_t &axes_location, + hb_vector_t &sb) +{ + if (axes_location.is_empty ()) + return true; + + hb_vector_t axis_tags; + for (auto tag : axes_location.keys ()) + axis_tags.push (tag); + axis_tags.qsort ([] (const hb_tag_t &a, const hb_tag_t &b) { return a < b ? -1 : a > b ? 1 : 0; }); + + hb_vector_t specs; + bool first = true; + for (hb_tag_t tag : axis_tags) + { + Triple triple = axes_location.get (tag); + if (!first) + specs.push (','); + first = false; + + hb_vector_t tag_buf; + _format_tag (tag, tag_buf); + + char buf[128]; + int len; + if (triple.minimum == triple.middle && triple.middle == triple.maximum) + { + len = snprintf (buf, sizeof (buf), "%.*s=%g", (int) tag_buf.length, tag_buf.arrayZ, (double) triple.middle); + } + else if (std::isnan (triple.minimum) && std::isnan (triple.middle) && std::isnan (triple.maximum)) + { + len = snprintf (buf, sizeof (buf), "%.*s=drop", (int) tag_buf.length, tag_buf.arrayZ); + } + else + { + len = snprintf (buf, sizeof (buf), "%.*s=%g:%g:%g", (int) tag_buf.length, tag_buf.arrayZ, + (double) triple.minimum, (double) triple.middle, (double) triple.maximum); + } + if (unlikely (len < 0 || (size_t) len >= sizeof (buf))) return false; + specs.extend (hb_bytes_t (buf, len)); + } + if (specs.length) + { + hb_vector_t opt; + opt.extend (hb_bytes_t ("--variations=", 13)); + opt.extend (specs.as_array ()); + opt.push ('\0'); + if (opt.arrayZ) _append_arg (sb, opt.arrayZ); + } + return true; +} + +/** + * hb_subset_input_to_string_or_fail: + * @input: a #hb_subset_input_t object. + * + * Produces a command line string representation of the given subset input + * suitable for use with the `hb-subset` command line tool. + * + * Return value: (transfer full): A new #hb_blob_t containing the command line + * string, or `NULL` if failed. Destroy with hb_blob_destroy(). + * + * XSince: EXPERIMENTAL + **/ +hb_blob_t * +hb_subset_input_to_string_or_fail (hb_subset_input_t *input) +{ + if (unlikely (!input || input->in_error ())) + return nullptr; + + hb_vector_t sb; + + struct flag_option_t { + hb_subset_flags_t flag; + char option[32]; + }; + static const flag_option_t flag_options[] = { + { HB_SUBSET_FLAGS_NO_HINTING, "no-hinting" }, + { HB_SUBSET_FLAGS_RETAIN_GIDS, "retain-gids" }, + { HB_SUBSET_FLAGS_DESUBROUTINIZE, "desubroutinize" }, + { HB_SUBSET_FLAGS_NAME_LEGACY, "name-legacy" }, + { HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG, "set-overlaps-flag" }, + { HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED, "passthrough-tables" }, + { HB_SUBSET_FLAGS_NOTDEF_OUTLINE, "notdef-outline" }, + { HB_SUBSET_FLAGS_GLYPH_NAMES, "glyph-names" }, + { HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES, "no-prune-unicode-ranges" }, + { HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE, "no-layout-closure" }, + { HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS, "optimize" }, + { HB_SUBSET_FLAGS_NO_BIDI_CLOSURE, "no-bidi-closure" }, +#ifdef HB_EXPERIMENTAL_API + { HB_SUBSET_FLAGS_IFTB_REQUIREMENTS, "iftb-requirements" }, + { HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS, "retain-num-glyphs" }, +#endif + { HB_SUBSET_FLAGS_DOWNGRADE_CFF2, "downgrade-cff2" }, + }; + +#ifdef HB_EXPERIMENTAL_API + static_assert (sizeof (flag_options) / sizeof (flag_options[0]) == 15, + "Check all flags in hb_subset_flags_t are handled here."); +#else + static_assert (sizeof (flag_options) / sizeof (flag_options[0]) == 13, + "Check all flags in hb_subset_flags_t are handled here."); +#endif + + for (const auto &fo : flag_options) + { + if (input->flags & fo.flag) + { + char buf[36]; + snprintf (buf, sizeof (buf), "--%s", fo.option); + _append_arg (sb, buf); + } + } + + hb_subset_input_t *default_input = hb_subset_input_create_or_fail (); + if (unlikely (!default_input)) + return nullptr; + + // Serialize all sets if they are not equal to their default setting: +#define PROCESS_NUMBER_SET(field, opt_name, ...) \ + if (!_is_set_default (input->sets.field, default_input->sets.field)) \ + _format_number_set_arg (input->sets.field, opt_name, sb, ##__VA_ARGS__) + +#define PROCESS_TAG_SET(field, opt_name) \ + if (!_is_set_default (input->sets.field, default_input->sets.field)) \ + _format_tag_set_arg (input->sets.field, opt_name, sb) + + PROCESS_NUMBER_SET (unicodes, "unicodes", 16); + PROCESS_NUMBER_SET (glyphs, "gids"); + PROCESS_NUMBER_SET (name_ids, "name-IDs"); + PROCESS_NUMBER_SET (name_languages, "name-languages"); + PROCESS_TAG_SET (layout_features, "layout-features"); + PROCESS_TAG_SET (layout_scripts, "layout-scripts"); + PROCESS_TAG_SET (drop_tables, "drop-tables"); + PROCESS_TAG_SET (no_subset_tables, "passthrough-tables"); + +#undef PROCESS_NUMBER_SET +#undef PROCESS_TAG_SET + + hb_subset_input_destroy (default_input); + + static_assert (sizeof (input->sets) / sizeof (hb_set_t*) == 8, + "Check all sets in hb_subset_input_t::sets_t are handled here."); + + if (unlikely (!_format_glyph_map_arg (input->glyph_map, sb))) + return nullptr; + + if (unlikely (!_format_axes_location_arg (input->axes_location, sb))) + return nullptr; + + sb.push ('\0'); + if (unlikely (sb.in_error ())) + return nullptr; + + unsigned len = 0; + char *buf = sb.steal (&len); + if (unlikely (!buf)) + return nullptr; + + return hb_blob_create_or_fail (buf, len, HB_MEMORY_MODE_WRITABLE, buf, hb_free); +} +#endif + /** * hb_subset_preprocess: * @source: a #hb_face_t object. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc index 78aab09c651..e430f255fea 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc @@ -32,28 +32,28 @@ * This should be safe. */ -constexpr static double EPSILON = 1.0 / (1 << 14); -constexpr static double MAX_F2DOT14 = double (0x7FFF) / (1 << 14); +constexpr static float EPSILON = 1.f / (1 << 14); +constexpr static float MAX_F2DOT14 = float (0x7FFF) / (1 << 14); static inline Triple _reverse_negate(const Triple &v) { return {-v.maximum, -v.middle, -v.minimum}; } -static inline double supportScalar (double coord, const Triple &tent) +static inline float supportScalar (float coord, const Triple &tent) { /* Copied from VarRegionAxis::evaluate() */ - double start = tent.minimum, peak = tent.middle, end = tent.maximum; + float start = tent.minimum, peak = tent.middle, end = tent.maximum; if (unlikely (start > peak || peak > end)) - return 1.; + return 1.f; if (unlikely (start < 0 && end > 0 && peak != 0)) - return 1.; + return 1.f; if (peak == 0 || coord == peak) - return 1.; + return 1.f; if (coord <= start || end <= coord) - return 0.; + return 0.f; /* Interpolate */ if (coord < peak) @@ -66,12 +66,12 @@ static inline void _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative = false) { out.reset(); - double axisMin = axisLimit.minimum; - double axisDef = axisLimit.middle; - double axisMax = axisLimit.maximum; - double lower = tent.minimum; - double peak = tent.middle; - double upper = tent.maximum; + float axisMin = axisLimit.minimum; + float axisDef = axisLimit.middle; + float axisMax = axisLimit.maximum; + float lower = tent.minimum; + float peak = tent.middle; + float upper = tent.maximum; // Mirror the problem such that axisDef <= peak if (axisDef > peak) @@ -129,7 +129,7 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative */ if (axisMax < peak) { - double mult = supportScalar (axisMax, tent); + float mult = supportScalar (axisMax, tent); tent = Triple{lower, axisMax, axisMax}; _solve (tent, axisLimit, out); @@ -142,13 +142,13 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative // lower <= axisDef <= peak <= axisMax - double gain = supportScalar (axisDef, tent); + float gain = supportScalar (axisDef, tent); out.push(hb_pair (gain, Triple{})); // First, the positive side // outGain is the scalar of axisMax at the tent. - double outGain = supportScalar (axisMax, tent); + float outGain = supportScalar (axisMax, tent); /* Case 3a: Gain is more than outGain. The tent down-slope crosses * the axis into negative. We have to split it into multiples. @@ -172,10 +172,10 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative // Note that this is the branch taken if both gain and outGain are 0. // Crossing point on the axis. - double crossing = peak + (1 - gain) * (upper - peak); + float crossing = peak + (1 - gain) * (upper - peak); Triple loc{hb_max (lower, axisDef), peak, crossing}; - double scalar = 1.0; + float scalar = 1.f; // The part before the crossing point. out.push (hb_pair (scalar - gain, loc)); @@ -190,7 +190,7 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative if (upper >= axisMax) { Triple loc {crossing, axisMax, axisMax}; - double scalar = outGain; + float scalar = outGain; out.push (hb_pair (scalar - gain, loc)); } @@ -220,11 +220,11 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative // Downslope. Triple loc1 {crossing, upper, axisMax}; - double scalar1 = 0.0; + float scalar1 = 0.f; // Eternity justify. Triple loc2 {upper, axisMax, axisMax}; - double scalar2 = 0.0; + float scalar2 = 0.f; out.push (hb_pair (scalar1 - gain, loc1)); out.push (hb_pair (scalar2 - gain, loc2)); @@ -253,7 +253,7 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative * | | newUpper * axisDef axisMax */ - double newUpper = peak + (1 - gain) * (upper - peak); + float newUpper = peak + (1 - gain) * (upper - peak); assert (axisMax <= newUpper); // Because outGain > gain /* Disabled because ots doesn't like us: * https://github.com/fonttools/fonttools/issues/3350 */ @@ -269,7 +269,7 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative } Triple loc {hb_max (axisDef, lower), peak, upper}; - double scalar = 1.0; + float scalar = 1.f; out.push (hb_pair (scalar - gain, loc)); } @@ -293,10 +293,10 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative else { Triple loc1 {hb_max (axisDef, lower), peak, axisMax}; - double scalar1 = 1.0; + float scalar1 = 1.f; Triple loc2 {peak, axisMax, axisMax}; - double scalar2 = outGain; + float scalar2 = outGain; out.push (hb_pair (scalar1 - gain, loc1)); // Don't add a dirac delta! @@ -324,7 +324,7 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative if (lower <= axisMin) { Triple loc {axisMin, axisMin, axisDef}; - double scalar = supportScalar (axisMin, tent); + float scalar = supportScalar (axisMin, tent); out.push (hb_pair (scalar - gain, loc)); } @@ -352,11 +352,11 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative // Downslope. Triple loc1 {axisMin, lower, axisDef}; - double scalar1 = 0.0; + float scalar1 = 0.f; // Eternity justify. Triple loc2 {axisMin, axisMin, lower}; - double scalar2 = 0.0; + float scalar2 = 0.f; out.push (hb_pair (scalar1 - gain, loc1)); out.push (hb_pair (scalar2 - gain, loc2)); @@ -366,48 +366,48 @@ _solve (Triple tent, Triple axisLimit, rebase_tent_result_t &out, bool negative static inline TripleDistances _reverse_triple_distances (const TripleDistances &v) { return TripleDistances (v.positive, v.negative); } -double renormalizeValue (double v, const Triple &triple, +float renormalizeValue (float v, const Triple &triple, const TripleDistances &triple_distances, bool extrapolate) { - double lower = triple.minimum, def = triple.middle, upper = triple.maximum; + float lower = triple.minimum, def = triple.middle, upper = triple.maximum; if (unlikely (!(lower <= def && def <= upper))) - return hb_clamp (v, -1.0, +1.0); + return hb_clamp (v, -1.f, +1.f); if (!extrapolate) v = hb_clamp (v, lower, upper); if (v == def) - return 0.0; + return 0.f; - if (def < 0.0) + if (def < 0.f) return -renormalizeValue (-v, _reverse_negate (triple), _reverse_triple_distances (triple_distances), extrapolate); /* default >= 0 and v != default */ if (v > def) { - double positive_range = upper - def; + float positive_range = upper - def; if (unlikely (!positive_range)) - return +1.0; + return +1.f; return (v - def) / positive_range; } /* v < def */ - if (lower >= 0.0) + if (lower >= 0.f) { - double negative_range = def - lower; + float negative_range = def - lower; if (unlikely (!negative_range)) - return -1.0; + return -1.f; return (v - def) / negative_range; } /* lower < 0 and v < default */ - double total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def; + float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def; if (unlikely (!total_distance)) - return 0.0; + return 0.f; - double v_distance; - if (v >= 0.0) + float v_distance; + if (v >= 0.f) v_distance = (def - v) * triple_distances.positive; else v_distance = (-v) * triple_distances.negative + triple_distances.positive * def; @@ -420,15 +420,15 @@ rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distance rebase_tent_result_t &out, rebase_tent_result_t &scratch) { - if (unlikely (!(-1.0 <= axisLimit.minimum && + if (unlikely (!(-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && - axisLimit.maximum <= +1.0) || - !(-2.0 <= tent.minimum && + axisLimit.maximum <= +1.f) || + !(-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && - tent.maximum <= +2.0) || - tent.middle == 0.0)) + tent.maximum <= +2.f) || + tent.middle == 0.f)) { out.reset (); return; @@ -437,7 +437,7 @@ rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distance rebase_tent_result_t &sols = scratch; _solve (tent, axisLimit, sols); - auto n = [&axisLimit, &axis_triple_distances] (double v) { return renormalizeValue (v, axisLimit, axis_triple_distances); }; + auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); }; out.reset(); for (auto &p : sols) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh index 574d58d53d8..6ea13ca156e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.hh @@ -30,23 +30,23 @@ /* pre-normalized distances */ struct TripleDistances { - TripleDistances (): negative (1.0), positive (1.0) {} - TripleDistances (double neg_, double pos_): negative (neg_), positive (pos_) {} - TripleDistances (double min, double default_, double max) + TripleDistances (): negative (1.f), positive (1.f) {} + TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {} + TripleDistances (float min, float default_, float max) { negative = default_ - min; positive = max - default_; } - double negative; - double positive; + float negative; + float positive; }; struct Triple { Triple () = default; - Triple (double minimum_, double middle_, double maximum_) : + Triple (float minimum_, float middle_, float maximum_) : minimum (minimum_), middle (middle_), maximum (maximum_) {} bool operator == (const Triple &o) const @@ -62,7 +62,7 @@ struct Triple bool is_point () const { return minimum == middle && middle == maximum; } - bool contains (double point) const + bool contains (float point) const { return minimum <= point && point <= maximum; } /* from hb_array_t hash ()*/ @@ -80,18 +80,18 @@ struct Triple return current; } - double minimum = 0; - double middle = 0; - double maximum = 0; + float minimum = 0; + float middle = 0; + float maximum = 0; }; -using rebase_tent_result_item_t = hb_pair_t; +using rebase_tent_result_item_t = hb_pair_t; using rebase_tent_result_t = hb_vector_t; /* renormalize a normalized value v to the range of an axis, * considering the prenormalized distances as well as the new axis limits. * Ported from fonttools */ -HB_INTERNAL double renormalizeValue (double v, const Triple &triple, +HB_INTERNAL float renormalizeValue (float v, const Triple &triple, const TripleDistances &triple_distances, bool extrapolate = true); /* Given a tuple (lower,peak,upper) "tent" and new axis limits diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh index 398fe81eca9..dab9fac5f33 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan-member-list.hh @@ -61,10 +61,17 @@ HB_SUBSET_PLAN_MEMBER (hb_set_t, drop_tables) // Old -> New glyph id mapping HB_SUBSET_PLAN_MEMBER (hb_map_t, glyph_map_gsub) +// Same mapping as glyph_map_gsub, as a flat array indexed by old gid, +// with HB_MAP_VALUE_INVALID entries for glyphs not retained. Sized to +// the highest retained GSUB gid plus one. +HB_SUBSET_PLAN_MEMBER (hb_vector_t, glyph_map_gsub_flat) + HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset) HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_gsub) HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_mathed) HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_colred) +HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_varced) +HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_cmaped) //active lookups we'd like to retain HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_lookups) @@ -94,12 +101,16 @@ HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gpo HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), gsub_feature_substitutes_map) HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), gpos_feature_substitutes_map) +//feature index->resolved lookup set mapping for fully-instanced lookup variations +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gsub_lookup_variations) +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gpos_lookup_variations) + // old feature_indexes set, used to reinstate the old features HB_SUBSET_PLAN_MEMBER (hb_set_t, gsub_old_features) HB_SUBSET_PLAN_MEMBER (hb_set_t, gpos_old_features) -//feature_index->pair of (address of old feature, feature tag), used for inserting a catch all record -//if necessary +//feature_index->pair of (address of old feature, feature tag), used for alternate feature +//parameter formats and inserting a catch all record if necessary HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E()>), gsub_old_feature_idx_tag_map) HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E()>), gpos_old_feature_idx_tag_map) @@ -116,6 +127,11 @@ HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_new_deltaset_idx_varidx_map) //Old layout item variation index -> (New varidx, delta) mapping HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E()>), layout_variation_idx_delta_map) +//Layout condition -> (source variation index, default value) +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E()>), layout_condition_values) +//Layout condition -> (private variation index, rescaled default value) +HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E()>), layout_condition_idx_value_map) + //gdef varstore retained varidx mapping HB_SUBSET_PLAN_MEMBER (hb_vector_t, gdef_varstore_inner_maps) @@ -133,6 +149,20 @@ HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), axes_triple_ //retained old axis index -> new axis index mapping in fvar axis array HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map) +//old intermediate coords (post-fvar, post-avar-v1, pre-avar-v2) at new min/default/max +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), old_intermediates) + +//avar2: reachable old-space final-coord range per axis, as Triple +//(minimum, unused middle, maximum), F2Dot14-quantized. Only axes with a +//constraining range (narrower than [-1, +1]) have entries. Used to cull +//variation tuples/regions that a partial instance can never reach. +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), avar2_reachable_ranges) + +//avar2: self-contained pinned axes -> constant old-space final coord. +//These axes are removed from fvar/avar entirely; their contribution is +//baked into the variation tables like an ordinary pin at that coord. +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), avar2_self_contained) + //axis_index->axis_tag mapping in fvar axis array HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_old_index_tag_map) //vector of retained axis tags in the order of axes given in the 'fvar' table diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc index 8c3fd97899b..77479861ffb 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc @@ -41,6 +41,7 @@ #include "OT/Color/COLR/colrv1-closure.hh" #include "OT/Color/CPAL/CPAL.hh" #include "hb-ot-var-fvar-table.hh" +#include "hb-ot-var-varc-table.hh" #include "hb-ot-stat-table.hh" #include "hb-ot-math-table.hh" @@ -104,8 +105,8 @@ _cmap_closure (hb_face_t *face, const hb_set_t *unicodes, hb_set_t *glyphset) { - OT::cmap::accelerator_t cmap (face); - cmap.table->closure_glyphs (unicodes, glyphset); + OT::cmap_accelerator_t cmap (face); + cmap.closure_glyphs (unicodes, glyphset); } static void _colr_closure (hb_subset_plan_t* plan, @@ -131,13 +132,6 @@ static void _colr_closure (hb_subset_plan_t* plan, _remap_palette_indexes (&palette_indices, &plan->colr_palettes); #ifndef HB_NO_VAR - if (!colr.has_var_store () || !variation_indices) return; - - const OT::ItemVariationStore &var_store = colr.get_var_store (); - // generated inner_maps is used by ItemVariationStore serialize(), which is subset only - unsigned subtable_count = var_store.get_sub_table_count (); - generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps); - /* colr variation indices mapping during planning phase: * generate colrv1_variation_idx_delta_map. When delta set index map is not * included, it's a mapping from varIdx-> (new varIdx,delta). Otherwise, it's @@ -146,21 +140,29 @@ static void _colr_closure (hb_subset_plan_t* plan, * Besides, we need to generate a delta set idx-> new var_idx map for updating * delta set index map if exists. This map will be updated again after * instancing. */ - if (!plan->all_axes_pinned) + if (colr.has_var_store () && variation_indices) { - remap_variation_indices (var_store, + const OT::ItemVariationStore &var_store = colr.get_var_store (); + // generated inner_maps is used by ItemVariationStore serialize(), which is subset only + unsigned subtable_count = var_store.get_sub_table_count (); + generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps); + + if (!plan->all_axes_pinned) + remap_variation_indices (var_store, variation_indices, plan->normalized_coords, false, /* no need to calculate delta for COLR during planning */ plan->all_axes_pinned, plan->colrv1_variation_idx_delta_map); - - if (colr.has_delta_set_index_map ()) - remap_colrv1_delta_set_index_indices (colr.get_delta_set_index_map (), - delta_set_indices, - plan->colrv1_variation_idx_delta_map, - plan->colrv1_new_deltaset_idx_varidx_map); } + + /* Sentinel-only maps still need their delta-set indices remapped, even + * when there are no live variation rows or no variation store. */ + if (!plan->all_axes_pinned && colr.has_delta_set_index_map ()) + remap_colrv1_delta_set_index_indices (colr.get_delta_set_index_map (), + delta_set_indices, + plan->colrv1_variation_idx_delta_map, + plan->colrv1_new_deltaset_idx_varidx_map); #endif } @@ -247,7 +249,7 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes_in, hb_set_t unicodes = _unicode_closure(unicodes_in, !(plan->flags & HB_SUBSET_FLAGS_NO_BIDI_CLOSURE)); - OT::cmap::accelerator_t cmap (plan->source); + OT::cmap_accelerator_t cmap (plan->source); unsigned size_threshold = plan->source->get_num_glyphs (); if (glyphs->is_empty () && unicodes.get_population () < size_threshold) @@ -405,7 +407,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf, for (auto &item : glyph.get_composite_iterator ()) operation_count = _glyf_add_gid_and_children (glyf, - item.get_gid (), + item.get_gid (glyph.is_extended ()), gids_to_retain, operation_count, depth); @@ -451,6 +453,14 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, plan->_glyphset_gsub.add (0); // Not-def _cmap_closure (plan->source, &plan->unicodes, &plan->_glyphset_gsub); + plan->_glyphset_cmaped = plan->_glyphset_gsub; + + if (!drop_tables->has (HB_OT_TAG_MATH)) + { + _math_closure (plan, &plan->_glyphset_gsub); + _remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ()); + } + plan->_glyphset_mathed = plan->_glyphset_gsub; #ifndef HB_NO_SUBSET_LAYOUT layout_populate_gids_to_retain(plan, drop_tables); @@ -458,14 +468,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ()); - plan->_glyphset_mathed = plan->_glyphset_gsub; - if (!drop_tables->has (HB_OT_TAG_MATH)) - { - _math_closure (plan, &plan->_glyphset_mathed); - _remove_invalid_gids (&plan->_glyphset_mathed, plan->source->get_num_glyphs ()); - } - - hb_set_t cur_glyphset = plan->_glyphset_mathed; + hb_set_t cur_glyphset = plan->_glyphset_gsub; if (!drop_tables->has (HB_OT_TAG_COLR)) { _colr_closure (plan, &cur_glyphset); @@ -474,7 +477,19 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, plan->_glyphset_colred = cur_glyphset; - // XXX TODO VARC closure / subset +#ifndef HB_NO_VAR_COMPOSITES + if (!drop_tables->has (OT::VARC::tableTag)) + { + if (unlikely (!plan->source->table.VARC->closure_glyphs (&cur_glyphset))) + { + plan->check_success (false); + return; + } + _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); + } +#endif + + plan->_glyphset_varced = cur_glyphset; _nameid_closure (plan, drop_tables); /* Populate a full set of glyphs to retain by adding all referenced @@ -507,18 +522,30 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, #endif } -static void +static bool _create_glyph_map_gsub (const hb_set_t* glyph_set_gsub, const hb_map_t* glyph_map, - hb_map_t* out) + hb_map_t* out, + hb_vector_t* out_flat) { + if (unlikely (glyph_set_gsub->in_error ())) + return false; + + hb_codepoint_t max_gid = HB_SET_VALUE_INVALID; + hb_set_previous (glyph_set_gsub, &max_gid); + unsigned flat_size = max_gid == HB_SET_VALUE_INVALID ? 0 : max_gid + 1; + if (unlikely (!out_flat->resize_dirty (flat_size))) + return false; + hb_memset (out_flat->arrayZ, 0xFF, flat_size * sizeof (hb_codepoint_t)); + out->alloc (glyph_set_gsub->get_population ()); - + hb_iter (glyph_set_gsub) - | hb_map ([&] (hb_codepoint_t gid) { - return hb_codepoint_pair_t (gid, glyph_map->get (gid)); - }) - | hb_sink (out) - ; + for (auto gid : *glyph_set_gsub) + { + hb_codepoint_t new_gid = glyph_map->get (gid); + out->set (gid, new_gid); + out_flat->arrayZ[gid] = new_gid; + } + return !out->in_error (); } static bool @@ -647,6 +674,7 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, all_axes_pinned = false; pinned_at_default = true; has_gdef_varstore = false; + has_avar2 = false; #ifdef HB_EXPERIMENTAL_API for (auto _ : input->name_table_overrides) @@ -676,10 +704,31 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, if (unlikely (in_error ())) return; +#ifndef HB_NO_VAR_COMPOSITES + if (!input->sets.drop_tables->has (OT::VARC::tableTag) && + input->sets.no_subset_tables->has (OT::VARC::tableTag) && + !(input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) && + face->table.VARC->has_data ()) + { + check_success (false); + return; + } +#endif + #ifndef HB_NO_VAR if (!check_success (normalize_axes_location (face, this))) return; #endif +#ifndef HB_NO_VAR_COMPOSITES + if (!user_axes_location.is_empty () && + !input->sets.drop_tables->has (OT::VARC::tableTag) && + input->sets.no_subset_tables->has (OT::VARC::tableTag) && + face->table.VARC->has_data ()) + { + check_success (false); + return; + } +#endif _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this); @@ -708,10 +757,12 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, } #endif - _create_glyph_map_gsub ( + if (!check_success (_create_glyph_map_gsub ( &_glyphset_gsub, glyph_map, - &glyph_map_gsub); + &glyph_map_gsub, + &glyph_map_gsub_flat))) + return; // Now that we have old to new gid map update the unicode to new gid list. for (unsigned i = 0; i < unicode_to_new_gid_list.length; i++) @@ -743,8 +794,10 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, if (unlikely (in_error ())) return; -#ifndef HB_NO_VAR +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_CFF) update_instance_metrics_map_from_cff2 (this); +#endif +#ifndef HB_NO_VAR if (!check_success (get_instance_glyphs_contour_points (this))) return; #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh index 0362ed7292e..82664de9b4c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh @@ -169,6 +169,9 @@ struct hb_subset_plan_t // whether GDEF ItemVariationStore is retained mutable bool has_gdef_varstore; + // whether we're doing avar2 partial instancing + bool has_avar2; + #define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name; #include "hb-subset-plan-member-list.hh" #undef HB_SUBSET_PLAN_MEMBER @@ -178,8 +181,8 @@ struct hb_subset_plan_t os2_info_t os2_info; - const hb_subset_accelerator_t* accelerator; - hb_subset_accelerator_t* inprogress_accelerator; + const hb_subset_accelerator_t* accelerator = nullptr; + hb_subset_accelerator_t* inprogress_accelerator = nullptr; public: @@ -212,6 +215,8 @@ struct hb_subset_plan_t bool in_error () const { return !successful; } + HB_INTERNAL double layout_variation_delta (unsigned var_idx); + bool check_success(bool success) { successful = (successful && success); @@ -238,6 +243,18 @@ struct hb_subset_plan_t return &_glyphset_gsub; } + /* + * Old-to-new glyph id mapping for GSUB glyphs, through the flat + * array; returns HB_MAP_VALUE_INVALID for glyphs not retained. + */ + inline hb_codepoint_t + map_gsub_glyph (hb_codepoint_t old_gid) const + { + return old_gid < glyph_map_gsub_flat.length + ? glyph_map_gsub_flat.arrayZ[old_gid] + : HB_MAP_VALUE_INVALID; + } + /* * The total number of output glyphs in the final subset. */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-serialize.h b/src/java.desktop/share/native/libharfbuzz/hb-subset-serialize.h index 9035d4ced7a..a3ca3bfbae6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-serialize.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-serialize.h @@ -26,6 +26,11 @@ #ifndef HB_SUBSET_SERIALIZE_H #define HB_SUBSET_SERIALIZE_H +#if !defined(HB_SUBSET_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) +// Disabled to not break pre-existing users. +//#error "Include instead." +#endif + #include "hb.h" HB_BEGIN_DECLS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc index 51134ed09ce..dc26b795901 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc @@ -90,20 +90,38 @@ static hb_tag_t known_tables[] { HB_TAG('g','a','s','p'), HB_TAG('G','D','E','F'), HB_TAG('g','l','y','f'), +#ifndef HB_NO_BEYOND_64K + HB_TAG('G','L','Y','F'), +#endif HB_TAG('G','P','O','S'), HB_TAG('G','S','U','B'), HB_TAG('g','v','a','r'), +#ifndef HB_NO_BEYOND_64K + HB_TAG('G','V','A','R'), +#endif HB_TAG('h','d','m','x'), HB_TAG('h','e','a','d'), HB_TAG('h','h','e','a'), +#ifndef HB_NO_BEYOND_64K + HB_TAG('H','H','E','A'), +#endif HB_TAG('h','m','t','x'), +#ifndef HB_NO_BEYOND_64K + HB_TAG('H','M','T','X'), +#endif HB_TAG('H','V','A','R'), HB_TAG('J','S','T','F'), HB_TAG('k','e','r','n'), HB_TAG('l','o','c','a'), +#ifndef HB_NO_BEYOND_64K + HB_TAG('L','O','C','A'), +#endif HB_TAG('L','T','S','H'), HB_TAG('M','A','T','H'), HB_TAG('m','a','x','p'), +#ifndef HB_NO_BEYOND_64K + HB_TAG('M','A','X','P'), +#endif HB_TAG('M','E','R','G'), HB_TAG('m','e','t','a'), HB_TAG('M','V','A','R'), @@ -115,8 +133,15 @@ static hb_tag_t known_tables[] { HB_TAG('S','V','G',' '), HB_TAG('V','D','M','X'), HB_TAG('v','h','e','a'), +#ifndef HB_NO_BEYOND_64K + HB_TAG('V','H','E','A'), +#endif HB_TAG('v','m','t','x'), +#ifndef HB_NO_BEYOND_64K + HB_TAG('V','M','T','X'), +#endif HB_TAG('V','O','R','G'), + HB_TAG('V','A','R','C'), HB_TAG('V','V','A','R'), HB_TAG('n','a','m','e'), HB_TAG('O','S','/','2') @@ -223,6 +248,9 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) case HB_TAG('a','v','a','r'): case HB_TAG('f','v','a','r'): case HB_TAG('g','v','a','r'): +#ifndef HB_NO_BEYOND_64K + case HB_TAG('G','V','A','R'): +#endif case HB_TAG('H','V','A','R'): case HB_TAG('V','V','A','R'): case HB_TAG('M','V','A','R'): @@ -238,15 +266,38 @@ _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag, const hb_set_t &subsetted_tags, const hb_set_t &pending_subset_tags) { + bool outline_pending = pending_subset_tags.has (HB_TAG('g','l','y','f')); +#ifndef HB_NO_BEYOND_64K + outline_pending |= pending_subset_tags.has (HB_TAG('G','L','Y','F')); +#endif + switch (tag) { case HB_TAG('h','m','t','x'): case HB_TAG('v','m','t','x'): case HB_TAG('m','a','x','p'): +#ifndef HB_NO_BEYOND_64K + case HB_TAG('H','M','T','X'): + case HB_TAG('V','M','T','X'): + case HB_TAG('M','A','X','P'): +#endif case HB_TAG('O','S','/','2'): - return !plan->normalized_coords || !pending_subset_tags.has (HB_TAG('g','l','y','f')); + return !plan->normalized_coords || !outline_pending; case HB_TAG('G','P','O','S'): + case HB_TAG('G','S','U','B'): return plan->all_axes_pinned || !pending_subset_tags.has (HB_TAG('G','D','E','F')); + /* For avar2, variation tables must wait for avar to be subsetted first. */ + case HB_TAG('g','v','a','r'): +#ifndef HB_NO_BEYOND_64K + case HB_TAG('G','V','A','R'): +#endif + case HB_TAG('c','v','a','r'): + case HB_TAG('H','V','A','R'): + case HB_TAG('V','V','A','R'): + case HB_TAG('M','V','A','R'): + case HB_TAG('G','D','E','F'): + case HB_TAG('C','F','F','2'): + return !plan->has_avar2 || !pending_subset_tags.has (HB_TAG('a','v','a','r')); default: return true; } @@ -275,9 +326,19 @@ _subset_table (hb_subset_plan_t *plan, switch (tag) { case HB_TAG('h','e','a','d'): - if (_is_table_present (plan->source, HB_TAG('g','l','y','f')) && !_should_drop_table (plan, HB_TAG('g','l','y','f'))) - return true; /* skip head, handled by glyf */ + { + bool outline_table_handles_head = + _is_table_present (plan->source, HB_TAG('g','l','y','f')) && + !_should_drop_table (plan, HB_TAG('g','l','y','f')); +#ifndef HB_NO_BEYOND_64K + outline_table_handles_head |= + _is_table_present (plan->source, HB_TAG('G','L','Y','F')) && + !_should_drop_table (plan, HB_TAG('G','L','Y','F')); +#endif + if (outline_table_handles_head) + return true; /* skip head, handled by the outline table */ return _hb_subset_table (plan, buf); + } case HB_TAG('S','T','A','T'): if (!plan->user_axes_location.is_empty ()) return _hb_subset_table (plan, buf); @@ -449,4 +510,4 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) end: return success ? hb_face_reference (plan->dest) : nullptr; -} \ No newline at end of file +} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.h b/src/java.desktop/share/native/libharfbuzz/hb-subset.h index edc13121825..c94e47fbaf1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.h @@ -26,9 +26,15 @@ #ifndef HB_SUBSET_H #define HB_SUBSET_H +#define HB_SUBSET_H_IN #include "hb.h" #include "hb-ot.h" +#include "hb-subset-serialize.h" +#include "hb-subset-depend.h" +#include "hb-subset-serialize.h" + +#undef HB_SUBSET_H_IN HB_BEGIN_DECLS @@ -84,9 +90,12 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; * HB_SUBSET_FLAGS_RETAIN_GIDS then the number of glyphs in the font won't * be reduced as a result of subsetting. If necessary empty glyphs will be * included at the end of the font to keep the number of glyphs unchanged. - * @HB_SUBSET_FLAGS_DOWNGRADE_CFF2: If set and instantiating a variable font, - * convert the output CFF2 table to CFF1. This enables compatibility with older - * renderers that don't support CFF2. Since: 13.0.0 + * @HB_SUBSET_FLAGS_DOWNGRADE_CFF2: If set and instantiating a variable font + * with all axes pinned, convert the output CFF2 table to CFF1. This enables + * compatibility with older renderers that don't support CFF2. Since: 13.0.0 + * @HB_SUBSET_FLAGS_CFF_IDENTITY_CHARSET: If set and subsetting a CID-keyed CFF + * font, the output CFF charset will use sequential identity CIDs (CID = new + * GID) rather than preserving the original CIDs. Since: 14.3.0 * * List of boolean properties that can be configured on the subset input. * @@ -111,6 +120,7 @@ typedef enum { /*< flags >*/ HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS = 0x00002000u, #endif HB_SUBSET_FLAGS_DOWNGRADE_CFF2 = 0x00004000u, + HB_SUBSET_FLAGS_CFF_IDENTITY_CHARSET = 0x00008000u, } hb_subset_flags_t; /** @@ -228,6 +238,9 @@ hb_subset_axis_range_to_string (hb_subset_input_t *input, unsigned size); #ifdef HB_EXPERIMENTAL_API +HB_EXTERN hb_blob_t * +hb_subset_input_to_string_or_fail (hb_subset_input_t *input); + HB_EXTERN hb_bool_t hb_subset_input_override_name_table (hb_subset_input_t *input, hb_ot_name_id_t name_id, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh index d2d23cf59b8..4d4b2b5e86d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh @@ -4,7 +4,7 @@ * * ./gen-ucd-table.py ucd.nounihan.grouped.xml hb-script-list.h * - * on file with this description: Unicode 17.0.0 + * on file with this description: Unicode 18.0.0 */ #ifndef HB_UCD_TABLE_HH @@ -14,7 +14,7 @@ #include -static const hb_script_t _hb_ucd_sc_map[176]= +static const hb_script_t _hb_ucd_sc_map[179]= { HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED, HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC, @@ -104,6 +104,8 @@ static const hb_script_t _hb_ucd_sc_map[176]= HB_SCRIPT_TODHRI, HB_SCRIPT_TULU_TIGALARI, HB_SCRIPT_BERIA_ERFE, HB_SCRIPT_SIDETIC, HB_SCRIPT_TAI_YO, HB_SCRIPT_TOLONG_SIKI, + HB_SCRIPT_JURCHEN, HB_SCRIPT_PROTO_CUNEIFORM, + HB_SCRIPT_SEAL, }; static const uint16_t _hb_ucd_dm1_p0_map[825]= { @@ -763,7 +765,7 @@ static const uint64_t _hb_ucd_dm2_u64_map[408]= #include -static const uint8_t _hb_ucd_u8[19845]= +static const uint8_t _hb_ucd_u8[19991]= { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 2, 2, 2, 2, 2, 2, @@ -774,27 +776,29 @@ static const uint8_t _hb_ucd_u8[19845]= 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 2, 58, 59, 0, 0, 0, 0, 60, 2, 2, 61, 2, 2, 2, 2, 2, - 2, 62, 2, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 64, 0, 0, 0, 2, 65, 66, 67, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 69, 70, 71, 0, 0, 0, 0, 72, 0, - 0, 0, 0, 0, 0, 0, 73, 74, 75, 76, 77, 78, 4, 79, 0, 80, - 81, 82, 83, 84, 85, 0, 86, 87, 88, 89, 4, 90, 91, 92, 0, 0, + 2, 58, 59, 60, 0, 0, 0, 61, 2, 2, 62, 2, 2, 2, 2, 2, + 2, 63, 2, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 65, 0, 0, 0, 2, 66, 67, 68, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 69, 2, 70, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 0, 0, 0, 0, 74, 0, + 0, 0, 0, 0, 0, 0, 75, 76, 77, 78, 79, 80, 4, 81, 0, 82, + 83, 84, 85, 86, 87, 0, 88, 89, 90, 91, 4, 92, 93, 94, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 93, 2, 2, 2, 2, 2, 2, 2, 2, 94, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 96, 2, 97, 0, 0, 0, 0, 2, 98, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,100, 0, 0, 0, 0, 0, + 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 96, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 97, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 98, 2, 99, 0, 0, 0, 0, 2,100, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2,101, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -875,9 +879,7 @@ static const uint8_t _hb_ucd_u8[19845]= 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -892,7 +894,7 @@ static const uint8_t _hb_ucd_u8[19845]= 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,102, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,105, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -904,590 +906,633 @@ static const uint8_t _hb_ucd_u8[19845]= 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, - 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, - 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, - 11, 11, 11, 11, 11, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, - 13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 16, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 14, - 1, 1, 1, 1, 14, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, - 1, 5, 0, 11, 11, 11, 11, 11, 1, 1, 1, 1, 1, 1, 14, 0, - 1, 1, 1, 1, 14, 0, 0, 0, 6, 6, 6, 6, 7, 7, 7, 7, - 1, 1, 1, 1, 1, 14, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 14, 0, 0, 0, 0, - 1, 1, 1, 14, 1, 1, 1, 14, 3, 3, 3, 3, 3, 3, 0, 0, - 28, 28, 28, 28, 28, 28, 28, 28, 11, 11, 11, 11, 11, 1, 1, 1, - 14, 17, 1, 1, 1, 1, 1, 1, 14, 0, 0, 0, 0, 0, 0, 0, - 14, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 0, 0, 0, - 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 29, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, + 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, 14, 14, 14, 14, 14, 14, 14, 14, + 1, 1, 1, 1, 1, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 15, 0, 0, 0, + 18, 18, 18, 18, 18, 18, 18, 18, 1, 1, 1, 1, 1, 15, 0, 0, + 1, 5, 0, 11, 11, 11, 11, 11, 1, 1, 1, 1, 1, 1, 15, 0, + 6, 6, 6, 6, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 15, 0, 0, 0, 0, + 1, 1, 1, 15, 1, 1, 1, 15, 28, 28, 28, 28, 28, 28, 28, 28, + 11, 11, 11, 11, 11, 1, 1, 1, 15, 17, 1, 1, 1, 1, 1, 1, + 15, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 29, 0, 1, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 6, 6, 6, 0, 0, 0, 11, 11, 11, 11, 11, 17, 1, 1, 1, 1, 1, 1, 1, - 11, 11, 11, 11, 11, 10, 10, 10, 1, 1, 1, 0, 0, 0, 0, 0, - 5, 46, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 41, 41, 41, 41, - 3, 3, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 0, 0, 12, - 1, 1, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, - 49, 10, 10, 10, 10, 10, 10, 10, 7, 6, 6, 6, 6, 6, 6, 6, - 44, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, - 3, 3, 3, 3, 0, 0, 0, 0, 11, 11, 11, 11, 11, 12, 9, 77, - 88, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,102,103,104, - 89, 6, 6, 6, 6, 6, 6, 6, 22, 22, 22, 22, 22, 22, 22, 22, - 26, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 5, 5, 5, 5, 5, + 11, 11, 11, 11, 11, 10, 10, 10, 3, 3, 3, 3, 3, 0, 0, 0, + 5, 45, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 42, 42, 42, 42, + 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 29, + 11, 11, 11, 11, 11, 0, 0, 13, 1, 1, 0, 0, 0, 0, 0, 0, + 48, 10, 10, 10, 10, 10, 10, 10, 7, 6, 6, 6, 6, 6, 6, 6, + 54, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 13, 9, 77, 88, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7,104,105,106, 89, 6, 6, 6, 6, 6, 6, 6, + 22, 22, 22, 22, 22, 22, 22, 22, 27, 5, 5, 5, 5, 5, 5, 5, + 1, 1, 1, 5, 5, 5, 5, 5, 25, 0, 0, 0, 0, 0, 0, 0, 5, 20, 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, - 11, 11, 11, 11, 11, 12, 12, 12, 1, 1, 1, 1, 14, 1, 1, 0, - 14, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 14, 1, 1, 1, 1, - 10, 10, 10, 10, 10, 10, 51, 0,115, 1, 1, 1, 1, 1, 1, 1, - 5, 5, 5, 5, 5, 5, 5, 0, 1, 1, 1, 1, 13, 13, 13, 12, - 6, 6, 6, 0, 7, 7, 7, 0, 30, 30, 30, 30, 30, 30, 30, 30, - 3, 3, 3, 3, 3, 29, 0, 0, 3, 3, 3, 3, 3, 3, 3, 29, + 11, 11, 11, 11, 11, 13, 13, 13, 1, 1, 1, 1, 15, 1, 1, 0, + 15, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 15, 1, 1, 1, 1, + 10, 10, 10, 10, 10, 10, 51, 0,117, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 14, 14, 14, 13, 6, 6, 6, 0, 7, 7, 7, 0, + 30, 30, 30, 30, 30, 30, 30, 30, 3, 3, 3, 3, 3, 29, 0, 0, 10, 10, 10, 10, 10, 3, 3, 3, 75, 10, 10, 10, 10, 10, 10, 10, - 3, 3, 3, 29, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 3, 3, 3, 29, 0, 0, 0, 0, 6, 8, 8, 8, 8, 8, 8, 8, + 6, 6, 6, 46, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 7, 7, 7, 7, 7, 32, 7, 7, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 51, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 10, - 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 15, 19, - 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 5, - 15, 15, 15, 15, 15, 15, 15, 15, 1, 14, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 23, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, - 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, - 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, - 3, 3, 3, 3, 29, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, - 87, 12,100, 12, 27,101, 76, 12, 6, 6, 6, 6, 6,105,106,135, - 87, 30, 30, 66,107,136,137,108, 50, 10, 89, 12,138,139, 10, 78, - 7, 7, 7, 59, 7, 7, 7, 8, 6, 6, 6, 60, 6, 6, 6, 6, - 8, 8, 8, 8, 21, 21, 21, 21, 21, 21, 21, 21, 6, 8, 8, 8, - 8, 8, 8, 8, 7, 21, 21, 6, 21, 8, 8, 7, 21, 7, 6, 7, - 7, 21, 8, 7, 8, 6, 7, 21, 8, 8, 8, 7, 21, 6, 8, 7, - 21, 7, 21, 21, 8, 67, 8, 6, 1, 1,109, 21,110,109, 21, 21, - 21, 21, 21, 21, 21, 21, 6, 8, 21,110, 8, 7, 8, 8, 8, 8, - 8, 8, 6, 6, 6, 7, 21, 8, 21, 21, 7, 8, 8, 8, 8, 8, - 6, 6, 1, 6, 6, 6, 6, 6, 13, 22, 22, 13, 13, 13, 13, 13, - 13, 22, 22, 22, 22, 22, 22, 22, 13, 13, 68, 22, 22, 22, 68, 68, - 8, 8, 68, 8, 0, 69, 6, 88, 0, 0, 22,140, 7, 32, 32, 7, - 21, 7, 7, 7, 7, 7, 7, 7, 7, 39, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 21, 6, 7, 8, 6, 8, 8, 8, 8, - 6, 6, 8, 90, 21, 8, 21, 7, 8, 43, 5, 5, 79, 8, 8, 8, - 7, 21, 21, 21, 21, 21, 21, 6, 39, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 32, 54, 12, 12, 12, 6, 6, 6, 6,111,141, 44, 70, - 5, 5, 5, 5, 5, 5, 5,142, 71, 36, 5, 71, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 14, 0, 17, 1, 40, 33, 0, 0, 0, 0, 0, - 18, 18, 18, 9, 77, 80, 12, 3, 5, 5, 5, 5, 5, 36,143, 12, - 52, 1, 1, 1, 1, 24, 5, 5, 11, 11, 11, 11, 11, 12, 12, 1, - 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 53, 5, 5, 5,144, 43, - 5, 5, 81, 72, 55, 5, 5, 1, 11, 11, 11, 11, 11, 1, 56, 82, - 12, 12, 12, 12, 12, 12, 12, 73, 24, 1, 1, 1, 1, 1, 1, 1, - 5, 5, 5, 5, 5, 23, 17, 1, 25, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 24, 5, 5, 5, 5, 13, 66, 12, 61, 26, 30, - 1, 1, 1, 5, 5, 72, 5, 5, 5, 5, 72, 5, 72, 5, 5, 0, - 12, 12, 12, 12, 12, 12, 12, 33, 1, 1, 1, 1, 24, 5, 0, 33, - 1, 1, 1, 1,145, 1, 1, 1, 18, 0, 0, 26, 5, 5, 5, 5, - 1, 1, 1, 1, 45, 5, 5, 5, 5, 91, 5, 5, 5, 5, 5, 5, - 1, 1, 1, 1, 1, 20, 25, 15, 19, 5, 5, 5, 20, 15, 19, 15, - 24, 5, 5, 5, 1, 1, 1, 1, 1, 5, 12, 11, 11, 11, 11, 11, - 62, 1, 1, 1, 1, 1, 1, 1, 24, 15, 17, 1, 1, 1, 14, 17, - 14, 14, 0, 1, 1, 0, 25, 15, 19, 5, 23, 35, 37, 35, 19, 14, - 0, 0, 0, 35, 0, 0, 1, 17, 1, 30, 10, 10, 10, 70, 40, 23, - 26, 20, 17, 1, 1, 14, 0, 17, 14, 1, 17, 14, 1, 0, 23, 15, - 19, 23, 0, 26, 23, 26, 5, 0, 26, 0, 0, 0, 17, 1, 14, 14, - 5, 1, 24, 33, 0, 0, 0, 0, 26, 20, 17, 1, 1, 1, 1, 17, - 14, 1, 17, 1, 1, 0, 25, 15, 19, 5, 5, 26, 20, 35, 19, 0, - 80, 0, 0, 0, 17, 5, 5, 5, 26, 15, 17, 1, 1, 1, 14, 17, - 14, 1, 17, 1, 1, 0, 25, 19, 19, 5, 23, 35, 37, 35, 19, 0, - 0, 0, 26, 20, 0, 0, 1, 17, 82, 10, 10, 10, 0, 0, 0, 0, - 0, 25, 17, 1, 1, 14, 0, 1, 14, 1, 1, 0, 17, 14, 14, 1, - 0, 17, 14, 0, 1, 14, 0, 1, 1, 1, 1, 1, 1, 0, 0, 15, - 20, 37, 0, 15, 37, 15, 19, 0, 14, 0, 0, 35, 0, 0, 0, 0, - 10, 63, 3, 3, 70, 29, 0, 0, 20, 15, 25, 1, 1, 1, 14, 1, - 1, 1, 1, 1, 1, 0, 25, 5, 20, 15, 37, 5, 23, 5, 5, 0, - 0, 0, 26, 23, 1, 14, 1, 0, 0, 0, 0, 38, 10, 10, 10, 63, - 24, 15, 53, 1, 1, 1, 14, 1, 1, 1, 17, 1, 1, 0, 25, 19, - 15, 15, 37, 20, 37, 15, 5, 0, 0, 0, 35, 37, 0, 0, 1, 14, - 17, 34, 0, 0, 0, 0, 0, 0, 5, 15, 1, 1, 1, 1, 14, 1, - 1, 1, 1, 1, 1, 24, 25, 15, 19, 5, 23, 15, 37, 15, 19, 56, - 0, 0, 1, 34, 10, 10, 10,112, 10, 10, 10, 10, 63, 1, 1, 1, - 26, 15, 17, 1, 1, 1, 1, 1, 1, 1, 1, 14, 0, 1, 1, 1, - 1, 17, 1, 1, 1, 1, 17, 0, 1, 1, 1, 14, 0, 23, 0, 35, - 15, 5, 23, 23, 15, 15, 15, 15, 0, 15, 33, 0, 0, 0, 0, 0, - 24, 1, 5, 5, 5, 23, 0,113, 1, 1, 1, 72, 5, 5, 5, 36, - 11, 11, 11, 11, 11, 12, 0, 0, 17, 14, 14, 1, 1, 14, 1, 1, + 1, 1, 1, 1, 1, 1, 16, 19, 1, 1, 1, 1, 1, 1, 1, 34, + 1, 1, 1, 1, 1, 1, 1, 5, 16, 16, 16, 16, 16, 16, 16, 16, + 1, 15, 0, 0, 0, 0, 0, 0, 5, 5, 5, 23, 0, 0, 0, 0, + 10, 10, 0, 0, 0, 0, 0, 0, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 3, 0, 87, 13,102, 13, 26,103, 76, 13, + 6, 6, 6, 6, 6,107,108,138, 87, 30, 30, 65,109,139,140,110, + 49, 10, 89, 13,141,142, 10, 78, 7, 7, 7, 59, 7, 7, 7, 8, + 6, 6, 6, 60, 6, 6, 6, 6, 8, 8, 8, 8, 21, 21, 21, 21, + 21, 21, 21, 21, 6, 8, 8, 8, 8, 8, 8, 8, 7, 21, 21, 6, + 21, 8, 8, 7, 21, 7, 6, 7, 7, 21, 8, 7, 8, 6, 7, 21, + 8, 8, 8, 7, 21, 6, 8, 7, 21, 7, 21, 21, 8, 66, 8, 6, + 1, 1,111, 21,112,111, 21, 21, 21, 21, 21, 21, 21, 21, 6, 8, + 21,112, 8, 7, 8, 8, 8, 8, 8, 8, 6, 6, 6, 7, 21, 8, + 21, 21, 7, 8, 8, 8, 8, 8, 6, 6, 1, 6, 6, 6, 6, 6, + 14, 22, 22, 14, 14, 14, 14, 14, 14, 22, 22, 22, 22, 22, 22, 22, + 14, 14, 67, 22, 22, 22, 67, 67, 8, 8, 67, 8, 0, 68, 6, 88, + 0, 0, 22,143, 7, 32, 32, 7, 21, 7, 7, 7, 7, 7, 7, 7, + 7, 39, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 21, + 6, 7, 8, 6, 8, 8, 8, 8, 6, 6, 8, 90, 21, 8, 21, 7, + 8, 41, 5, 5, 79, 8, 8, 8, 7, 21, 21, 21, 21, 21, 21, 6, + 39, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 32, 14, 13, 13, 13, + 6, 6, 6, 6,113, 91,144, 69, 5, 5, 5, 5, 5, 5, 5,145, + 70, 36, 5, 70, 5, 0, 0, 0, 1, 1, 1, 1, 1, 15, 0, 17, + 1, 40, 33, 0, 0, 0, 0, 0, 18, 18, 18, 9, 77, 80, 13, 3, + 5, 5, 5, 5, 5, 36,146, 13, 52, 1, 1, 1, 1, 24, 5, 5, + 11, 11, 11, 11, 11, 13, 13, 1, 25, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 53, 5, 5, 5,147, 41, 5, 5, 81, 71, 50, 5, 5, 1, + 11, 11, 11, 11, 11, 1, 55, 72, 13, 13, 13, 13, 13, 13, 13, 73, + 24, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 23, 17, 1, + 1, 1, 1, 1, 1, 24, 5, 5, 5, 5, 14, 65, 13, 82, 27, 30, + 1, 1, 1, 5, 5, 71, 5, 5, 5, 5, 71, 5, 71, 5, 5, 0, + 13, 13, 13, 13, 13, 13, 13, 33, 1, 1, 1, 1, 24, 5, 0, 33, + 1, 1, 1, 1,148, 1, 1, 1, 18, 0, 0, 27, 5, 5, 5, 5, + 1, 1, 1, 1, 44, 5, 5, 5, 5, 92, 5, 5, 5, 5, 5, 5, + 1, 1, 1, 1, 1, 20, 25, 16, 19, 5, 5, 5, 20, 16, 19, 16, + 24, 5, 5, 5, 1, 1, 1, 1, 1, 5, 13, 11, 11, 11, 11, 11, + 61, 1, 1, 1, 1, 1, 1, 1, 24, 16, 17, 1, 1, 1, 15, 17, + 15, 15, 0, 1, 1, 0, 25, 16, 19, 5, 23, 35, 37, 35, 19, 15, + 0, 0, 0, 35, 0, 0, 1, 17, 1, 30, 10, 10, 10, 69, 40, 23, + 27, 20, 17, 1, 1, 15, 0, 17, 15, 1, 17, 15, 1, 0, 23, 16, + 19, 23, 0, 27, 23, 27, 5, 0, 27, 0, 0, 0, 17, 1, 15, 15, + 5, 1, 24, 33, 0, 0, 0, 0, 27, 20, 17, 1, 1, 1, 1, 17, + 15, 1, 17, 1, 1, 0, 25, 16, 19, 5, 5, 27, 20, 35, 19, 0, + 80, 0, 0, 0, 17, 5, 5, 5, 27, 16, 17, 1, 1, 1, 15, 17, + 15, 1, 17, 1, 1, 0, 25, 19, 19, 5, 23, 35, 37, 35, 19, 0, + 0, 27, 5, 20, 0, 0, 1, 17, 72, 10, 10, 10, 0, 0, 0, 0, + 0, 25, 17, 1, 1, 15, 0, 1, 15, 1, 1, 0, 17, 15, 15, 1, + 0, 17, 15, 0, 1, 15, 0, 1, 1, 1, 1, 1, 1, 0, 0, 16, + 20, 37, 0, 16, 37, 16, 19, 0, 15, 0, 0, 35, 0, 0, 0, 0, + 10, 62, 3, 3, 69, 29, 0, 0, 20, 16, 25, 1, 1, 1, 15, 1, + 1, 1, 1, 1, 1, 0, 25, 5, 20, 16, 37, 5, 23, 5, 5, 0, + 0, 0, 27, 23, 1, 15, 1, 0, 0, 0, 0, 38, 10, 10, 10, 62, + 24, 16, 53, 1, 1, 1, 15, 1, 1, 1, 17, 1, 1, 0, 25, 19, + 16, 16, 37, 20, 37, 16, 5, 0, 0, 0, 35, 37, 0, 0, 1, 15, + 17, 34, 0, 0, 0, 0, 0, 0, 5, 16, 1, 1, 1, 1, 15, 1, + 1, 1, 1, 1, 1, 24, 25, 16, 19, 5, 23, 16, 37, 16, 19, 55, + 0, 0, 1, 34, 10, 10, 10,114, 10, 10, 10, 10, 62, 1, 1, 1, + 27, 16, 17, 1, 1, 1, 1, 1, 1, 1, 1, 15, 0, 1, 1, 1, + 1, 17, 1, 1, 1, 1, 17, 0, 1, 1, 1, 15, 0, 23, 0, 35, + 16, 5, 23, 23, 16, 16, 16, 16, 0, 16, 33, 0, 0, 0, 0, 0, + 24, 1, 5, 5, 5, 23, 0,115, 1, 1, 1, 71, 5, 5, 5, 36, + 11, 11, 11, 11, 11, 13, 0, 0, 17, 15, 15, 1, 1, 15, 1, 1, 1, 1, 17, 17, 1, 1, 1, 1, 24, 1, 5, 5, 5, 5, 25, 0, - 1, 1, 14, 61, 5, 5, 5, 23, 11, 11, 11, 11, 11, 0, 1, 1, - 56, 3, 12, 12, 12, 12, 12, 12, 12, 57, 57, 3, 5, 3, 3, 3, - 10, 10, 43, 43, 43, 27, 27, 15, 1, 1, 1, 1, 17, 1, 1, 1, - 26, 5, 5, 5, 5, 5, 5, 20, 5, 5, 36, 5, 1, 1, 24, 5, - 5, 5, 5, 5, 26, 5, 5, 5, 5, 5, 5, 5, 5, 5, 23, 3, - 3, 3, 3, 55, 3, 3, 29, 3, 12, 12, 57, 3, 66, 33, 0, 0, + 1, 1, 15, 82, 5, 5, 5, 23, 11, 11, 11, 11, 11, 0, 1, 1, + 55, 3, 13, 13, 13, 13, 13, 13, 13, 56, 56, 3, 5, 3, 3, 3, + 10, 10, 41, 41, 41, 26, 26, 16, 1, 1, 1, 1, 17, 1, 1, 1, + 27, 5, 5, 5, 5, 5, 5, 20, 5, 5, 36, 5, 1, 1, 24, 5, + 5, 5, 5, 5, 27, 5, 5, 5, 5, 5, 5, 5, 5, 5, 23, 3, + 3, 3, 3, 50, 3, 3, 29, 3, 13, 13, 56, 3, 65, 33, 0, 0, 1, 1, 1, 1, 1, 34, 19, 5, 20, 5, 5, 5, 19, 20, 19, 25, - 1, 1, 1, 15, 5, 1, 1, 5, 25, 15, 46, 34, 15, 15, 15, 1, - 24, 5, 25, 1, 1, 1, 1, 1, 1, 20, 19, 20, 15, 15, 19, 34, - 11, 11, 11, 11, 11, 15, 19, 3, 7, 7, 7, 39, 0, 0, 39, 0, - 6, 6, 6, 6, 6,111, 69, 6, 1, 1, 1, 14, 14, 1, 1, 0, - 14, 1, 1, 0, 1, 1, 1, 14, 1, 1, 1, 1, 1, 14, 26, 5, - 12, 12, 12, 12,114, 10, 10, 10, 7, 7, 7, 0, 6, 6, 6, 0, - 1, 1, 1, 1, 1, 1, 56, 53,146, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1,147,116, 0, 1, 1, 1, 1, 1, 40, 12, 16, - 148, 1, 1, 1, 14, 0, 0, 0, 1, 5, 20, 0, 0, 0, 0, 17, + 1, 1, 1, 16, 5, 1, 1, 5, 25, 16, 45, 34, 16, 16, 16, 1, + 24, 5, 25, 1, 1, 1, 1, 1, 1, 20, 19, 20, 16, 16, 19, 34, + 11, 11, 11, 11, 11, 16, 19, 3, 7, 7, 7, 39, 0, 0, 39, 0, + 6, 6, 6, 6, 6,113, 68, 6, 1, 1, 1, 15, 15, 1, 1, 0, + 15, 1, 1, 0, 1, 1, 1, 15, 1, 1, 1, 1, 1, 15, 27, 5, + 13, 13, 13, 13,116, 10, 10, 10, 7, 7, 7, 0, 6, 6, 6, 0, + 1, 1, 1, 1, 1, 1, 55, 53,149, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1,150,151, 0, 1, 1, 1, 1, 1, 40, 13, 12, + 152, 1, 1, 1, 15, 0, 0, 0, 1, 5, 20, 0, 0, 0, 0, 17, 1, 5, 83, 33, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 14, 1, 14, 5, 0, 0, 0, 0, 0, 0, - 1, 1, 5, 19, 5, 5, 5, 15, 15, 15, 15, 20, 19, 5, 5, 5, - 5, 5, 12, 62, 12, 80, 24, 0, 10, 10, 10, 10, 10, 0, 0, 0, - 12, 12, 12, 92, 12, 71, 5, 91, 1, 45, 1, 1, 1, 1, 1, 1, - 1, 1, 24, 25, 1, 1, 1, 1, 1, 1, 1, 1, 24, 14, 0, 0, - 5, 20, 15, 19, 20, 15, 0, 0, 15, 20, 15, 15, 19, 5, 0, 0, - 29, 0, 12, 11, 11, 11, 11, 11, 1, 1, 14, 0, 0, 0, 0, 0, - 11, 11, 11, 11, 11, 51, 0, 3, 1, 1, 1, 24, 20, 19, 0, 12, - 1, 1, 34, 20, 5, 5, 5, 23, 20, 20, 19, 5, 5, 5, 20, 15, - 15, 19, 5, 5, 5, 5, 23, 26, 12, 12, 12, 62, 12, 12, 12, 0, - 5, 5, 5, 5, 5, 5, 5, 93, 5, 5, 5, 5, 5, 5, 0, 0, - 5, 5, 46, 1, 1, 1, 1, 1, 1, 1, 20, 5, 5, 20, 20, 15, - 15, 20, 46, 1, 1, 1, 14, 12, 57, 3, 3, 3, 3, 43, 5, 5, - 5, 5, 3, 3, 3, 3, 66, 12, 34, 5, 5, 15, 5, 19, 5, 1, - 1, 1, 1, 20, 5, 15, 19, 19, 5, 15, 0, 0, 0, 0, 12, 12, - 1, 1, 15, 15, 15, 15, 5, 5, 5, 5, 15, 5, 0, 38, 12, 12, - 11, 11, 11, 11, 11, 0, 17, 1, 6, 6, 6, 6, 21, 47, 0, 0, - 7, 7, 7, 7, 7, 32, 39, 7, 12, 12, 12, 12, 0, 0, 0, 0, - 5, 36, 5, 5, 5, 5, 5, 5, 20, 5, 5, 5, 25, 1, 24, 1, - 1, 1, 25, 34, 5, 14, 0, 0, 6, 6, 6, 6, 6, 6, 13, 13, - 13, 13, 13, 13, 13, 69, 6, 6, 6, 6, 6, 6, 69, 6, 6, 6, - 6, 6, 6, 6, 6,117, 13, 13, 8, 8, 8, 6, 6, 6, 6, 8, - 6, 6, 6, 6, 39, 39, 39, 39, 6, 6, 6, 6, 6, 6, 6, 0, - 6, 6, 47, 6, 7, 7, 94,118, 22, 6, 47, 6, 7, 7, 94, 22, - 6, 6, 0, 6, 7, 7,149, 22, 6, 6, 6, 6, 7, 7,150, 22, - 0, 6, 47, 6, 7, 7, 94,151, 74, 74, 74, 74, 74,152, 18, 18, - 84, 84, 84, 12, 58,119, 58,119, 12, 12, 12, 12,153, 18, 18,154, - 12, 12, 12, 12,120,121, 12,122,123, 12, 64, 65, 12, 12, 12, 12, - 12, 77,123, 12, 12, 12, 12,155, 18, 18,156, 18, 18, 18, 18, 18, - 157, 0, 10, 10, 10, 9, 64,158, 10, 10, 10, 10, 10, 9, 64,116, - 13, 13, 13, 13, 13, 13, 61, 0, 30, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 5, 5,159, 79, 93, 79, 93, 5, 5, 5, 5, 5, - 23, 0, 0, 0, 0, 0, 0, 0, 3, 85, 3, 95, 3, 21, 7, 6, - 7, 8, 95, 3, 90, 7, 7, 3, 3, 3, 85, 85, 85, 7, 7,160, - 7, 7, 67, 1,124, 3, 6, 7, 9, 9, 90, 6, 6, 50, 3,125, - 16,161,162, 16,126, 3, 0, 0, 9, 9, 48, 3, 3, 9, 3, 3, - 48, 50, 3, 48, 3, 3, 3, 48, 3, 3, 3, 3, 3, 3, 3, 9, - 3, 48, 48, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, - 3, 3, 3, 3, 27, 27, 3, 3, 9, 3, 3, 3,163,164, 3, 3, - 3, 3, 3, 3, 3, 3, 48, 3, 3, 3, 3, 3, 3, 50, 9, 9, - 9, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, - 9, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, 10, 10, 10, 3, 3, - 3, 3, 3, 3, 3, 10, 10, 10, 3, 3, 3, 50, 3, 3, 3, 3, - 50, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, - 3, 3, 3, 3, 3, 3, 3, 50, 3, 3, 3, 3, 27, 27, 27, 27, - 27, 27, 27, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, - 9, 9, 64,127, 9, 9, 9, 9, 9, 9, 9, 27, 27, 27, 27, 27, - 9, 64, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,127, 9, 9, 9, - 9, 9, 9, 9, 27, 27, 9, 9, 9, 9, 9, 9, 9, 9, 27, 9, - 9, 9, 48, 50, 9, 9, 48, 3, 3, 3, 0, 3, 3, 3, 3, 3, - 8, 7, 8, 21, 21, 21, 21, 7, 8, 8, 21, 6, 6, 6, 13, 7, - 8, 8,125, 3, 3, 95, 21,165, 5, 8, 0, 0, 38, 12,114, 12, - 6, 6, 6, 42, 0, 0, 42, 0, 1, 1, 1, 1, 0, 0, 0, 54, - 33, 0, 0, 0, 0, 0, 0, 26, 12, 58, 58, 12,120,121, 58, 12, - 12, 12, 12, 76, 12, 92, 58, 12, 58, 27, 27, 27, 27, 12, 12, 62, - 12, 12, 12, 12, 12, 84, 12, 12, 92,166, 12, 12, 12, 12, 12, 12, - 3, 12, 96, 31, 31, 31,167, 0, 3, 3, 3, 3, 3, 44, 3, 3, - 87, 12,168,128, 27, 27, 27, 27, 27, 3, 27, 27, 27, 27,129,169, - 170, 16, 16, 16, 16, 5, 5, 15,130, 13, 13, 3, 16,171, 40, 3, - 1, 1, 1, 14, 26,172,131, 52, 1, 1, 1, 1, 1, 40, 13, 52, + 1, 1, 1, 1, 1, 1, 15, 1, 15, 5, 0, 0, 0, 0, 0, 0, + 1, 1, 5, 19, 5, 5, 5, 16, 16, 16, 16, 20, 19, 5, 5, 5, + 5, 5, 13, 61, 13, 80, 24, 0, 10, 10, 10, 10, 10, 0, 0, 0, + 13, 13, 13, 93, 13, 70, 5, 92, 1, 44, 1, 1, 1, 1, 1, 1, + 1, 1, 24, 25, 1, 1, 1, 1, 1, 1, 1, 1, 24, 15, 0, 0, + 5, 20, 16, 19, 20, 16, 0, 0, 16, 20, 16, 16, 19, 5, 0, 0, + 29, 0, 13, 11, 11, 11, 11, 11, 1, 1, 15, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 51, 0, 3, 1, 1, 1, 24, 20, 19, 0, 13, + 1, 1, 34, 20, 5, 5, 5, 23, 20, 20, 19, 5, 5, 5, 20, 16, + 16, 19, 5, 5, 5, 5, 23, 27, 13, 13, 13, 61, 13, 13, 13, 0, + 5, 5, 5, 5, 5, 5, 5, 94, 5, 5, 45, 1, 1, 1, 1, 1, + 1, 1, 20, 5, 5, 20, 20, 16, 16, 20, 45, 1, 1, 1, 15, 13, + 56, 3, 3, 3, 3, 41, 5, 5, 5, 5, 3, 3, 3, 3, 65, 13, + 34, 5, 5, 16, 5, 19, 5, 1, 1, 1, 1, 20, 5, 16, 19, 19, + 5, 16, 0, 0, 0, 0, 13, 13, 1, 1, 16, 16, 16, 16, 5, 5, + 5, 5, 16, 5, 0, 38, 13, 13, 11, 11, 11, 11, 11, 0, 17, 1, + 6, 6, 6, 6, 21, 46, 0, 0, 7, 7, 7, 7, 7, 32, 39, 7, + 13, 13, 13, 13, 0, 0, 0, 0, 5, 36, 5, 5, 5, 5, 5, 5, + 20, 5, 5, 5, 25, 1, 24, 1, 1, 1, 25, 34, 5, 15, 0, 0, + 6, 6, 6, 6, 6, 6, 14, 14, 14, 14, 14, 14, 14, 68, 6, 6, + 6, 6, 6, 6, 68, 6, 6, 6, 6, 6, 6, 6, 6,118, 14, 14, + 8, 8, 8, 6, 6, 6, 6, 8, 6, 6, 6, 6, 39, 39, 39, 39, + 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 46, 6, 7, 7, 95,119, + 22, 6, 46, 6, 7, 7, 95, 22, 6, 6, 0, 6, 7, 7,120, 22, + 6, 6, 6, 6, 7, 7,153, 22, 0, 6, 46, 6, 7, 7, 95,154, + 74, 74, 74, 74, 74,155, 18, 18, 84, 84, 84, 13, 57,121, 57,121, + 13, 13, 13, 13,156, 18, 18,157, 13, 13, 13, 13,122,123, 13,124, + 125, 13, 63, 64, 13, 13, 13, 13, 13, 77,125, 13, 13, 13, 13,158, + 18, 18,159, 18, 18, 18, 18, 18,160, 0, 10, 10, 10, 9, 63,126, + 10, 10, 10, 10, 10, 9, 63,126, 30, 30,127, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5,161, 79, 94, 79, 94, 5, 5, 5, 5, 5, + 3, 85, 3, 96, 3, 21, 7, 6, 7, 8, 96, 3, 90, 7, 7, 3, + 3, 3, 85, 85, 85, 7, 7,162, 7, 7, 66, 1,128, 3, 6, 7, + 9, 9, 90, 6, 6, 49, 3,129, 12,163,164, 12,130, 3, 0, 0, + 9, 9, 47, 3, 3, 9, 3, 3, 47, 49, 3, 47, 3, 3, 3, 47, + 3, 3, 3, 3, 3, 3, 3, 9, 3, 47, 47, 3, 3, 3, 3, 3, + 3, 3, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 26, 26, 3, 3, + 9, 3, 3, 3,165,166, 3, 3, 3, 3, 3, 3, 3, 3, 47, 3, + 3, 3, 3, 3, 3, 49, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 9, 9, 9, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, + 3, 3, 3, 49, 3, 3, 3, 3, 49, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, 3, 49, + 3, 3, 3, 3, 26, 26, 26, 26, 26, 26, 26, 10, 10, 10, 10, 10, + 10, 10, 3, 3, 3, 3, 3, 3, 9, 9, 63,131, 9, 9, 9, 9, + 9, 9, 9, 26, 26, 26, 26, 26, 9, 63, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31,131, 9, 9, 9, 9, 9, 9, 9, 26, 26, 9, 9, + 9, 9, 9, 9, 9, 9, 26, 9, 9, 9, 47, 49, 9, 9, 47, 3, + 3, 3, 0, 3, 3, 3, 3, 3, 8, 7, 8, 21, 21, 21, 21, 7, + 8, 8, 21, 6, 6, 6, 14, 7, 8, 8,129, 3, 3, 96, 21,167, + 5, 8, 0, 0, 38, 13,116, 13, 6, 6, 6, 43, 0, 0, 43, 0, + 1, 1, 1, 1, 0, 0, 0, 58, 33, 0, 0, 0, 0, 0, 0, 27, + 13, 57, 57, 13,122,123, 57, 13, 13, 13, 13, 76, 13, 93, 57, 13, + 57, 26, 26, 26, 26, 13, 13, 61, 13, 13, 13, 13, 13, 84, 13, 13, + 93,168, 13, 13, 13, 13, 13, 13, 3, 13, 97, 31, 31, 31,169, 0, + 13, 26, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 54, 3, 3, + 87, 13,170,132, 26, 26, 26, 26, 26, 3, 26, 26, 26, 26,133,171, + 172, 12, 12, 12, 12, 5, 5, 16, 91, 14, 14, 3, 12,173, 40, 3, + 1, 1, 1, 15, 27,174,134, 52, 1, 1, 1, 1, 1, 40, 14, 52, 0, 0, 17, 1, 1, 1, 1, 1, 3, 10, 10, 3, 3, 3, 3, 3, - 3, 3, 3, 0, 0, 0, 0, 44, 3, 3, 3, 3, 10, 10, 10, 10, - 1, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,132, 12, + 3, 3, 3, 0, 0, 0, 0, 54, 3, 3, 3, 3, 10, 10, 10, 10, + 1, 1, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,135, 13, 11, 11, 11, 11, 11, 1, 0, 0, 8, 8, 8, 8, 8, 8, 8, 24, - 79,173, 5, 5, 5, 5, 5, 62, 8, 8, 8, 8, 8, 8, 13, 5, - 1, 1, 1, 16, 16, 16, 16, 16, 5, 12, 12, 12, 0, 0, 0, 0, - 22, 22, 22,131, 13, 13, 13, 13, 22, 8, 8, 8, 8, 8, 8, 8, - 6, 8, 8, 8, 8, 8, 8, 8, 69, 6, 6, 6, 21, 21, 21, 8, - 8, 8, 8, 8, 68,174, 21, 67, 8, 8, 6, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 7, 7, 8, 7, 7, 8, 8, 8, 8, 8, 8, - 8, 8, 7, 7, 21, 21, 8, 8, 8, 8, 8, 8, 8, 8, 32, 0, - 54, 13,175, 67, 13, 67, 1, 1, 1, 25, 1, 25, 1, 24, 1, 1, - 1, 34, 19, 20, 3, 3, 23, 0, 10, 10, 10, 3, 97, 0, 0, 0, - 1, 1, 12, 12, 0, 0, 0, 0, 15, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 5, 0, 0, 0, 0, 12, - 5, 1, 1, 1, 12, 53, 53, 24, 1, 1, 1, 5, 5, 5, 5, 12, - 1, 1, 1, 24, 5, 5, 5, 5, 5, 15, 0, 0, 0, 0, 0, 38, - 1, 24, 15, 5, 5, 15, 5, 15, 83, 12, 12, 12, 12, 12, 12, 54, - 1, 1, 24, 52, 1, 1, 1, 1, 11, 11, 11, 11, 11, 1, 1, 14, + 79,175, 5, 5, 5, 5, 5, 61, 8, 8, 8, 8, 8, 8, 14, 5, + 1, 1, 1, 12, 12, 12, 12, 12, 5, 13, 13, 13, 0, 0, 0, 0, + 22, 22, 22,134, 14, 14, 14, 14, 22, 8, 8, 8, 8, 8, 8, 8, + 68, 6, 6, 6, 21, 21, 21, 8, 8, 8, 8, 8, 67,176, 21, 66, + 8, 8, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 8, + 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 21, 21, 8, 8, + 8, 8, 8, 8, 8, 8, 7, 0, 0, 32, 0, 0, 0, 0, 0, 0, + 58, 14,177, 66, 14, 66, 1, 1, 1, 25, 1, 25, 1, 24, 1, 1, + 1, 34, 19, 20, 3, 3, 23, 0, 10, 10, 10, 3, 98, 0, 0, 0, + 1, 1, 13, 13, 0, 0, 0, 0, 16, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 16, 16, 16, 16, 16, 16, 16, 16, 5, 0, 0, 0, 0, 13, + 5, 1, 1, 1, 13, 53, 53, 24, 1, 1, 1, 5, 5, 5, 5, 13, + 1, 1, 1, 24, 5, 5, 5, 5, 5, 16, 0, 0, 0, 0, 0, 38, + 1, 24, 16, 5, 5, 16, 5, 16, 83, 13, 13, 13, 13, 13, 13, 58, + 1, 1, 24, 52, 1, 1, 1, 1, 11, 11, 11, 11, 11, 1, 1, 15, 1, 1, 1, 1, 24, 5, 5, 20, 19, 20, 19, 23, 0, 0, 0, 0, - 1, 24, 1, 1, 1, 1, 20, 0, 11, 11, 11, 11, 11, 0, 12, 12, - 52, 1, 1, 56, 3, 34, 20, 1, 25, 5, 25, 24, 25, 1, 1, 5, - 24, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 45, 12, - 1, 1, 1, 1, 1, 34, 5, 15, 12, 45,176, 23, 0, 0, 0, 0, - 17, 1, 1, 14, 17, 1, 1, 14, 17, 1, 1, 14, 0, 0, 0, 0, - 6, 6, 6, 6, 6,118, 13, 13, 6, 6, 6, 6,117, 22, 0, 0, - 1, 34, 19, 15, 20, 83, 19, 0, 1, 1, 1, 14, 0, 17, 1, 1, - 6, 6, 6, 47, 0, 0, 0, 0, 0, 42, 6, 6, 0, 0, 17, 25, - 1, 1, 1, 1,177, 1, 1, 1, 1, 1, 1, 14, 1, 1, 14, 14, - 1, 17, 14, 1, 1, 1, 1, 1, 1, 22, 22, 22, 22, 22, 22, 22, - 22,107, 3, 3, 3, 3, 3, 3, 3, 82, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 31, 3, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 97, 3, - 12, 12, 12, 96, 65, 0, 0, 0, 76,178,179, 31, 31, 31, 31, 31, - 31, 31, 65, 96, 65, 12,122,180, 12, 33, 12, 12,129, 31, 31, 65, - 12,181, 9, 98, 80, 12, 0, 0, 1, 1, 14, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 14, 73, 38, 12,100, 12, 27,101, 76, 12, - 6, 6, 6, 6, 6,105,106, 64, 65, 27, 12, 1, 1, 1, 1, 1, - 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, - 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 14, 0, - 30,182, 70,183, 50, 9, 48, 29, 0, 0, 0, 0, 73, 18, 3, 0, - 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, 14, 1, 17, - 12, 33, 0, 49, 10, 10, 10, 10, 10, 10, 0, 44, 3, 3, 3, 3, - 16, 16,126, 10, 63, 3, 3, 3, 3, 3, 3, 3, 3, 10, 3, 29, - 3, 3, 3, 3, 3, 3, 43, 0,133, 10, 10, 10, 10, 10, 10, 10, + 1, 24, 1, 1, 1, 1, 20, 0, 11, 11, 11, 11, 11, 0, 13, 13, + 52, 1, 1, 55, 3, 34, 20, 1, 25, 5, 25, 24, 25, 1, 1, 5, + 24, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 44, 13, + 1, 1, 1, 1, 1, 34, 5, 16, 13, 44,178, 23, 0, 0, 0, 0, + 17, 1, 1, 15, 17, 1, 1, 15, 17, 1, 1, 15, 0, 0, 0, 0, + 6, 6, 6, 6, 6,119, 14, 14, 6, 6, 6, 6,118, 22, 7, 0, + 1, 34, 19, 16, 20, 83, 19, 0, 1, 1, 1, 15, 0, 17, 1, 1, + 0, 43, 6, 6, 0, 0, 17, 25, 1, 1, 1, 1,179, 1, 1, 1, + 1, 1, 1, 15, 1, 1, 15, 15, 1, 17, 15, 1, 1, 1, 1, 1, + 1, 22, 22, 22, 22, 22, 22, 22, 22,109, 3, 3, 3, 3, 3, 3, + 3, 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 98, 3, 13, 13, 13, 97, 64, 0, 0, 0, + 76,180,181, 31, 31, 31, 31, 31, 31, 31, 64, 97, 64, 13,124,182, + 13, 33, 13, 13,133, 31, 31, 64, 13,183, 9, 99, 80, 13, 0, 0, + 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 73, + 38, 13,102, 13, 26,103, 76, 13, 6, 6, 6, 6, 6,107,108, 63, + 64, 26, 13, 1, 1, 1, 1, 1, 52, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 14, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 15, 0, 30,184, 69,127, 49, 9, 47, 29, + 0, 0, 0, 0, 73, 18, 3, 0, 1, 1, 1, 1, 1, 1, 17, 1, + 1, 1, 1, 1, 1, 15, 1, 17, 13, 33, 0, 48, 10, 10, 10, 10, + 10, 10, 0, 54, 3, 3, 3, 3, 12, 12,130, 10, 62, 3, 3, 3, + 3, 3, 3, 3, 3, 10, 3, 29, 29, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 41, 0,136, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 10, 10, 0, 0, 0, 0, 17, 1, - 128, 1, 1, 1, 1, 99, 0, 0, 1, 1, 1, 5, 5, 23, 0, 0, + 132, 1, 1, 1, 1,100, 0, 0, 1, 1, 1, 5, 5, 23, 0, 0, 1, 1, 1, 1, 1, 1, 1, 38, 1, 1, 0, 0, 1, 1, 1, 1, - 184, 16, 16, 0, 0, 0, 0, 0, 7, 7, 7, 7, 6, 6, 6, 6, + 137, 12, 12, 0, 0, 0, 0, 0, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, - 1, 1, 0, 0, 0, 0, 0, 38, 7, 32, 7, 42, 6, 6, 6, 6, - 6, 42, 6, 6, 6, 6, 6, 6, 6, 42, 6, 6, 6, 42, 47, 0, - 13, 13, 13, 54, 13, 13, 13, 13, 61, 13, 13, 13, 13, 61, 0, 0, - 1, 1, 1, 0, 14, 1, 1, 1, 1, 1, 1, 17, 14, 0, 14, 17, - 1, 1, 1, 38, 10, 10, 10, 10, 1, 1, 1, 56, 75, 10, 10, 10, - 0, 0, 0, 49, 10, 10, 10, 10, 1, 14, 1, 0, 0, 49, 10, 10, + 1, 1, 0, 0, 0, 0, 0, 38, 7, 32, 7, 43, 6, 6, 6, 6, + 6, 43, 6, 6, 6, 6, 6, 6, 6, 43, 6, 6, 6, 43, 46, 0, + 14, 14, 14, 58, 14, 14, 14, 14, 82, 14, 14, 14, 14, 14, 14, 14, + 1, 1, 1, 0, 15, 1, 1, 1, 1, 1, 1, 17, 15, 0, 15, 17, + 1, 1, 1, 38, 10, 10, 10, 10, 1, 1, 1, 55, 75, 10, 10, 10, + 0, 0, 0, 48, 10, 10, 10, 10, 1, 15, 1, 0, 0, 48, 10, 10, 1, 1, 1, 10, 10, 10, 0, 38, 1, 1, 1, 1, 1, 0, 0, 38, - 1, 1, 1, 1, 0, 0, 10, 1, 24, 5, 26, 23, 0, 0, 5, 5, - 1, 1, 17, 1, 17, 1, 1, 1, 1, 1, 1, 0, 5, 23, 0, 26, - 12, 12, 12, 12, 33, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 78, - 1, 1, 1, 1, 82, 1, 1, 1, 1, 1, 24, 23, 0, 49, 10, 10, - 12, 12, 12, 33, 0, 0, 0, 0, 1, 1, 1, 0, 38, 12, 12, 12, - 1, 1, 1, 0, 10, 10, 10, 10, 1, 14, 0, 0, 10, 10, 10, 10, - 1, 0, 0, 0, 38, 12, 33, 0, 0, 0, 0, 0, 49, 10, 10, 10, - 7, 32, 0, 0, 0, 0, 0, 0, 6, 47, 0, 0, 0, 10, 10, 10, + 1, 1, 1, 1, 0, 0, 10, 1, 24, 5, 27, 23, 0, 0, 5, 5, + 1, 1, 17, 1, 17, 1, 1, 1, 1, 1, 1, 0, 5, 23, 0, 27, + 13, 13, 13, 13, 33, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 78, + 1, 1, 1, 1, 72, 1, 1, 1, 1, 1, 24, 23, 0, 48, 10, 10, + 13, 13, 13, 33, 0, 0, 0, 0, 1, 1, 1, 0, 38, 13, 13, 13, + 1, 1, 1, 0, 10, 10, 10, 10, 1, 15, 0, 0, 10, 10, 10, 10, + 1, 0, 0, 0, 38, 13, 33, 0, 0, 0, 0, 0, 48, 10, 10, 10, + 7, 32, 0, 0, 0, 0, 0, 0, 6, 46, 0, 0, 0, 10, 10, 10, 1, 1, 5, 5, 0, 0, 0, 0, 11, 11, 11, 11, 11, 1, 1, 52, - 7, 7, 7, 0, 26, 5, 5,130, 6, 6, 6, 0, 0, 0, 0, 9, - 10, 10, 10, 10, 10, 10, 10, 51, 1, 1, 1, 1, 1, 26,185, 0, - 0, 1, 45, 1, 0, 0, 0, 0, 57, 3, 3, 3, 29, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 5, 5, 10, 10, 10,112, 0, 0, 0, 0, - 133, 10, 78, 12, 12, 0, 0, 0, 1, 5, 5, 12, 12, 0, 0, 0, - 1, 1, 86, 10, 10, 10, 0, 0, 19, 46, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 36, 12, 12, 12, 0, - 10, 10, 10, 11, 11, 11, 11, 11, 25, 24, 25, 0, 0, 0, 0, 26, - 15, 19, 5, 20, 19, 36,186, 12, 12, 23, 0, 0, 0, 0, 73, 0, - 5, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, 5, 5, 19, 5, - 5, 5, 23, 11, 11, 11, 11, 11, 12, 12, 34, 46, 0, 0, 0, 0, - 1, 24, 12, 14, 0, 0, 0, 0, 1, 34, 15, 5, 5, 5, 5, 20, - 46, 1, 40, 12, 71, 5, 36, 19, 11, 11, 11, 11, 11, 40, 40, 12, - 10, 10, 51, 0, 0, 0, 0, 0, 5, 15, 20, 5, 12, 12, 12, 25, - 24, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 14, 14, 1, 1, 17, - 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 40, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 24, 15, 19, 5, 5, 5, 23, 0, 0, - 5, 15, 17, 1, 1, 1, 14, 17, 14, 1, 17, 1, 1, 26, 25, 15, - 20, 15, 37, 35, 37, 35, 15, 0, 14, 0, 0, 35, 0, 0, 17, 1, - 1, 15, 0, 5, 5, 5, 23, 0, 5, 5, 23, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 17, 0, 14, 1, 1, 1, 17, 15, 19, 5, 5, - 23, 37, 35, 35, 15, 37, 15, 20, 25, 25, 12, 38, 33, 0, 0, 0, - 26, 23, 0, 0, 0, 0, 0, 0, 1, 1, 34, 15, 5, 5, 5, 5, - 15, 5, 20, 25, 1, 40, 12, 12, 11, 11, 11, 11, 11, 12, 38, 25, - 15, 19, 5, 5, 20, 20, 15, 19, 20, 5, 1, 53, 0, 0, 0, 0, - 15, 5, 5, 0, 15, 15, 5, 19, 36, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 1, 1, 5, 0, 15, 19, 5, 5, 5, 20, 19, 19, - 36, 12, 14, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 33, 0, - 1, 1, 1, 1, 1, 24, 19, 15, 5, 5, 5, 19, 40, 0, 0, 0, - 11, 11, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14, 26, 19, - 15, 5, 5, 19, 5, 5, 0, 0, 11, 11, 11, 11, 11, 10, 12, 57, - 5, 5, 5, 5, 19, 36, 0, 0, 10, 51, 0, 0, 0, 0, 0, 17, - 1, 1, 1, 14, 17, 0, 1, 1, 1, 1, 17, 14, 1, 1, 1, 1, - 15, 15, 15, 35, 37, 26, 20, 25, 46, 19, 12, 33, 0, 0, 0, 0, - 1, 1, 1, 1, 0, 1, 1, 1, 34, 15, 5, 5, 0, 5, 15, 15, - 25, 53, 37, 0, 0, 0, 0, 0, 24, 5, 5, 5, 5, 25, 1, 1, - 1, 24, 5, 5, 20, 24, 5, 36, 12, 12, 12, 71, 0, 0, 0, 0, - 24, 5, 5, 20, 19, 5, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, - 5, 5, 5, 20, 5, 12, 53, 12, 12, 33, 0, 0, 0, 0, 0, 0, - 12, 12, 12, 12, 12, 0, 0, 0, 20, 5, 20, 20, 0, 0, 0, 0, - 40, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 23, 5, 5, 5, 19, - 40, 12, 12, 0, 0, 0, 0, 0, 12, 1, 1, 1, 1, 1, 1, 1, - 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 35, 5, 5, 5, - 20, 5, 19, 23, 0, 0, 0, 0, 1, 1, 1, 14, 1, 17, 1, 1, - 24, 5, 5, 23, 0, 23, 5, 26, 5, 5, 5, 24, 0, 0, 0, 0, - 1, 1, 1, 17, 14, 1, 1, 1, 1, 1, 1, 1, 1, 15, 15, 37, - 5, 35, 19, 19, 14, 0, 0, 0, 1, 1, 1, 1, 45, 1, 0, 0, - 1, 24, 20, 83, 33, 0, 0, 0, 5, 34, 1, 1, 1, 1, 1, 1, - 1, 1, 15, 5, 5, 23, 0, 15, 20, 36, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 23, 0, 0, 10, 10, 63, 3, 3, 3, 70, 30, - 97, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 38, - 16, 16, 16, 16, 16, 16, 16, 99, 12, 12, 33, 0, 0, 0, 0, 0, - 40, 33, 0, 0, 0, 0, 0, 0, 25, 1, 1, 24, 5, 5, 5, 5, - 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 15, 19, 5, - 5, 5, 36, 0, 0, 0, 0, 0, 5, 5, 5, 36, 12, 12, 3, 3, - 13, 13, 57, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 49, 10, 10, - 10, 17, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 17, 1, - 13, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45,132, 12, - 10, 10, 10, 78, 12, 33, 0, 0, 7, 7, 7, 7, 32, 42, 6, 6, - 6, 6, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14, 0, 26, - 34, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 26, - 5, 81, 13, 13, 13, 13, 13, 13, 13, 62, 23, 0, 0, 0, 0, 0, - 15, 13, 16, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, - 13, 13, 54, 13, 13, 13, 54, 61, 0, 14, 0, 0, 0, 0, 0, 0, - 1, 14, 17, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 43, 36, 18, 18, 0, 0, 0, 0, 0, 0, - 11, 11, 11, 11, 11, 3, 29, 0, 3, 3, 0, 0, 0, 3, 3, 3, - 98, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 29, 44, 3, 3, 3, - 3, 3,134, 19, 5, 3,134, 15, 15,187, 18, 18, 18, 91, 5, 5, - 5, 55, 43, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, - 3, 5, 55, 0, 0, 0, 0, 0, 6, 6, 47, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 32, 7, 0, 32, 39, 32, 39, 7, 32, 7, - 7, 7, 7, 6, 6, 42, 42, 6, 6, 6, 42, 6, 6, 6, 6, 6, - 6, 6, 7, 39, 7, 32, 39, 7, 7, 7, 32, 7, 7, 7, 32, 6, - 6, 6, 6, 6, 7, 39, 7, 32, 7, 7, 32, 32, 0, 7, 7, 7, - 32, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 7, 7, 7, 7, - 59, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 60, 6, 6, - 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 59, 6, 6, - 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 59, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, - 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, 8, 0, 11, - 5, 5, 5, 55, 3, 43, 5, 5, 5, 5, 5, 5, 5, 5, 55, 3, - 3, 3, 43, 3, 3, 3, 3, 3, 3, 3, 55, 66, 12, 12, 0, 0, - 0, 0, 0, 0, 0, 26, 5, 5, 6, 6, 6, 6, 6,124, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 47, 0, 0, 42, 6, 6, 47, 0, 0, - 5, 5, 5, 23, 5, 5, 5, 5, 5, 5, 5, 5, 23, 26, 5, 5, - 5, 26, 23, 5, 5, 23, 0, 0, 13, 13, 13, 13, 13, 13, 13, 0, - 0, 0, 0, 0, 0, 0, 0, 26, 5, 5, 5, 81, 13, 13, 13, 0, - 11, 11, 11, 11, 11, 0, 0, 56, 1, 1, 1, 1, 1, 1, 1, 23, - 1, 1, 1, 1, 1, 1, 5, 5, 11, 11, 11, 11, 11, 0, 0,113, - 1, 1, 1, 1, 1, 45, 5, 5,188, 11, 11, 11, 11,189, 0, 38, - 1, 24, 1, 25, 1, 1, 1, 5, 1, 1, 24, 0, 0, 0, 0, 45, - 1, 1, 1, 14, 1, 1, 17, 14, 1, 1, 14, 49, 10, 10, 10, 10, + 7, 7, 7, 0, 27, 5, 5, 91, 6, 6, 6, 0, 0, 0, 0, 9, + 10, 10, 10, 10, 10, 10, 10, 51, 1, 1, 1, 1, 1, 27,185, 0, + 0, 1, 44, 1,120,186, 5, 5, 56, 3, 3, 3, 72, 1, 1, 1, + 10, 10, 10,114, 0, 0, 0, 0,136, 10, 78, 13, 13, 0, 0, 0, + 1, 5, 5, 13, 13, 0, 0, 0, 1, 1, 86, 10, 10, 10, 0, 0, + 19, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, + 5, 5, 5, 36, 13, 13, 13, 0, 10, 10, 10, 11, 11, 11, 11, 11, + 25, 24, 25, 0, 0, 0, 0, 27, 16, 19, 5, 20, 19, 36,187, 13, + 13, 23, 0, 0, 0, 0, 73, 0, 5, 25, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 24, 5, 5, 19, 5, 5, 5, 23, 11, 11, 11, 11, 11, + 13, 13, 34, 45, 0, 0, 0, 0, 1, 24, 13, 15, 0, 0, 0, 0, + 1, 34, 16, 5, 5, 5, 5, 20, 45, 1, 40, 13, 70, 5, 36, 19, + 11, 11, 11, 11, 11, 40, 40, 13, 10, 10, 51, 0, 0, 0, 0, 0, + 5, 16, 20, 5, 13, 13, 13, 25, 24, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 15, 15, 1, 1, 17, 1, 1, 1, 1, 1, 1, 1, 17, + 1, 1, 1, 1, 40, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 24, + 16, 19, 5, 5, 5, 23, 0, 0, 5, 16, 17, 1, 1, 1, 15, 17, + 15, 1, 17, 1, 1, 27, 25, 16, 20, 16, 37, 35, 37, 35, 16, 0, + 15, 0, 0, 35, 0, 0, 17, 1, 1, 16, 0, 5, 5, 5, 23, 0, + 5, 5, 23, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17, 0, 15, + 1, 1, 1, 17, 16, 19, 5, 5, 23, 37, 35, 35, 16, 37, 16, 20, + 25, 25, 13, 38, 33, 0, 0, 0, 27, 23, 0, 0, 0, 0, 0, 0, + 1, 1, 34, 16, 5, 5, 5, 5, 16, 5, 20, 25, 1, 40, 13, 13, + 11, 11, 11, 11, 11, 13, 38, 25, 16, 19, 5, 5, 20, 20, 16, 19, + 20, 5, 1, 53, 0, 0, 0, 0, 16, 5, 5, 0, 16, 16, 5, 19, + 36, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 5, 0, + 16, 19, 5, 5, 5, 20, 19, 19, 36, 13, 15, 0, 0, 0, 0, 0, + 13, 13, 13, 13, 13, 13, 33, 0, 1, 1, 1, 1, 1, 24, 19, 16, + 5, 5, 5, 19, 40, 0, 0, 0, 11, 11, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 15, 27, 19, 16, 5, 5, 19, 5, 5, 0, 0, + 11, 11, 11, 11, 11, 10, 13, 56, 5, 5, 5, 5, 19, 36, 0, 0, + 10, 51, 0, 0, 0, 0, 0, 17, 1, 1, 1, 15, 17, 0, 1, 1, + 1, 1, 17, 15, 1, 1, 1, 1, 16, 16, 16, 35, 37, 27, 20, 25, + 45, 19, 13, 33, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, + 34, 16, 5, 5, 0, 5, 16, 16, 25, 53, 37, 0, 0, 0, 0, 0, + 24, 5, 5, 5, 5, 25, 1, 1, 1, 24, 5, 5, 20, 24, 5, 36, + 13, 13, 13, 70, 0, 0, 0, 0, 24, 5, 5, 20, 19, 5, 1, 1, + 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 20, 5, 13, 53, 13, + 13, 33, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 15, 0, 0, + 20, 5, 20, 20, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 23, 5, 5, 5, 19, 40, 13, 13, 0, 0, 0, 0, 0, + 13, 1, 1, 1, 1, 1, 1, 1, 0, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 35, 5, 5, 5, 20, 5, 19, 23, 0, 0, 0, 0, + 1, 1, 1, 15, 1, 17, 1, 1, 24, 5, 5, 23, 0, 23, 5, 27, + 5, 5, 5, 24, 0, 0, 0, 0, 1, 1, 1, 17, 15, 1, 1, 1, + 1, 1, 1, 1, 1, 16, 16, 37, 5, 35, 19, 19, 15, 0, 0, 0, + 1, 1, 1, 1, 44, 1, 0, 0, 1, 24, 20, 83, 33, 0, 0, 0, + 5, 34, 1, 1, 1, 1, 1, 1, 1, 1, 16, 5, 5, 23, 0, 16, + 20, 36, 13, 13, 13, 13, 13, 13, 11, 11, 11, 11, 11, 23, 0, 0, + 10, 10, 62, 3, 3, 3, 69, 30, 98, 3, 3, 3, 3, 3, 3, 3, + 3, 0, 0, 0, 0, 0, 0, 38, 13, 13,137, 12, 12, 12, 12, 12, + 12, 12, 12,100, 0, 0, 0, 0, 40, 33, 0, 0, 0, 0, 0, 0, + 25, 1, 1, 24, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 16, 19, 5, 5, 5, 36, 0, 0, 0, 0, 0, + 5, 5, 5, 36, 13, 13, 3, 3, 14, 14, 56, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 48, 10, 10, 10, 17, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 17, 1, 14, 52, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 44,135, 13, 10, 10, 10, 78, 13, 33, 0, 0, + 7, 7, 7, 7, 32, 43, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 15, 0, 27, 34, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 0, 0, 0, 27, 5, 81, 14, 14, 14, 14, 14, 14, + 14, 61, 23, 0, 0, 0, 0, 0, 16, 14, 12,100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 14, 14, 58, 14, 14, 14, 58, 82, + 0, 15, 0, 0, 0, 0, 0, 0, 1, 15, 17, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 15, 0, 0, 0, 1, 1, 1, 1, 1, 0, 41, 36, + 18, 18, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 3, 29, 0, + 3, 3, 0, 0, 0, 3, 3, 3, 29, 3, 29, 0, 0, 0,188, 9, + 9, 9, 9, 9, 9, 9, 9, 0, 5, 5, 5, 5, 5, 5, 5, 0, + 3, 3, 3, 41, 50, 3, 3, 3, 3, 3,101, 19, 5, 3,101, 16, + 16,189, 18, 18, 18, 92, 5, 5, 5, 50, 41, 5, 5, 5, 3, 3, + 3, 3, 3, 3, 3, 5, 5, 3, 3, 5, 50, 0, 0, 0, 0, 0, + 16,190, 3, 3, 3, 41, 50,101, 16, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 46, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 32, 7, + 0, 32, 39, 32, 39, 7, 32, 7, 7, 7, 7, 6, 6, 43, 43, 6, + 6, 6, 43, 6, 6, 6, 6, 6, 6, 6, 7, 39, 7, 32, 39, 7, + 7, 7, 32, 7, 7, 7, 32, 6, 6, 6, 6, 6, 7, 39, 7, 32, + 7, 7, 32, 32, 0, 7, 7, 7, 32, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 46, 7, 7, 7, 7, 59, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, + 7, 7, 59, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 60, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 59, + 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 59, 6, 6, 6, + 6, 60, 6, 6, 6, 8, 0, 11, 5, 5, 5, 50, 3, 41, 5, 5, + 5, 5, 5, 5, 5, 5, 50, 3, 3, 3, 41, 3, 3, 3, 3, 3, + 3, 3, 50, 65, 13, 13, 0, 0, 0, 0, 0, 0, 0, 27, 5, 5, + 9, 9, 9, 9, 9, 9, 99, 0, 6, 6, 6, 6, 6,128, 6, 6, + 8, 6, 6, 6, 8, 8, 21, 6, 21, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 58, 14, + 5, 5, 5, 23, 5, 5, 5, 5, 5, 5, 5, 5, 23, 27, 5, 5, + 5, 27, 23, 5, 5, 23, 0, 0, 14, 14, 14, 14, 14, 14, 14, 0, + 0, 0, 0, 0, 0, 0, 0, 27, 5, 5, 5, 81, 14, 14, 14, 0, + 11, 11, 11, 11, 11, 0, 0, 55, 1, 1, 1, 1, 1, 1, 1, 23, + 1, 1, 1, 1, 1, 1, 5, 5, 11, 11, 11, 11, 11, 0, 0,115, + 1, 1, 1, 1, 1, 44, 5, 5,191, 11, 11, 11, 11,192, 0, 38, + 1, 24, 1, 25, 1, 1, 1, 5, 1, 1, 24, 0, 0, 0, 0, 44, + 1, 1, 1, 15, 1, 1, 17, 15, 1, 1, 15, 48, 10, 10, 10, 10, 6, 6, 5, 5, 5, 81, 0, 0, 10, 10, 10, 10, 10, 10, 75, 10, - 190, 10, 51, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 75, + 193, 10, 51, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 75, 10, 10, 10, 10, 10, 10, 10, 0, 1, 1, 17, 1, 1, 1, 1, 1, - 17, 14, 14, 17, 17, 1, 1, 1, 1, 14, 1, 1, 17, 17, 0, 0, - 0, 14, 0, 17, 17, 17, 17, 1, 17, 14, 14, 17, 17, 17, 17, 17, - 17, 14, 14, 17, 1, 14, 1, 1, 1, 14, 1, 1, 17, 1, 14, 14, + 17, 15, 15, 17, 17, 1, 1, 1, 1, 15, 1, 1, 17, 17, 0, 0, + 0, 15, 0, 17, 17, 17, 17, 1, 17, 15, 15, 17, 17, 17, 17, 17, + 17, 15, 15, 17, 1, 15, 1, 1, 1, 15, 1, 1, 17, 1, 15, 15, 1, 1, 1, 1, 1, 17, 1, 1, 17, 1, 17, 1, 1, 17, 1, 1, - 9, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 63, 3, + 9, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 62, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 29, 0, 0, 0, 0, 0, 0, - 3, 3, 3, 3, 3,108, 22, 22, 3, 3, 3, 3, 29, 0, 3, 3, - 9, 9, 9, 9, 98, 0, 0, 0, 3, 3, 3, 3, 3, 29, 0, 3, - 3, 3, 3, 29, 29, 0, 44, 3, 3, 3, 3, 3, 3, 3, 29, 44, - 3, 3, 3, 3, 3, 29, 0, 44, 3, 29, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 29, 0, 0, 0, 3, 3, 3, 3, 3,110, 22, 22, + 3, 3, 3, 3, 3, 0, 3, 3, 9, 9, 9, 9, 99, 0, 0, 0, + 3, 3, 3, 29, 29, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 54, + 3, 3, 3, 3, 3, 3, 0, 54, 3, 29, 3, 3, 3, 3, 3, 3, 11, 11, 11, 11, 11, 29, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 7, 7, 3, 3, 26, 26, 4, 4, 12, 12, 5, 5, 9, 9, 9, 5, 25, 25, 15, 15, 13, 13, - 21, 21, 6, 6, 7, 2, 10, 10, 14, 14, 2, 7, 1, 1, 10, 12, - 12, 10, 5, 9, 24, 24, 12, 2, 7, 12, 12, 7, 2, 12, 22, 18, + 14, 14, 21, 21, 6, 6, 7, 2, 10, 10, 2, 7, 1, 1, 10, 12, + 12, 10, 5, 9, 24, 24, 12, 2, 7, 12, 12, 7, 22, 18, 2, 12, 0, 0, 26, 2, 23, 23, 18, 22, 9, 2, 21, 2, 7, 10, 2, 10, - 12, 21, 10, 2, 2, 21, 2, 9, 7, 21, 8, 8, 2, 5, 26, 12, - 2, 26, 7, 6, 10, 7, 5, 2, 25, 26, 2, 15, 26, 25, 15, 2, - 6, 7, 21, 7, 2, 6, 12, 26, 7, 26, 21, 26, 20, 19, 9, 25, - 5, 25, 6, 2, 21, 6, 15, 26, 25, 22, 18, 21, 26, 21, 5, 7, - 6, 24, 6, 5, 26, 23, 21, 12, 6, 12, 2, 1, 29, 29, 26, 15, - 21, 17, 25, 21, 15, 21, 11, 11, 21, 23, 12, 6, 26, 7, 10, 21, - 17, 17, 9, 26, 7, 15, 29, 21, 21, 9, 24, 5, 25, 9, 1, 12, - 17, 21, 11, 12, 8, 24, 26, 9, 21, 22, 23, 26, 25, 2, 14, 2, - 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, 5, 22, 25, 18, 24, 26, - 26, 24, 9, 8, 8, 5, 5, 21, 15, 7, 2, 23, 21, 15, 17, 7, - 18, 2, 5, 6, 5, 24, 22, 20, 21, 20, 19, 21, 21, 16, 16, 21, - 7, 5, 5, 26, 14, 15, 18, 25, 7, 14, 17, 22, 17, 6, 24, 6, - 6, 21, 12, 15, 26, 10, 25, 0, 7, 20, 25, 1, 24, 15, 7, 19, - 9, 21, 17, 2, 17, 12, 1, 21, 12, 1, 24, 7, 29, 7, 7, 22, - 14, 7, 2, 24, 9, 24, 24, 2, 29, 1, 27, 28, 1, 29, 21, 29, - 1, 2, 15, 6, 18, 6, 12, 11, 26, 5, 14, 9, 5, 14, 26, 22, - 18, 26, 5, 12, 22, 21, 18, 17, 26, 6, 18, 18, 26, 14, 14, 6, - 12, 24, 11, 21, 24, 9, 6, 9, 6, 10, 7, 25, 17, 16, 16, 22, - 16, 16, 25, 17, 25, 24, 23, 2, 21, 14, 12, 17, 21, 1, 10, 1, - 7, 13, 13, 2, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, - 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, 45, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 15, - 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 0, 19, 0, 20, 21, 0, - 0, 22, 23, 24, 25, 26, 0, 0, 0, 0, 27, 28, 29, 30, 0, 31, - 0, 32, 33, 0, 2, 34, 0, 0, 2, 1, 35, 0, 2, 1, 0, 0, - 2, 1, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 2, 36, 0, 0, - 2, 1, 0, 0, 37, 1, 0, 0, 0, 38, 0, 0, 39, 40, 0, 0, - 41, 42, 0, 43, 44, 0, 45, 46, 0, 47, 0, 0, 48, 0, 0, 49, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 51, 4, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, - 53, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 55, 0, 0, 56, 0, - 57, 58, 59, 0, 60, 5, 61, 0, 62, 0, 63, 0, 64, 0, 0, 0, - 0, 65, 66, 0, 0, 0, 0, 0, 0, 67, 68, 0, 0, 0, 0, 0, - 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 71, 0, 0, 0, 3, 0, 0, 0, 72, 0, 73, 0, 0, 74, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 76, - 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 6, 78, 0, 0, 0, - 0, 5, 79, 0, 80, 81, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, - 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, - 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 0, 90, 91, 0, 0, 0, - 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 93, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 95, 0, 96, 0, 0, 97, 0, 98, 0, 0, 0, 0, 0, 6, 99, 0, - 9, 0, 0,100,101, 0, 7, 0, 0,102, 0, 0,103, 0, 0, 0, - 0, 0,104, 0,105, 1,106, 0, 0,107, 0, 0, 0,108, 0, 0, - 0,109, 0, 0, 0, 0, 0, 0, 3,110, 0, 0, 3, 0, 0, 0, - 111, 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0,113,114, 0, 0, 0, 0, 8, 0, 4,115, 0,116, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0,117, 0,118, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,121, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,122, 0, 0, 0, 0,123, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,124,125,126, 0, 0, 0, 0,127, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129, 0, 0,130, - 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 131, 0,132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,133, 0, 0, 0, 0, 0, 0, 0,134, 0, 0, 0, 0, 0, - 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,136, 0, 0, 0,137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, - 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 1, 12, 0, 0, 1, 1, - 1, 1, 1, 49, 50, 5, 51, 52, 53, 5, 5, 22, 32, 23, 1, 54, - 24, 55, 16, 33, 56, 57, 58, 1, 1, 1, 0, 0, 0, 0, 6, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 7, 60, 1, 34, 5, - 7, 61, 62, 63, 64, 65, 66, 67, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 68, 0, 0, 0, 69, 70, 71, 35, 1, 25, 0, 0, - 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 8, 1, 26, 16, 26, - 73, 27, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, - 0, 0, 36, 25, 75, 37, 7, 37, 76, 0, 0, 0, 0, 0, 0, 0, - 6, 1, 7, 0, 0, 17, 0, 0, 0, 0, 0, 8, 38, 1, 1, 13, - 13, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, - 0, 0, 0, 6, 18, 1, 0, 0, 8, 16, 5, 1, 1, 1, 77, 7, - 36, 18, 78, 7, 35, 1, 0, 0, 0, 4, 79, 10, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 19, 0, 0, 0, 4, 0, 80, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 3, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 81, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 83, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 85, 86, 0, 0, 0, - 0, 0, 87, 88, 89, 90, 91, 92, 0, 0, 0, 0, 0, 0, 0, 93, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 28, 0, 0, 0, - 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, - 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 14, 0, 0, 20, 0, 0, - 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, - 0, 0, 0, 6, 29, 0, 3, 0, 0, 0, 0, 13, 1, 96, 0, 0, - 0, 0, 1, 18, 33, 97, 25, 23, 7, 1, 1, 1, 1, 27, 1, 7, - 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, - 6, 23, 1, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 21, - 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, - 0, 0, 12, 32, 24, 5, 99, 22, 42, 17, 0, 10, 11, 0, 7, 1, - 7,100,101, 1, 1, 1, 1, 1, 1, 1, 1,102,103,104, 0, 0, - 0, 0,105, 1,106, 10, 20,107,108, 5, 10, 0, 0, 0, 0, 0, - 0, 6, 11, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 109,110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 0, 0, 0, - 0, 6, 0, 1, 1, 11, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 0, 11, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, - 1, 1, 11, 0, 0, 0, 0, 0, 43, 40, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 44,112, 10, 8, 20, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, - 0, 0, 0, 0, 0,113, 1, 16, 5, 24, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 17, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 12, 0, 0, 0, 0,114, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,115, 2, 0,116, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 13, 11, 0, 0, 0, 0, 0, 0, - 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 39, 0, 45, - 16, 18, 29, 0, 0, 0, 46, 27, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 3, 0, 0, 3, 0, 21, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 31, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, 0, 0, - 0, 30, 3, 0, 0, 0, 14, 21, 0, 0, 0, 0, 0, 19, 47, 0, - 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 47, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 28, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 21, 41, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 28, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 22, 42, 0, 0, 0, 0, 0, 0,118, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,119, 0,120,121,122,123, 0, 43, 5, 48, 13, - 34, 0, 0, 0, 0, 0, 0, 0, 8, 11, 0, 0, 0, 0, 8, 10, - 0, 0, 0, 0, 0, 0, 1, 12, 1, 1, 1, 1, 26, 1, 38, 44, - 12, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, - 0, 19, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0,124, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 6, 19, - 0, 8, 0, 20, 0, 0, 0, 0, 0, 0, 5, 48, 0, 0, 0, 1, - 125, 0, 0, 0, 0, 0,230,230,230,230, 0, 0, 0, 9, 9, 0, - 0, 0, 0, 9, 0, 0,220,220,220,220, 0, 0, 0,230,230,230, - 220,230, 0, 0,230,230, 7, 0, 0, 0,230, 0, 0, 0,230,230, - 0, 0,230,230,230, 0, 0,230,230,230, 0, 0, 9, 0, 0, 0, - 0, 7,230,230,230,220, 0,220, 0, 0,230,220,220,220, 0, 0, - 230, 0, 0,230, 0, 0, 0, 0, 7, 0, 1, 1, 1, 1,220,230, - 230,230,220,220,230,230,220,230,230,220,230, 0, 0,230,230,220, - 0, 0, 0, 9, 9, 0,220, 0, 0, 0, 0, 0, 9, 9, 0, 9, - 7, 0, 1,220,220,220,220,220,220,230,230,230,220,220,230,220, - 220,230,230,220,230,230,220,230,220,230,230,230, 0,230, 0,220, - 220,220,220,220, 0, 0, 9, 9, 0, 0, 1, 0, 0, 0, 0, 0, - 0,220,230, 0,230,230, 0, 0,220,220, 0, 0,230,220, 0, 0, - 9, 7,220,220,220, 0,230,232,220,220,220,220,232,216,220,202, - 202,220,220,220,220,202,202,220,220,220,230,240,230,220,230,220, - 220, 0,232,220,220,230,233,234,234,233,234,234,233,230, 0,220, - 230,230,230,230,222,220,230,222,228,230, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, - 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, - 34,230, 35, 0, 0, 0,230, 0,220,230, 0, 36, 0, 0,220,220, - 230,220,220,230,230, 0,230,230, 0,220, 27, 28, 29,230, 0,230, - 220,230, 0, 84, 91, 0,103,103, 9, 0,107,107,107,107,118,118, - 9, 0,122,122,122,122, 0,220, 0,220, 0,216, 0, 0, 0,129, - 130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0, - 230,230, 9, 0,230,230, 0, 0,220, 0, 0,228, 0, 0, 0,222, - 230,220,230, 0, 0,220,230,220, 0,220,230,230,230,234,230, 0, - 1, 1,230,234,214,220,202,230,230,230,230,230,232,228,228,220, - 218,230,233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, - 1,230,220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, - 8, 0,220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1, - 220, 0, 0,230,220, 0, 0, 7, 9, 0, 6, 6, 0, 0, 0, 0, - 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216, - 216, 0,232,232,220,230,230,230, 7, 0, 1, 0, 0, 0, 0, 0, - 0, 32, 0, 0, 0, 3, 0, 0, 0, 0, 4,101, 0,112,128,169, - 0, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,237, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 1, 1, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, - 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, - 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, - 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 2, 1, 40, 41, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 36, 0, 0, - 8, 0, 0, 0, 0, 44, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, - 0, 0, 0, 0, 16, 8, 0, 0, 0, 0, 0, 0, 24, 48, 0, 0, - 0, 0, 0, 0, 28, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 28, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, - 60, 64, 0, 68, 0, 72, 76, 80, 0, 0, 0, 0, 0, 8, 84, 88, - 0, 92, 16, 8, 0, 0, 0, 4, 4, 16, 4, 4, 4, 4, 4, 4, - 4, 24, 20, 0, 96, 0, 16,100,104, 0, 4, 4,108, 0, 0, 0, - 40,112, 8, 16, 4, 4, 4, 4, 4, 8,116,120,124,128, 0, 0, - 4, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, - 4, 4, 4, 8, 0, 0, 24, 20,132, 36, 0, 28, 0,136, 16, 4, - 4, 4, 0, 0, 0, 0, 24, 12, 12,140,144, 12,148, 0,152, 8, - 4, 4, 0, 0,156, 0, 8, 8, 0, 24, 20, 8, 4, 0, 0, 0, - 8, 0, 0,160, 8, 8, 0, 0, 24, 20, 0, 8, 0, 8, 0, 8, - 0, 0, 0, 0, 40, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 16, - 4,164, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 0,168,172,176, - 0,180, 0, 24, 20, 0, 0, 0, 0, 0, 0, 0, 0,184, 16, 8, - 28, 8, 0, 0, 0, 8, 4, 4, 8, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 40, 12, 48, 0, 0, 4, 4, 8, 4, 4, 0, 0, 0, - 0, 0, 0, 0, 40, 20, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 32,188,192, 0, 0, 0, 0, 0, 0, 0, 4, 5, - 6, 7, 8, 9, 10, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 12, 13, 2, 2, 2, 2, 14, 0, 0, 0, 0, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 25, 26, 3, 3, 3, 27, - 0, 0, 0, 28, 29, 30, 0, 31, 32, 33, 34, 35, 36, 37, 1, 1, + 12, 21, 10, 2, 2, 21, 2, 9, 7, 21, 26, 12, 8, 8, 2, 5, + 7, 6, 10, 7, 5, 2, 25, 26, 2, 15, 26, 25, 12, 26, 15, 2, + 6, 7, 21, 7, 2, 26, 7, 26, 21, 26, 20, 19, 2, 6, 9, 25, + 5, 25, 21, 6, 15, 26, 25, 22, 18, 21, 26, 21, 5, 7, 6, 24, + 6, 5, 26, 23, 21, 12, 6, 12, 26, 7, 2, 1, 29, 29, 26, 15, + 21, 17, 25, 21, 15, 21, 11, 11, 21, 23, 12, 6, 6, 2, 10, 21, + 17, 17, 9, 26, 7, 15, 29, 21, 21, 9, 24, 5, 25, 9, 17, 6, + 1, 12, 17, 21, 11, 12, 8, 24, 26, 9, 21, 22, 23, 26, 25, 2, + 14, 2, 26, 10, 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, 5, 22, + 25, 18, 24, 26, 26, 24, 9, 8, 8, 5, 5, 21, 15, 7, 2, 23, + 21, 15, 17, 7, 5, 6, 5, 24, 2, 24, 22, 20, 21, 20, 19, 21, + 21, 16, 16, 21, 18, 6, 23, 2, 7, 5, 5, 26, 14, 15, 18, 25, + 7, 14, 17, 22, 24, 6, 6, 21, 12, 15, 21, 14, 25, 0, 7, 20, + 25, 1, 24, 15, 7, 19, 9, 21, 6, 26, 17, 12, 1, 21, 12, 1, + 24, 7, 29, 7, 7, 22, 18, 2, 14, 7, 9, 24, 24, 2, 29, 1, + 27, 28, 1, 29, 21, 29, 1, 2, 15, 6, 12, 11, 26, 5, 14, 9, + 5, 14, 26, 22, 18, 26, 5, 12, 22, 21, 18, 17, 26, 6, 18, 18, + 26, 14, 14, 6, 12, 24, 11, 21, 24, 9, 6, 9, 6, 10, 7, 25, + 17, 16, 16, 22, 16, 16, 25, 17, 25, 24, 12, 17, 24, 12, 21, 1, + 2, 25, 10, 1, 10, 26, 7, 13, 13, 2, 23, 15, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, + 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, + 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, + 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, + 0, 36, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, + 0, 19, 0, 20, 21, 0, 0, 22, 23, 24, 25, 26, 0, 0, 0, 0, + 27, 28, 29, 30, 0, 31, 0, 32, 33, 0, 2, 34, 0, 0, 2, 1, + 35, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 0, 1, + 0, 0, 2, 36, 0, 0, 2, 1, 0, 0, 37, 1, 0, 0, 0, 38, + 0, 0, 39, 40, 0, 0, 41, 42, 0, 43, 44, 0, 45, 46, 0, 47, + 0, 0, 48, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 4, 0, 0, 0, 0, 52, + 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 54, 0, 0, 0, 0, 0, + 0, 55, 0, 0, 56, 0, 57, 58, 59, 0, 60, 5, 61, 0, 62, 0, + 63, 0, 64, 0, 0, 0, 0, 65, 66, 0, 0, 0, 0, 0, 0, 67, + 68, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 3, 0, 0, 0, + 72, 0, 73, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 75, 76, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, + 0, 6, 78, 0, 0, 0, 0, 5, 79, 0, 80, 81, 0, 0, 7, 8, + 0, 0, 0, 0, 0, 0, 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, + 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 87, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, + 0, 90, 91, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 94, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 95, 96, 97, 0, 0, 98, 0, 99, 0, 0, + 0, 0, 0, 6,100, 0, 9, 0, 0,101,102, 0, 7, 0, 0,103, + 0, 0,104, 0, 0, 0, 0, 0,105, 0,106, 1,107, 0, 0,108, + 0, 0, 0,109, 0, 0, 0,110, 0, 0, 0, 0, 0, 0, 3,111, + 0, 0, 3, 0, 0, 0,112, 0, 0, 0,113, 0, 0, 0, 0, 0, + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,114,115, 0, 0, 0, 0, + 8, 0, 4,116, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0,118, 0,119, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,121, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,122, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 123, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,125, 0,126,127,128, 0, + 0, 0, 0,129, 0,130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,131,132, 0, 0,133, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,134, 0,135, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,136, 0, 0, 0, 0, 0, 0, 0, + 137, 0, 0, 0, 0, 0, 0, 0,138, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,139, 0, 0, 0,140, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, + 1, 12, 0, 0, 1, 1, 1, 1, 1, 49, 50, 6, 51, 52, 53, 6, + 6, 25, 36, 26, 1, 54, 17, 55, 16, 27, 56, 57, 58, 1, 1, 1, + 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 59, 7, 60, 1, 18, 6, 7, 61, 62, 63, 64, 65, 66, 67, 68, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 69, 0, 0, 0, 70, 71, + 72, 37, 1, 28, 0, 0, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 1, 29, 16, 29, 74, 38, 0, 0, 0, 0, 0, 0, 0, 0, + 75, 0, 0, 0, 0, 0, 0, 0, 30, 28, 76, 31, 7, 31, 77, 0, + 0, 0, 0, 0, 0, 0, 5, 1, 7, 0, 0, 19, 0, 0, 0, 0, + 0, 8, 39, 1, 1, 13, 13, 11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 40, 0, 0, 0, 0, 0, 0, 5, 20, 1, 0, 0, 8, 16, + 6, 1, 1, 1, 78, 7, 30, 20, 79, 7, 37, 1, 0, 0, 0, 4, + 80, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 4, + 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 14, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 83, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 85, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, + 0, 86, 87, 0, 0, 0, 0, 0, 88, 89, 90, 91, 92, 93, 0, 0, + 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 15, 32, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 22, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 96, 0, 0, 0, 0, 0, 0, 5, 23, 0, 3, 0, 0, 0, + 0, 13, 1, 97, 0, 0, 0, 0, 1, 20, 27, 98, 28, 26, 7, 1, + 1, 1, 1, 30, 1, 7, 99, 18, 10, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 0, 0, 0, 0, 5, 26, 1, 0, 0, 0, 0, 0, 33, 0, + 0, 0, 0, 0, 0, 24, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, + 0, 15, 0, 0, 0, 0, 0, 0, 12, 36, 17, 6,100, 25, 43, 19, + 0, 10, 11, 0, 7, 1, 7,101,102, 1, 1, 1, 1, 1, 1, 1, + 1,103,104,105, 0, 0, 0, 0,106, 1,107, 10, 22,108,109, 6, + 10, 0, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0,110,111, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,112, 0, 0, 0, 0, 5, 0, 1, 1, 11, 0, 0, 0, 0, + 0, 0, 0, 8, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 3, + 0, 0, 0, 0, 1, 1, 1, 1, 11, 0, 0, 0, 0, 0, 34, 41, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 44,113, 10, 8, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0,114, 1, 16, 6, 17, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 0, 0, 0, 0,115, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,116, 2, 0,117, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 13, 11, + 0, 0, 0, 0, 0, 0, 5, 10, 0, 0, 0, 0, 0, 0, 5, 17, + 0, 0, 0, 0, 0, 0, 0, 0, 27, 31, 18, 40, 0,118, 16, 20, + 23, 0, 0, 0, 45, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 3, 0, 0, 3, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 35, 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, 0, 0, 0, 33, + 3, 0, 0, 0, 14, 24, 0, 0, 0, 0, 0, 21, 46, 0, 0, 0, + 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 24, 42, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 25, 43, 0, 0, 0, 0, 0, 0,120, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,121, 0, 34, 23, 0, 0, 0, 0, 0, 0,122,123,124, + 47, 0, 34, 6, 48, 13, 18, 0, 0, 0, 0, 0, 0, 0, 8, 11, + 0, 0, 0, 0, 8, 10, 0, 0, 47, 0,125,126,127, 0, 0, 0, + 0, 0, 0, 0, 1, 12, 1, 1, 1, 1, 29, 1, 39, 44, 12, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 21, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,128, + 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 5, 21, 0, 8, + 0, 22, 0, 0, 0, 0, 0, 0, 6, 48, 0, 0, 0, 1,129, 0, + 0, 0, 0, 0,230,230,230,230, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 9, 0, 0, 0, 0, 0,230,220,220,220,220,230,230,220,230, + 0, 0,230,230, 7, 0, 0, 0,230, 0, 0, 0,230,230, 0, 0, + 230,230,230, 0, 0,230,230,230, 0, 0, 9, 0, 0, 0, 0, 7, + 230,230,230,220,220,220,230,230,230,230,220,220, 0,220, 0, 0, + 230,220,220,220, 0, 0,230, 0, 0,230, 0, 0,220, 0, 0, 0, + 0, 0, 7, 0, 1, 1, 1, 1,220,230,230,230,220,220,220,230, + 220,230,230,220,230, 0, 0,230,230,220,230,230,220,230,220,230, + 0, 9, 9, 0, 0, 0, 9, 9, 0, 0, 0,220, 0, 9, 7, 0, + 1,220,220,220,230,220,220,230,230,220, 0, 0,230,230, 0,230, + 0,220,220,220,220,220, 0, 0, 9, 9, 0, 0, 1, 0, 0, 0, + 230, 0,230,230, 0, 0,230,220, 0, 0, 9, 7,216,216,216, 0, + 220,220,220, 0,230,232,220,220,220,220,232,216,220,202,202,220, + 220,220,220,202,202,220,220,220,230,240,230,220,230,220,220, 0, + 232,220,220,230,233,234,234,233,234,234,233,230, 0,220,230,230, + 230,230,222,220,230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, + 10, 21, 0, 0, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, + 32, 33, 34,230, 35, 0, 0, 0,230, 0,220,230, 0, 36, 0, 0, + 220,220,230,220,220,230,230, 0,230,230, 0,220, 27, 28, 29,230, + 0,230,220,230, 0, 84, 91, 0,103,103, 9, 0,107,107,107,107, + 118,118, 9, 0,122,122,122,122, 0,220, 0,220, 0,216, 0, 0, + 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0, + 130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, 0,228, 0, 0, + 0,222,230,220,230, 0, 0,220,230,220, 0,220,230,230,230,234, + 230, 0, 1, 1,230,234,214,220,202,230,230,230,230,230,232,228, + 228,220,218,230,233,220,230,220,230,230, 1, 1, 1, 1, 1,230, + 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,232,222,224,224, + 0, 8, 8, 0,220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230, + 230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, 0, 7, 9, 0, + 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, + 0,226,216,216, 0, 0, 0, 1, 1, 0, 0,216,216,216, 0, 0, + 232,232,220,230,230,230, 7, 0, 1, 0, 0, 32, 0, 48, 0, 0, + 84, 96,135,144, 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,176, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 1, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 26, 0, + 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, + 35, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 39, 40, 0, 0, 0, 0, 2, 1, 41, 42, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 32, 36, 0, 0, 8, 0, 0, 0, 0, 44, + 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 16, 8, + 0, 0, 0, 0, 0, 0, 24, 48, 0, 0, 0, 0, 0, 0, 28, 0, + 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, + 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 60, 64, 0, 68, 0, 72, + 76, 80, 0, 0, 0, 0, 0, 8, 84, 88, 0, 92, 16, 8, 0, 0, + 0, 4, 4, 16, 4, 4, 4, 4, 4, 4, 4, 24, 20, 0, 96, 0, + 16,100,104, 0, 4, 4,108, 0, 0, 0, 40,112, 8, 16, 4, 4, + 4, 4, 4, 8,116,120,124,128, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 0, 0, + 24, 20,132, 36, 0, 28, 0,136, 16, 4, 4, 4, 0, 0, 0, 0, + 24, 12, 12,140,144, 12,148, 0,152, 8, 4, 4, 0, 0,156, 0, + 8, 8, 0, 24, 20, 8, 4, 0, 0, 0, 8, 0, 0,160, 8, 8, + 0, 0, 24, 20, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 40, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 20, 16, 4,164, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 20, 0,168,172,176, 0,180, 0, 24, 20, 0, + 0, 0, 0, 0, 0, 0, 0,184, 16, 8, 28, 8, 0, 0, 0, 8, + 4, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 12, 48, + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 4, 4, 0, + 0, 0, 0, 0, 0, 0, 40, 20, 0, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 32,188,192, 0, 0, 0, 0, 0, 0, 0, + 24, 20, 8, 0,196, 0, 0, 0, 19, 19, 19, 19, 20, 18, 20, 18, + 20, 18, 19, 19, 18, 20, 18, 20, 19, 19, 20, 18, 18, 20, 18, 19, + 19, 19, 19, 20, 19, 20, 18, 19, 19, 19, 19, 21, 19, 17, 19, 19, + 19, 20, 18, 20, 21, 19, 17, 19, 18, 19, 19, 19, 19, 19, 19, 25, + 19, 19, 19, 13, 22, 22, 22, 16, 16, 16, 19, 19, 19, 32, 19, 19, + 19, 38, 19, 37, 31, 29, 30, 19, 36, 19, 19, 19, 19, 19, 19, 26, + 19, 23, 19, 19, 15, 19, 19, 19, 28, 19, 19, 19, 19, 19, 33, 19, + 35, 34, 19, 34, 27, 19, 19, 19, 18, 12, 19, 19, 20, 18, 24, 24, + 24, 19, 23, 23, 19, 19, 14, 14, 14, 15, 15, 19, 20, 18, 19, 21, + 11, 20, 18, 19, 18, 22, 20, 18, 16, 20, 18, 20, 18, 19, 19, 9, + 8, 19, 19, 7, 10, 19, 19, 19, 19, 6, 19, 19, 20, 18, 19, 20, + 19, 19, 5, 19, 19, 19, 19, 4, 3, 4, 19, 19, 20, 18, 2, 19, + 19, 19, 1, 19, 19, 17, 19, 20, 18, 19, 20, 18, 0, 19, 19, 19, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, + 1, 1, 1, 19, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 20, 21, 22, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 23, 0, 0, 0, 0, 0, 0, 0, 0, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 36, 5, 37, 5, 5, + 38, 39, 0, 0, 0, 0, 0, 0, 40, 0, 41, 42, 4, 4, 4, 4, + 4, 4, 43, 44, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 48, + 0, 0, 0, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 38, 1, 1, 39, 1, 40, 1, 1, 1, 41, 0, 42, 1, 1, - 43, 1, 1, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 61, 1, 1, 1, 1, 62, 1, + 1, 1, 1, 63, 1, 1, 1, 1, 1, 1, 64, 65, 0, 0, 66, 0, + 1, 1, 1, 1, 67, 1, 1, 1, 1, 1, 1, 1, 1, 68, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1508,506 +1553,472 @@ static const uint8_t _hb_ucd_u8[19845]= 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 20, - 21, 8, 8, 8, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 2, 2, 51, 52, 53, 54, 9, 9, 9, 9, 9, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 8, 8, 70, 71, 72, - 73, 74, 75, 5, 5, 5, 5, 76, 5, 5, 5, 5, 5, 5, 5, 15, - 15, 5, 5, 5, 5, 77, 5, 78, 79, 80, 81, 82, 83, 1, 84, 85, - 86, 87, 88, 89, 90, 91, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 92, 1, 1, 1, 1, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 93, 16, 16, 94, 95, 96, 97, 98, - 99,100,101,102,103,104,105, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,106, 0, - 0, 1, 1,107,108,109, 13, 13, 13,110,111,112,113,114,115,116, - 117,118,119, 0,120,121,122,123,124,125,126, 17, 17,127,128,129, - 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145, - 146,147,148,149,150,151,152,153,154, 0,155,156,157,158, 0,159, - 160,161,162,163,164,165,166,167,168,169,170, 0,171,172,173, 7, - 7, 7, 7, 7, 7, 7,174,175, 7,176, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,177, 4, - 4, 4, 4, 4, 4, 4, 4,178, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4,179, 11, 11, 11, 11,180, 0, 0, 0, 0, - 0,181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, - 12, 12, 12,182,183,184,185, 0, 0,186, 0,187,188,189,190, 3, - 3, 3, 3, 3, 3, 14, 14, 14,191,192,193, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,194,195, - 196,197, 18, 18,198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,199,200, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 5,201, 5, 5, 5,202,203,204, 5, - 205,206,207,208,209,210, 0,211,212,213, 5, 5,214, 5,215, 10, - 10, 10, 10, 10,216, 0, 0, 0, 0, 0, 0, 0, 0,217, 0,218, - 219,220, 0, 0,221, 0, 0, 0,222, 0,223, 0,224, 0,225,226, - 227,228, 0, 0, 0, 0, 0,229,230,231, 0,232,233, 0, 0,234, - 235, 5,236,237, 0, 5, 5, 5, 5, 5, 5, 5,238, 5,239,240, - 241, 5, 5,242,243, 5,244, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,245, 1, 1,246, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,247, 1, 1, 1, - 1, 1, 1, 1, 1, 1,248, 1, 1, 1, 1,249, 0, 0, 0, 1, - 1, 1, 1,250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 1,251, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1,252, 0, 0, 0, 0, 0, 0, 0,253, - 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, - 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 12, - 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0,136, - 136,136,136,136,136,136,136, 80, 80, 80, 80, 80, 80, 80, 80, 19, - 19, 19, 19, 19, 19, 19, 19, 3, 3, 3, 3, 3, 3, 3, 3, 63, - 63, 63, 63, 63, 63, 63, 63, 39, 39, 39, 39, 39, 39, 39, 39, 28, - 28, 28, 28, 28, 28, 28, 28, 79, 79, 79, 79, 79, 79, 79, 79,131, - 131,131,131,131,131,131,131, 1, 1, 1, 1, 1, 1, 1, 1,127, - 127,127,127,127,127,127,127, 6, 6, 6, 6, 6, 6, 6, 6,155, - 155,155,155,155,155,155,155,139,139,139,139,139,139,139,139, 9, - 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15, 15, 15, 30, - 30, 30, 30, 30, 30, 30, 30,110,110,110,110,110,110,110,110, 77, - 77, 77, 77, 77, 77, 77, 77, 17, 17, 17, 17, 17, 17, 17, 17, 27, - 27, 27, 27, 27, 27, 27, 27, 33, 33, 33, 33, 33, 33, 33, 33,113, - 113,113,113,113,113,113,113, 49, 49, 49, 49, 49, 49, 49, 49, 25, - 25, 25, 25, 25, 25, 25, 25, 29, 29, 29, 29, 29, 29, 29, 29, 7, - 7, 7, 7, 7, 7, 7, 7, 32, 32, 32, 32, 32, 32, 32, 32, 8, - 8, 8, 8, 8, 8, 8, 8, 99, 99, 99, 99, 99, 99, 99, 99, 31, - 31, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30, 30, 2,105, - 105,105,105,105,105,105,105, 55, 55, 55, 55, 55, 55, 55, 55, 62, - 62, 62, 62, 62, 62, 62, 62, 56, 56, 56, 56, 56, 56, 56, 56, 91, - 91, 91, 91, 91, 91, 91, 91, 0, 0, 0, 0, 2, 2, 2, 2,100, - 100,100,100,100,100,100,100,119,119,119,119,119,119,119,119, 14, - 14, 14, 14, 14, 14, 14, 14,130,130,130,130,130,130,130,130, 94, - 94, 94, 94, 94, 94, 94, 94,157,157,157,157,157,157,157,157,137, - 137,137,137,137,137,137,137,146,146,146,146,146,146,146,146, 20, - 20, 20, 20, 20, 20, 20, 20, 35, 35, 35, 35, 35, 35, 35, 35, 0, - 0, 0, 0, 0, 0, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 40, - 40, 40, 40, 40, 40, 40, 40, 97, 97, 97, 97, 97, 97, 97, 97,124, - 124,124,124,124,124,124,124,123,123,123,123,123,123,123,123,125, - 125,125,125,125,125,125,125,140,140,140,140,140,140,140,140,159, - 159,159,159,159,159,159,159,132,132,132,132,132,132,132,132, 37, - 37, 37, 37, 37, 37, 37, 37, 22, 22, 22, 22, 22, 22, 22, 22, 24, - 24, 24, 24, 24, 24, 24, 24, 58, 58, 58, 58, 58, 58, 58, 58, 76, - 76, 76, 76, 76, 76, 76, 76, 26, 26, 26, 26, 26, 26, 26, 26, 75, - 75, 75, 75, 75, 75, 75, 75, 89, 89, 89, 89, 89, 89, 89, 89,114, - 114,114,114,114,114,114,114,141,141,141,141,141,141,141,141,133, - 133,133,133,133,133,133,133,163,163,163,163,163,163,163,163, 4, - 4, 4, 4, 4, 4, 4, 4, 70, 70, 70, 70, 70, 70, 70, 70, 0, - 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 68, - 68, 68, 68, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 87, - 87, 87, 87, 87, 87, 87, 87,135,135,135,135,135,135,135,135, 85, - 85, 85, 85, 85, 85, 85, 85, 96, 96, 96, 96, 96, 96, 96, 96,109, - 109,109,109,109,109,109,109,102,102,102,102,102,102,102,102, 64, - 64, 64, 64, 64, 64, 64, 64, 61, 61, 61, 61, 61, 61, 61, 61, 65, - 65, 65, 65, 65, 65, 65, 65, 2, 0, 0, 0, 0, 0, 0, 0,108, - 108,108,108,108,108,108,108,142,142,142,142,142,142,142,142,121, - 121,121,121,121,121,121,121,166,166,166,166,166,166,166,166,167, - 167,167,167,167,167,167,167, 0, 2, 2, 2, 2, 2, 2, 2,151, - 151,151,151,151,151,151,151,152,152,152,152,152,152,152,152, 38, - 38, 38, 38, 38, 38, 38, 38, 90, 90, 90, 90, 90, 90, 90, 90, 23, - 23, 23, 23, 23, 23, 23, 23, 36, 36, 36, 36, 36, 36, 36, 36, 30, - 2, 30, 30, 30, 30, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 93, - 93, 93, 93, 93, 93, 93, 93, 73, 73, 73, 73, 73, 73, 73, 73, 9, - 9, 9, 9, 9, 9, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 86, - 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 2, 2, 2, 67, - 67, 67, 67, 67, 67, 67, 67, 51, 51, 51, 51, 51, 51, 51, 51,104, - 104,104,104,104,104,104,104,170,170,170,170,170,170,170,170, 78, - 78, 78, 78, 78, 78, 78, 78,144,144,144,144,144,144,144,144,165, - 165,165,165,165,165,165,165,171,171,171,171,171,171,171,171,126, - 126,126,126,126,126,126,126,150,150,150,150,150,150,150,150,134, - 134,134,134,134,134,134,134,138,138,138,138,138,138,138,138,175, - 175,175,175,175,175,175,175, 18, 18, 18, 18, 18, 18, 18, 18, 0, - 0, 0, 0, 0, 2, 0, 0, 60, 60, 60, 60, 60, 60, 60, 60, 69, - 69, 69, 69, 69, 69, 69, 69,118,118,118,118,118,118,118,118, 59, - 59, 59, 59, 59, 59, 59, 59,106,106,106,106,106,106,106,106,156, - 156,156,156,156,156,156,156,147,147,147,147,147,147,147,147,148, - 148,148,148,148,148,148,148,169,169,169,169,169,169,169,169,172, - 172,172,172,172,172,172,172,164,164,164,164,164,164,164,164,168, - 168,168,168,168,168,168,168,174,174,174,174,174,174,174,174, 0, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 5, - 5, 5, 5, 5, 5, 5, 5, 21, 21, 21, 21, 21, 21, 21, 21, 16, - 16, 16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 12, 12, 12, 2, 74, - 74, 74, 74, 74, 74, 74, 74, 42, 42, 42, 42, 42, 42, 42, 42, 50, - 50, 50, 50, 50, 50, 50, 50,161,161,161,161,161,161,161,161, 47, - 47, 47, 47, 47, 47, 47, 47,120,120,120,120,120,120,120,120,116, - 116,116,116,116,116,116,116, 98, 98, 98, 98, 98, 98, 98, 98, 57, - 57, 57, 57, 57, 57, 57, 57, 88, 88, 88, 88, 88, 88, 88, 88,117, - 117,117,117,117,117,117,117,112,112,112,112,112,112,112,112,101, - 101,101,101,101,101,101,101,111,111,111,111,111,111,111,111,154, - 154,154,154,154,154,154,154,143,143,143,143,143,143,143,143,115, - 115,115,115,115,115,115,115, 0, 0, 19, 0, 0, 0, 0, 0, 95, - 95, 95, 95, 95, 95, 95, 95, 11, 11, 11, 11, 11, 11, 11, 11, 10, - 10, 10, 10, 10, 10, 10, 10, 22, 22, 22, 2, 2, 2, 22, 22, 2, - 25, 25, 25, 25, 25, 25, 25, 34, 34, 34, 34, 34, 34, 34, 34, 52, - 52, 52, 52, 52, 52, 52, 52, 54, 54, 54, 54, 54, 54, 54, 54, 0, - 0, 0, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, - 2, 12, 12, 12, 12, 12, 12, 71, 71, 71, 71, 71, 71, 71, 71, 41, - 41, 41, 41, 41, 41, 41, 41, 53, 53, 53, 53, 53, 53, 53, 53, 81, - 81, 81, 81, 81, 81, 81, 81, 66, 66, 66, 66, 66, 66, 66, 66, 72, - 72, 72, 72, 72, 72, 72, 72,173,173,173,173,173,173,173,173, 83, - 83, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82,158, - 158,158,158,158,158,158,158,153,153,153,153,153,153,153,153,145, - 145,145,145,145,145,145,145,103,103,103,103,103,103,103,103,160, - 160,160,160,160,160,160,160, 2, 3, 3, 2, 3, 2, 2, 3, 3, - 3, 3, 2, 3, 3, 3, 3, 19, 19, 19, 19, 19, 19, 19, 0, 2, - 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 0, 3, 3, 5, - 5, 5, 5, 5, 2, 2, 5, 11, 11, 11, 2, 2, 2, 2, 11, 10, - 10, 10, 10, 10, 10, 2, 10, 21, 21, 21, 21, 21, 2, 2, 21, 22, - 2, 22, 22, 22, 22, 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, - 2, 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 2, 16, 16, 16, - 2, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 2, 20, 20, 20, - 2, 20, 20, 20, 20, 20, 20, 36, 36, 36, 36, 36, 36, 36, 2, 25, - 25, 25, 25, 25, 2, 25, 25, 8, 8, 8, 8, 8, 8, 2, 8, 2, - 2, 2, 2, 2, 8, 2, 2, 29, 29, 29, 29, 29, 29, 2, 2, 45, - 45, 45, 45, 45, 45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 44, 43, - 43, 43, 43, 43, 43, 43, 43, 31, 31, 2, 2, 2, 2, 2, 2, 48, - 48, 48, 48, 2, 2, 2, 2, 91, 91, 2, 2, 2, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 2, 2, 9, 9, 9, 9, 9, 2, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, - 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 61, 0, - 17, 17, 17, 17, 17, 17, 17, 12, 12, 12, 12, 2, 2, 2, 2, 13, - 13, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 0, - 0, 0, 2, 0, 0, 0, 0, 49, 49, 49, 49, 49, 49, 2, 2, 0, - 0, 0, 2, 2, 2, 2, 0,135,135,135,135, 2, 2, 2, 2,161, - 161,161, 2,161,161,161,161,161,161, 2,161,161,161,161,161, 19, - 19, 19, 2, 2, 2, 2, 2,128,128,128,128,128,128,128,128, 57, - 2, 2, 2, 2, 2, 2, 2,112,112,112,112,112,112,112, 2,122, - 122,122,122,122,122,122,122,130,130,130, 2, 2, 2, 2, 2,165, - 165,165,165,165,165, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,149, - 149,149,149,149,149,149,149, 94, 94, 94, 94, 94, 94, 2, 2,129, - 129,129,129,129,129,129,129,107,107,107,107,107, 2, 2,107,107, - 107,107,107,107,107,107,107,107,107,107,107,107, 2, 2, 2,171, - 171,171,171,171,171, 2,171,123,123,123,123,123,123, 2, 2,102, - 102, 2, 2, 2, 2, 2, 2,154,154,154,154,154,154,154, 2, 2, - 2,150,150,150,150,150,150,169,169, 2, 2, 2, 2, 2, 2,138, - 138,138,138,138,138,138, 2,103,103,103,103,103,103, 2, 2,119, - 119, 2,119,119,119,119,119, 2, 2, 0, 0, 0, 0, 0, 0, 3, - 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 19, - 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, - 0, 26, 26, 0, 0, 0, 0, 9, 9, 9, 9, 0, 9, 9, 9, 2, - 2, 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, - 9, 9, 2, 9, 2, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, - 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 4, - 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 14, 14, - 14, 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 0, 3, 3, 3, 3, - 3, 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, - 3, 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 2, 37, 37, - 37, 37, 2, 2, 37, 37, 37, 38, 38, 2, 2, 2, 2, 2, 2, 64, - 64, 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 2, 2, 90, - 90, 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 2, 2, 95, 2, 37, - 37, 37, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, - 3, 0, 3, 3, 3, 3, 3, 7, 1, 1, 1, 1, 7, 7, 7, 7, - 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, - 2, 2, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, - 2, 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, - 2, 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, - 2, 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, - 2, 2, 11, 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, - 2, 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, - 2, 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, - 11, 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, - 10, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, - 2, 10, 10, 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, - 10, 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, - 10, 10, 10, 2, 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, - 10, 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, - 2, 2, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, - 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, - 2, 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, - 2, 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, - 2, 22, 22, 2, 22, 22, 22, 2, 22, 22, 2, 22, 2, 22, 22, 2, - 2, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 2, 22, 22, 22, - 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, - 22, 22, 2, 2, 2, 2, 2, 23, 23, 2, 2, 23, 23, 23, 23, 23, - 2, 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, - 23, 23, 2, 23, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, - 2, 2, 2, 2, 2, 2, 23, 16, 16, 16, 16, 2, 16, 16, 16, 16, - 16, 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, - 2, 2, 2, 2, 16, 16, 2, 2, 2, 2, 2, 16, 16, 16, 2, 16, - 16, 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 2, - 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, - 36, 36, 36, 2, 36, 36, 36, 2, 2, 36, 36, 36, 36, 36, 36, 36, - 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, - 2, 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, - 2, 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, - 24, 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, - 18, 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, - 18, 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, - 18, 18, 18, 18, 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, - 25, 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 0, 0, 0, 0, - 25, 25, 2, 2, 2, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 30, - 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, - 30, 2, 2, 2, 2, 2, 2, 34, 34, 34, 34, 34, 2, 2, 2, 35, - 35, 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, - 45, 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, - 44, 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 2, 2, 2, 2, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, - 2, 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 2, 2, 32, - 32, 0, 0, 32, 0, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, - 2, 2, 2, 2, 2, 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, - 28, 28, 28, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48, 48, 2, 48, - 2, 2, 2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 2, 2, 52, - 52, 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 2, 2, 2, 2, 58, - 58, 2, 2, 2, 2, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, - 54, 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 2, 91, - 91, 91, 91, 91, 2, 2, 91, 91, 91, 91, 91, 91, 91, 2, 2, 1, - 1, 1, 1, 2, 2, 2, 2, 62, 62, 62, 62, 62, 2, 62, 62, 93, - 93, 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 2, - 2, 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 6, - 6, 6, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, - 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, - 1, 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, - 9, 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, - 9, 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 2, - 9, 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, - 9, 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 0, - 0, 0, 0, 1, 1, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 19, 1, 2, 2, 2, 2, 2, 2, 2, 0, - 0, 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 55, - 55, 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, - 2, 2, 2, 2, 2, 2, 2, 13, 13, 2, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, - 13, 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 17, - 17, 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 2, - 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 0, 12, - 12, 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, - 39, 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 77, - 77, 77, 77, 2, 2, 2, 2, 0, 0, 19, 19, 19, 19, 19, 19, 0, - 0, 0, 19, 19, 19, 19, 19, 2, 19, 19, 19, 19, 19, 19, 19, 60, - 60, 60, 60, 60, 2, 2, 2, 75, 75, 75, 75, 75, 75, 2, 2, 2, - 2, 2, 2, 2, 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, - 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, - 84, 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, - 33, 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 2, 68, - 68, 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, - 92, 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, - 87, 87, 87, 87, 87, 87, 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 87, - 87, 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 12, 12, 12, 12, 12, 2, 2, 2, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, - 14, 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, - 3, 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 3, - 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, - 2, 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, - 49, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, - 49, 49, 2, 49, 49, 2, 49, 49, 49, 49, 2, 2, 2, 2, 2, 0, - 0, 0, 0, 2, 2, 2, 0, 9, 2, 2, 2, 2, 2, 2, 2, 0, - 0, 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 2, 2, 2, 67, - 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 42, - 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, - 41, 41, 2, 2, 2, 2, 2,118,118,118, 2, 2, 2, 2, 2, 53, - 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 2, 2, 2, 2, 59, - 59, 59, 59, 59, 59, 2, 2, 50, 50, 50, 50, 50, 50, 2, 2, 50, - 50, 2, 2, 2, 2, 2, 2,104,104,104,104, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2,104,161,161,161, 2,161,161, 2,161,161, - 161, 2,161,161, 2, 2, 2,170,170,170,170, 2, 2, 2, 2,110, - 110,110,110,110,110,110, 2,110,110,110,110,110,110, 2, 2, 19, - 19, 19, 19, 19, 19, 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 47, - 47, 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, - 81, 81, 81, 81, 81, 2, 81,116,116,116,116,116,116,116, 2, 2, - 2, 2, 2, 2, 2, 2,116,128,128,128, 2,128,128, 2, 2, 2, - 2, 2,128,128,128,128,128, 66, 66, 66, 66, 2, 2, 2, 66, 72, - 72, 2, 2, 2, 2, 2, 72,173,173, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, - 57, 57, 57, 2, 57, 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, - 57, 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, - 57, 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 2, - 2, 2,112,112,112,112,112, 78, 78, 78, 78, 78, 78, 2, 2, 2, - 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 2, 2, 82, - 82, 82, 2, 2, 2, 2, 2,122,122, 2, 2, 2, 2, 2, 2, 2, - 122,122,122,122, 2, 2, 2, 2,122,122,122,122,122,122,122, 89, - 2, 2, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144, - 144, 2, 2, 2, 2, 2, 2, 2,165,165,165,165,165,165,165, 2, - 2, 2, 2, 2, 2,165,165, 3, 3, 3, 3, 3, 3, 3, 2,156, - 156, 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 3, - 2, 2, 2, 2, 2, 2, 2,148,148, 2, 2, 2, 2, 2, 2,158, - 158, 2, 2, 2, 2, 2, 2,153,153,153,153, 2, 2, 2, 2,149, - 149,149,149,149,149,149, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, - 2, 2, 2, 2, 2, 2, 94, 85, 85, 85, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 85, 2, 2,101, 2, 2, 2, 2, 2, 2, 2,101, - 101, 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 2, 96, 96,111, - 111,111,111,111,111,111, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 2, 2, 2,108,108, 2,108,108,108,108,108,108, - 108, 2, 2, 2, 2, 2, 2,129,129,129,129,129,129,129, 2,129, - 2,129,129,129,129, 2,129,129,129,129,129,129,129, 2,129,129, - 129, 2, 2, 2, 2, 2, 2,109,109,109, 2, 2, 2, 2, 2,109, - 109, 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107, - 2, 2,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, - 2,107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, - 2, 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, - 2, 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,171, - 171, 2,171, 2, 2,171, 2,171, 2,171, 2, 2,171, 2,171,171, - 171,171, 2,171,171,171,171,171, 2, 2, 2, 2, 2, 2, 2, 2, - 171,171, 2, 2, 2, 2, 2,137,137,137,137, 2,137,137,137,137, - 137, 2, 2, 2, 2, 2, 2,124,124, 2, 2, 2, 2, 2, 2,114, - 114,114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, - 32, 32, 32, 32, 2, 2, 2, 33, 33, 33, 33, 2, 2, 2, 2,126, - 126,126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,126, - 126,126,126,126,126,126, 2,142,142,142,142, 2, 2, 2, 2,125, - 125,125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125, 2, - 154, 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154, - 154,154,154,154,154, 2,154,154, 2, 2,154,154,154,154,154,154, - 154, 2, 2, 2, 2, 2, 2,150,150,150,150,150, 2, 2, 2,140, - 140,140, 2, 2, 2, 2, 2,121, 2, 2, 2, 2, 2, 2, 2, 7, - 7, 2, 2, 2, 2, 2, 2,133, 2,133,133,133,133,133,133,133, - 133,133,133,133,133,133, 2,133,133,133,133,133,133, 2, 2,133, - 133,133,133,133, 2, 2, 2, 2, 2,134,134,134,134,134,134, 2, - 134,134,134,134,134,134,134,134,134,134,134,134,134,134, 2,138, - 138, 2,138,138,138,138,138, 2, 2,138, 2,138,138, 2,138,138, - 138, 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, - 2,143,143,143,143,143,143,143,143,143,143,143,143,143, 2,143, - 143, 2,143,143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143, - 143, 2, 2, 2, 2, 2, 2,175,175,175,175, 2, 2, 2, 2,175, - 175, 2, 2, 2, 2, 2, 2,145, 2, 2, 2, 2, 2, 2, 2,163, - 2,163,163,163,163,163,163,163,163,163, 2, 2, 2,163,163,163, - 163,163, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, - 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, - 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, - 63, 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157, - 157,157, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 2, 2, 80, - 80, 80, 2, 2, 2, 2, 2,127,127,127,127,127,127,127, 2,166, - 166, 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, 2, 2, 2,115, - 115,115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159, - 159,159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,119, - 119,119,119,119,119, 2, 2, 2, 2, 2, 2, 2,119,119,119,167, - 167, 2, 2, 2, 2, 2, 2,146,146,146, 2, 2, 2, 2, 2,172, - 2, 2,172,172,172,172,172,172,172,172,172, 2, 2, 2, 2, 99, - 99, 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136, - 139, 13, 13,155, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 2,155, - 155,155,155,155,155, 2, 2, 2, 2, 2, 2, 2, 2, 2,155,136, - 136,136,136,136,136,136, 2,136,136,136, 2, 2, 2, 2, 2, 17, - 17, 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, - 15, 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, - 2, 15, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 17, 2, 2, 2, - 2, 2, 2, 17, 17, 17, 17,139,139,139,139, 2, 2, 2, 2,105, - 105,105, 2, 2, 2, 2, 2,105,105,105,105,105, 2, 2, 2,105, - 2, 2, 2, 2, 2, 2, 2,105,105, 2, 2,105,105,105,105, 1, - 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, - 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, - 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0,131, - 131,131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2, - 131,131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, - 56, 56, 56, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, - 56, 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, - 6, 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151, - 151,151,151,151, 2, 2, 2,151,151,151,151,151,151, 2, 2,151, - 151, 2, 2, 2, 2,151,151,160,160,160,160,160,160,160, 2,152, - 152, 2, 2, 2, 2, 2,152,164,164, 2, 2, 2, 2, 2, 2,168, - 168,168, 2, 2, 2, 2,168,174,174,174,174,174,174,174, 2,174, - 174,174,174,174,174, 2, 2, 2, 2, 2, 2, 2, 2,174,174, 30, - 30, 30, 30, 2, 30, 30, 2,113,113,113,113,113, 2, 2,113,113, - 113,113,113,113,113,113, 2,132,132,132,132, 2, 2, 2, 2,132, - 132, 2, 2, 2, 2,132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, - 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, - 2, 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 2, - 3, 3, 3, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 0, - 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, - 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 13, - 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, - 0, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 0, 0, 0, 0, 10, 0, 11, 12, 13, 0, 0, 0, 14, 0, 0, 15, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 16, 17, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 19, - 20, 21, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 24, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, - 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, - 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, - 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, - 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, - 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, - 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, - 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 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,100,101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, - 0,107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, - 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123, - 124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,128,129,130,131,132,133,134,135,136,137,138, - 139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154, - 155,156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,162, 0,163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,164,165, - 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0,168,169, 0, - 0,170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,176,177, 0, 0, 0, 0, - 178,179, 0, 0, 0,180,181,182,183,184,185,186,187,188,189,190, - 191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, - 207,208,209,210,211,212,213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, + 70, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, + 13, 12, 12, 12, 12, 12, 12, 12, 12,178,178,178,178,178,178,178, + 178, 0, 0, 0, 0, 0, 0, 0, 0,136,136,136,136,136,136,136, + 136, 80, 80, 80, 80, 80, 80, 80, 80, 19, 19, 19, 19, 19, 19, 19, + 19, 63, 63, 63, 63, 63, 63, 63, 63, 3, 3, 3, 3, 3, 3, 3, + 3, 39, 39, 39, 39, 39, 39, 39, 39,176,176,176,176,176,176,176, + 176, 28, 28, 28, 28, 28, 28, 28, 28, 79, 79, 79, 79, 79, 79, 79, + 79,131,131,131,131,131,131,131,131, 1, 1, 1, 1, 1, 1, 1, + 1,127,127,127,127,127,127,127,127, 6, 6, 6, 6, 6, 6, 6, + 6,155,155,155,155,155,155,155,155,139,139,139,139,139,139,139, + 139, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15, 15, + 15, 30, 30, 30, 30, 30, 30, 30, 30,110,110,110,110,110,110,110, + 110, 77, 77, 77, 77, 77, 77, 77, 77, 17, 17, 17, 17, 17, 17, 17, + 17, 27, 27, 27, 27, 27, 27, 27, 27, 33, 33, 33, 33, 33, 33, 33, + 33,113,113,113,113,113,113,113,113, 49, 49, 49, 49, 49, 49, 49, + 49, 25, 25, 25, 25, 25, 25, 25, 25, 29, 29, 29, 29, 29, 29, 29, + 29,177,177,177,177,177,177,177,177, 7, 7, 7, 7, 7, 7, 7, + 7, 32, 32, 32, 32, 32, 32, 32, 32, 8, 8, 8, 8, 8, 8, 8, + 8, 99, 99, 99, 99, 99, 99, 99, 99, 31, 31, 31, 31, 31, 31, 31, + 31, 30, 30, 30, 30, 30, 30, 30, 2,105,105,105,105,105,105,105, + 105, 55, 55, 55, 55, 55, 55, 55, 55, 62, 62, 62, 62, 62, 62, 62, + 62, 0, 0, 0, 0, 2, 2, 2, 2, 56, 56, 56, 56, 56, 56, 56, + 56, 91, 91, 91, 91, 91, 91, 91, 91,100,100,100,100,100,100,100, + 100,119,119,119,119,119,119,119,119, 14, 14, 14, 14, 14, 14, 14, + 14,130,130,130,130,130,130,130,130, 94, 94, 94, 94, 94, 94, 94, + 94,157,157,157,157,157,157,157,157,137,137,137,137,137,137,137, + 137,146,146,146,146,146,146,146,146, 4, 4, 4, 4, 4, 4, 4, + 4, 20, 20, 20, 20, 20, 20, 20, 20, 35, 35, 35, 35, 35, 35, 35, + 35, 84, 84, 84, 84, 84, 84, 84, 84, 40, 40, 40, 40, 40, 40, 40, + 40, 97, 97, 97, 97, 97, 97, 97, 97,124,124,124,124,124,124,124, + 124,123,123,123,123,123,123,123,123,125,125,125,125,125,125,125, + 125,140,140,140,140,140,140,140,140,159,159,159,159,159,159,159, + 159,132,132,132,132,132,132,132,132, 37, 37, 37, 37, 37, 37, 37, + 37, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 24, 24, 24, + 24, 58, 58, 58, 58, 58, 58, 58, 58, 76, 76, 76, 76, 76, 76, 76, + 76, 0, 0, 0, 0, 0, 0, 2, 2, 26, 26, 26, 26, 26, 26, 26, + 26, 75, 75, 75, 75, 75, 75, 75, 75, 89, 89, 89, 89, 89, 89, 89, + 89,114,114,114,114,114,114,114,114,141,141,141,141,141,141,141, + 141,133,133,133,133,133,133,133,133,163,163,163,163,163,163,163, + 163, 70, 70, 70, 70, 70, 70, 70, 70, 0, 0, 0, 0, 0, 2, 2, + 2, 68, 68, 68, 68, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, + 92, 87, 87, 87, 87, 87, 87, 87, 87, 0, 0, 0, 0, 0, 0, 0, + 2,135,135,135,135,135,135,135,135, 85, 85, 85, 85, 85, 85, 85, + 85, 96, 96, 96, 96, 96, 96, 96, 96,109,109,109,109,109,109,109, + 109,102,102,102,102,102,102,102,102, 64, 64, 64, 64, 64, 64, 64, + 64, 0, 0, 2, 2, 2, 2, 2, 2, 61, 61, 61, 61, 61, 61, 61, + 61, 65, 65, 65, 65, 65, 65, 65, 65,108,108,108,108,108,108,108, + 108,142,142,142,142,142,142,142,142,121,121,121,121,121,121,121, + 121,166,166,166,166,166,166,166,166,167,167,167,167,167,167,167, + 167,151,151,151,151,151,151,151,151,152,152,152,152,152,152,152, + 152, 38, 38, 38, 38, 38, 38, 38, 38, 90, 90, 90, 90, 90, 90, 90, + 90, 23, 23, 23, 23, 23, 23, 23, 23, 36, 36, 36, 36, 36, 36, 36, + 36, 30, 2, 30, 30, 30, 30, 2, 2, 48, 48, 48, 48, 48, 48, 48, + 48, 93, 93, 93, 93, 93, 93, 93, 93, 73, 73, 73, 73, 73, 73, 73, + 73, 9, 9, 9, 9, 9, 9, 2, 2, 86, 86, 86, 86, 86, 86, 86, + 86, 2, 0, 0, 0, 0, 0, 0, 0, 67, 67, 67, 67, 67, 67, 67, + 67, 51, 51, 51, 51, 51, 51, 51, 51,104,104,104,104,104,104,104, + 104,170,170,170,170,170,170,170,170, 78, 78, 78, 78, 78, 78, 78, + 78,144,144,144,144,144,144,144,144,165,165,165,165,165,165,165, + 165,171,171,171,171,171,171,171,171,126,126,126,126,126,126,126, + 126,150,150,150,150,150,150,150,150,134,134,134,134,134,134,134, + 134,138,138,138,138,138,138,138,138,175,175,175,175,175,175,175, + 175, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 2, 0, + 0, 13, 13, 13, 13, 13, 13, 2, 2, 60, 60, 60, 60, 60, 60, 60, + 60, 69, 69, 69, 69, 69, 69, 69, 69,118,118,118,118,118,118,118, + 118, 59, 59, 59, 59, 59, 59, 59, 59,106,106,106,106,106,106,106, + 106,156,156,156,156,156,156,156,156,147,147,147,147,147,147,147, + 147,148,148,148,148,148,148,148,148,169,169,169,169,169,169,169, + 169,172,172,172,172,172,172,172,172,164,164,164,164,164,164,164, + 164,168,168,168,168,168,168,168,168,174,174,174,174,174,174,174, + 174, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, + 0, 5, 5, 5, 5, 5, 5, 5, 5, 21, 21, 21, 21, 21, 21, 21, + 21, 16, 16, 16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 12, 12, 12, + 2, 74, 74, 74, 74, 74, 74, 74, 74, 42, 42, 42, 42, 42, 42, 42, + 42, 50, 50, 50, 50, 50, 50, 50, 50,161,161,161,161,161,161,161, + 161, 47, 47, 47, 47, 47, 47, 47, 47,120,120,120,120,120,120,120, + 120,116,116,116,116,116,116,116,116, 98, 98, 98, 98, 98, 98, 98, + 98, 57, 57, 57, 57, 57, 57, 57, 57, 88, 88, 88, 88, 88, 88, 88, + 88,117,117,117,117,117,117,117,117,112,112,112,112,112,112,112, + 112,101,101,101,101,101,101,101,101,111,111,111,111,111,111,111, + 111,154,154,154,154,154,154,154,154,143,143,143,143,143,143,143, + 143,115,115,115,115,115,115,115,115, 0, 0, 19, 0, 0, 0, 0, + 0, 95, 95, 95, 95, 95, 95, 95, 95, 11, 11, 11, 11, 11, 11, 11, + 11, 10, 10, 10, 10, 10, 10, 10, 10, 22, 22, 22, 2, 2, 2, 22, + 22, 2, 25, 25, 25, 25, 25, 25, 25, 34, 34, 34, 34, 34, 34, 34, + 34, 52, 52, 52, 52, 52, 52, 52, 52, 54, 54, 54, 54, 54, 54, 54, + 54, 0, 0, 0, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, + 2, 2, 2, 12, 12, 12, 12, 12, 12, 71, 71, 71, 71, 71, 71, 71, + 71, 41, 41, 41, 41, 41, 41, 41, 41, 53, 53, 53, 53, 53, 53, 53, + 53, 81, 81, 81, 81, 81, 81, 81, 81, 66, 66, 66, 66, 66, 66, 66, + 66, 72, 72, 72, 72, 72, 72, 72, 72,173,173,173,173,173,173,173, + 173, 83, 83, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, + 82,158,158,158,158,158,158,158,158,153,153,153,153,153,153,153, + 153,145,145,145,145,145,145,145,145,103,103,103,103,103,103,103, + 103, 0, 2, 2, 2, 2, 2, 2, 2,160,160,160,160,160,160,160, + 160, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, + 3, 19, 19, 19, 19, 19, 19, 19, 0, 3, 3, 3, 3, 3, 0, 3, + 3, 5, 5, 5, 5, 5, 2, 2, 5, 11, 11, 11, 2, 2, 2, 2, + 11, 10, 10, 10, 10, 10, 10, 2, 10, 21, 21, 21, 21, 21, 2, 2, + 21, 22, 2, 22, 22, 22, 22, 2, 2, 23, 23, 23, 23, 23, 2, 23, + 23, 23, 2, 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 2, 16, + 16, 16, 2, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 2, 20, + 20, 20, 2, 20, 20, 20, 20, 20, 20, 36, 36, 36, 36, 36, 36, 36, + 2, 25, 25, 25, 25, 25, 2, 25, 25, 8, 8, 8, 8, 8, 8, 2, + 8, 2, 2, 2, 2, 2, 8, 2, 2, 29, 29, 29, 29, 29, 29, 2, + 2, 45, 45, 45, 45, 45, 45, 45, 45, 44, 44, 44, 44, 44, 44, 44, + 44, 43, 43, 43, 43, 43, 43, 43, 43, 31, 31, 2, 2, 2, 2, 2, + 2, 48, 48, 48, 48, 2, 2, 2, 2, 91, 91, 2, 2, 2, 2, 2, + 2, 1, 2, 2, 2, 2, 2, 2, 2, 9, 9, 9, 9, 9, 2, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 2, 2, 0, + 0, 2, 2, 2, 2, 2, 2, 2, 61, 0, 17, 17, 17, 17, 17, 17, + 17, 12, 12, 12, 12, 2, 2, 2, 2, 13, 13, 2, 2, 2, 2, 2, + 2, 19, 19, 19, 19, 19, 19, 19, 2, 0, 0, 0, 2, 0, 0, 0, + 0, 49, 49, 49, 49, 49, 49, 2, 2, 0, 0, 0, 0, 2, 2, 2, + 0, 1, 0, 0, 0, 0, 0, 0, 0,135,135,135,135, 2, 2, 2, + 2,161,161,161, 2,161,161,161,161,161,161, 2,161,161,161,161, + 161,128,128,128,128,128,128,128,128, 57, 2, 2, 2, 2, 2, 2, + 2,112,112,112,112,112,112,112, 2,122,122,122,122,122,122,122, + 122,130,130,130, 2, 2, 2, 2, 2,165,165,165,165,165,165, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, + 3,149,149,149,149,149,149,149,149, 94, 94, 94, 94, 94, 94, 2, + 2,129,129,129,129,129,129,129,129,107,107,107,107,107, 2, 2, + 107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2, 2, + 2,171,171,171,171,171,171, 2,171,123,123,123,123,123,123, 2, + 2,102,102, 2, 2, 2, 2, 2, 2,154,154,154,154,154,154,154, + 2, 2, 2,150,150,150,150,150,150,169,169, 2, 2, 2, 2, 2, + 2,138,138,138,138,138,138,138, 2,103,103,103,103,103,103, 2, + 2,119,119, 2,119,119,119,119,119, 13, 13, 13, 13, 13, 13, 13, + 2, 17, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, + 0, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, 0, 9, 9, 9, 9, 0, 9, 9, + 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, + 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9, 2, 9, 9, 9, 9, + 9, 9, 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 1, 1, + 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, + 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, + 2, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, + 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, + 3, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, + 37, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64, 64, 2, 2, 64, 64, + 64, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, + 2, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, + 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 0, 3, 3, 3, 3, + 3, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, + 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, + 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, + 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, + 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, + 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 2, 2, 11, 11, 11, 11, + 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, + 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, + 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, + 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, + 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, + 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, + 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, + 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, + 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, + 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, + 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, + 2, 2, 2, 2, 21, 21, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, + 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, + 22, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, + 2, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, 2, 2, + 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 2, + 2, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, + 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 23, 23, 2, + 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, + 23, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, + 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, + 2, 2, 2, 2, 2, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, + 16, 2, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 20, 20, 20, + 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, + 36, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, + 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, + 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, + 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, + 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, + 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 2, 2, + 2, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, + 2, 8, 8, 8, 0, 8, 8, 8, 8, 30, 30, 30, 2, 2, 30, 30, + 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, 2, 2, + 2, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35, 35, 0, 0, 0, 35, + 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 0, 0, + 2, 43, 43, 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, + 2, 31, 31, 31, 31, 31, 31, 2, 2, 32, 32, 0, 0, 32, 0, 32, + 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, + 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, + 2, 48, 48, 48, 48, 48, 48, 48, 2, 48, 2, 2, 2, 48, 48, 48, + 48, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, + 2, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, + 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 2, 2, 54, + 54, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, + 91, 91, 91, 91, 91, 91, 91, 2, 2, 62, 62, 62, 62, 62, 2, 62, + 62, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, + 93, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, + 70, 6, 6, 6, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, + 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, + 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, + 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, + 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 9, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 2, 2, 9, + 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, + 9, 0, 0, 0, 0, 1, 1, 0, 0, 0, 19, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, + 0, 19, 0, 0, 0, 2, 2, 2, 2, 55, 55, 55, 55, 2, 2, 2, + 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 2, 2, 2, 2, 2, 2, + 2, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, + 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13, 13, 13, 0, 0, 0, + 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 2, 2, 1, 1, 0, 0, 15, 15, 15, 17, 17, 17, 0, 0, 17, 17, + 17, 2, 2, 2, 2, 2, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, + 12, 2, 2, 2, 2, 2, 2, 2, 0, 12, 12, 12, 12, 12, 12, 12, + 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39, 39, 39, 39, 2, 2, + 2, 39, 39, 39, 39, 39, 39, 39, 2, 77, 77, 77, 77, 2, 2, 2, + 2, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 19, 2, 2, 2, 2, + 2, 2, 19, 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 2, 2, + 2, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, 75, + 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 0, + 69, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 2, + 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, + 2, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68, 2, + 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, 92, 2, 2, 2, 2, + 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, + 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, + 19, 19, 19, 0, 0, 19, 19, 2, 2, 87, 87, 87, 87, 87, 87, 2, + 2, 87, 87, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, + 12, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, 14, + 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, 3, 3, 3, 3, 0, + 0, 1, 1, 1, 1, 1, 1, 6, 6, 3, 3, 3, 3, 3, 2, 3, + 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 17, + 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 2, 2, + 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 2, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, 2, + 49, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, + 0, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 2, + 2, 71, 71, 71, 71, 71, 2, 2, 2, 67, 2, 2, 2, 2, 2, 2, + 2, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, + 42, 41, 41, 41, 2, 2, 2, 2, 2,118,118,118, 2, 2, 2, 2, + 2, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 2, 2, 2, + 2, 59, 59, 59, 59, 59, 59, 2, 2, 50, 50, 50, 50, 50, 50, 2, + 2, 50, 50, 2, 2, 2, 2, 2, 2,104,104,104,104, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2,104,161,161,161, 2,161,161, 2, + 161,161,161, 2,161,161, 2, 2, 2,170,170,170,170, 2, 2, 2, + 2,110,110,110,110,110,110,110, 2,110,110,110,110,110,110, 2, + 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2, 19, 19, 19, 19, 19, + 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, + 47, 81, 81, 81, 81, 81, 81, 2, 81,116,116,116,116,116,116,116, + 2, 2, 2, 2, 2, 2, 2, 2,116,128,128,128, 2,128,128, 2, + 2, 2, 2, 2,128,128,128,128,128, 66, 66, 66, 66, 2, 2, 2, + 66, 72, 72, 2, 2, 2, 2, 2, 72,173,173, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, + 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2, 2, 2, 57, 57, 57, + 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, + 57, 2, 2, 2,112,112,112,112,112, 78, 78, 78, 78, 78, 78, 2, + 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 2, + 2, 82, 82, 82, 2, 2, 2, 2, 2,122,122, 2, 2, 2, 2, 2, + 2, 2,122,122,122,122, 2, 2, 2, 2,122,122,122,122,122,122, + 122, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130, + 130,144,144, 2, 2, 2, 2, 2, 2, 2,165,165,165,165,165,165, + 165, 2, 2, 2, 2, 2, 2,165,165,156,156, 2,156,156,156, 2, + 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, + 3,148,148, 2, 2, 2, 2, 2, 2,158,158, 2, 2, 2, 2, 2, + 2,153,153,153,153, 2, 2, 2, 2,149,149,149,149,149,149,149, + 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, + 94, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, + 2,101, 2, 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, 2, + 2, 96, 96, 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111, + 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, + 2,108,108, 2,108,108,108,108,108,108,108, 2, 2, 2, 2, 2, + 2,129,129,129,129,129,129,129, 2,129, 2,129,129,129,129, 2, + 129,129,129,129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, + 2,109,109,109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, 2, + 2,107,107,107,107, 2,107,107,107,107, 2, 2,107,107,107,107, + 107,107, 2,107,107,107,107,107,107,107, 2,107,107, 2,107,107, + 107,107,107, 2, 1,107,107,107,107,107, 2, 2,107,107,107, 2, + 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,107, + 107,107,107,107,107, 2, 2,107,107,171,171, 2,171, 2, 2,171, + 2,171, 2,171, 2, 2,171, 2,171,171,171,171, 2,171,171,171, + 171,171, 2, 2, 2, 2, 2, 2, 2, 2,171,171, 2, 2, 2, 2, + 2,137,137,137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, + 2,124,124, 2, 2, 2, 2, 2, 2,114,114,114,114,114, 2, 2, + 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 2, 2, + 2, 33, 33, 33, 33, 2, 2, 2, 2,126,126,126, 2, 2,126,126, + 126,126,126,126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, + 2,142,142,142,142, 2, 2, 2, 2,125,125,125, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2,125, 2,154, 2, 2,154,154,154, + 154,154,154,154,154, 2,154,154, 2,154,154,154,154,154,154, 2, + 154,154, 2, 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, + 2,150,150,150,150,150, 2, 2, 2,140,140,140, 2, 2, 2, 2, + 2,121, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 2, 2, 2, 2, + 2,133, 2,133,133,133,133,133,133,133,133,133,133,133,133,133, + 2,133,133,133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, + 2, 2, 2,134,134,134,134,134,134, 2,134,134,134,134,134,134, + 134,134,134,134,134,134,134,134, 2,138,138, 2,138,138,138,138, + 138, 2, 2,138, 2,138,138, 2,138,138,138, 2, 2, 2, 2, 2, + 2,143,143,143,143,143,143, 2,143,143, 2,143,143,143,143,143, + 143,143,143,143,143,143,143,143, 2,143,143, 2,143,143,143,143, + 143,143, 2, 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, + 2,175,175,175,175, 2, 2, 2, 2,175,175, 2, 2, 2, 2, 2, + 2, 5, 5, 2, 2, 2, 2, 2, 2,145, 2, 2, 2, 2, 2, 2, + 2,163, 2,163,163,163,163,163,163,163,163,163, 2, 2, 2,163, + 163,163,163,163, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, + 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 22, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, + 2,177,177,177,177, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 2,157,157,157, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 2, + 2, 80, 80, 80, 2, 2, 2, 2, 2,127,127,127,127,127,127,127, + 2,166,166, 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, 2, 2, + 2,115,115,115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115, + 115,159,159,159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, + 2,119,119,119,119,119,119, 2, 2, 2, 2, 2, 2, 2,119,119, + 119,167,167, 2, 2, 2, 2, 2, 2,146,146,146, 2, 2, 2, 2, + 2,172, 2, 2,172,172,172,172,172,172,172,172,172, 2, 2, 2, + 2, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, + 99,136,139, 13, 13,155, 2, 2, 2,155,155,155, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2,155,136, 2, 2, 2, 2, 2, 2, + 2,136,136,136, 2, 2, 2, 2, 2,176,176, 2, 2, 2, 2, 2, + 2,176,176,176, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, + 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, + 15, 17, 17, 17, 15, 17, 17, 17, 17, 2, 2, 15, 2, 2, 2, 2, + 2, 15, 15, 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, 17, 17, + 17,139,139,139,139, 2, 2, 2, 2,105,105,105, 2, 2, 2, 2, + 2,105,105,105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, + 2,105,105, 2, 2,105,105,105,105, 0, 2, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, + 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 2, 2, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, + 2, 0, 2, 0, 0, 0, 0, 0, 0,131,131,131,131, 2, 2, 2, + 2, 2, 2, 2,131,131,131,131,131, 2,131,131,131,131,131,131, + 131, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, + 19, 19, 19, 19, 9, 9, 19, 19, 19, 56, 56, 56, 56, 56, 56, 56, + 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, + 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 6,151,151,151,151,151, 2, 2, + 2,151,151,151,151,151,151, 2, 2,151,151, 2, 2, 2, 2,151, + 151,160,160,160,160,160,160,160, 2,152,152, 2, 2, 2, 2, 2, + 152,164,164, 2, 2, 2, 2, 2, 2,168,168,168, 2, 2, 2, 2, + 168,174,174,174,174,174,174,174, 2,174,174,174,174,174,174, 2, + 2, 2, 2, 2, 2, 2, 2,174,174, 30, 30, 30, 30, 2, 30, 30, + 2,113,113,113,113,113, 2, 2,113,113,113,113,113,113,113,113, + 2,132,132,132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132, + 132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, + 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, + 2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, + 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, + 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, + 2, 2, 0, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 0, 0, 0, 10, 0, 11, 12, 13, 0, 0, 0, 14, 0, + 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 16, 17, 0, 0, 0, 0, 18, 0, 0, 0, 0, + 0, 19, 20, 21, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, + 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, + 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, + 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, + 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, + 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, + 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, + 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 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,100,101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, + 105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, + 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0, + 122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132,133,134,135,136, + 137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, + 153,154,155,156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,162, 0,163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 164,165, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0,168, + 169, 0, 0,170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,173, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,175, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,176,177, 0, 0, + 0, 0,178,179, 0, 0, 0,180,181,182,183,184,185,186,187,188, + 189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204, + 205,206,207,208,209,210,211,212,213, 0, 0, 0, 0, 0, 0, 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 uint16_t _hb_ucd_u16[10784]= +static const uint16_t _hb_ucd_u16[11240]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2019,716 +2030,737 @@ static const uint16_t _hb_ucd_u16[10784]= 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 224, 224, 768, 424, 432, 440, 448, 776, 224, 224, 784, 792, 72, 800, 40, 808, - 48, 48, 48, 816, 824, 48, 48, 832, 840, 848, 856, 864, 872, 880, 48, 888, - 48, 48, 48, 896, 904, 40, 40, 40, 40, 912, 40, 96, 920, 928, 936, 456, - 64, 64, 64, 64, 64, 64, 64, 944, 952, 960, 968, 40, 976, 984, 48, 992, - 72, 72, 72, 40, 40, 40, 48, 48,1000, 48, 48, 48,1008, 48, 48, 48, - 48, 48, 48,1016, 72,1024, 40, 40,1032, 464, 64,1040,1048, 8,1056,1064, - 1072,1080, 8, 8,1088, 64,1096,1104, 8, 8, 8, 8, 8,1112,1120,1128, - 1136,1144, 8, 64,1152, 8, 8, 8, 8, 8, 472,1160, 232, 8,1168,1176, - 8,1184,1192,1200, 8,1208, 176, 8,1216,1224, 8, 8,1232, 64,1240, 64, - 480, 8, 8,1248,1256,1264,1272,1280,1288, 240, 128,1296,1304,1312, 144,1320, - 1328, 240, 128,1336,1344,1352, 304,1360,1368, 488, 128,1376,1384, 248, 144,1392, - 1400, 240, 128,1408,1416,1424, 144,1432,1440,1448,1456,1464,1472,1480, 304,1488, - 1496, 256, 128,1504,1512,1520, 144,1528,1536, 256, 128,1544,1552,1560, 144,1568, - 1576, 256, 8,1584,1592,1600, 144,1608,1616,1624, 8,1632,1640,1648, 304,1656, + 232, 232, 776, 416, 424, 432, 440, 784, 232, 232, 792, 800, 72, 808, 40, 816, + 64, 64, 64, 824, 832, 64, 64, 840, 848, 856, 864, 872, 880, 888, 64, 896, + 64, 64, 64, 904, 912, 40, 40, 40, 40, 920, 40, 104, 928, 936, 944, 448, + 48, 48, 48, 48, 48, 48, 48, 952, 960, 968, 976, 40, 984, 992, 64,1000, + 72, 72, 72, 40, 40, 40, 64, 64,1008, 64, 64, 64,1016, 64, 64, 64, + 64, 64, 64,1024, 72,1032, 40, 40,1040, 456, 48,1048,1056, 8,1064,1072, + 1080,1088, 8, 8,1096, 48,1104,1112, 8, 8, 8, 8, 8,1120,1128,1136, + 1144,1152, 8, 48,1160, 8, 8, 8, 8, 8, 464, 472, 240, 8,1168,1176, + 8,1184,1192,1200, 8,1208, 152, 8,1216,1224, 8, 8,1232, 48,1240, 48, + 480, 8, 8,1248,1256,1264,1272,1280,1288, 248, 128,1296,1304,1312, 160,1320, + 1328, 248, 128,1336,1344,1352, 304,1360,1368, 488, 128,1376,1384, 192, 160,1392, + 1400, 248, 128,1408,1416,1424, 160,1432,1440,1448,1456,1464,1472,1480, 304,1488, + 1496, 256, 128,1504,1512,1520, 160,1528,1536, 256, 128,1544,1552,1560, 160,1568, + 1576, 256, 8,1584,1592,1600, 160,1608,1616,1624, 8,1632,1640,1648, 304,1656, 312, 8, 8,1664,1672,1680, 0, 0,1688, 8,1696,1704,1712,1720, 0, 0, - 1728,1736, 320,1744,1752, 8, 152,1760,1768,1776, 64,1784,1792,1800, 0, 0, + 1728,1736, 320,1744,1752, 8, 168,1760,1768,1776, 48,1784,1792,1800, 0, 0, 8, 8,1808,1816, 496,1824,1832,1840,1848,1856, 72, 72,1864, 40, 40,1872, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 504,1880, 8, 8, 504, 8, 8,1888, 512, 520, 8, 8, - 8, 512, 8, 8, 8,1896,1904, 528, 8, 264, 72, 72, 72, 72, 72,1912, + 8, 512, 8, 8, 8,1896,1904, 528, 8, 328, 72, 72, 72, 72, 72,1912, 536, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,1920, 8,1928,1936, 8, 8, 8, 8,1944,1952, - 8,1960, 8,1968, 8,1976,1984,1992, 8, 8, 8,2000,2008,2016, 80,2024, - 2032, 80, 8, 8,2040, 8, 8, 160,2048, 8,2056, 8, 8, 8, 8, 328, - 8, 120,2064,2072,2080, 8, 112,2088, 8, 8, 184, 8, 192,2096, 24, 24, - 8,2104, 8, 8, 8,2112,2120,2128, 80, 80,2136,2144, 64, 544,2152, 0, - 2160, 8, 8,2168,2176, 496,2184,2192, 336, 8,2200, 232, 8, 8,2208,2216, - 8, 8,2224,2232,2240, 232, 8, 552,2248, 72, 72,2256,2264,2272,2280,2288, - 40, 40,2296, 96, 96, 96,2304,2312, 40,2320, 96, 96, 64, 64, 64, 64, - 48, 48, 48, 48, 48, 48, 48, 48, 48,2328, 48, 48, 48, 48, 48, 48, - 168, 560, 168, 168, 560,2336, 168,2344, 344, 344, 344,2352,2360,2368,2376,2384, - 2392,2400,2408,2416,2424,2432,2440,2448,2456,2464, 568, 568,2472,2480,2488,2496, - 2504,2512,2520,2528,2536, 88, 104, 104,2544,2552,2560, 24,2568,2576, 24,2584, + 8,1960, 8,1968, 8,1976,1984,1992, 8, 8, 8,2000,2008,2016, 88,2024, + 2032, 88, 8, 8,2040, 8, 8, 136,2048, 8,2056, 8, 8, 8, 8, 544, + 8, 112,2064,2072,2080, 8, 120,2088, 8, 8, 200, 8, 208,2096, 24, 24, + 8,2104, 8, 8, 8,2112,2120,2128, 88, 88,2136,2144, 48, 48, 48, 552, + 2152, 8, 8,2160,2168, 496,2176,2184, 336, 8,2192, 240, 8, 8,2200,2208, + 8, 8,2216,2224,2232, 240, 8, 560,2240, 72, 72,2248,2256,2264,2272,2280, + 40, 40,2288, 104, 104, 104,2296,2304, 40,2312, 104, 104, 48, 48, 48, 48, + 64, 64, 64, 64, 64, 64, 64, 64, 64,2320, 64, 64, 64, 64, 64, 64, + 176, 568, 176, 176, 568,2328, 176,2336, 344, 344, 344,2344,2352,2360,2368,2376, + 2384,2392,2400,2408,2416,2424,2432,2440,2448, 104, 576, 576,2456,2464,2472, 552, + 2480,2488,2496,2504,2512, 96, 80, 80,2520,2528,2536, 24,2544,2552, 24,2560, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 2592, 24,2600, 24, 24, 24, 24,2608, 24,2616, 56,2624, 24,2632,2640, 24, - 24, 24, 264, 0, 576, 0, 88, 88, 88,2648, 24, 24, 24, 24,2656, 88, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,2664,2672, 24, 24,2680, - 24, 24, 24, 24, 24, 24,2688, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24,2696,2704, 88,2712, 24, 24,2720, 56,2728, 56, + 2568, 24,2576, 24, 24, 24, 24,2584, 24,2592, 56,2600, 24,2608,2616, 24, + 24, 24, 328, 0, 584, 0, 96, 96, 96,2624, 24, 24, 24, 24,2632, 96, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,2640,2648, 24, 24,2656, + 24, 24, 24, 24, 24, 24,2664, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24,2672,2680, 96,2688, 24, 24,2696, 56,2704, 56, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 56, 56, 56, 56, 56, 56, 56, 56,2736,2744, 56, 56, 56,2752, 56,2760, + 56, 56, 56, 56, 56, 56, 56, 56,2712,2720, 56, 56, 56,2728, 56,2736, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 24, 24, 24, 56,2768, 24, 24,2776, 24, 24, 24, 24, 24, 24, 24, 24, - 72, 72, 72, 40, 40, 40,2784,2792, 48, 48, 48, 48, 48, 48,2800,2808, - 40, 40,2816, 8, 8, 8,2824,2832, 8, 200, 208, 208, 208, 208, 64, 64, - 2840,2848,2856,2864,2872,2880, 0, 0, 24,2888, 24, 24, 24, 24, 24, 352, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 272, 0, 24, - 2896,2904,2912,2920, 312, 8, 8, 8, 8,2928, 536, 8, 8, 8, 8,2936, - 2944, 8, 8, 312, 8, 8, 8, 8, 120,2952, 8, 8, 24, 24,2960, 8, - 24, 584, 592, 24,2968, 600, 24, 24, 592, 24, 24, 600, 24, 24, 24, 24, + 24, 24, 24, 56,2744, 24, 24,2752, 24, 24, 24, 24, 24, 24, 24, 24, + 72, 72, 72, 40, 40, 40,2760,2768, 64, 64, 64, 64, 64, 64,2776,2784, + 40, 40,2792, 8, 8, 8,2800,2808, 8, 216, 224, 224, 224, 224, 48, 48, + 2816,2824,2832,2840,2848,2856,2864, 0, 24,2872, 24, 24, 24, 24, 24, 352, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 264, 0, 24, + 2880,2888,2896,2904, 312, 8, 8, 8, 8,2912, 536, 8, 8, 8, 8,2920, + 2928, 8, 8, 312, 8, 8, 8, 8, 112,2936, 8, 8, 24, 24,2944, 8, + 24, 360, 592, 24,2952, 600, 24, 24, 592, 24, 24, 600, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, - 8,2976, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8,2960, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 152, 24, 24, 24, 608, 8, 8, 552, + 8, 8, 8, 8, 8, 8, 8, 8, 168, 24, 24, 24, 608, 8, 8, 560, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 2984, 8,2992, 0, 48, 48,3000,3008, 48,3016, 8, 8, 8, 8,3024,3032, - 456,3040,3048,3056, 48, 48, 48,3064,3072,3080,3088,3096,3104,3112, 0,3120, - 3128, 8,3136,3144, 8, 8, 8,3152,3160, 8, 8,3168,3176, 80, 64,3184, - 232, 8,3192, 8,3200,3208, 8, 152, 480, 8, 8,3216,3224, 360,3232,3240, - 8, 8,3248,3256,3264,3272, 8,3280, 8, 8, 8,3288,3296,3304,3312,3320, - 3328,3336, 208, 40, 40,3344,3352, 40, 40, 40, 40, 40, 8, 8,3360, 80, + 2968, 8,2976, 0, 64, 64,2984,2992, 64,3000, 8, 8, 8, 8,3008,3016, + 448,3024,3032, 616, 64, 64, 64,3040,3048,3056,3064,3072,3080,3088,3096,3104, + 3112, 8,3120,3128, 8, 8, 8,3136,3144, 8, 8,3152,3160, 88, 48,3168, + 240, 8,3176, 8,3184,3192, 8, 168, 480, 8, 8,3200,3208, 368,3216,3224, + 8, 8,3232,3240,3248,3256, 8,3264, 8, 8, 8,3272,3280,3288,3296,3304, + 3312,3320, 224, 40, 40,3328,3336, 40, 40, 40, 40, 40, 8, 8,3344, 88, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 368, 8,3368, 8, 8, 184, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 376, 8,3352, 8, 8, 200, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 112, 8, 8, 8, 8, 8, 8, 192, 0, 0, - 3376,3384,3392,3400,3408, 8, 8, 8, 8, 8, 8,3416,3424,3432, 8, 8, + 8, 8, 8, 8, 8, 8, 120, 8, 8, 8, 8, 8, 8, 208, 0, 0, + 624,3360,3368,3376,3384, 8, 8, 8, 8, 8, 8,3392,3400,3408, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8,3440, 24, 8, 8, 8, 8,3448, 8, 8,3456, 0, 0,3464, - 64,3472, 64,3480,3488,3496,3504,3512, 8, 8, 8, 8, 8, 8, 8,3520, - 3528, 424, 432, 440, 448,3536,3544,3552, 8,3560, 8, 120,3568,3576,3584,3592, - 3600, 8, 520,3608, 112, 112, 0, 0, 8, 8, 8, 8, 8, 8, 8, 176, - 3616, 88, 88,3624, 104, 104, 104,3632,3640, 280, 376, 0, 0, 24, 24,3648, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 152, 8, 8, 8, 248,3656,3664, - 8, 8,3672, 8,3680, 8, 8,3688, 8,3696, 8, 8,3704,3712, 0, 0, - 72, 72,3720, 40, 40, 8, 8, 8, 8, 112, 80, 72, 72,3728, 40,3736, - 8, 8, 616, 8, 8, 8,3744, 624, 624,3752,3760,3768, 8, 8, 8, 368, + 8, 8, 8,3416, 24, 8, 8, 8, 8,3424, 8, 8,3432, 0, 0,3440, + 48,3448, 48,3456,3464,3472,3480,3488, 8, 8, 8, 8, 8, 8, 8,3496, + 3504, 416, 424, 432, 440,3512,3520,3528, 8,3536, 8, 112,3544,3552,3560,3568, + 3576, 8, 520,3584, 120, 120, 0, 0, 8, 8, 8, 8, 8, 8, 8, 152, + 3592, 96, 96,3600, 80, 80, 80,3608,3616, 272,3624, 0, 0, 24, 24,3632, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 168, 8, 8, 8, 192,3640,3648, + 8, 8,3656, 8,3664, 8, 8,3672, 8,3680, 8, 8,3688,3696, 0, 0, + 72, 72,3704, 40, 40, 8, 8, 8, 8, 120, 88, 72, 72,3712, 40,3720, + 8, 8, 632, 8, 8, 8,3728, 640, 640,3736,3744,3752, 8, 8, 8, 376, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 200, 8, 328, 616, 0,3776, 96, 96,3784, 0, 0, 0, 0, - 3792, 8, 8,3800, 8,3808, 8,3816, 8, 120,3824, 0, 0, 0, 8,3832, - 8,3840, 8,3848, 8, 192, 0, 0, 8, 8, 8,3856, 88, 632, 88, 88, - 3864,3872, 8,3880, 640,3888, 8,3896, 8, 648, 0, 0,3904, 8,3912,3920, - 8, 8, 8,3928, 8,3936, 8,3944, 8,3952,3960, 0, 0, 0, 0, 0, - 8, 8, 8, 8, 160, 0, 0, 0, 72, 72, 72,3968, 40, 40, 40,3976, - 8, 8,3984, 80,3992, 72,4000, 40,4008, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 88,4016, 8, 8,4024, 656,4032,4040, 0,4048, - 8, 648,4056, 8, 472,4064, 0, 8,4072, 0, 0, 8,4080, 0, 8, 200, - 4088, 8, 8,4096,4104, 632,4112,4120, 336, 8, 8,4128,4136, 8, 160, 80, - 4144, 8,4152,4160,4168, 8, 8,4176, 336, 8, 8,4184,4192,4200, 384,4208, - 8, 488, 664,4216,4224, 0, 0, 0,4232,4240,4248, 8, 8,4256,4264, 80, - 4272, 240, 128,4280,4288,4296,4304,4312,4320, 8, 8,4328,4336,4344,4352, 0, - 8, 8, 8,4360,4368,4376, 656, 0, 8, 8, 8,4384,4392, 80, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 672,4400,4408,4416, 0, 0, - 8, 8, 8,4424,4432, 80,4440, 0, 8, 8,4448,4456, 80, 288,4464, 0, - 8,4472,4480,4488, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 664,4496, 0, 0, 0, 0, 0, 0, 72, 72, 40, 40, 320,4504, - 4512,4520, 8,4528,4536, 80, 0, 0, 0, 0,4544, 8, 8,4552,4560, 0, - 4568, 8, 8,4576,4584,4592, 8, 8,4600,4608,4616, 8, 8, 8, 8, 160, - 4624, 0, 0, 0, 0, 0,4632, 0, 0, 0, 0, 0, 8, 8,4640, 80, - 128, 8, 672,4648,4656, 320, 528,4664, 8,4672,4680,4688, 0, 0, 0, 0, - 4696, 8, 8,4704,4712, 80,4720, 8,4728,4736, 80, 8, 8,4744, 80, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,4752, - 4760, 256, 8,4768,4776,4784, 0, 0, 0, 0, 0, 248, 88,4792,4800,4808, + 8, 8, 8, 216, 8, 544, 632, 0,3760, 104, 104,3768, 0, 0, 0, 0, + 3776, 8, 8,3784, 8,3792, 8,3800, 8, 112,3808, 0, 0, 0, 8,3816, + 8,3824, 8,3832, 8, 208, 0, 0, 8, 8, 8,3840, 96, 648, 96, 96, + 3848,3856, 8,3864, 656,3872, 8,3880, 8, 664, 0, 0,3888, 8,3896,3904, + 8, 8, 8,3912, 8,3920, 8,3928, 8,3936,3944, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 136, 0, 0, 0, 72, 72, 72,3952, 40, 40, 40,3960, + 8, 8,3968, 88,3976, 72,3984, 40,3992, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 96,4000, 8, 8,4008, 280,4016,4024, 112, 48, + 8, 664,4032, 8, 464,4040, 0, 8,4048, 0, 0, 8,4056, 0, 8, 216, + 4064, 8, 8,4072,4080, 648,4088,4096, 336, 8, 8,4104,4112, 8, 136, 88, + 4120, 8,4128,4136,4144, 8, 8,4152, 336, 8, 8,4160,4168,4176, 384,4184, + 8, 488, 672,4192,4200, 0, 0, 0,4208,4216,4224, 8, 8,4232,4240, 88, + 4248, 248, 128,4256,4264,4272,4280,4288,4296, 8, 8,4304,4312,4320,4328, 0, + 8, 8, 8,4336,4344,4352, 280, 0, 8, 8, 8,4360,4368, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 680,4376,4384,4392, 0, 0, + 8, 8, 8,4400,4408, 88,4416, 0, 8, 8,4424,4432, 88, 288,4440, 0, + 8,4448,4456,4464, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 672,4472, 0, 0, 0, 0, 0, 0, 72, 72, 40, 40, 320,4480, + 4488,4496, 8,4504,4512, 88, 0, 0, 0, 0,4520, 8, 8,4528,4536, 0, + 4544, 8, 8,4552,4560,4568, 8, 8,4576,4584,4592, 8, 8, 8, 8, 136, + 4600, 0, 0, 0, 0, 0,4608, 0, 0, 0, 0, 0, 8, 8,4616, 88, + 128, 8, 680,4624,4632, 320, 528,4640, 8,4648,4656,4664, 0, 0, 0, 0, + 4672, 8, 8,4680,4688, 88,4696, 8,4704,4712, 88, 8, 8,4720, 88, 472, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,4728, + 4736, 256, 8,4744,4752,4760, 0, 0, 0, 0, 0, 192, 96,4768,4776,4784, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 192, 0, 0, 0, 0, 0, 0, - 104, 104, 104, 104, 104, 104,4816,4824, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 208, 0, 0, 0, 0, 0, 0, + 80, 80, 80, 80, 80, 80, 80,4792, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 376, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80,4800, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8,4832, - 8, 8, 8, 136,4840,4848, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8,4808, + 8, 8, 8, 144,4816,4824, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 176, - 8, 8, 8, 8, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 152, + 8, 8, 8, 8, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 680,4856, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 8, 160, 8, 120, 360, 8, 8, 8, 8, 120, 80, 8, 112,4864, - 8, 8, 8,4872,4880,4888,4896,4904, 8, 0, 0, 0, 0, 0, 0, 0, + 8, 688,4832, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 136, 8, 112, 368, 8, 8, 8, 8, 112, 88, 8, 120,4840, + 8, 8, 8,4848,4856,4864,4872,4880, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,4912, 8,4920, 80, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 72, 72, 40, 40, 88,4928, 72,4936, 40,4944, 0, 0, - 8, 8, 8, 8,4952,4960, 688, 688,4968,4976, 0, 0, 0, 0,4984,4992, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 328, 0,5000, - 8, 120, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 696, + 0, 0, 0, 0,4888, 8,4896, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 72, 72, 40, 40, 96,4904, 72,4912, 40,4920, 0, 0, + 8, 8, 8, 8,4928,4936, 696, 696,4944,4952, 0, 0, 0, 0,4960,4968, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 152, 0,4976, + 8, 8, 192, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 704, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 280, 8, 8, 8, 704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5008, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,4984, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 696,5016, 0,5024,5032, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 184, + 8, 8, 136,4992, 0,5000,5008, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 8, 8, 8, 8, 176, 152, 160,5040,5048, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 152, 168, 136,5016,5024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5056, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5032, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5064, 24, 376, 24,5072, - 64, 64, 544, 64, 704, 24, 24, 24, 24, 24, 24, 24, 352, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 272, - 24, 24,5080, 24, 24, 24,5088,5096,5104, 24,5112, 24, 24, 24, 576, 0, - 24, 24, 24, 24,5120, 0, 0, 0, 0, 0, 0, 0, 88, 712, 88, 712, - 24, 24, 24, 24, 24, 608, 88, 640, 0, 0, 0, 0, 0, 0, 0, 0, - 72, 296, 40, 720, 728,5128, 168, 72, 392,5136,5144,5152,5160, 72, 296, 40, - 5168,5176, 40,5184,5192,5200, 736, 72, 744, 40, 72, 296, 40, 720, 728, 40, - 168, 72, 392, 736, 72, 744, 40, 72, 296, 40,5208, 72,5216,5224,5232,5240, - 40,5248, 72,5256,5264,5272,5280, 40,5288, 72,5296, 40,5304, 288, 288, 288, - 64, 64, 64,5312, 64, 64,5320,5328,5336,5344, 464, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5040, 24,5048, 24,5056, + 48, 48,5064, 48, 712, 24, 24, 24, 24, 24, 24, 24, 352, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 264, + 24, 24,5072, 24, 24, 24,5080,5088,5096, 24,5104, 24, 24, 24, 24, 24, + 24, 24, 24, 24,5112,5120, 24, 24,5128, 0, 0, 0, 96, 720, 96, 720, + 24, 24, 24, 24, 24, 608, 96, 656, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 296, 40, 728, 736,5136, 176, 72, 392,5144,5152,5160,5168, 72, 296, 40, + 5176,5184, 40,5192,5200,5208, 744, 72, 752, 40, 72, 296, 40, 728, 736, 40, + 176, 72, 392, 744, 72, 752, 40, 72, 296, 40,5216, 72,5224,5232,5240,5248, + 40,5256, 72,5264,5272,5280,5288, 40,5296, 72,5304, 40,5312, 288, 288, 288, + 48, 48, 48,5320, 48, 48,5328,5336,5344,5352, 456, 0, 0, 0, 0, 0, + 56,5360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5352,5360,5368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5376,5384,5392, 96, 96, 96,5400, 0,5408, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 152,5416,5424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5432, 0, 8, 8,5440,5448, + 5368, 40, 40, 40,5376,5384,5392, 616, 280, 624, 0, 0,5400, 104, 104, 104, + 5408,5416,5424, 104, 104, 104,5432, 0,5440, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 168,5448,5456, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5464, 0, 8, 8,5472,5480, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5456, 80, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 680,5464, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120,5472,5480, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5488, 120, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,5496, 704, 0, 0, - 72, 72, 392, 40,5504, 360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 384, 88, 88,5512,5520, 0, 0, 0, 0, - 384, 88,5528,5536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5544, 8,5552,5560,5568,5576,5584,5592,5600, 184,5608, 184, 0, 0, 0,5616, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5488, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 688,5496, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 112,5504,5512, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5520, 112, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,5528, 712, 0, 0, + 72, 72, 392, 40,5536, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 384, 96, 96,5544,5552, 0, 0, 0, 0, + 384, 96,5560,5568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5576, 8,5584,5592,5600,5608,5616,5624,5632, 200,5640, 200, 0, 0, 0,5648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 24, 24, 216, 24, 24, 24, 24, 24, 24, 352, 584, 400, 400, 400, 24, 272, - 5624, 24, 24, 24, 24, 24, 24, 24, 24, 24, 408, 0, 0, 0,5632, 24, - 5640, 24, 24, 216, 752, 760, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5648, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5656, 280, 280, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 264, 216, 376, - 216, 24, 24, 24, 416, 264, 24, 24, 416, 24, 408, 216, 760,5664, 0, 0, + 24, 24, 184, 24, 24, 24, 24, 24, 24, 352, 360, 400, 400, 400, 24, 264, + 5656, 24, 24, 24, 24, 24, 24, 24, 24, 24, 360, 0, 0, 0,5664, 24, + 5672, 24, 24, 184,5680, 760, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5688, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5696, 272, 272, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 184, 184, 24, + 184, 24, 24, 24, 408, 328, 24, 24, 408, 24, 768, 184, 760,5704, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 416, 408, 280,5672, 24, 24, 24,5680,5688,5696, 752, - 24, 24, 24, 24, 24, 24, 24, 24, 24,5704, 24, 24, 24, 24, 24,5712, + 24, 24, 24, 24, 24, 408, 768, 272, 24, 24, 24, 24,5712,5720,5728, 584, + 24, 24, 24, 24, 24, 24, 24, 24, 24,5736, 24, 24, 24, 24, 24,5744, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 112, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 112, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 120, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 248, 8, - 8, 8, 8, 8, 8, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 192, 8, + 8, 8, 8, 8, 8, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 176, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 192, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 152, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5720, 0, 136, 136, 136, 136, 136, 136, 0, 0, 0, 0, 0, 0, 0, 0, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, + 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5752, 0, 144, 144, 144, 144, 144, 144, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,5728, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,5760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, - 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, - 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, - 24, 24, 24, 24, 24, 24, 24, 24,1104, 48, 48,1112,1104, 48, 48,1112, - 24, 24, 24, 24, 24,1288, 24,1288, 48, 48,1512, 48, 48, 48,1512, 48, - 48, 48, 48, 48, 48, 48, 48,2048, 24, 24, 24, 24,2056,2064, 24, 24, - 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,2072,2080, - 2088,2096, 144, 144,2104, 144, 144, 144, 144, 144, 144, 144,2112, 296, 144, 144, - 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, - 2120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120,1520, 592, 592, 592,2128,1520, 592, 592, 592, 592, - 592,2136,2144, 352, 352, 352, 352, 352, 352, 0, 352, 352, 352,2152,2160, 0, - 1528,2168, 56,2176, 56, 56, 56, 56,2184,2192,2200, 56, 56, 56,2208, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,1528, 56, 56, 56, 56, - 496,2216, 496, 496, 496, 496, 496, 496, 496,2224, 56, 56, 56, 56, 56, 56, - 784, 784, 784, 784, 784, 784,2232, 0, 688, 688, 688, 688, 688, 688, 688,2240, - 792, 792, 792, 792, 792,2248, 792,2256,1296,1296,1296,2264, 496,2272, 56, 56, - 56, 56,2280, 56, 56, 56, 56, 56, 56, 56, 56, 56,2288, 56, 56, 56, - 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,2296, 240,2304, 240, 240, 240, - 2312,1536,2320,1120,1120,2328,2336,2344,1536,2352,2360,2368,2376,1120,1120,2384, - 2392,1544,2400,1304,1304,2408,2416,2424,1544,2432,2440,2448,2456,1304,2464, 0, - 2472,1552,2480,1312,1312,2488,2496,2504,1552,2512,2520, 0,2528,1312,2536,2544, - 2552,1560,2560,1128,1128,2568,2576,2584,1560,2592,2600,2608,2616,1128,1128, 0, - 2624,1320,1568,2632,2640,1320, 504,2648,1320,1568,2656, 0,2664, 504, 504,2672, - 800,1576,1584, 800, 800,1584, 800,2680,1576,2688,2696,2704,2712, 800,2720, 800, - 1136,1592,1600,1136,1136,1600,2728,2736,1592,2744,2752,2760,2768,1136,2776, 0, - 400,1608,1616, 400, 400, 400, 400, 400,1608,1616,2784, 400,2792, 400, 400, 400, - 2800, 808,1624,2808, 808, 808,2816,2824,1624,2832,2840, 808,2848, 808,2856, 0, - 2864, 512, 512, 512, 512, 512, 512,2872, 512, 512, 512,2880, 0, 0, 0, 0, - 2888,2896, 984, 984,2904, 984, 984,2912,2920,2928, 984,2936, 0, 0, 0, 0, - 224, 224, 224, 224, 224, 224, 224, 224, 224,1328, 224, 224, 224,2944,1328, 224, - 224, 224, 224,1328, 224, 224, 224,1632, 224,1632,2952,2960, 0, 0, 0, 0, - 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, - 200, 200, 200, 200, 256, 256, 256, 256,1640,1648, 256, 256, 256, 256, 256,2968, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 816, 280, 816, 160, 160, 160, 160, - 160, 816, 160, 160, 160, 160, 816, 280, 816, 160, 280, 160, 160, 160, 160, 160, - 160, 160, 816, 160, 160, 160, 160, 160, 160, 160, 160,2976, 160, 160, 160,2984, - 160, 160, 160,2992, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,1656,1656, - 1336,1336,1336,3000, 408, 408, 408, 408, 408, 408, 408, 408, 408,3008, 408,3016, - 1664,1664,3024,3032,1672,1672,3040, 0,1680,1680,3048, 0,3056,3064,3072, 0, - 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272,3080, 272,1688, 272,1688, - 3088, 248, 248,3096, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,3104, - 248, 248, 248, 248, 248,3112, 80, 80, 80, 80, 80, 80, 80, 80,3120, 0, - 824, 824, 824,3128, 824,1696, 824,1696,3136, 824,1344,1344,1344,3144,3152, 0, - 520, 520, 520, 520, 520,3160, 520, 520, 520,3168, 520,3176, 272, 272, 272, 272, - 1352,1352,1352,3184, 320, 320, 320, 320, 320, 320, 320,3192, 320, 320, 320,3200, - 320,1704, 320,1704, 320,3208, 104, 104, 104, 104, 104,1712, 104,3216, 0, 0, - 304, 304, 304, 304, 304, 304, 304, 304, 304,3224, 304, 304, 304, 304, 304, 304, - 528, 528, 528, 528, 528, 528, 528, 528, 832, 832, 832, 832, 832, 832,3232,3240, - 600, 600, 600, 600, 600, 600, 600,3248, 600,3256, 840, 840, 840, 840, 840, 840, - 120,3264, 256, 256, 256, 256, 256,3272, 528, 0,3280, 104,3288,3296,3304,3312, - 48, 48, 48, 48,3320,3328, 48, 48, 48, 48, 48,3336,3344,3352, 48,3360, - 48, 48, 48, 48, 48, 48, 48,3368, 104, 104, 104, 104, 104, 104, 104, 104, - 144, 144, 848, 848, 144, 144, 144, 144, 848, 848, 144,3376, 144, 144, 144, 848, - 144, 144, 144, 144, 144, 144,1720, 144,1720, 144,3384,3392, 144, 144,3400,1728, - 24,3408, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 992, 24,3416,3424, - 24, 608, 48,1736, 24, 24, 24, 24, 616, 0, 104, 104, 104, 104,3432, 0, - 24, 24, 24, 24,3440,3448,1288, 24, 24,3456, 24, 24, 48, 48, 48, 48, - 48,3464, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 616, 0, 0, 24,1360, 0, 0, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,1744, 24, - 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 48, 48, 48, 48, - 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296,3472,3480, - 256, 256, 256, 256,1640,1648, 696, 696, 696, 696, 696, 696, 696,1752,3488,1752, - 160, 160, 280, 0, 280, 280, 280, 280, 280, 280, 280, 280, 120, 120, 120, 120, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 416, 0, 0, 0, 0, - 8, 8, 8,3496, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,3504, 0, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 856, 0, 0, 0, 24, 24, - 3512, 24, 24, 24,3520,3528, 24,3536,3544, 152, 152, 152, 152, 152, 152, 152, - 152, 152,3552,3560,1760, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,3568, - 3576, 536, 536, 536, 536, 536,3584, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16,1144, 24, 24, 536, 536, 536, 536, 24, 24, 24, 24, 416,3592, 184, 184, - 16, 16, 16,1144, 24, 24, 24, 24, 24, 24, 24, 24, 16, 16, 16,3600, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 184, 184, 184, 184, 184,3608, - 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 24, 24, 24, 24, 24, - 8, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, 24, 24, 24, 24, - 72,3616, 72, 72, 72, 72, 72, 72,3624, 0, 864, 864, 864, 864, 864, 864, - 176, 176, 176, 176, 176,3632, 0, 0, 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 0, - 24, 24, 24, 24,3640, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48,3648, 48, 48, 48, 48, 48, 48, 48, 48, 48,1736, 0, 0,3656, 48, - 1000,1000,1000,1000,1000,3664, 24, 616, 704, 704, 704, 704, 704, 704, 704, 0, - 544, 544, 544, 544, 544, 544, 544, 544,3672,3680, 544,3688, 240, 240, 240, 240, - 1008,1008,1008,1008,1008,3696,1152,1152,1152,1152,3704,3712, 16, 16, 16,3720, - 424, 424, 424, 424, 424, 424, 424, 424, 424,3728, 424,3736, 200, 200, 200,3744, - 624, 624, 624, 624, 624, 624,3752, 0, 624,3760, 624,3768, 200, 200, 200, 200, - 632, 632, 632, 632, 632, 632, 632, 632,3776, 0, 0,3784, 640, 640,3792, 0, - 1368,1368,1368, 0, 280, 280, 48, 48, 48, 48, 48,3800,3808,3816, 232, 232, - 232, 232, 232, 232, 232, 232, 232, 232, 640, 640, 640, 640, 640,3824, 640,3832, - 16, 16, 16, 16,1768, 0, 16, 16,1144,3840, 16, 16, 16, 16, 16,1768, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 856, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,1776, 0, 0, 0, 0, - 1784, 0,3848,3856, 352, 352,3864,3872,3880, 352, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56,3888, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 0, 0, 0, 0, 56, 56, - 104, 104, 24, 616, 104,3896, 24, 24, 24, 24,1792, 24, 608, 328,3904, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,3912, - 712, 24, 24, 24,1104, 48, 48,1112,1104, 48, 48,1112,3920, 184,1760, 184, - 184, 184, 184,3928, 16, 16, 16,1144,1376,1376,1376,3936, 608, 608, 0,3944, - 216,3952, 216, 216,3960, 216, 216,3968, 216,1800, 216,1800, 0, 0, 0, 0, - 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216,3976, - 1808, 24, 24, 24, 24, 24,3984, 24, 144, 144, 144, 144, 144, 144, 144, 144, - 144,1728, 24, 872,3992, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24,4000, - 1384,1384,1384,4008, 880, 880, 880, 880, 880, 880,4016, 0,4024, 24, 24, 328, - 1160,1160,1160,1160,4032,4040,1392,1392,1392,4048,1016,1016,1016,1016,1016,4056, - 1400,1400,1400,4064,1024,1024,1024,1024,4072,1024,4080, 0, 0, 0, 0, 0, - 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 888, 888, 888, 888, 888, 888, - 1168,1168,1168,4088,1168,4096, 648, 648, 648, 648,1816, 648, 648, 648, 648,1816, - 1032,1032,1032,1032,1032, 0, 896, 896, 896, 896, 896, 896,4104,4112,1176,1824, - 1176,1824,4120,1176,1832,1176,1832,4128, 904, 904, 904, 904, 904, 904,4136, 0, - 168, 168, 168, 168, 168, 168,4144, 0, 168, 168,4152, 0, 168, 0, 0, 0, - 4160, 48, 48, 48, 48, 48,4168,1840, 0, 0, 0, 0, 0, 0, 0, 0, - 4176,4184,1184,1184,1184,1184,4192,4200,1408,1408,4208,1408,1192,1192,1192,1192, - 1200,1200,1200,4216,4224,1200, 0, 0, 0, 0, 0, 0,1848,1848,4232,4240, - 1416,1416,1416,4248,1424,1424,1424,4256,1432,1432,1432,4264, 0, 0, 0, 0, - 1208,1208,1208,1208, 440, 440, 440,4272, 440, 440,4280, 440, 440, 440, 440, 440, - 4288,4296,4304,4312,1216,1216,4320,4328,1216,1856,1216,1856,1224,1224,1224,1224, - 1232,1232,1232,1232, 0, 0, 0, 0,1240,1240,1240,1240,1864,4336,1864, 0, - 912, 912, 912, 912, 912, 912,4344,4352,1440,1440,4360,1440,1448,1448,4368,1448, - 1872,1872,4376,4384, 0,4392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 552, 552, 552, 552, 552, 552, 552, 552, 552,4400, 0, 0, 0, 0, 0, 0, - 360, 360, 360, 360, 360, 360,1880, 0, 360, 360, 360, 360, 360, 360,1880,4408, - 920, 920, 920, 920, 920, 0, 920,4416, 928, 928, 928, 928,1888,4424, 928, 928, - 1888,4432, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 56, 56,4440, - 1040,1040,1040,1040,1040,4448,4456, 0,1896, 0, 56,4464, 0, 0, 0,1896, - 1048,1048,1048,1048,1048, 0,1056,1056,1056,1056,1056,4472, 0, 0,1456,1456, - 1456,4480, 0, 0, 0, 0,1464,1464,1464,4488, 0, 0,1904,1904,4496, 0, - 368, 368, 368, 368, 368, 368, 368, 368, 368,1912,4504, 368, 368, 368,1912,4512, - 656, 656, 656, 656, 656, 656, 656, 656,4520,4528,1248,1248,1248,4536,1248,4544, - 664, 664, 664, 664, 664, 664,4552, 664, 664, 0,1256,1256,1256,1256,4560, 0, - 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336,4568, 808,4576, 0, - 720, 720,4584, 720, 720, 720, 720, 720,4592, 0, 0, 0, 0, 0, 0, 0, - 4600,4608,1920,4616,1920,4624, 672, 672, 672, 672, 672, 672, 672,4632, 672,4640, - 4648,1928,4656,1936,1936,4664,4672,4680,1928,4688,4696,4704,4712,1944,1944, 0, - 936,4720, 936, 936, 936, 936,1952, 936,4728,4736,1952,4744,4752, 0, 0, 0, - 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,4760,4768, 0, 0, 0, - 448, 448, 448, 448, 448, 448, 448, 448, 448, 0, 448,4776, 0, 0, 0, 0, - 456, 456, 456, 456, 456, 456,1960, 456, 456, 456, 456,1960, 0, 0, 0, 0, - 560, 560, 560, 560, 560, 560, 560, 560,4784, 0, 560,4792, 248,4800, 0, 0, - 680, 680, 680, 680, 680, 680, 680,1968, 680,1968, 200, 200,4808, 0, 0, 0, - 944, 944, 944,4816, 944,4824, 944, 944,4832, 0, 0, 0, 0, 0, 0, 0, - 728, 728, 728, 728, 728, 728, 728,4840, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 464, 464, 464, 464, 464, 464, 464, 464, 464, 464,4848,4856, - 1976,4864,4872,1264,1264,1264,4880,4888,1976, 0,1264,4896, 0, 0, 0, 0, - 0, 0, 0, 0, 952,1984, 952, 952, 952, 952, 952,1984,4904, 0, 0, 0, - 568, 568, 568, 568, 568, 568, 568, 568, 568, 0, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472,4912, 0, 80, 80, 736, 736, 736, 736, 736, 736, 736,4920, - 240,4928, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 336, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1064,1064,1064,1064,1992, 0,1064,1992, - 576,4936, 576, 576, 576, 576,4944, 576,4952, 0, 576, 576, 576,4960, 960, 960, - 960, 960,4968, 960, 960,4976,4984, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2000,4992, 968, 968, 968, 968,2000,5000, 968, 0, 968,5008,5016,5024,1272,1272, - 1272,5032,5040,5048,1272,5056, 976, 976, 976, 976, 976,5064, 976,5072, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1472,1472,1472,5080, - 584, 584,5088, 584, 584, 584, 584,5096, 584, 584, 584,5104, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,5112, 0, 504, 504, 504, 504, 504, 504,5120,5128, - 64, 64, 64,5136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,5144,5152, 0, - 64, 64, 64, 64, 64, 64, 64, 64,5160, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376,5168, 0, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,5176, 0, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,5184, - 112, 112, 112, 112, 112, 112, 112, 112,5192, 0, 0, 0, 0, 0, 0, 0, - 744, 744, 744, 744, 744, 744, 744,5200, 0, 0, 0, 0, 0, 0, 0, 0, - 88, 88, 88, 88, 88, 88, 88,5208,1280,1280,1280,5216,1280,5224, 480, 480, - 480, 480, 480, 480, 480, 480, 480,5232, 480,5240,1480,1480,1480,2008,2008, 0, - 344, 344, 344, 344, 344, 344, 344, 344,5248, 0, 344,2016,2016, 344, 344,5256, - 344, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 752, 752, 752, 752, 752, 752, 752,5264, - 0, 0, 0, 0, 0, 0, 0, 0, 392, 392, 392, 392, 392, 392, 392, 392, - 392, 392, 392,5272,1072,1072,1072,5280,1072,1072,5288, 0, 0, 0, 0, 0, - 264, 264, 264, 264, 264, 264, 264, 264, 264,5296, 264, 264, 264, 264, 264, 264, - 264,5304, 264, 264, 0, 0, 0, 0, 0, 0, 0, 0,5312, 0,5320, 0, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,5328, 0, 0, 0, 0,5336, - 32, 32, 32,5344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,5352, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5360,5368, - 5376, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, - 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, - 152, 152, 152, 152,5384, 0,5392, 0, 0, 0,5400, 0,5408, 0, 136, 136, - 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,5416, - 288, 288, 288, 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,5424, 288,5432, - 288,5440, 288,5448, 328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 872, - 24, 24, 24, 24, 24, 24, 328,2024, 24, 24, 760, 0, 24, 24, 760, 0, - 104, 104, 104, 104, 104,1712, 104, 104,5456, 0, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 328, 0, 0, 0, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 416, 0, - 24, 24, 24, 24, 608, 712, 24, 24, 24, 24, 24, 24,5464,5472, 24,5480, - 5488,5496, 24, 24, 24,5504, 24, 24, 24, 24, 24, 24, 24,1360, 0, 0, - 144, 144, 144, 144, 144, 144, 144, 144, 848, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 328, 0, 24, 24, 328, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 608, 0, 24, 24, 24, 760, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 992, 24, 24, 24, 24, 24, - 24, 24, 24, 992,5512,5520, 24,5528,5536, 24, 24, 24, 24, 24, 24, 24, - 5544,5552, 992, 992, 24, 24, 24,5560,5568,2024,5576, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 416, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24,1744, 24, 24, 24, 24, 24, 24, - 96,5584, 0,5592,5600, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 48, 48, 48,1784,5608,1840, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5616, 312, 312,5624,5632,5640, 120, 120, 120, 120, 120, 120, 120,5648, 0, 0, - 0,5656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 768, 768, 768, 768, 768,5664, 768,5672, 768,5680, 0, 0, 0, 0, 0, 0, - 0, 0,1488,1488,1488,5688, 0, 0, 776, 776, 776, 776, 776, 776, 776,5696, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1080,1080,1080,1080,1080,5704, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1088,1088,1088,1088,1088,5712, - 0, 0, 0, 0, 0, 0, 0, 0,1096,1096,1096,5720,1096,1096,5728,5736, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280,5744, 160, 280, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, - 208, 208, 208, 208, 208, 208, 208, 208,5752, 208,5760, 0, 0, 0, 0, 0, - 488, 488, 488, 488, 488, 488, 488, 488, 488,5768, 488,5776, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 712, 24, - 24, 24, 24, 24, 24, 24, 872, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 712, 24, 24, 24, 24, 24, 24, 416, 0, 0, 0, 0, 0, 0, 0, 0, - 5784, 56, 56, 56,1496,5792,1504,5800,5808,5816,1496,5824,1496,1504,1504,5832, - 56,2032, 56,2040,5840,2032, 56,2040, 0, 0, 0, 0, 0, 0,5848, 0, - 24, 24, 24, 24, 24, 328, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 328, 0, 24, 608, 712, 24, 712, 24, 712, 24, 24, 24, 416, 0, - 24, 24, 24, 24, 24, 416, 0, 0, 0, 0, 0, 0,5856, 24, 24, 24, - 5864, 0, 24, 24, 24, 24, 24, 328, 24, 760, 616, 0, 416, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5872, 24, 872, 24, 872, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 616, 24, 328, 760, 0, - 24, 328, 24, 24, 24, 24, 24, 24, 24, 0, 24, 616, 24, 24, 24, 24, - 24, 0, 24, 24, 24, 416, 24, 328, 616, 0, 24, 760, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 24, 416, 24, 872, - 24,5880, 24, 24, 24, 24, 24, 24, 608,5888, 24,5896, 24,1808, 24, 760, - 24, 24,1792, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,1360, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, - 8, 8, 8, 856, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 856, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,5904, 0, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 856, 0, 0, 0, 0, - 8, 8, 8, 856, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 8, 8, 8, 8, 8, 8, 8,5912, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,1776, - 5920, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 40, 240, 248, 256, 80, 80, 80, 80, 80, 80, 264, 272, 136, 280, 288, 296, + 152, 152, 304, 152, 312, 320, 328, 336, 344, 352, 88, 360, 368, 376, 384, 392, + 400, 408, 416, 424, 432, 440, 448, 456, 464, 472, 480, 488, 496, 504, 512, 520, + 528, 536, 544, 552, 560, 568, 576, 584, 592, 600, 608, 616, 624, 632, 640, 648, + 200, 200, 656, 664, 16, 16, 16, 16, 672, 680, 688, 696, 704, 712, 720, 728, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 736, 744, 752, 760, 768, 776, + 784, 792, 800, 808, 816, 824, 832, 840, 848, 856, 864, 872, 880, 888, 896, 904, + 912, 920, 928, 936, 944, 952, 960, 136, 80, 80, 80, 80, 968, 976, 984, 992, + 1000,1008,1016,1024,1032,1040,1048, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 1056,1064, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 160, 160, 160, 160, 40, 40, 40, 40, 40, 40, 40, 40, 40,1072, 40, 40, + 1080,1088,1096,1104,1112,1120,1128,1136, 40,1144,1152,1160, 8, 8, 8,1168, + 1176,1184,1192,1200,1208, 16,1216,1224,1232,1240, 40,1248,1256,1264, 40, 40, + 8, 8, 8, 8, 8, 8, 8, 40, 8, 8, 8, 8, 8, 8, 8, 8, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64,1272,1280, 168, 168, 168, 168,1288, 152,1296,1304,1312, 80,1320,1328, + 1336,1344,1352,1360,1368,1376,1384,1392,1400,1408,1416,1424,1432,1440,1448,1456, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,1464,1472, + 0, 0, 0, 0, 8, 8, 8, 8, 8, 208, 8,1480,1488,1496, 88, 88, + 88, 88, 88, 88,1504, 88, 88,1512,1520,1528, 88,1536,1544,1552,1560,1568, + 1576,1584,1592,1600,1608, 216,1616,1624, 0, 0,1632,1640,1648,1656,1664,1672, + 1680,1688,1696,1704,1712,1720,1728,1736, 176, 176, 176, 176,1744,1752,1760, 0, + 1768,1776,1784,1792,1800,1808,1816,1824,1832,1840,1848,1856,1864,1872,1880, 0, + 1888,1896,1904,1912,1920,1928,1936, 0, 0,1944,1952,1960,1968,1976,1984,1992, + 2000,2008,2016,2024,2032,2040,2048,2056,2064,2072,2080,2088,2096,2104,2112,2120, + 2128,2136,2144,2152, 0, 0,2160,2168,2176,2184,2192,2200,2208,2216, 0, 0, + 2224, 0,2232,2240,2248,2256,2264,2272,2280,2288,2296,2304,2312,2320, 0,2328, + 2336,2344,2352, 0,2360,2368,2376,2384, 0, 0, 0,2392,2400,2408,2416,2424, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,2432, 0, + 56, 56, 56, 56, 56,2440,2448, 224, 224,2456,2464, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,2472,2480, + 48,2488, 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, 48, 48, 48, 48,2496, + 112, 112, 112, 112, 112, 112, 112, 112, 112,2504, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,2512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 120, 120, 120, 120, 120, 120, 120, 120,2520,2528,2536,2544,2552,2560,2568, 0, + 0, 0, 0, 0, 0,2576, 0, 0, 0,2584,2592,2600,2608,2616,2624,2632, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 128, 128, 128, 128, + 128, 128, 128,2640,2648, 0, 32,2656, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72,2664,2672, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,2680, + 2688, 184, 184, 184,2696,2704, 144, 144, 144, 144, 144,2712, 0, 0, 0, 0, + 2720,2728,2736, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 40, 40, 40,2744, 40, 40, 40, 40, 40, 40,2752,2760,2768,2776, 40,2784, + 40, 40, 40,2792,2800,2808,2816, 40, 216,2824,2832,2840, 40,2848, 0, 0, + 40,2856,2864,2872,2880,2888, 40, 40, 40, 40,2896, 40, 40, 40, 40,2904, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,2912, 0,2920, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80,2928,2936, + 2944,2952,2960, 0,2968,2976, 0, 0, 0, 0,2984,2992, 0, 0, 0, 0, + 0, 0, 0,3000, 0, 0, 0,3008, 0, 0, 0,3016, 0, 0, 0,3024, + 192, 192, 192,3032,3040,3048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,3056,3064, 0,3072, 0, 0, 0,3080,3088,3096,3104, 0, 0, 0, 0, + 3112, 40,3120,3128, 40, 40,3136,3144,3152,3160, 0, 0, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,3168, 40, 40, 40,3176, + 3184,3192,3200,3208, 40, 40, 40, 40, 40,3216, 40,3224, 40, 40,3232,3240, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,3248, 8, 8, 8, 8, + 3256, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 208, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,3264, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 232, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 232, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,3272, 8, 8, + 8,3280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3288, 40, 0, 0, 136, 136, 136, 136, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, + 24, 24, 24, 24, 24, 24, 24, 24, 40, 40, 40, 40, 40, 40, 40, 40, + 32, 32, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, + 64, 64, 64, 64, 64, 64, 64, 64, 80, 80, 80, 80, 80, 80, 80, 80, + 88, 88, 88, 88, 88, 88, 88, 88, 56, 56, 56, 56, 56, 56, 56, 56, + 72, 72, 72, 72, 72, 72, 72, 72, 96, 96, 96, 96, 96, 96, 96, 96, + 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, + 104, 104, 104, 104, 104, 104, 104, 104, 144, 144, 144, 144, 144, 144, 144, 144, + 120, 120, 120, 120, 120, 120, 120, 120, 152, 152, 152, 152, 152, 152, 152, 152, + 136, 136, 136, 136, 136, 136, 136, 136, 208, 208, 208, 208, 208, 208, 208, 208, + 192, 192, 192, 192, 192, 192, 192, 192, 184, 184, 184, 184, 184, 184, 184, 184, + 168, 168, 168, 168, 168, 168, 168, 168, 224, 224, 224, 224, 224, 224, 224, 224, + 216, 216, 216, 216, 216, 216, 216, 216, 8, 8, 8, 8, 8,1008, 8, 8, + 160, 160, 160, 160, 160, 160, 160, 160, 256, 256, 256, 256, 256, 256, 256, 256, + 8, 8, 8,1008, 0, 0, 0, 0,1120, 56, 56,1128,1120, 56, 56,1128, + 32, 32, 32, 32, 32,1304, 32,1304, 56, 56,1536, 56, 56, 56,1536, 56, + 56, 56, 56, 56, 56, 56, 56,2096, 32, 32, 32, 32,2104,2112, 32, 32, + 120, 120, 120, 120, 120, 120,2120,2128,2136,2144, 160, 160,2152, 160, 160, 160, + 160, 160, 160, 160,2160, 320, 160, 160,2168, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136,2176, 424, 424, 424,2184, 424, 424, 424, 424, 424, + 424, 424,2192, 376, 376, 376, 376, 376, 376,2200, 376, 376, 376,2208,2216, 0, + 1544,2224, 72,2232, 72, 72, 72, 72,2240,2248,2256, 72, 72, 72,2264, 72, + 72, 72, 72,1544, 72, 72, 72, 72, 520,2272, 520, 520, 520, 520, 520, 520, + 520,2280, 72, 72, 72, 72, 72, 72, 800, 800, 800, 800, 800, 800,2288, 0, + 712, 712, 712, 712, 712, 712, 712,2296, 808, 808, 808, 808, 808,2304, 808,2312, + 1312,1312,1312,2320, 520,2328, 72, 72, 72, 72,2336, 72, 72, 72, 72, 72, + 72, 72, 72, 72,2344, 72, 72, 72, 264, 264, 264, 264, 264, 264, 264, 264, + 264, 264,2352, 264,2360, 264, 264, 264,2368,1552,2376,1136,1136,2384,2392,2400, + 1552,2408,2416,2424,2432,1136,1136,2440,2448,1560,2456,1320,1320,2464,2472,2480, + 1560,2488,2496,2504,2512,1320,2520, 0,2528,1568,2536,1328,1328,2544,2552,2560, + 1568,2568,2576, 0,2584,1328,2592,2600,2608,1576,2616,1144,1144,2624,2632,2640, + 1576,2648,2656,2664,2672,1144,1144, 0,2680,1336,1584,2688,2696,1336, 528,2704, + 1336,1584,2712, 0,2720, 528, 528,2728, 816,1592,1600, 816, 816,1600, 816,2736, + 1592,2744,2752,2760,2768, 816,2776, 816,1152,1608,1616,1152,1152,1616,2784,2792, + 1608,2800,2808,2816,2824,1152,2832, 0, 432,1624,1632, 432, 432, 432, 432, 432, + 1624,1632,2840, 432,2848, 432, 432, 432,2856, 824,1640,2864, 824, 824,2872,2880, + 1640,2888,2896, 824,2904, 824,2912, 0,2920, 536, 536, 536, 536, 536, 536,2928, + 536, 536, 536,2936, 0, 0, 0, 0,2944,2952, 992, 992,2960, 992, 992,2968, + 2976,2984, 992,2992, 0, 0, 0, 0, 240, 240, 240, 240, 240, 240, 240, 240, + 240,1344, 240, 240, 240,3000,1344, 240, 240, 240, 240,1344, 240, 240, 240,1648, + 240,1648,3008,3016, 0, 0, 0, 0, 216, 216, 216, 216, 280, 280, 280, 280, + 1656,1664, 280, 280, 280, 280, 280,3024, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 832, 304, 832, 176, 176, 176, 176, 176, 832, 176, 176, 176, 176, 832, 304, + 832, 176, 304, 176, 176, 176, 176, 176, 176, 176, 832, 176, 176, 176, 176, 176, + 176, 176, 176,3032, 176, 176, 176,3040, 176, 176, 176,3048, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248,1672,1672,1352,1352,1352,3056, 440, 440, 440, 440, + 440, 440, 440, 440, 440,3064, 440,3072,1680,1680,3080,3088,1688,1688,3096, 0, + 1696,1696,3104, 0,3112,3120,3128, 0, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296,3136, 296,1704, 296,1704,3144, 272, 272,3152, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272,3160, 272, 272, 272, 272, 272,3168, 96, 96, + 96, 96, 96, 96, 96, 96,3176, 0, 840, 840, 840,3184, 840,1712, 840,1712, + 3192, 840,1360,1360,1360,3200,3208, 0, 544, 544, 544, 544, 544,3216, 544, 544, + 544,3224, 544,3232, 296, 296, 296, 296,1368,1368,1368,3240, 352, 352, 352, 352, + 352, 352, 352,3248, 352, 352, 352,3256, 352,1720, 352,1720, 352,3264, 120, 120, + 120, 120, 120, 120, 120, 120,1728, 0, 328, 328, 328, 328, 328, 328, 328, 328, + 328,3272, 328, 328, 328, 328, 328, 328, 552, 552, 552, 552, 552, 552, 552, 552, + 848, 848, 848, 848, 848, 848,3280,3288, 624, 624, 624, 624, 624, 624, 624,3296, + 624,3304, 856, 856, 856, 856, 856, 856, 136,3312, 280, 280, 280, 280, 280,3320, + 552, 0,3328, 120,3336,3344,3352,3360, 56, 56, 56, 56,3368,3376, 56, 56, + 56, 56, 56,3384,3392,3400, 56,3408, 56, 56, 56, 56, 56, 56, 56,3416, + 160, 160, 864, 864, 160, 160, 160, 160, 864, 864, 160,3424, 160, 160, 160, 864, + 160, 160, 160, 160, 160, 160,1736, 160,1736, 160,3432,3440, 160, 160,3448,1744, + 32,3456, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,1000, 32,3464,3472, + 32, 32, 56, 56, 32, 32, 32, 32, 632, 0, 120, 120, 120, 120,1728, 0, + 32, 32, 32, 32,3480,3488,1304, 32, 32,3496, 32, 32, 56, 56, 56, 56, + 56,3504, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 720, 0, 0, + 32,1376, 0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,1752, 32, + 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 56, 56, 56, 56, + 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320,3512,3520, + 280, 280, 280, 280,1656,1664, 728, 728, 728, 728, 728, 728, 728,1760,3528,1760, + 176, 176, 304, 0, 304, 304, 304, 304, 304, 304, 304, 304, 136, 136, 136, 136, + 32, 32, 32, 560, 336, 0, 0, 0, 8, 8, 8,3536, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8,3544, 0, 8, 8,1008, 0, 0, 0, 32, 32, + 3552, 32, 32, 32,3560,3568, 32,3576,3584, 168, 168, 168, 168, 168, 168, 168, + 168, 168,3592,3600,1768, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,3608, + 3616, 568, 568, 568, 568, 568,3624, 16, 16,1160, 32, 32, 568, 568, 568, 568, + 32, 32, 32, 32, 560,3632, 200, 200, 16, 16, 16,1160, 32, 32, 32, 32, + 32, 32, 32, 32, 16, 16, 16,3640, 32, 32, 200, 200, 200, 200, 200,3648, + 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 32, 32, 32, 32, 32, + 80,3656, 80, 80, 80, 80, 80, 80,3664, 0, 872, 872, 872, 872, 872, 872, + 192, 192, 192, 192, 192,3672, 0, 0, 136, 136, 136, 136, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 0, 32, 32, 32, 32,3680, 56, 56, 56, + 56,3688, 56, 56, 56, 56, 56, 56, 56, 56, 56,3696,3704, 0,3712, 56, + 1016,1016,1016,1016,1016,3720, 32, 720, 736, 736, 736, 736, 736, 736, 736, 0, + 576, 576, 576, 576, 576, 576, 576, 576,3728,3736, 576,3744, 264, 264, 264, 264, + 1024,1024,1024,1024,1024,3752,1168,1168,1168,1168,3760,3768, 16, 16, 16,3776, + 448, 448, 448, 448, 448, 448, 448, 448, 448,3784, 448,3792, 216, 216, 216,3800, + 640, 640, 640, 640, 640, 640,3808, 0, 640,3816, 640,3824, 216, 216, 216, 216, + 648, 648, 648, 648, 648, 648, 648, 648,3832, 0, 0,3840, 656, 656,3848, 0, + 1384,1384,1384, 0, 304, 304, 56, 56, 56, 56, 56,3856,3864,3872, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 656, 656, 656, 656, 656,3880, 656,3888, + 16, 16, 16, 16,1776, 0, 16, 16,1160,3896, 16, 16, 16, 16, 16,1776, + 8, 8, 8,1784, 0, 0, 0, 0,1792, 0,3904,3912, 376, 376,3920,3928, + 3936, 376, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,3944, + 72, 72, 0, 0, 0, 0, 72, 72, 120, 120, 32, 720, 120,3952, 32, 32, + 32, 32,1800, 32, 664, 336,3960, 72, 72, 72, 72, 72, 72, 72, 72,3968, + 880, 32, 32, 32,1120, 56, 56,1128,1120, 56, 56,1128,3976, 200,1768, 200, + 200, 200, 200,3984, 16, 16, 16,1160,1392,1392,1392,3992, 664, 664, 0,4000, + 232,4008, 232, 232,4016, 232, 232,4024, 232,1808, 232,1808, 0, 0, 0, 0, + 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,4032, + 4040, 32, 32, 32, 32, 32,1816, 32, 160,1744, 32, 632,4048, 0, 0, 0, + 0, 0, 32, 32, 32, 32, 32,4056,1400,1400,1400,4064, 888, 888, 888, 888, + 888, 888,4072, 0,1824, 32, 32, 336,1176,1176,1176,1176,4080,4088,1408,1408, + 1408,4096,1032,1032,1032,1032,1032,4104,1416,1416,1416,4112,1040,1040,1040,1040, + 4120,1040,4128, 0, 0, 0, 0, 0, 456, 456, 456, 456, 456, 456, 456, 456, + 456, 456, 896, 896, 896, 896, 896, 896,1184,1184,1184,4136,1184,4144, 672, 672, + 672, 672,1832, 672, 672, 672, 672,1832,1048,1048,1048,1048,1048, 0, 904, 904, + 904, 904, 904, 904,4152,4160,1192,1840,1192,1840,4168,1192,1848,1192,1848,4176, + 912, 912, 912, 912, 912, 912,4184, 0, 184, 184, 184, 184, 184, 184,4192, 0, + 184, 184,4200, 0, 184, 0, 0, 0,4208, 56, 56, 56, 56, 56,4216, 56, + 4224,4232,1200,1200,1200,1200,4240,4248,1424,1424,4256,1424,1208,1208,1208,1208, + 1216,1216,1216,4264,4272,1216, 0, 0, 0, 0, 0, 0,1856,1856,4280,4288, + 1432,1432,1432,4296,1440,1440,1440,4304,1448,1448,1448,4312, 0, 0, 0, 0, + 1224,1224,1224,1224, 464, 464, 464,4320, 464, 464,4328, 464, 464, 464, 464, 464, + 4336,4344,4352,4360,1232,1232,4368,4376,1232,1864,1232,1864,1240,1240,1240,1240, + 1248,1248,1248,1248, 0, 0, 0, 0,1256,1256,1256,1256,1872,4384,1872, 0, + 920, 920, 920, 920, 920, 920,4392,4400,1456,1456,4408,1456,1464,1464,4416,1464, + 1880,1880,4424,4432, 0,4440, 0, 0, 584, 584, 584, 584, 584, 584, 584, 584, + 584,4448, 0, 0, 0, 0, 0, 0, 384, 384, 384, 384, 384, 384,1888, 0, + 384, 384, 384, 384, 384, 384,1888,4456, 928, 928, 928, 928, 928, 0, 928,4464, + 936, 936, 936, 936,1896,4472, 936, 936,1896,4480, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 72, 72, 72,1904,1056,1056,1056,1056,1056,4488,4496, 0, + 4504,1912, 72, 72, 72,1904, 72, 72,1064,1064,1064,1064,1064, 0,1072,1072, + 1072,1072,1072,4512, 0, 0,1472,1472,1472,4520, 0, 0, 0, 0,1480,1480, + 1480,4528, 0, 0,1920,1920,4536, 0, 392, 392, 392, 392, 392, 392, 392, 392, + 392,1928,4544, 392, 392, 392,1928,4552, 680, 680, 680, 680, 680, 680, 680, 680, + 4560,4568,1264,1264,1264,4576,1264,4584, 688, 688, 688, 688, 688, 688,4592, 688, + 688, 0,1272,1272,1272,1272,4600, 0, 360, 360, 360, 360, 360, 360, 360, 360, + 360, 360, 360, 360,4608, 824,4616, 0, 744, 744,4624, 744, 744, 744, 744, 744, + 4632, 0, 0, 0, 0, 0, 0, 0,4640,4648,1936,4656,1936,4664, 696, 696, + 696, 696, 696, 696, 696,4672, 696,4680,4688,1944,4696,1952,1952,4704,4712,4720, + 1944,4728,4736,4744,4752,1960,1960, 0, 944,4760, 944, 944, 944, 944,1968, 944, + 4768,4776,1968,4784,4792, 0, 0, 0, 408, 408, 408, 408, 408, 408, 408, 408, + 408, 408, 408,4800,4808, 0, 0, 0, 472, 472, 472, 472, 472, 472, 472, 472, + 472, 0, 472,4816, 0, 0, 0, 0, 480, 480, 480, 480, 480, 480,1976, 480, + 480, 480, 480,1976, 0, 0, 0, 0, 592, 592, 592, 592, 592, 592, 592, 592, + 4824, 0, 592,4832, 272,4840, 0, 0, 704, 704, 704, 704, 704, 704, 704,1984, + 704,1984, 216, 216,4848, 0, 0, 0, 952, 952, 952,4856, 952,4864, 952, 952, + 4872, 0, 0, 0, 0, 0, 0, 0, 752, 752, 752, 752, 752, 752, 752,4880, + 0, 0, 0, 0, 488, 488, 488, 488, 488, 488, 488, 488, 488, 488,4888,4896, + 1992,4904,4912,1280,1280,1280,4920,4928,1992, 0,1280,4936, 0, 0, 0, 0, + 0, 0, 0, 0, 960,2000, 960, 960, 960, 960, 960,2000,4944, 0, 0, 0, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 496, 496, 496, 496, 496, 496, + 496, 496, 496, 496,4952, 0, 96, 96, 760, 760, 760, 760, 760, 760, 760,4960, + 264,4968, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, + 1080,1080,1080,1080,2008, 0,1080,2008, 608,4976, 608, 608, 608, 608,4984, 608, + 4992, 0, 608, 608, 608,5000, 968, 968, 968, 968,5008, 968, 968,5016,5024, 0, + 2016,5032, 976, 976, 976, 976,2016,5040, 976, 0, 976,5048,5056,5064,1288,1288, + 1288,5072,5080,5088,1288,5096, 984, 984, 984, 984, 984,5104, 984,5112,5120, 0, + 0, 0, 0, 0,1488,1488,1488,5128, 616, 616,5136, 616, 616, 616, 616,5144, + 616, 616, 616,5152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5160, 0, + 528, 528, 528, 528, 528, 528,5168,5176, 64, 64, 64,5184, 0, 0, 0, 0, + 5192, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 256, 256, 256, + 256,5200, 64, 64, 64, 64, 64, 64,5208, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400,5216, 0, + 48, 48,5224, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,5232, + 5240, 0, 0, 0, 0, 0, 0, 0, 768, 768, 768, 768, 768, 768, 768,5248, + 104, 104, 104, 104, 104, 104, 104,5256,1296,1296,1296,5264,1296,5272, 504, 504, + 504, 504, 504, 504, 504, 504, 504,5280, 504,5288,1496,1496,1496,2024,2024, 0, + 368, 368, 368, 368, 368, 368, 368, 368,5296, 0, 368,2032,2032, 368, 368,5304, + 368, 368, 0, 0, 0, 0, 0, 0, 776, 776, 776, 776, 776, 776, 776,5312, + 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, 416,5320,1088,1088,1088,5328, + 1088,1088,5336, 0, 0, 0, 0, 0, 288, 288, 288, 288, 288, 288, 288, 288, + 288,5344, 288, 288, 288, 288, 288, 288, 288,5352, 288, 288, 0, 0, 0, 0, + 0, 0, 0, 0,5360, 0,2040, 0, 144, 144, 144,5368, 0, 0, 0,5376, + 40, 40, 40, 40,5384, 0, 0, 0, 40, 40, 40, 40, 40, 40,5392, 0, + 88, 88,5400, 0, 88, 88, 88, 88, 88, 88,5408, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,5416,5424,5432, 168, 168, 168, 168, 168, 168, 168, + 168, 168, 168, 168,5440,2048,5448, 0, 0, 0,5456, 0,5464,2048, 152, 152, + 152, 152, 152, 152, 152, 152, 152,5472, 312, 312, 312, 312, 312, 312, 312, 312, + 312, 312, 312, 312, 312,5480, 312,5488, 312,5496, 312,5504, 336, 0, 0, 0, + 32, 32, 32, 32, 32, 32, 32, 632, 32, 32, 32, 32, 32, 32, 336,2056, + 32, 32,5512,5520, 32, 32, 32, 560, 120, 120, 120, 120, 120,5528, 120, 120, + 5536, 0, 32, 32, 32, 32, 32, 32, 336, 0, 0, 0, 0, 0, 0, 0, + 32, 32, 32, 32, 32, 32, 560, 0, 32, 32, 32, 32,2064,1824, 32, 32, + 32, 32, 32, 32,2064,5544, 32,5552,5560,5568, 32, 32, 32,5576, 32, 32, + 864, 0, 32,5584, 32, 32, 32, 32, 720, 0, 0, 0, 0, 0, 0, 0, + 32, 32, 336, 0, 32, 32, 336, 0, 32, 32, 664, 0, 32, 32, 32,1504, + 32, 32,1000, 32, 32, 32, 32, 32, 32, 32, 32,1000,5592,5600, 32,5608, + 5616, 32, 32, 32, 32, 32, 32, 32,2072,5624,1000,1000, 32, 32, 32,5632, + 5640,2056,5648, 32, 32, 32, 32, 32, 32, 32, 32, 32, 664, 32, 32, 32, + 32,1752, 32, 32, 32, 32, 32, 32, 112,5656, 0,5664,5672, 112, 0, 0, + 32, 32, 32, 632, 0, 0, 0, 0,5680, 0,1792, 0, 0, 0, 0, 0, + 0,5688, 56, 56, 56, 56,5696, 56,5704, 344, 344,5712,5720,5728, 136, 136, + 136, 136, 136, 136, 136,5736, 0, 0, 0,5744, 0, 0, 0, 0, 0, 0, + 784, 784, 784, 784, 784,5752, 784,5760, 784,5768, 0, 0, 0, 0, 0, 0, + 0, 0,1512,1512,1512,5776, 0, 0, 792, 792, 792, 792, 792, 792, 792,5784, + 0, 0,1096,1096,1096,1096,1096,5792, 0, 0,1104,1104,1104,1104,1104,5800, + 1112,1112,1112,5808,1112,1112,5816,5824, 0, 0, 0, 0, 304,5832, 176, 304, + 5840, 224,5848, 0, 0, 0, 0, 0, 512, 512, 512, 512, 512, 512, 512, 512, + 512,5856, 512,5864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 880, 32, + 32, 32, 32, 32, 32, 32, 632, 0, 880, 32, 32, 32, 32, 32, 32, 560, + 5872, 72, 72, 72,1520,1912,1528,5880,5888,5896,1520,5904,1520,1528,1528,5912, + 72,2080, 72,2088,5920,2080, 72,2088, 0, 0, 0, 0, 0, 0,5928, 0, + 32, 32, 32, 32, 32, 336, 32, 32, 32, 32, 336, 0, 32, 664, 880, 32, + 880, 32, 880, 32, 32, 32, 560, 0, 32, 32, 32, 32, 32, 664, 0, 0, + 0, 0, 0, 0,5936, 32, 32, 32,5944, 0, 32, 32, 32, 32, 32, 336, + 32,1504, 720, 0, 560, 0, 0, 0, 32, 32, 32,5952, 32, 632, 32, 632, + 32, 32, 32, 336, 32, 336, 32, 32, 32, 336, 32, 32, 32, 32, 32, 32, + 32, 0, 32, 720, 32, 32, 32, 32, 32, 0, 32, 32, 32, 560, 32, 336, + 720, 0, 32,1504, 0, 0, 0, 0, 32, 32, 32, 0, 32, 560, 32, 632, + 664,5960, 32,2072, 32,1816, 32,1376, 32, 32,1800, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32,1376, 8, 8, 8, 8, 0, 0, 0, 0, + 8, 8, 8,2040, 8, 8, 8, 8, 8, 8, 8, 8,5968, 0, 8, 8, + 8,5976, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,1784, + 5984, 0, 0, 0, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, + 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, + 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147, + 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0, + 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143, + 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160, + 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0, + 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206, + 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035, + 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250, + 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0, + 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299, + 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340, + 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177, + 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0, + 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165, + 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279, + 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130, + 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 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, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5, + 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522, + 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567, + 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549, + 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559, + 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0, + 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, - 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, - 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, - 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, - 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, - 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, - 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199, - 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, - 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231, - 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258, - 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275, - 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0, - 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093, - 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010, - 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347, - 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424, - 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, - 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238, - 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, - 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232, - 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 9, 0, 10,1425, 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, 1, 0, - 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461, - 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486, - 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0, - 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0, - 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, - 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, - 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560, - 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, - 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, - 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, - 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, - 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0, - 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, - 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, - 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, - 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, - 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, - 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0, - 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, - 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, - 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356, - 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214, - 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363, - 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251, - 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266, - 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287, - 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302, - 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, - 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375, - 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353, - 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234, - 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403, - 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412, - 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0, - 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721, - 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0, - 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757, - 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776, - 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0, - 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793, - 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814, - 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0, - 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728, - 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764, - 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821, - 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, - 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828, - 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833, - 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, - 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, - 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, - 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, - 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, - 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938, - 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0, - 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870, - 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0, - 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0, - 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0, - 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, - 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0, - 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0, - 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0, - 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, - 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, - 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, - 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, - 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, - 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, - 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, - 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, - 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, - 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, - 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, - 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, - 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, - 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, - 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, - 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, - 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, - 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, - 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, - 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, - 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, - 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, - 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, - 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, - 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, - 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, - 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, - 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, - 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, - 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, - 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, - 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575, - 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0, - 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0,1939, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1940, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1943,1944, 0, 0, 0, - 0, 0, 0,1945, 0,1946, 0, 0, 0, 0, 0, 0, 0, 0,1947, 0, - 0,1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1950, 0,1949,1951, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1953,1952, 0,1954, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1957, 0, 0, 0, 0, 0, 0, 0, - 0,1958,1961,1959,1965,1960,1962,1964,1963, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1967,1966,1968, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1969,1970, - 1971,1972,1973,1974,1975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1976,1977,1978,1980,1979, - 1981, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, - 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, - 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, - 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, - 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, - 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, - 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, - 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, - 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, - 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, - 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, - 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, - 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, - 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, - 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, - 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, - 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, - 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, - 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, - 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, - 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, - 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, - 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, - 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, - 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, - 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, - 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, - 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, - 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, - 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, - 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, - 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, - 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, - 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, + 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648, + 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662, + 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0, + 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671, + 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0, + 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142, + 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381, + 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181, + 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210, + 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222, + 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243, + 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389, + 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284, + 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291, + 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260, + 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343, + 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696, + 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698, + 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359, + 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274, + 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304, + 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707, + 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0, + 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743, + 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770, + 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0, + 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790, + 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800, + 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24, + 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714, + 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750, + 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807, + 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825, + 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829, + 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515, + 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518, + 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830, + 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, + 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0, + 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847, + 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0, + 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0, + 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0, + 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0, + 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890, + 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897, + 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0, + 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917, + 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924, + 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929, + 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825, + 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500, + 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679, + 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722, + 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540, + 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589, + 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101, + 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110, + 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801, + 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610, + 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494, + 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748, + 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161, + 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727, + 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684, + 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566, + 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729, + 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525, + 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0, + 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213, + 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458, + 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591, + 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735, + 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171, + 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325, + 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438, + 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526, + 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693, + 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777, + 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916, + 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0, + 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599, + 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1936, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1937, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1938, 0,1939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1940, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1943,1944, 0, 0, 0, 0, 0, 0,1945, 0,1946, 0, 0, + 0, 0, 0, 0, 0, 0,1947, 0, 0,1948, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1950, 0,1949, + 1951, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1953,1952, 0,1954, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1955,1956, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1957, 0, 0, 0, 0, 0, 0, 0, 0,1958,1961,1959,1965,1960,1962,1964, + 1963, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1967,1966,1968, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1969,1970,1971,1972,1973,1974,1975, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1976,1977,1978,1980,1979,1981, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121, + 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142, + 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169, + 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185, + 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206, + 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224, + 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39, + 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266, + 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286, + 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852, + 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324, + 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351, + 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50, + 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78, + 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55, + 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861, + 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436, + 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467, + 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873, + 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875, + 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531, + 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559, + 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73, + 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898, + 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902, + 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904, + 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81, + 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669, + 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686, + 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719, + 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753, + 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925, + 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800, + 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, + 817, 818, 819, 820, 821, 935, 0, 0, }; -static const int16_t _hb_ucd_i16[196]= +static const int32_t _hb_ucd_palette[39]= { - 0, 0, 0, 0, 1, -1, 1, -1, 1, -1, 0, 0, -1, 1, -1, 1, - 0, 0, 1, -1, -1, 1, -1, 0, 0, 0, 0, 1, 0, 1, -1, 0, - 0, 0, 0, 2, 0, -2, 0, 0, 0, 1, -1, 1, 2, 0, -2, 0, - -1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 3, 3, 3, -3, - -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0, - 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0, - 1824, 0, 0, 0, 0, 0, 2104, 0, 2108, 2106, 0, 2106, 1316, 0, 0, 0, - -1, -138, 0, 0, 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, - -8, -7, -7, 0, 1, -1, 0, 2,-1316, 1, -1, 0, -1, 3, 1, -1, - -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0, - 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106, - -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1, - -1, 0, 1, -1, + -112883, -2527, -2250, -2108, -2106, -2104, -2016, -1923, + -1918, -1914, -1824, -1316, -138, -16, -8, -7, + -3, -2, -1, 0, 1, 2, 3, 7, + 8, 16, 138, 1316, 1824, 1914, 1918, 1923, + 2016, 2104, 2106, 2108, 2250, 2527, 112883, }; static inline uint8_t _hb_ucd_gc (unsigned u) { /* packtab: [2^8,2^5,2^3,2^1] */ - return u<1114110u ? (uint8_t)(_hb_ucd_u8[7912u+((_hb_ucd_u8[2176u+_hb_ucd_u16[((_hb_ucd_u8[((((((u)>>1))>>3))>>5)])<<5)+((((((u)>>1))>>3))&31)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; + return u<1114110u ? (uint8_t)(_hb_ucd_u8[7944u+((_hb_ucd_u8[2176u+_hb_ucd_u16[((_hb_ucd_u8[((((((u)>>1))>>3))>>5)])<<5)+((((((u)>>1))>>3))&31)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; } static inline uint8_t _hb_ucd_ccc (unsigned u) { /* packtab: [2^8,2^4,2^3,2^2] */ - return u<125259u ? (uint8_t)(_hb_ucd_u8[10370u+((_hb_ucd_u8[9270u+((_hb_ucd_u8[8539u+((_hb_ucd_u8[8294u+((((((u)>>2))>>3))>>4)])<<4)+((((((u)>>2))>>3))&15)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)]) : 0; + return u<125259u ? (uint8_t)(_hb_ucd_u8[10432u+((_hb_ucd_u8[9308u+((_hb_ucd_u8[8577u+((_hb_ucd_u8[8332u+((((((u)>>2))>>3))>>4)])<<4)+((((((u)>>2))>>3))&15)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)]) : 0; } static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) { return (a[i>>1]>>((i&1)<<2))&15; } -static inline int16_t _hb_ucd_bmg (unsigned u) +static inline int32_t _hb_ucd_bmg (unsigned u) { - /* packtab: [2^4,2^3,2^3,2^2] */ - return u<65380u ? (int16_t)(_hb_ucd_i16[_hb_ucd_u8[11118u+((_hb_ucd_u8[11002u+((_hb_ucd_b4(_hb_ucd_u8+10874u,((((((u)>>2))>>3))>>3)))<<3)+((((((u)>>2))>>3))&7)])<<3)+((((u)>>2))&7)]+((u)&3)]) : 0; + /* packtab: [2^4,2^4,2^3,2^2] palette[39] */ + return u<121617u ? (int32_t)(_hb_ucd_palette[_hb_ucd_u8[11624u+_hb_ucd_u8[11272u+((_hb_ucd_u8[11071u+((_hb_ucd_b4(_hb_ucd_u8+10952u,((((((u)>>2))>>3))>>4)))<<4)+((((((u)>>2))>>3))&15)])<<3)+((((u)>>2))&7)]+((u)&3)]]) : 0; } static inline uint8_t _hb_ucd_sc (unsigned u) { - /* packtab: [2^8,2^4,2^4,2^3] */ - return u<918000u ? (uint8_t)(_hb_ucd_u8[12639u+_hb_ucd_u16[3296u+((_hb_ucd_u8[11903u+((_hb_ucd_u8[11454u+((((((u)>>3))>>4))>>4)])<<4)+((((((u)>>3))>>4))&15)])<<4)+((((u)>>3))&15)]+((u)&7)]) : 2; + /* packtab: [2^8,2^4,2^3,2^3] */ + return u<918000u ? (uint8_t)(_hb_ucd_u8[12721u+_hb_ucd_u16[4520u+_hb_ucd_u16[3392u+((_hb_ucd_u8[11824u+((((((u)>>3))>>3))>>4)])<<4)+((((((u)>>3))>>3))&15)]+((((u)>>3))&7)]+((u)&7)]) : 2; } static inline uint16_t _hb_ucd_dm (unsigned u) { /* packtab: [2^8,2^5,2^4] */ - return u<195102u ? (uint16_t)(_hb_ucd_u16[7360u+((_hb_ucd_u8[18949u+((_hb_ucd_u8[18567u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; + return u<195102u ? (uint16_t)(_hb_ucd_u16[7816u+((_hb_ucd_u8[19095u+((_hb_ucd_u8[18713u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; } @@ -2736,12 +2768,12 @@ static inline uint16_t _hb_ucd_dm (unsigned u) #include -static const uint8_t _hb_ucd_u8[14763]= +static const uint8_t _hb_ucd_u8[18025]= { 3, 4, 5, 6, 7, 2, 2, 2, 2, 2, 8, 2, 2, 9, 1, 10, - 11, 12, 13, 14, 15, 0, 16, 2, 17, 0, 18, 19, 20, 21, 22, 23, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 25, 26, 2, 27, 28, - 2, 29, 2, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 11, 12, 13, 14, 15, 0, 16, 2, 17, 18, 19, 20, 21, 22, 23, 24, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 25, 26, 27, 2, 28, 29, + 2, 30, 2, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2752,1637 +2784,1772 @@ static const uint8_t _hb_ucd_u8[14763]= 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, + 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 7, 8, 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, 33, 34, 35, + 22, 1, 23, 24, 25, 1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 5, 38, 39, 40, 41, 42, 3, 43, 5, 44, 45, 46, 47, 48, - 49, 50, 51, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 52, 2, 2, - 53, 2, 2, 2, 54, 2, 55, 56, 57, 58, 59, 60, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 61, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 62, 63, 2, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 2, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 49, 50, 51, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 52, 1, 1, + 53, 1, 1, 1, 54, 1, 55, 56, 57, 58, 59, 60, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 61, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 62, 63, 1, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 1, 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, - 2, 2, 2, 98, 99,100, 0, 0, 0, 0, 0, 0, 0, 0, 0,101, - 2, 2, 2, 2,102, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2,103, 2, 2,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,105, 0, 0, 0, 0, 0, 0, 2, 2,106,107, 0,108,109,110, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,111,112, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113, - 2,114,115, 0, 0, 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 3,118,119, - 120,121,122,123,124,125,126,127, 3, 3,128, 0, 0, 0, 0,129, - 130,131,132, 0,133,134,135,136,137,138, 0, 0,139,140,141, 0, - 142,143,144,145, 3, 3,146,147,148, 3,149,150, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2,151, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2,152, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,153, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,154, 2, 2,155, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,156, 0, 0, 0, 0, 0, - 2, 2, 2,157, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2,158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 159,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,161, + 1, 1, 1, 98, 99,100,101, 0, 0, 0, 0, 0, 0, 0, 0,102, + 1, 1, 1, 1,103, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1,104, 1, 1,105, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,106, 0, 0, 0, 0, 0, 0, 1, 1,107,108, 0,109,110,111, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,112,113, 1, 1, + 1,114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115, + 1,116,117, 0, 0, 0, 0, 0, 0, 0, 0, 0,118, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,119, 3,120,121, + 122,123,124,125,126,127,128,129, 3, 3,130,131, 0, 0, 0,132, + 133,134,135, 0,136,137,138,139,140,141, 0, 0,142,143,144, 0, + 145,146,147,148, 3, 3,149,150,151, 3,152,153, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1,154, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1,155, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,156, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,157, 1, 1,158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,159, 0, 0, 0, 0, 0, + 1, 1, 1,160, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,162, 0, 0, 0, + 163,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,165, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, - 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, - 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, - 11, 11, 11, 11, 11, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, - 13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 16, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 14, - 1, 1, 1, 1, 14, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, - 1, 5, 0, 11, 11, 11, 11, 11, 1, 1, 1, 1, 1, 1, 14, 0, - 1, 1, 1, 1, 14, 0, 0, 0, 6, 6, 6, 6, 7, 7, 7, 7, - 1, 1, 1, 1, 1, 14, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 14, 0, 0, 0, 0, - 1, 1, 1, 14, 1, 1, 1, 14, 3, 3, 3, 3, 3, 3, 0, 0, - 28, 28, 28, 28, 28, 28, 28, 28, 11, 11, 11, 11, 11, 1, 1, 1, - 14, 17, 1, 1, 1, 1, 1, 1, 14, 0, 0, 0, 0, 0, 0, 0, - 14, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 0, 0, 0, - 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 29, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, + 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, 14, 14, 14, 14, 14, 14, 14, 14, + 1, 1, 1, 1, 1, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 15, 0, 0, 0, + 18, 18, 18, 18, 18, 18, 18, 18, 1, 1, 1, 1, 1, 15, 0, 0, + 1, 5, 0, 11, 11, 11, 11, 11, 1, 1, 1, 1, 1, 1, 15, 0, + 6, 6, 6, 6, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 15, 0, 0, 0, 0, + 1, 1, 1, 15, 1, 1, 1, 15, 28, 28, 28, 28, 28, 28, 28, 28, + 11, 11, 11, 11, 11, 1, 1, 1, 15, 17, 1, 1, 1, 1, 1, 1, + 15, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 29, 0, 1, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 6, 6, 6, 0, 0, 0, 11, 11, 11, 11, 11, 17, 1, 1, 1, 1, 1, 1, 1, - 11, 11, 11, 11, 11, 10, 10, 10, 1, 1, 1, 0, 0, 0, 0, 0, - 5, 46, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 41, 41, 41, 41, - 3, 3, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 0, 0, 12, - 1, 1, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, - 49, 10, 10, 10, 10, 10, 10, 10, 7, 6, 6, 6, 6, 6, 6, 6, - 44, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, - 3, 3, 3, 3, 0, 0, 0, 0, 11, 11, 11, 11, 11, 12, 9, 77, - 88, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,102,103,104, - 89, 6, 6, 6, 6, 6, 6, 6, 22, 22, 22, 22, 22, 22, 22, 22, - 26, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 5, 5, 5, 5, 5, + 11, 11, 11, 11, 11, 10, 10, 10, 3, 3, 3, 3, 3, 0, 0, 0, + 5, 45, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 42, 42, 42, 42, + 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 29, + 11, 11, 11, 11, 11, 0, 0, 13, 1, 1, 0, 0, 0, 0, 0, 0, + 48, 10, 10, 10, 10, 10, 10, 10, 7, 6, 6, 6, 6, 6, 6, 6, + 54, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 13, 9, 77, 88, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7,104,105,106, 89, 6, 6, 6, 6, 6, 6, 6, + 22, 22, 22, 22, 22, 22, 22, 22, 27, 5, 5, 5, 5, 5, 5, 5, + 1, 1, 1, 5, 5, 5, 5, 5, 25, 0, 0, 0, 0, 0, 0, 0, 5, 20, 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, - 11, 11, 11, 11, 11, 12, 12, 12, 1, 1, 1, 1, 14, 1, 1, 0, - 14, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 14, 1, 1, 1, 1, - 10, 10, 10, 10, 10, 10, 51, 0,115, 1, 1, 1, 1, 1, 1, 1, - 5, 5, 5, 5, 5, 5, 5, 0, 1, 1, 1, 1, 13, 13, 13, 12, - 6, 6, 6, 0, 7, 7, 7, 0, 30, 30, 30, 30, 30, 30, 30, 30, - 3, 3, 3, 3, 3, 29, 0, 0, 3, 3, 3, 3, 3, 3, 3, 29, + 11, 11, 11, 11, 11, 13, 13, 13, 1, 1, 1, 1, 15, 1, 1, 0, + 15, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 15, 1, 1, 1, 1, + 10, 10, 10, 10, 10, 10, 51, 0,117, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 14, 14, 14, 13, 6, 6, 6, 0, 7, 7, 7, 0, + 30, 30, 30, 30, 30, 30, 30, 30, 3, 3, 3, 3, 3, 29, 0, 0, 10, 10, 10, 10, 10, 3, 3, 3, 75, 10, 10, 10, 10, 10, 10, 10, - 3, 3, 3, 29, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 3, 3, 3, 29, 0, 0, 0, 0, 6, 8, 8, 8, 8, 8, 8, 8, + 6, 6, 6, 46, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 7, 7, 7, 7, 7, 32, 7, 7, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 51, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 10, - 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 15, 19, - 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 5, - 15, 15, 15, 15, 15, 15, 15, 15, 1, 14, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 23, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, - 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, - 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, - 3, 3, 3, 3, 29, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, - 87, 12,100, 12, 27,101, 76, 12, 6, 6, 6, 6, 6,105,106,135, - 87, 30, 30, 66,107,136,137,108, 50, 10, 89, 12,138,139, 10, 78, - 7, 7, 7, 59, 7, 7, 7, 8, 6, 6, 6, 60, 6, 6, 6, 6, - 8, 8, 8, 8, 21, 21, 21, 21, 21, 21, 21, 21, 6, 8, 8, 8, - 8, 8, 8, 8, 7, 21, 21, 6, 21, 8, 8, 7, 21, 7, 6, 7, - 7, 21, 8, 7, 8, 6, 7, 21, 8, 8, 8, 7, 21, 6, 8, 7, - 21, 7, 21, 21, 8, 67, 8, 6, 1, 1,109, 21,110,109, 21, 21, - 21, 21, 21, 21, 21, 21, 6, 8, 21,110, 8, 7, 8, 8, 8, 8, - 8, 8, 6, 6, 6, 7, 21, 8, 21, 21, 7, 8, 8, 8, 8, 8, - 6, 6, 1, 6, 6, 6, 6, 6, 13, 22, 22, 13, 13, 13, 13, 13, - 13, 22, 22, 22, 22, 22, 22, 22, 13, 13, 68, 22, 22, 22, 68, 68, - 8, 8, 68, 8, 0, 69, 6, 88, 0, 0, 22,140, 7, 32, 32, 7, - 21, 7, 7, 7, 7, 7, 7, 7, 7, 39, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 21, 6, 7, 8, 6, 8, 8, 8, 8, - 6, 6, 8, 90, 21, 8, 21, 7, 8, 43, 5, 5, 79, 8, 8, 8, - 7, 21, 21, 21, 21, 21, 21, 6, 39, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 32, 54, 12, 12, 12, 6, 6, 6, 6,111,141, 44, 70, - 5, 5, 5, 5, 5, 5, 5,142, 71, 36, 5, 71, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 14, 0, 17, 1, 40, 33, 0, 0, 0, 0, 0, - 18, 18, 18, 9, 77, 80, 12, 3, 5, 5, 5, 5, 5, 36,143, 12, - 52, 1, 1, 1, 1, 24, 5, 5, 11, 11, 11, 11, 11, 12, 12, 1, - 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 53, 5, 5, 5,144, 43, - 5, 5, 81, 72, 55, 5, 5, 1, 11, 11, 11, 11, 11, 1, 56, 82, - 12, 12, 12, 12, 12, 12, 12, 73, 24, 1, 1, 1, 1, 1, 1, 1, - 5, 5, 5, 5, 5, 23, 17, 1, 25, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 24, 5, 5, 5, 5, 13, 66, 12, 61, 26, 30, - 1, 1, 1, 5, 5, 72, 5, 5, 5, 5, 72, 5, 72, 5, 5, 0, - 12, 12, 12, 12, 12, 12, 12, 33, 1, 1, 1, 1, 24, 5, 0, 33, - 1, 1, 1, 1,145, 1, 1, 1, 18, 0, 0, 26, 5, 5, 5, 5, - 1, 1, 1, 1, 45, 5, 5, 5, 5, 91, 5, 5, 5, 5, 5, 5, - 1, 1, 1, 1, 1, 20, 25, 15, 19, 5, 5, 5, 20, 15, 19, 15, - 24, 5, 5, 5, 1, 1, 1, 1, 1, 5, 12, 11, 11, 11, 11, 11, - 62, 1, 1, 1, 1, 1, 1, 1, 24, 15, 17, 1, 1, 1, 14, 17, - 14, 14, 0, 1, 1, 0, 25, 15, 19, 5, 23, 35, 37, 35, 19, 14, - 0, 0, 0, 35, 0, 0, 1, 17, 1, 30, 10, 10, 10, 70, 40, 23, - 26, 20, 17, 1, 1, 14, 0, 17, 14, 1, 17, 14, 1, 0, 23, 15, - 19, 23, 0, 26, 23, 26, 5, 0, 26, 0, 0, 0, 17, 1, 14, 14, - 5, 1, 24, 33, 0, 0, 0, 0, 26, 20, 17, 1, 1, 1, 1, 17, - 14, 1, 17, 1, 1, 0, 25, 15, 19, 5, 5, 26, 20, 35, 19, 0, - 80, 0, 0, 0, 17, 5, 5, 5, 26, 15, 17, 1, 1, 1, 14, 17, - 14, 1, 17, 1, 1, 0, 25, 19, 19, 5, 23, 35, 37, 35, 19, 0, - 0, 0, 26, 20, 0, 0, 1, 17, 82, 10, 10, 10, 0, 0, 0, 0, - 0, 25, 17, 1, 1, 14, 0, 1, 14, 1, 1, 0, 17, 14, 14, 1, - 0, 17, 14, 0, 1, 14, 0, 1, 1, 1, 1, 1, 1, 0, 0, 15, - 20, 37, 0, 15, 37, 15, 19, 0, 14, 0, 0, 35, 0, 0, 0, 0, - 10, 63, 3, 3, 70, 29, 0, 0, 20, 15, 25, 1, 1, 1, 14, 1, - 1, 1, 1, 1, 1, 0, 25, 5, 20, 15, 37, 5, 23, 5, 5, 0, - 0, 0, 26, 23, 1, 14, 1, 0, 0, 0, 0, 38, 10, 10, 10, 63, - 24, 15, 53, 1, 1, 1, 14, 1, 1, 1, 17, 1, 1, 0, 25, 19, - 15, 15, 37, 20, 37, 15, 5, 0, 0, 0, 35, 37, 0, 0, 1, 14, - 17, 34, 0, 0, 0, 0, 0, 0, 5, 15, 1, 1, 1, 1, 14, 1, - 1, 1, 1, 1, 1, 24, 25, 15, 19, 5, 23, 15, 37, 15, 19, 56, - 0, 0, 1, 34, 10, 10, 10,112, 10, 10, 10, 10, 63, 1, 1, 1, - 26, 15, 17, 1, 1, 1, 1, 1, 1, 1, 1, 14, 0, 1, 1, 1, - 1, 17, 1, 1, 1, 1, 17, 0, 1, 1, 1, 14, 0, 23, 0, 35, - 15, 5, 23, 23, 15, 15, 15, 15, 0, 15, 33, 0, 0, 0, 0, 0, - 24, 1, 5, 5, 5, 23, 0,113, 1, 1, 1, 72, 5, 5, 5, 36, - 11, 11, 11, 11, 11, 12, 0, 0, 17, 14, 14, 1, 1, 14, 1, 1, + 1, 1, 1, 1, 1, 1, 16, 19, 1, 1, 1, 1, 1, 1, 1, 34, + 1, 1, 1, 1, 1, 1, 1, 5, 16, 16, 16, 16, 16, 16, 16, 16, + 1, 15, 0, 0, 0, 0, 0, 0, 5, 5, 5, 23, 0, 0, 0, 0, + 10, 10, 0, 0, 0, 0, 0, 0, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 3, 0, 87, 13,102, 13, 26,103, 76, 13, + 6, 6, 6, 6, 6,107,108,138, 87, 30, 30, 65,109,139,140,110, + 49, 10, 89, 13,141,142, 10, 78, 7, 7, 7, 59, 7, 7, 7, 8, + 6, 6, 6, 60, 6, 6, 6, 6, 8, 8, 8, 8, 21, 21, 21, 21, + 21, 21, 21, 21, 6, 8, 8, 8, 8, 8, 8, 8, 7, 21, 21, 6, + 21, 8, 8, 7, 21, 7, 6, 7, 7, 21, 8, 7, 8, 6, 7, 21, + 8, 8, 8, 7, 21, 6, 8, 7, 21, 7, 21, 21, 8, 66, 8, 6, + 1, 1,111, 21,112,111, 21, 21, 21, 21, 21, 21, 21, 21, 6, 8, + 21,112, 8, 7, 8, 8, 8, 8, 8, 8, 6, 6, 6, 7, 21, 8, + 21, 21, 7, 8, 8, 8, 8, 8, 6, 6, 1, 6, 6, 6, 6, 6, + 14, 22, 22, 14, 14, 14, 14, 14, 14, 22, 22, 22, 22, 22, 22, 22, + 14, 14, 67, 22, 22, 22, 67, 67, 8, 8, 67, 8, 0, 68, 6, 88, + 0, 0, 22,143, 7, 32, 32, 7, 21, 7, 7, 7, 7, 7, 7, 7, + 7, 39, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 21, + 6, 7, 8, 6, 8, 8, 8, 8, 6, 6, 8, 90, 21, 8, 21, 7, + 8, 41, 5, 5, 79, 8, 8, 8, 7, 21, 21, 21, 21, 21, 21, 6, + 39, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 32, 14, 13, 13, 13, + 6, 6, 6, 6,113, 91,144, 69, 5, 5, 5, 5, 5, 5, 5,145, + 70, 36, 5, 70, 5, 0, 0, 0, 1, 1, 1, 1, 1, 15, 0, 17, + 1, 40, 33, 0, 0, 0, 0, 0, 18, 18, 18, 9, 77, 80, 13, 3, + 5, 5, 5, 5, 5, 36,146, 13, 52, 1, 1, 1, 1, 24, 5, 5, + 11, 11, 11, 11, 11, 13, 13, 1, 25, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 53, 5, 5, 5,147, 41, 5, 5, 81, 71, 50, 5, 5, 1, + 11, 11, 11, 11, 11, 1, 55, 72, 13, 13, 13, 13, 13, 13, 13, 73, + 24, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 23, 17, 1, + 1, 1, 1, 1, 1, 24, 5, 5, 5, 5, 14, 65, 13, 82, 27, 30, + 1, 1, 1, 5, 5, 71, 5, 5, 5, 5, 71, 5, 71, 5, 5, 0, + 13, 13, 13, 13, 13, 13, 13, 33, 1, 1, 1, 1, 24, 5, 0, 33, + 1, 1, 1, 1,148, 1, 1, 1, 18, 0, 0, 27, 5, 5, 5, 5, + 1, 1, 1, 1, 44, 5, 5, 5, 5, 92, 5, 5, 5, 5, 5, 5, + 1, 1, 1, 1, 1, 20, 25, 16, 19, 5, 5, 5, 20, 16, 19, 16, + 24, 5, 5, 5, 1, 1, 1, 1, 1, 5, 13, 11, 11, 11, 11, 11, + 61, 1, 1, 1, 1, 1, 1, 1, 24, 16, 17, 1, 1, 1, 15, 17, + 15, 15, 0, 1, 1, 0, 25, 16, 19, 5, 23, 35, 37, 35, 19, 15, + 0, 0, 0, 35, 0, 0, 1, 17, 1, 30, 10, 10, 10, 69, 40, 23, + 27, 20, 17, 1, 1, 15, 0, 17, 15, 1, 17, 15, 1, 0, 23, 16, + 19, 23, 0, 27, 23, 27, 5, 0, 27, 0, 0, 0, 17, 1, 15, 15, + 5, 1, 24, 33, 0, 0, 0, 0, 27, 20, 17, 1, 1, 1, 1, 17, + 15, 1, 17, 1, 1, 0, 25, 16, 19, 5, 5, 27, 20, 35, 19, 0, + 80, 0, 0, 0, 17, 5, 5, 5, 27, 16, 17, 1, 1, 1, 15, 17, + 15, 1, 17, 1, 1, 0, 25, 19, 19, 5, 23, 35, 37, 35, 19, 0, + 0, 27, 5, 20, 0, 0, 1, 17, 72, 10, 10, 10, 0, 0, 0, 0, + 0, 25, 17, 1, 1, 15, 0, 1, 15, 1, 1, 0, 17, 15, 15, 1, + 0, 17, 15, 0, 1, 15, 0, 1, 1, 1, 1, 1, 1, 0, 0, 16, + 20, 37, 0, 16, 37, 16, 19, 0, 15, 0, 0, 35, 0, 0, 0, 0, + 10, 62, 3, 3, 69, 29, 0, 0, 20, 16, 25, 1, 1, 1, 15, 1, + 1, 1, 1, 1, 1, 0, 25, 5, 20, 16, 37, 5, 23, 5, 5, 0, + 0, 0, 27, 23, 1, 15, 1, 0, 0, 0, 0, 38, 10, 10, 10, 62, + 24, 16, 53, 1, 1, 1, 15, 1, 1, 1, 17, 1, 1, 0, 25, 19, + 16, 16, 37, 20, 37, 16, 5, 0, 0, 0, 35, 37, 0, 0, 1, 15, + 17, 34, 0, 0, 0, 0, 0, 0, 5, 16, 1, 1, 1, 1, 15, 1, + 1, 1, 1, 1, 1, 24, 25, 16, 19, 5, 23, 16, 37, 16, 19, 55, + 0, 0, 1, 34, 10, 10, 10,114, 10, 10, 10, 10, 62, 1, 1, 1, + 27, 16, 17, 1, 1, 1, 1, 1, 1, 1, 1, 15, 0, 1, 1, 1, + 1, 17, 1, 1, 1, 1, 17, 0, 1, 1, 1, 15, 0, 23, 0, 35, + 16, 5, 23, 23, 16, 16, 16, 16, 0, 16, 33, 0, 0, 0, 0, 0, + 24, 1, 5, 5, 5, 23, 0,115, 1, 1, 1, 71, 5, 5, 5, 36, + 11, 11, 11, 11, 11, 13, 0, 0, 17, 15, 15, 1, 1, 15, 1, 1, 1, 1, 17, 17, 1, 1, 1, 1, 24, 1, 5, 5, 5, 5, 25, 0, - 1, 1, 14, 61, 5, 5, 5, 23, 11, 11, 11, 11, 11, 0, 1, 1, - 56, 3, 12, 12, 12, 12, 12, 12, 12, 57, 57, 3, 5, 3, 3, 3, - 10, 10, 43, 43, 43, 27, 27, 15, 1, 1, 1, 1, 17, 1, 1, 1, - 26, 5, 5, 5, 5, 5, 5, 20, 5, 5, 36, 5, 1, 1, 24, 5, - 5, 5, 5, 5, 26, 5, 5, 5, 5, 5, 5, 5, 5, 5, 23, 3, - 3, 3, 3, 55, 3, 3, 29, 3, 12, 12, 57, 3, 66, 33, 0, 0, + 1, 1, 15, 82, 5, 5, 5, 23, 11, 11, 11, 11, 11, 0, 1, 1, + 55, 3, 13, 13, 13, 13, 13, 13, 13, 56, 56, 3, 5, 3, 3, 3, + 10, 10, 41, 41, 41, 26, 26, 16, 1, 1, 1, 1, 17, 1, 1, 1, + 27, 5, 5, 5, 5, 5, 5, 20, 5, 5, 36, 5, 1, 1, 24, 5, + 5, 5, 5, 5, 27, 5, 5, 5, 5, 5, 5, 5, 5, 5, 23, 3, + 3, 3, 3, 50, 3, 3, 29, 3, 13, 13, 56, 3, 65, 33, 0, 0, 1, 1, 1, 1, 1, 34, 19, 5, 20, 5, 5, 5, 19, 20, 19, 25, - 1, 1, 1, 15, 5, 1, 1, 5, 25, 15, 46, 34, 15, 15, 15, 1, - 24, 5, 25, 1, 1, 1, 1, 1, 1, 20, 19, 20, 15, 15, 19, 34, - 11, 11, 11, 11, 11, 15, 19, 3, 7, 7, 7, 39, 0, 0, 39, 0, - 6, 6, 6, 6, 6,111, 69, 6, 1, 1, 1, 14, 14, 1, 1, 0, - 14, 1, 1, 0, 1, 1, 1, 14, 1, 1, 1, 1, 1, 14, 26, 5, - 12, 12, 12, 12,114, 10, 10, 10, 7, 7, 7, 0, 6, 6, 6, 0, - 1, 1, 1, 1, 1, 1, 56, 53,146, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1,147,116, 0, 1, 1, 1, 1, 1, 40, 12, 16, - 148, 1, 1, 1, 14, 0, 0, 0, 1, 5, 20, 0, 0, 0, 0, 17, + 1, 1, 1, 16, 5, 1, 1, 5, 25, 16, 45, 34, 16, 16, 16, 1, + 24, 5, 25, 1, 1, 1, 1, 1, 1, 20, 19, 20, 16, 16, 19, 34, + 11, 11, 11, 11, 11, 16, 19, 3, 7, 7, 7, 39, 0, 0, 39, 0, + 6, 6, 6, 6, 6,113, 68, 6, 1, 1, 1, 15, 15, 1, 1, 0, + 15, 1, 1, 0, 1, 1, 1, 15, 1, 1, 1, 1, 1, 15, 27, 5, + 13, 13, 13, 13,116, 10, 10, 10, 7, 7, 7, 0, 6, 6, 6, 0, + 1, 1, 1, 1, 1, 1, 55, 53,149, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1,150,151, 0, 1, 1, 1, 1, 1, 40, 13, 12, + 152, 1, 1, 1, 15, 0, 0, 0, 1, 5, 20, 0, 0, 0, 0, 17, 1, 5, 83, 33, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 14, 1, 14, 5, 0, 0, 0, 0, 0, 0, - 1, 1, 5, 19, 5, 5, 5, 15, 15, 15, 15, 20, 19, 5, 5, 5, - 5, 5, 12, 62, 12, 80, 24, 0, 10, 10, 10, 10, 10, 0, 0, 0, - 12, 12, 12, 92, 12, 71, 5, 91, 1, 45, 1, 1, 1, 1, 1, 1, - 1, 1, 24, 25, 1, 1, 1, 1, 1, 1, 1, 1, 24, 14, 0, 0, - 5, 20, 15, 19, 20, 15, 0, 0, 15, 20, 15, 15, 19, 5, 0, 0, - 29, 0, 12, 11, 11, 11, 11, 11, 1, 1, 14, 0, 0, 0, 0, 0, - 11, 11, 11, 11, 11, 51, 0, 3, 1, 1, 1, 24, 20, 19, 0, 12, - 1, 1, 34, 20, 5, 5, 5, 23, 20, 20, 19, 5, 5, 5, 20, 15, - 15, 19, 5, 5, 5, 5, 23, 26, 12, 12, 12, 62, 12, 12, 12, 0, - 5, 5, 5, 5, 5, 5, 5, 93, 5, 5, 5, 5, 5, 5, 0, 0, - 5, 5, 46, 1, 1, 1, 1, 1, 1, 1, 20, 5, 5, 20, 20, 15, - 15, 20, 46, 1, 1, 1, 14, 12, 57, 3, 3, 3, 3, 43, 5, 5, - 5, 5, 3, 3, 3, 3, 66, 12, 34, 5, 5, 15, 5, 19, 5, 1, - 1, 1, 1, 20, 5, 15, 19, 19, 5, 15, 0, 0, 0, 0, 12, 12, - 1, 1, 15, 15, 15, 15, 5, 5, 5, 5, 15, 5, 0, 38, 12, 12, - 11, 11, 11, 11, 11, 0, 17, 1, 6, 6, 6, 6, 21, 47, 0, 0, - 7, 7, 7, 7, 7, 32, 39, 7, 12, 12, 12, 12, 0, 0, 0, 0, - 5, 36, 5, 5, 5, 5, 5, 5, 20, 5, 5, 5, 25, 1, 24, 1, - 1, 1, 25, 34, 5, 14, 0, 0, 6, 6, 6, 6, 6, 6, 13, 13, - 13, 13, 13, 13, 13, 69, 6, 6, 6, 6, 6, 6, 69, 6, 6, 6, - 6, 6, 6, 6, 6,117, 13, 13, 8, 8, 8, 6, 6, 6, 6, 8, - 6, 6, 6, 6, 39, 39, 39, 39, 6, 6, 6, 6, 6, 6, 6, 0, - 6, 6, 47, 6, 7, 7, 94,118, 22, 6, 47, 6, 7, 7, 94, 22, - 6, 6, 0, 6, 7, 7,149, 22, 6, 6, 6, 6, 7, 7,150, 22, - 0, 6, 47, 6, 7, 7, 94,151, 74, 74, 74, 74, 74,152, 18, 18, - 84, 84, 84, 12, 58,119, 58,119, 12, 12, 12, 12,153, 18, 18,154, - 12, 12, 12, 12,120,121, 12,122,123, 12, 64, 65, 12, 12, 12, 12, - 12, 77,123, 12, 12, 12, 12,155, 18, 18,156, 18, 18, 18, 18, 18, - 157, 0, 10, 10, 10, 9, 64,158, 10, 10, 10, 10, 10, 9, 64,116, - 13, 13, 13, 13, 13, 13, 61, 0, 30, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 5, 5,159, 79, 93, 79, 93, 5, 5, 5, 5, 5, - 23, 0, 0, 0, 0, 0, 0, 0, 3, 85, 3, 95, 3, 21, 7, 6, - 7, 8, 95, 3, 90, 7, 7, 3, 3, 3, 85, 85, 85, 7, 7,160, - 7, 7, 67, 1,124, 3, 6, 7, 9, 9, 90, 6, 6, 50, 3,125, - 16,161,162, 16,126, 3, 0, 0, 9, 9, 48, 3, 3, 9, 3, 3, - 48, 50, 3, 48, 3, 3, 3, 48, 3, 3, 3, 3, 3, 3, 3, 9, - 3, 48, 48, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, - 3, 3, 3, 3, 27, 27, 3, 3, 9, 3, 3, 3,163,164, 3, 3, - 3, 3, 3, 3, 3, 3, 48, 3, 3, 3, 3, 3, 3, 50, 9, 9, - 9, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, - 9, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, 10, 10, 10, 3, 3, - 3, 3, 3, 3, 3, 10, 10, 10, 3, 3, 3, 50, 3, 3, 3, 3, - 50, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, - 3, 3, 3, 3, 3, 3, 3, 50, 3, 3, 3, 3, 27, 27, 27, 27, - 27, 27, 27, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, - 9, 9, 64,127, 9, 9, 9, 9, 9, 9, 9, 27, 27, 27, 27, 27, - 9, 64, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,127, 9, 9, 9, - 9, 9, 9, 9, 27, 27, 9, 9, 9, 9, 9, 9, 9, 9, 27, 9, - 9, 9, 48, 50, 9, 9, 48, 3, 3, 3, 0, 3, 3, 3, 3, 3, - 8, 7, 8, 21, 21, 21, 21, 7, 8, 8, 21, 6, 6, 6, 13, 7, - 8, 8,125, 3, 3, 95, 21,165, 5, 8, 0, 0, 38, 12,114, 12, - 6, 6, 6, 42, 0, 0, 42, 0, 1, 1, 1, 1, 0, 0, 0, 54, - 33, 0, 0, 0, 0, 0, 0, 26, 12, 58, 58, 12,120,121, 58, 12, - 12, 12, 12, 76, 12, 92, 58, 12, 58, 27, 27, 27, 27, 12, 12, 62, - 12, 12, 12, 12, 12, 84, 12, 12, 92,166, 12, 12, 12, 12, 12, 12, - 3, 12, 96, 31, 31, 31,167, 0, 3, 3, 3, 3, 3, 44, 3, 3, - 87, 12,168,128, 27, 27, 27, 27, 27, 3, 27, 27, 27, 27,129,169, - 170, 16, 16, 16, 16, 5, 5, 15,130, 13, 13, 3, 16,171, 40, 3, - 1, 1, 1, 14, 26,172,131, 52, 1, 1, 1, 1, 1, 40, 13, 52, + 1, 1, 1, 1, 1, 1, 15, 1, 15, 5, 0, 0, 0, 0, 0, 0, + 1, 1, 5, 19, 5, 5, 5, 16, 16, 16, 16, 20, 19, 5, 5, 5, + 5, 5, 13, 61, 13, 80, 24, 0, 10, 10, 10, 10, 10, 0, 0, 0, + 13, 13, 13, 93, 13, 70, 5, 92, 1, 44, 1, 1, 1, 1, 1, 1, + 1, 1, 24, 25, 1, 1, 1, 1, 1, 1, 1, 1, 24, 15, 0, 0, + 5, 20, 16, 19, 20, 16, 0, 0, 16, 20, 16, 16, 19, 5, 0, 0, + 29, 0, 13, 11, 11, 11, 11, 11, 1, 1, 15, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 51, 0, 3, 1, 1, 1, 24, 20, 19, 0, 13, + 1, 1, 34, 20, 5, 5, 5, 23, 20, 20, 19, 5, 5, 5, 20, 16, + 16, 19, 5, 5, 5, 5, 23, 27, 13, 13, 13, 61, 13, 13, 13, 0, + 5, 5, 5, 5, 5, 5, 5, 94, 5, 5, 45, 1, 1, 1, 1, 1, + 1, 1, 20, 5, 5, 20, 20, 16, 16, 20, 45, 1, 1, 1, 15, 13, + 56, 3, 3, 3, 3, 41, 5, 5, 5, 5, 3, 3, 3, 3, 65, 13, + 34, 5, 5, 16, 5, 19, 5, 1, 1, 1, 1, 20, 5, 16, 19, 19, + 5, 16, 0, 0, 0, 0, 13, 13, 1, 1, 16, 16, 16, 16, 5, 5, + 5, 5, 16, 5, 0, 38, 13, 13, 11, 11, 11, 11, 11, 0, 17, 1, + 6, 6, 6, 6, 21, 46, 0, 0, 7, 7, 7, 7, 7, 32, 39, 7, + 13, 13, 13, 13, 0, 0, 0, 0, 5, 36, 5, 5, 5, 5, 5, 5, + 20, 5, 5, 5, 25, 1, 24, 1, 1, 1, 25, 34, 5, 15, 0, 0, + 6, 6, 6, 6, 6, 6, 14, 14, 14, 14, 14, 14, 14, 68, 6, 6, + 6, 6, 6, 6, 68, 6, 6, 6, 6, 6, 6, 6, 6,118, 14, 14, + 8, 8, 8, 6, 6, 6, 6, 8, 6, 6, 6, 6, 39, 39, 39, 39, + 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 46, 6, 7, 7, 95,119, + 22, 6, 46, 6, 7, 7, 95, 22, 6, 6, 0, 6, 7, 7,120, 22, + 6, 6, 6, 6, 7, 7,153, 22, 0, 6, 46, 6, 7, 7, 95,154, + 74, 74, 74, 74, 74,155, 18, 18, 84, 84, 84, 13, 57,121, 57,121, + 13, 13, 13, 13,156, 18, 18,157, 13, 13, 13, 13,122,123, 13,124, + 125, 13, 63, 64, 13, 13, 13, 13, 13, 77,125, 13, 13, 13, 13,158, + 18, 18,159, 18, 18, 18, 18, 18,160, 0, 10, 10, 10, 9, 63,126, + 10, 10, 10, 10, 10, 9, 63,126, 30, 30,127, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5,161, 79, 94, 79, 94, 5, 5, 5, 5, 5, + 3, 85, 3, 96, 3, 21, 7, 6, 7, 8, 96, 3, 90, 7, 7, 3, + 3, 3, 85, 85, 85, 7, 7,162, 7, 7, 66, 1,128, 3, 6, 7, + 9, 9, 90, 6, 6, 49, 3,129, 12,163,164, 12,130, 3, 0, 0, + 9, 9, 47, 3, 3, 9, 3, 3, 47, 49, 3, 47, 3, 3, 3, 47, + 3, 3, 3, 3, 3, 3, 3, 9, 3, 47, 47, 3, 3, 3, 3, 3, + 3, 3, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 26, 26, 3, 3, + 9, 3, 3, 3,165,166, 3, 3, 3, 3, 3, 3, 3, 3, 47, 3, + 3, 3, 3, 3, 3, 49, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 9, 9, 9, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, + 3, 3, 3, 49, 3, 3, 3, 3, 49, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, 3, 49, + 3, 3, 3, 3, 26, 26, 26, 26, 26, 26, 26, 10, 10, 10, 10, 10, + 10, 10, 3, 3, 3, 3, 3, 3, 9, 9, 63,131, 9, 9, 9, 9, + 9, 9, 9, 26, 26, 26, 26, 26, 9, 63, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31,131, 9, 9, 9, 9, 9, 9, 9, 26, 26, 9, 9, + 9, 9, 9, 9, 9, 9, 26, 9, 9, 9, 47, 49, 9, 9, 47, 3, + 3, 3, 0, 3, 3, 3, 3, 3, 8, 7, 8, 21, 21, 21, 21, 7, + 8, 8, 21, 6, 6, 6, 14, 7, 8, 8,129, 3, 3, 96, 21,167, + 5, 8, 0, 0, 38, 13,116, 13, 6, 6, 6, 43, 0, 0, 43, 0, + 1, 1, 1, 1, 0, 0, 0, 58, 33, 0, 0, 0, 0, 0, 0, 27, + 13, 57, 57, 13,122,123, 57, 13, 13, 13, 13, 76, 13, 93, 57, 13, + 57, 26, 26, 26, 26, 13, 13, 61, 13, 13, 13, 13, 13, 84, 13, 13, + 93,168, 13, 13, 13, 13, 13, 13, 3, 13, 97, 31, 31, 31,169, 0, + 13, 26, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 54, 3, 3, + 87, 13,170,132, 26, 26, 26, 26, 26, 3, 26, 26, 26, 26,133,171, + 172, 12, 12, 12, 12, 5, 5, 16, 91, 14, 14, 3, 12,173, 40, 3, + 1, 1, 1, 15, 27,174,134, 52, 1, 1, 1, 1, 1, 40, 14, 52, 0, 0, 17, 1, 1, 1, 1, 1, 3, 10, 10, 3, 3, 3, 3, 3, - 3, 3, 3, 0, 0, 0, 0, 44, 3, 3, 3, 3, 10, 10, 10, 10, - 1, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,132, 12, + 3, 3, 3, 0, 0, 0, 0, 54, 3, 3, 3, 3, 10, 10, 10, 10, + 1, 1, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,135, 13, 11, 11, 11, 11, 11, 1, 0, 0, 8, 8, 8, 8, 8, 8, 8, 24, - 79,173, 5, 5, 5, 5, 5, 62, 8, 8, 8, 8, 8, 8, 13, 5, - 1, 1, 1, 16, 16, 16, 16, 16, 5, 12, 12, 12, 0, 0, 0, 0, - 22, 22, 22,131, 13, 13, 13, 13, 22, 8, 8, 8, 8, 8, 8, 8, - 6, 8, 8, 8, 8, 8, 8, 8, 69, 6, 6, 6, 21, 21, 21, 8, - 8, 8, 8, 8, 68,174, 21, 67, 8, 8, 6, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 7, 7, 8, 7, 7, 8, 8, 8, 8, 8, 8, - 8, 8, 7, 7, 21, 21, 8, 8, 8, 8, 8, 8, 8, 8, 32, 0, - 54, 13,175, 67, 13, 67, 1, 1, 1, 25, 1, 25, 1, 24, 1, 1, - 1, 34, 19, 20, 3, 3, 23, 0, 10, 10, 10, 3, 97, 0, 0, 0, - 1, 1, 12, 12, 0, 0, 0, 0, 15, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 5, 0, 0, 0, 0, 12, - 5, 1, 1, 1, 12, 53, 53, 24, 1, 1, 1, 5, 5, 5, 5, 12, - 1, 1, 1, 24, 5, 5, 5, 5, 5, 15, 0, 0, 0, 0, 0, 38, - 1, 24, 15, 5, 5, 15, 5, 15, 83, 12, 12, 12, 12, 12, 12, 54, - 1, 1, 24, 52, 1, 1, 1, 1, 11, 11, 11, 11, 11, 1, 1, 14, + 79,175, 5, 5, 5, 5, 5, 61, 8, 8, 8, 8, 8, 8, 14, 5, + 1, 1, 1, 12, 12, 12, 12, 12, 5, 13, 13, 13, 0, 0, 0, 0, + 22, 22, 22,134, 14, 14, 14, 14, 22, 8, 8, 8, 8, 8, 8, 8, + 68, 6, 6, 6, 21, 21, 21, 8, 8, 8, 8, 8, 67,176, 21, 66, + 8, 8, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 8, + 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 21, 21, 8, 8, + 8, 8, 8, 8, 8, 8, 7, 0, 0, 32, 0, 0, 0, 0, 0, 0, + 58, 14,177, 66, 14, 66, 1, 1, 1, 25, 1, 25, 1, 24, 1, 1, + 1, 34, 19, 20, 3, 3, 23, 0, 10, 10, 10, 3, 98, 0, 0, 0, + 1, 1, 13, 13, 0, 0, 0, 0, 16, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 16, 16, 16, 16, 16, 16, 16, 16, 5, 0, 0, 0, 0, 13, + 5, 1, 1, 1, 13, 53, 53, 24, 1, 1, 1, 5, 5, 5, 5, 13, + 1, 1, 1, 24, 5, 5, 5, 5, 5, 16, 0, 0, 0, 0, 0, 38, + 1, 24, 16, 5, 5, 16, 5, 16, 83, 13, 13, 13, 13, 13, 13, 58, + 1, 1, 24, 52, 1, 1, 1, 1, 11, 11, 11, 11, 11, 1, 1, 15, 1, 1, 1, 1, 24, 5, 5, 20, 19, 20, 19, 23, 0, 0, 0, 0, - 1, 24, 1, 1, 1, 1, 20, 0, 11, 11, 11, 11, 11, 0, 12, 12, - 52, 1, 1, 56, 3, 34, 20, 1, 25, 5, 25, 24, 25, 1, 1, 5, - 24, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 45, 12, - 1, 1, 1, 1, 1, 34, 5, 15, 12, 45,176, 23, 0, 0, 0, 0, - 17, 1, 1, 14, 17, 1, 1, 14, 17, 1, 1, 14, 0, 0, 0, 0, - 6, 6, 6, 6, 6,118, 13, 13, 6, 6, 6, 6,117, 22, 0, 0, - 1, 34, 19, 15, 20, 83, 19, 0, 1, 1, 1, 14, 0, 17, 1, 1, - 6, 6, 6, 47, 0, 0, 0, 0, 0, 42, 6, 6, 0, 0, 17, 25, - 1, 1, 1, 1,177, 1, 1, 1, 1, 1, 1, 14, 1, 1, 14, 14, - 1, 17, 14, 1, 1, 1, 1, 1, 1, 22, 22, 22, 22, 22, 22, 22, - 22,107, 3, 3, 3, 3, 3, 3, 3, 82, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 31, 3, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 97, 3, - 12, 12, 12, 96, 65, 0, 0, 0, 76,178,179, 31, 31, 31, 31, 31, - 31, 31, 65, 96, 65, 12,122,180, 12, 33, 12, 12,129, 31, 31, 65, - 12,181, 9, 98, 80, 12, 0, 0, 1, 1, 14, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 14, 73, 38, 12,100, 12, 27,101, 76, 12, - 6, 6, 6, 6, 6,105,106, 64, 65, 27, 12, 1, 1, 1, 1, 1, - 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, - 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 14, 0, - 30,182, 70,183, 50, 9, 48, 29, 0, 0, 0, 0, 73, 18, 3, 0, - 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, 14, 1, 17, - 12, 33, 0, 49, 10, 10, 10, 10, 10, 10, 0, 44, 3, 3, 3, 3, - 16, 16,126, 10, 63, 3, 3, 3, 3, 3, 3, 3, 3, 10, 3, 29, - 3, 3, 3, 3, 3, 3, 43, 0,133, 10, 10, 10, 10, 10, 10, 10, + 1, 24, 1, 1, 1, 1, 20, 0, 11, 11, 11, 11, 11, 0, 13, 13, + 52, 1, 1, 55, 3, 34, 20, 1, 25, 5, 25, 24, 25, 1, 1, 5, + 24, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 44, 13, + 1, 1, 1, 1, 1, 34, 5, 16, 13, 44,178, 23, 0, 0, 0, 0, + 17, 1, 1, 15, 17, 1, 1, 15, 17, 1, 1, 15, 0, 0, 0, 0, + 6, 6, 6, 6, 6,119, 14, 14, 6, 6, 6, 6,118, 22, 7, 0, + 1, 34, 19, 16, 20, 83, 19, 0, 1, 1, 1, 15, 0, 17, 1, 1, + 0, 43, 6, 6, 0, 0, 17, 25, 1, 1, 1, 1,179, 1, 1, 1, + 1, 1, 1, 15, 1, 1, 15, 15, 1, 17, 15, 1, 1, 1, 1, 1, + 1, 22, 22, 22, 22, 22, 22, 22, 22,109, 3, 3, 3, 3, 3, 3, + 3, 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 98, 3, 13, 13, 13, 97, 64, 0, 0, 0, + 76,180,181, 31, 31, 31, 31, 31, 31, 31, 64, 97, 64, 13,124,182, + 13, 33, 13, 13,133, 31, 31, 64, 13,183, 9, 99, 80, 13, 0, 0, + 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 73, + 38, 13,102, 13, 26,103, 76, 13, 6, 6, 6, 6, 6,107,108, 63, + 64, 26, 13, 1, 1, 1, 1, 1, 52, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 14, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 15, 0, 30,184, 69,127, 49, 9, 47, 29, + 0, 0, 0, 0, 73, 18, 3, 0, 1, 1, 1, 1, 1, 1, 17, 1, + 1, 1, 1, 1, 1, 15, 1, 17, 13, 33, 0, 48, 10, 10, 10, 10, + 10, 10, 0, 54, 3, 3, 3, 3, 12, 12,130, 10, 62, 3, 3, 3, + 3, 3, 3, 3, 3, 10, 3, 29, 29, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 41, 0,136, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 10, 10, 0, 0, 0, 0, 17, 1, - 128, 1, 1, 1, 1, 99, 0, 0, 1, 1, 1, 5, 5, 23, 0, 0, + 132, 1, 1, 1, 1,100, 0, 0, 1, 1, 1, 5, 5, 23, 0, 0, 1, 1, 1, 1, 1, 1, 1, 38, 1, 1, 0, 0, 1, 1, 1, 1, - 184, 16, 16, 0, 0, 0, 0, 0, 7, 7, 7, 7, 6, 6, 6, 6, + 137, 12, 12, 0, 0, 0, 0, 0, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, - 1, 1, 0, 0, 0, 0, 0, 38, 7, 32, 7, 42, 6, 6, 6, 6, - 6, 42, 6, 6, 6, 6, 6, 6, 6, 42, 6, 6, 6, 42, 47, 0, - 13, 13, 13, 54, 13, 13, 13, 13, 61, 13, 13, 13, 13, 61, 0, 0, - 1, 1, 1, 0, 14, 1, 1, 1, 1, 1, 1, 17, 14, 0, 14, 17, - 1, 1, 1, 38, 10, 10, 10, 10, 1, 1, 1, 56, 75, 10, 10, 10, - 0, 0, 0, 49, 10, 10, 10, 10, 1, 14, 1, 0, 0, 49, 10, 10, + 1, 1, 0, 0, 0, 0, 0, 38, 7, 32, 7, 43, 6, 6, 6, 6, + 6, 43, 6, 6, 6, 6, 6, 6, 6, 43, 6, 6, 6, 43, 46, 0, + 14, 14, 14, 58, 14, 14, 14, 14, 82, 14, 14, 14, 14, 14, 14, 14, + 1, 1, 1, 0, 15, 1, 1, 1, 1, 1, 1, 17, 15, 0, 15, 17, + 1, 1, 1, 38, 10, 10, 10, 10, 1, 1, 1, 55, 75, 10, 10, 10, + 0, 0, 0, 48, 10, 10, 10, 10, 1, 15, 1, 0, 0, 48, 10, 10, 1, 1, 1, 10, 10, 10, 0, 38, 1, 1, 1, 1, 1, 0, 0, 38, - 1, 1, 1, 1, 0, 0, 10, 1, 24, 5, 26, 23, 0, 0, 5, 5, - 1, 1, 17, 1, 17, 1, 1, 1, 1, 1, 1, 0, 5, 23, 0, 26, - 12, 12, 12, 12, 33, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 78, - 1, 1, 1, 1, 82, 1, 1, 1, 1, 1, 24, 23, 0, 49, 10, 10, - 12, 12, 12, 33, 0, 0, 0, 0, 1, 1, 1, 0, 38, 12, 12, 12, - 1, 1, 1, 0, 10, 10, 10, 10, 1, 14, 0, 0, 10, 10, 10, 10, - 1, 0, 0, 0, 38, 12, 33, 0, 0, 0, 0, 0, 49, 10, 10, 10, - 7, 32, 0, 0, 0, 0, 0, 0, 6, 47, 0, 0, 0, 10, 10, 10, + 1, 1, 1, 1, 0, 0, 10, 1, 24, 5, 27, 23, 0, 0, 5, 5, + 1, 1, 17, 1, 17, 1, 1, 1, 1, 1, 1, 0, 5, 23, 0, 27, + 13, 13, 13, 13, 33, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 78, + 1, 1, 1, 1, 72, 1, 1, 1, 1, 1, 24, 23, 0, 48, 10, 10, + 13, 13, 13, 33, 0, 0, 0, 0, 1, 1, 1, 0, 38, 13, 13, 13, + 1, 1, 1, 0, 10, 10, 10, 10, 1, 15, 0, 0, 10, 10, 10, 10, + 1, 0, 0, 0, 38, 13, 33, 0, 0, 0, 0, 0, 48, 10, 10, 10, + 7, 32, 0, 0, 0, 0, 0, 0, 6, 46, 0, 0, 0, 10, 10, 10, 1, 1, 5, 5, 0, 0, 0, 0, 11, 11, 11, 11, 11, 1, 1, 52, - 7, 7, 7, 0, 26, 5, 5,130, 6, 6, 6, 0, 0, 0, 0, 9, - 10, 10, 10, 10, 10, 10, 10, 51, 1, 1, 1, 1, 1, 26,185, 0, - 0, 1, 45, 1, 0, 0, 0, 0, 57, 3, 3, 3, 29, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 5, 5, 10, 10, 10,112, 0, 0, 0, 0, - 133, 10, 78, 12, 12, 0, 0, 0, 1, 5, 5, 12, 12, 0, 0, 0, - 1, 1, 86, 10, 10, 10, 0, 0, 19, 46, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 36, 12, 12, 12, 0, - 10, 10, 10, 11, 11, 11, 11, 11, 25, 24, 25, 0, 0, 0, 0, 26, - 15, 19, 5, 20, 19, 36,186, 12, 12, 23, 0, 0, 0, 0, 73, 0, - 5, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, 5, 5, 19, 5, - 5, 5, 23, 11, 11, 11, 11, 11, 12, 12, 34, 46, 0, 0, 0, 0, - 1, 24, 12, 14, 0, 0, 0, 0, 1, 34, 15, 5, 5, 5, 5, 20, - 46, 1, 40, 12, 71, 5, 36, 19, 11, 11, 11, 11, 11, 40, 40, 12, - 10, 10, 51, 0, 0, 0, 0, 0, 5, 15, 20, 5, 12, 12, 12, 25, - 24, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 14, 14, 1, 1, 17, - 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 40, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 24, 15, 19, 5, 5, 5, 23, 0, 0, - 5, 15, 17, 1, 1, 1, 14, 17, 14, 1, 17, 1, 1, 26, 25, 15, - 20, 15, 37, 35, 37, 35, 15, 0, 14, 0, 0, 35, 0, 0, 17, 1, - 1, 15, 0, 5, 5, 5, 23, 0, 5, 5, 23, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 17, 0, 14, 1, 1, 1, 17, 15, 19, 5, 5, - 23, 37, 35, 35, 15, 37, 15, 20, 25, 25, 12, 38, 33, 0, 0, 0, - 26, 23, 0, 0, 0, 0, 0, 0, 1, 1, 34, 15, 5, 5, 5, 5, - 15, 5, 20, 25, 1, 40, 12, 12, 11, 11, 11, 11, 11, 12, 38, 25, - 15, 19, 5, 5, 20, 20, 15, 19, 20, 5, 1, 53, 0, 0, 0, 0, - 15, 5, 5, 0, 15, 15, 5, 19, 36, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 1, 1, 5, 0, 15, 19, 5, 5, 5, 20, 19, 19, - 36, 12, 14, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 33, 0, - 1, 1, 1, 1, 1, 24, 19, 15, 5, 5, 5, 19, 40, 0, 0, 0, - 11, 11, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14, 26, 19, - 15, 5, 5, 19, 5, 5, 0, 0, 11, 11, 11, 11, 11, 10, 12, 57, - 5, 5, 5, 5, 19, 36, 0, 0, 10, 51, 0, 0, 0, 0, 0, 17, - 1, 1, 1, 14, 17, 0, 1, 1, 1, 1, 17, 14, 1, 1, 1, 1, - 15, 15, 15, 35, 37, 26, 20, 25, 46, 19, 12, 33, 0, 0, 0, 0, - 1, 1, 1, 1, 0, 1, 1, 1, 34, 15, 5, 5, 0, 5, 15, 15, - 25, 53, 37, 0, 0, 0, 0, 0, 24, 5, 5, 5, 5, 25, 1, 1, - 1, 24, 5, 5, 20, 24, 5, 36, 12, 12, 12, 71, 0, 0, 0, 0, - 24, 5, 5, 20, 19, 5, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, - 5, 5, 5, 20, 5, 12, 53, 12, 12, 33, 0, 0, 0, 0, 0, 0, - 12, 12, 12, 12, 12, 0, 0, 0, 20, 5, 20, 20, 0, 0, 0, 0, - 40, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 23, 5, 5, 5, 19, - 40, 12, 12, 0, 0, 0, 0, 0, 12, 1, 1, 1, 1, 1, 1, 1, - 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 35, 5, 5, 5, - 20, 5, 19, 23, 0, 0, 0, 0, 1, 1, 1, 14, 1, 17, 1, 1, - 24, 5, 5, 23, 0, 23, 5, 26, 5, 5, 5, 24, 0, 0, 0, 0, - 1, 1, 1, 17, 14, 1, 1, 1, 1, 1, 1, 1, 1, 15, 15, 37, - 5, 35, 19, 19, 14, 0, 0, 0, 1, 1, 1, 1, 45, 1, 0, 0, - 1, 24, 20, 83, 33, 0, 0, 0, 5, 34, 1, 1, 1, 1, 1, 1, - 1, 1, 15, 5, 5, 23, 0, 15, 20, 36, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 23, 0, 0, 10, 10, 63, 3, 3, 3, 70, 30, - 97, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 38, - 16, 16, 16, 16, 16, 16, 16, 99, 12, 12, 33, 0, 0, 0, 0, 0, - 40, 33, 0, 0, 0, 0, 0, 0, 25, 1, 1, 24, 5, 5, 5, 5, - 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 15, 19, 5, - 5, 5, 36, 0, 0, 0, 0, 0, 5, 5, 5, 36, 12, 12, 3, 3, - 13, 13, 57, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 49, 10, 10, - 10, 17, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 17, 1, - 13, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45,132, 12, - 10, 10, 10, 78, 12, 33, 0, 0, 7, 7, 7, 7, 32, 42, 6, 6, - 6, 6, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14, 0, 26, - 34, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 26, - 5, 81, 13, 13, 13, 13, 13, 13, 13, 62, 23, 0, 0, 0, 0, 0, - 15, 13, 16, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, - 13, 13, 54, 13, 13, 13, 54, 61, 0, 14, 0, 0, 0, 0, 0, 0, - 1, 14, 17, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 43, 36, 18, 18, 0, 0, 0, 0, 0, 0, - 11, 11, 11, 11, 11, 3, 29, 0, 3, 3, 0, 0, 0, 3, 3, 3, - 98, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 29, 44, 3, 3, 3, - 3, 3,134, 19, 5, 3,134, 15, 15,187, 18, 18, 18, 91, 5, 5, - 5, 55, 43, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, - 3, 5, 55, 0, 0, 0, 0, 0, 6, 6, 47, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 32, 7, 0, 32, 39, 32, 39, 7, 32, 7, - 7, 7, 7, 6, 6, 42, 42, 6, 6, 6, 42, 6, 6, 6, 6, 6, - 6, 6, 7, 39, 7, 32, 39, 7, 7, 7, 32, 7, 7, 7, 32, 6, - 6, 6, 6, 6, 7, 39, 7, 32, 7, 7, 32, 32, 0, 7, 7, 7, - 32, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 7, 7, 7, 7, - 59, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 60, 6, 6, - 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 59, 6, 6, - 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 59, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, - 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, 8, 0, 11, - 5, 5, 5, 55, 3, 43, 5, 5, 5, 5, 5, 5, 5, 5, 55, 3, - 3, 3, 43, 3, 3, 3, 3, 3, 3, 3, 55, 66, 12, 12, 0, 0, - 0, 0, 0, 0, 0, 26, 5, 5, 6, 6, 6, 6, 6,124, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 47, 0, 0, 42, 6, 6, 47, 0, 0, - 5, 5, 5, 23, 5, 5, 5, 5, 5, 5, 5, 5, 23, 26, 5, 5, - 5, 26, 23, 5, 5, 23, 0, 0, 13, 13, 13, 13, 13, 13, 13, 0, - 0, 0, 0, 0, 0, 0, 0, 26, 5, 5, 5, 81, 13, 13, 13, 0, - 11, 11, 11, 11, 11, 0, 0, 56, 1, 1, 1, 1, 1, 1, 1, 23, - 1, 1, 1, 1, 1, 1, 5, 5, 11, 11, 11, 11, 11, 0, 0,113, - 1, 1, 1, 1, 1, 45, 5, 5,188, 11, 11, 11, 11,189, 0, 38, - 1, 24, 1, 25, 1, 1, 1, 5, 1, 1, 24, 0, 0, 0, 0, 45, - 1, 1, 1, 14, 1, 1, 17, 14, 1, 1, 14, 49, 10, 10, 10, 10, + 7, 7, 7, 0, 27, 5, 5, 91, 6, 6, 6, 0, 0, 0, 0, 9, + 10, 10, 10, 10, 10, 10, 10, 51, 1, 1, 1, 1, 1, 27,185, 0, + 0, 1, 44, 1,120,186, 5, 5, 56, 3, 3, 3, 72, 1, 1, 1, + 10, 10, 10,114, 0, 0, 0, 0,136, 10, 78, 13, 13, 0, 0, 0, + 1, 5, 5, 13, 13, 0, 0, 0, 1, 1, 86, 10, 10, 10, 0, 0, + 19, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, + 5, 5, 5, 36, 13, 13, 13, 0, 10, 10, 10, 11, 11, 11, 11, 11, + 25, 24, 25, 0, 0, 0, 0, 27, 16, 19, 5, 20, 19, 36,187, 13, + 13, 23, 0, 0, 0, 0, 73, 0, 5, 25, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 24, 5, 5, 19, 5, 5, 5, 23, 11, 11, 11, 11, 11, + 13, 13, 34, 45, 0, 0, 0, 0, 1, 24, 13, 15, 0, 0, 0, 0, + 1, 34, 16, 5, 5, 5, 5, 20, 45, 1, 40, 13, 70, 5, 36, 19, + 11, 11, 11, 11, 11, 40, 40, 13, 10, 10, 51, 0, 0, 0, 0, 0, + 5, 16, 20, 5, 13, 13, 13, 25, 24, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 15, 15, 1, 1, 17, 1, 1, 1, 1, 1, 1, 1, 17, + 1, 1, 1, 1, 40, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 24, + 16, 19, 5, 5, 5, 23, 0, 0, 5, 16, 17, 1, 1, 1, 15, 17, + 15, 1, 17, 1, 1, 27, 25, 16, 20, 16, 37, 35, 37, 35, 16, 0, + 15, 0, 0, 35, 0, 0, 17, 1, 1, 16, 0, 5, 5, 5, 23, 0, + 5, 5, 23, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17, 0, 15, + 1, 1, 1, 17, 16, 19, 5, 5, 23, 37, 35, 35, 16, 37, 16, 20, + 25, 25, 13, 38, 33, 0, 0, 0, 27, 23, 0, 0, 0, 0, 0, 0, + 1, 1, 34, 16, 5, 5, 5, 5, 16, 5, 20, 25, 1, 40, 13, 13, + 11, 11, 11, 11, 11, 13, 38, 25, 16, 19, 5, 5, 20, 20, 16, 19, + 20, 5, 1, 53, 0, 0, 0, 0, 16, 5, 5, 0, 16, 16, 5, 19, + 36, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 5, 0, + 16, 19, 5, 5, 5, 20, 19, 19, 36, 13, 15, 0, 0, 0, 0, 0, + 13, 13, 13, 13, 13, 13, 33, 0, 1, 1, 1, 1, 1, 24, 19, 16, + 5, 5, 5, 19, 40, 0, 0, 0, 11, 11, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 15, 27, 19, 16, 5, 5, 19, 5, 5, 0, 0, + 11, 11, 11, 11, 11, 10, 13, 56, 5, 5, 5, 5, 19, 36, 0, 0, + 10, 51, 0, 0, 0, 0, 0, 17, 1, 1, 1, 15, 17, 0, 1, 1, + 1, 1, 17, 15, 1, 1, 1, 1, 16, 16, 16, 35, 37, 27, 20, 25, + 45, 19, 13, 33, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, + 34, 16, 5, 5, 0, 5, 16, 16, 25, 53, 37, 0, 0, 0, 0, 0, + 24, 5, 5, 5, 5, 25, 1, 1, 1, 24, 5, 5, 20, 24, 5, 36, + 13, 13, 13, 70, 0, 0, 0, 0, 24, 5, 5, 20, 19, 5, 1, 1, + 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 20, 5, 13, 53, 13, + 13, 33, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 15, 0, 0, + 20, 5, 20, 20, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 23, 5, 5, 5, 19, 40, 13, 13, 0, 0, 0, 0, 0, + 13, 1, 1, 1, 1, 1, 1, 1, 0, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 35, 5, 5, 5, 20, 5, 19, 23, 0, 0, 0, 0, + 1, 1, 1, 15, 1, 17, 1, 1, 24, 5, 5, 23, 0, 23, 5, 27, + 5, 5, 5, 24, 0, 0, 0, 0, 1, 1, 1, 17, 15, 1, 1, 1, + 1, 1, 1, 1, 1, 16, 16, 37, 5, 35, 19, 19, 15, 0, 0, 0, + 1, 1, 1, 1, 44, 1, 0, 0, 1, 24, 20, 83, 33, 0, 0, 0, + 5, 34, 1, 1, 1, 1, 1, 1, 1, 1, 16, 5, 5, 23, 0, 16, + 20, 36, 13, 13, 13, 13, 13, 13, 11, 11, 11, 11, 11, 23, 0, 0, + 10, 10, 62, 3, 3, 3, 69, 30, 98, 3, 3, 3, 3, 3, 3, 3, + 3, 0, 0, 0, 0, 0, 0, 38, 13, 13,137, 12, 12, 12, 12, 12, + 12, 12, 12,100, 0, 0, 0, 0, 40, 33, 0, 0, 0, 0, 0, 0, + 25, 1, 1, 24, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 16, 19, 5, 5, 5, 36, 0, 0, 0, 0, 0, + 5, 5, 5, 36, 13, 13, 3, 3, 14, 14, 56, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 48, 10, 10, 10, 17, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 17, 1, 14, 52, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 44,135, 13, 10, 10, 10, 78, 13, 33, 0, 0, + 7, 7, 7, 7, 32, 43, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 15, 0, 27, 34, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 0, 0, 0, 27, 5, 81, 14, 14, 14, 14, 14, 14, + 14, 61, 23, 0, 0, 0, 0, 0, 16, 14, 12,100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 14, 14, 58, 14, 14, 14, 58, 82, + 0, 15, 0, 0, 0, 0, 0, 0, 1, 15, 17, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 15, 0, 0, 0, 1, 1, 1, 1, 1, 0, 41, 36, + 18, 18, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 3, 29, 0, + 3, 3, 0, 0, 0, 3, 3, 3, 29, 3, 29, 0, 0, 0,188, 9, + 9, 9, 9, 9, 9, 9, 9, 0, 5, 5, 5, 5, 5, 5, 5, 0, + 3, 3, 3, 41, 50, 3, 3, 3, 3, 3,101, 19, 5, 3,101, 16, + 16,189, 18, 18, 18, 92, 5, 5, 5, 50, 41, 5, 5, 5, 3, 3, + 3, 3, 3, 3, 3, 5, 5, 3, 3, 5, 50, 0, 0, 0, 0, 0, + 16,190, 3, 3, 3, 41, 50,101, 16, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 46, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 32, 7, + 0, 32, 39, 32, 39, 7, 32, 7, 7, 7, 7, 6, 6, 43, 43, 6, + 6, 6, 43, 6, 6, 6, 6, 6, 6, 6, 7, 39, 7, 32, 39, 7, + 7, 7, 32, 7, 7, 7, 32, 6, 6, 6, 6, 6, 7, 39, 7, 32, + 7, 7, 32, 32, 0, 7, 7, 7, 32, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 46, 7, 7, 7, 7, 59, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, + 7, 7, 59, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 60, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 59, + 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 59, 6, 6, 6, + 6, 60, 6, 6, 6, 8, 0, 11, 5, 5, 5, 50, 3, 41, 5, 5, + 5, 5, 5, 5, 5, 5, 50, 3, 3, 3, 41, 3, 3, 3, 3, 3, + 3, 3, 50, 65, 13, 13, 0, 0, 0, 0, 0, 0, 0, 27, 5, 5, + 9, 9, 9, 9, 9, 9, 99, 0, 6, 6, 6, 6, 6,128, 6, 6, + 8, 6, 6, 6, 8, 8, 21, 6, 21, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 58, 14, + 5, 5, 5, 23, 5, 5, 5, 5, 5, 5, 5, 5, 23, 27, 5, 5, + 5, 27, 23, 5, 5, 23, 0, 0, 14, 14, 14, 14, 14, 14, 14, 0, + 0, 0, 0, 0, 0, 0, 0, 27, 5, 5, 5, 81, 14, 14, 14, 0, + 11, 11, 11, 11, 11, 0, 0, 55, 1, 1, 1, 1, 1, 1, 1, 23, + 1, 1, 1, 1, 1, 1, 5, 5, 11, 11, 11, 11, 11, 0, 0,115, + 1, 1, 1, 1, 1, 44, 5, 5,191, 11, 11, 11, 11,192, 0, 38, + 1, 24, 1, 25, 1, 1, 1, 5, 1, 1, 24, 0, 0, 0, 0, 44, + 1, 1, 1, 15, 1, 1, 17, 15, 1, 1, 15, 48, 10, 10, 10, 10, 6, 6, 5, 5, 5, 81, 0, 0, 10, 10, 10, 10, 10, 10, 75, 10, - 190, 10, 51, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 75, + 193, 10, 51, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 75, 10, 10, 10, 10, 10, 10, 10, 0, 1, 1, 17, 1, 1, 1, 1, 1, - 17, 14, 14, 17, 17, 1, 1, 1, 1, 14, 1, 1, 17, 17, 0, 0, - 0, 14, 0, 17, 17, 17, 17, 1, 17, 14, 14, 17, 17, 17, 17, 17, - 17, 14, 14, 17, 1, 14, 1, 1, 1, 14, 1, 1, 17, 1, 14, 14, + 17, 15, 15, 17, 17, 1, 1, 1, 1, 15, 1, 1, 17, 17, 0, 0, + 0, 15, 0, 17, 17, 17, 17, 1, 17, 15, 15, 17, 17, 17, 17, 17, + 17, 15, 15, 17, 1, 15, 1, 1, 1, 15, 1, 1, 17, 1, 15, 15, 1, 1, 1, 1, 1, 17, 1, 1, 17, 1, 17, 1, 1, 17, 1, 1, - 9, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 63, 3, + 9, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 62, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 29, 0, 0, 0, 0, 0, 0, - 3, 3, 3, 3, 3,108, 22, 22, 3, 3, 3, 3, 29, 0, 3, 3, - 9, 9, 9, 9, 98, 0, 0, 0, 3, 3, 3, 3, 3, 29, 0, 3, - 3, 3, 3, 29, 29, 0, 44, 3, 3, 3, 3, 3, 3, 3, 29, 44, - 3, 3, 3, 3, 3, 29, 0, 44, 3, 29, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 29, 0, 0, 0, 3, 3, 3, 3, 3,110, 22, 22, + 3, 3, 3, 3, 3, 0, 3, 3, 9, 9, 9, 9, 99, 0, 0, 0, + 3, 3, 3, 29, 29, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 54, + 3, 3, 3, 3, 3, 3, 0, 54, 3, 29, 3, 3, 3, 3, 3, 3, 11, 11, 11, 11, 11, 29, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 7, 7, 3, 3, 26, 26, 4, 4, 12, 12, 5, 5, 9, 9, 9, 5, 25, 25, 15, 15, 13, 13, - 21, 21, 6, 6, 7, 2, 10, 10, 14, 14, 2, 7, 1, 1, 10, 12, - 12, 10, 5, 9, 24, 24, 12, 2, 7, 12, 12, 7, 2, 12, 22, 18, + 14, 14, 21, 21, 6, 6, 7, 2, 10, 10, 2, 7, 1, 1, 10, 12, + 12, 10, 5, 9, 24, 24, 12, 2, 7, 12, 12, 7, 22, 18, 2, 12, 0, 0, 26, 2, 23, 23, 18, 22, 9, 2, 21, 2, 7, 10, 2, 10, - 12, 21, 10, 2, 2, 21, 2, 9, 7, 21, 8, 8, 2, 5, 26, 12, - 2, 26, 7, 6, 10, 7, 5, 2, 25, 26, 2, 15, 26, 25, 15, 2, - 6, 7, 21, 7, 2, 6, 12, 26, 7, 26, 21, 26, 20, 19, 9, 25, - 5, 25, 6, 2, 21, 6, 15, 26, 25, 22, 18, 21, 26, 21, 5, 7, - 6, 24, 6, 5, 26, 23, 21, 12, 6, 12, 2, 1, 29, 29, 26, 15, - 21, 17, 25, 21, 15, 21, 11, 11, 21, 23, 12, 6, 26, 7, 10, 21, - 17, 17, 9, 26, 7, 15, 29, 21, 21, 9, 24, 5, 25, 9, 1, 12, - 17, 21, 11, 12, 8, 24, 26, 9, 21, 22, 23, 26, 25, 2, 14, 2, - 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, 5, 22, 25, 18, 24, 26, - 26, 24, 9, 8, 8, 5, 5, 21, 15, 7, 2, 23, 21, 15, 17, 7, - 18, 2, 5, 6, 5, 24, 22, 20, 21, 20, 19, 21, 21, 16, 16, 21, - 7, 5, 5, 26, 14, 15, 18, 25, 7, 14, 17, 22, 17, 6, 24, 6, - 6, 21, 12, 15, 26, 10, 25, 0, 7, 20, 25, 1, 24, 15, 7, 19, - 9, 21, 17, 2, 17, 12, 1, 21, 12, 1, 24, 7, 29, 7, 7, 22, - 14, 7, 2, 24, 9, 24, 24, 2, 29, 1, 27, 28, 1, 29, 21, 29, - 1, 2, 15, 6, 18, 6, 12, 11, 26, 5, 14, 9, 5, 14, 26, 22, - 18, 26, 5, 12, 22, 21, 18, 17, 26, 6, 18, 18, 26, 14, 14, 6, - 12, 24, 11, 21, 24, 9, 6, 9, 6, 10, 7, 25, 17, 16, 16, 22, - 16, 16, 25, 17, 25, 24, 23, 2, 21, 14, 12, 17, 21, 1, 10, 1, - 7, 13, 13, 2, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, - 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, 45, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 9, 0, 0, - 0, 10, 11, 12, 13, 0, 14, 15, 16, 0, 17, 18, 19, 20, 21, 1, - 22, 1, 23, 1, 2, 1, 2, 1, 2, 0, 2, 1, 24, 1, 2, 25, - 2, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 36, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 38, - 0, 0, 39, 0, 0, 40, 0, 41, 0, 0, 0, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 0, 0, 51, 0, 0, 0, 52, 0, 0, 0, 53, 0, - 0, 0, 0, 0, 0, 0, 54, 0, 3, 0, 55, 56, 0, 57, 0, 0, - 0, 0, 0, 0, 58, 59, 60, 0, 0, 0, 0, 61, 0, 0, 62, 63, - 64, 4, 65, 0, 0, 66, 67, 0, 0, 0, 68, 0, 0, 0, 0, 69, - 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 71, 0, 0, 0, 72, 0, 73, 0, 0, 74, 0, 0, 75, 0, - 0, 0, 0, 0, 0, 0, 0, 76, 77, 0, 0, 0, 0, 78, 79, 0, - 80, 81, 0, 0, 82, 5, 0, 83, 4, 0, 84, 85, 0, 0, 86, 87, - 88, 0, 89, 0, 90, 0, 91, 0, 0, 3, 92, 3, 0, 93, 0, 94, - 0, 0, 0, 5, 0, 0, 0, 95, 96, 0, 97, 98, 99,100, 0, 0, - 0, 0, 0, 3, 0, 0, 0, 0,101,102, 0, 0, 0, 0, 0, 0, - 103, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105, 6, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,106, 0, 0,107, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,108,109, 0, 0,110, 0, 0, 0, - 0, 0, 0,111, 0,112, 0, 6, 0, 0, 0, 0, 0,113,114, 0, - 0, 0, 0, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,117, 0, - 0, 0, 0, 0, 0, 0,118, 0,119, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 11, 0, 0, 0, - 14, 0, 0, 0, 16, 3, 17, 18, 19, 20, 21, 22, 0, 23, 0, 0, - 0, 0, 24, 25, 26, 27, 0, 0, 0, 0, 28, 0, 0, 29, 30, 0, - 31, 0, 32, 33, 0, 0, 34, 0, 35, 36, 0, 0, 0, 0, 0, 37, - 38, 0, 39, 40, 0, 0, 41, 0, 0, 0, 42, 0, 0, 43, 44, 45, - 46, 1, 47, 0, 0, 1, 0, 0, 7, 1, 48, 0, 0, 0, 0, 0, - 49, 50, 0, 0, 0, 0, 0, 0, 51, 52, 0, 0, 0, 0, 0, 0, - 53, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 57, 58, 0, 0, - 0, 59, 0, 0, 0, 0, 0, 0, 60, 12, 0, 0, 0, 0, 61, 0, - 0, 0, 62, 0, 5, 0, 63, 0, 0, 0, 0, 64, 0, 0, 0, 0, - 65, 0, 66, 0, 0, 0, 0, 6, 67, 0, 0, 0, 68, 69, 70, 71, - 0, 0, 0, 0, 72, 5, 0, 73, 74, 0, 0, 75, 0, 0, 0, 76, - 77, 0, 0, 0, 78, 0, 79, 80, 81, 82, 83, 3, 84, 0, 85, 86, - 87, 0, 0, 8, 9, 0, 0, 3, 3, 0, 0, 88, 0, 0, 89, 0, - 0, 0, 0, 8, 90, 0, 91, 0, 0, 0, 0, 0, 9, 10, 0, 92, - 0, 5, 0, 3, 9, 0, 0, 93, 0, 0, 94, 0, 0, 6, 0, 0, - 0, 0, 0, 0, 95, 96, 0, 0, 10, 0, 0, 1, 0, 0, 97, 0, - 0, 0, 0, 98, 0, 0, 0, 0, 12, 0, 0, 13, 0, 0, 0, 0, - 99,100, 0, 0,101, 0, 0,102, 0, 0, 0,103, 0, 0, 0,104, - 0, 0, 0,105, 0, 0, 0, 0,106,107, 13, 0, 0,108, 0, 0, - 0, 10, 0, 0,109,110, 0, 0,111,112, 0, 0, 0, 0, 0, 0, - 113, 0, 0,114, 0, 0, 0, 0,115, 1, 0,116,117,118, 6, 0, - 0,119, 7, 0, 0,120, 0, 0, 0,121, 0, 0, 0, 0, 0, 0, - 122, 0, 0,123, 0, 0, 0, 0,124, 11, 0, 0, 0, 0, 0, 6, - 0, 0, 0, 0, 5, 15, 0, 0, 0, 0,125, 0, 0,126, 0, 0, - 0, 0, 15, 0, 0,127, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, - 128, 0, 0, 0,129, 0,130, 0, 0, 0, 0,131,132,133, 0,134, - 0,135, 0, 0, 0,136,137,138, 0, 8, 0, 0, 0, 0, 0, 7, - 0, 0, 0,139, 0, 0, 0,140, 0, 0, 0,141, 0, 0, 0,142, - 143, 0,144, 0, 0,145, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, - 0, 9, 1, 1, 1, 1, 0, 0, 0, 2, 0, 3, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 19, 0, 0, 0, 6, 11, 0, 0, 0, 0, 14, - 0, 0, 15, 0, 0, 0, 0, 0, 0, 17, 29, 0, 0, 0, 0, 0, - 31, 0, 0, 2, 0, 0, 1, 12, 0, 0, 1, 49, 50, 5, 51, 52, - 53, 5, 5, 22, 32, 23, 1, 54, 24, 55, 16, 33, 56, 57, 58, 1, - 1, 1, 6, 1, 0, 0, 59, 7, 60, 1, 34, 5, 7, 61, 62, 63, - 64, 65, 66, 67, 0, 0, 1, 1, 68, 0, 0, 0, 69, 70, 71, 35, - 1, 25, 72, 0, 0, 0, 0, 8, 1, 26, 16, 26, 73, 27, 74, 0, - 0, 0, 36, 25, 75, 37, 7, 37, 76, 0, 0, 0, 6, 1, 7, 0, - 0, 17, 0, 8, 38, 1, 1, 13, 13, 11, 0, 0, 39, 0, 0, 6, - 18, 1, 0, 0, 8, 16, 5, 1, 1, 1, 77, 7, 36, 18, 78, 7, - 35, 1, 79, 10, 0, 0, 0, 80, 0, 0, 0, 0, 2, 3, 0, 0, - 14, 0, 0, 0, 81, 0, 0, 0, 82, 0, 0, 0, 83, 0, 0, 0, - 84, 0, 0, 0, 40, 0, 0, 85, 86, 0, 87, 88, 89, 90, 91, 92, - 0, 0, 0, 93, 0, 0, 0, 15, 28, 0, 0, 0, 0, 13, 0, 41, - 0, 0, 14, 0, 0, 20, 0, 0, 94, 0, 0, 0, 95, 0, 0, 6, - 29, 0, 0, 13, 1, 96, 1, 18, 33, 97, 25, 23, 7, 1, 1, 1, - 1, 27, 1, 7, 98, 0, 0, 9, 0, 0, 0, 0, 6, 23, 1, 0, - 0, 0, 0, 0, 30, 0, 0, 21, 0, 0, 30, 0, 0, 0, 0, 15, - 0, 0, 12, 32, 24, 5, 99, 22, 42, 17, 0, 10, 11, 0, 7, 1, - 7,100,101, 1, 1, 1, 1,102,103,104,105, 1,106, 10, 20,107, - 108, 5, 10, 0, 0, 0, 0, 0,109,110, 0, 0,111, 0, 0, 1, - 1, 11, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 43, 40, 2, 0, - 0, 0, 44,112, 10, 8, 20, 0, 0, 0, 0, 0, 0,113, 1, 16, - 5, 24, 0, 8, 12, 0, 0, 0, 0,114, 0, 0,115, 2, 0,116, - 0, 0, 0, 1, 0, 0, 0, 0, 13, 11, 0, 0, 6, 10, 0, 0, - 45, 39, 0, 45, 16, 18, 46, 27, 0, 0, 3, 0, 0, 2, 12, 0, - 0, 0, 2, 3, 0, 0, 3, 0, 21, 0, 0, 31, 0, 0, 0, 0, - 117, 0, 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, 0, 0, - 0, 30, 14, 21, 0, 0, 47, 0, 0, 0, 9, 0, 0, 0, 0, 47, - 0, 0, 0, 0, 2, 0, 0, 0, 0, 28, 0, 0, 4, 0, 21, 41, - 0, 0, 28, 0, 0, 0, 22, 42, 0, 0,118, 0, 0, 0, 0, 0, - 0,119, 0,120,121,122,123, 0, 43, 5, 48, 13, 34, 0, 0, 0, - 8, 11, 8, 10, 0, 0, 1, 12, 1, 1, 1, 1, 26, 1, 38, 44, - 12, 0, 0, 0, 0, 1, 0, 0, 0,124, 0, 0, 0, 46, 6, 19, - 0, 8, 0, 20, 0, 0, 5, 48, 0, 0, 0, 1,125, 0, 0, 0, - 0,230,230,230,230, 0, 0, 0, 9, 9, 0, 0, 0, 0, 9, 0, - 0,220,220,220,220, 0, 0, 0,230,230,230,220,230, 0, 0,230, - 230, 7, 0, 0, 0,230, 0, 0, 0,230,230, 0, 0,230,230,230, - 0, 0,230,230,230, 0, 0, 9, 0, 0, 0, 0, 7,230,230,230, - 220, 0,220, 0, 0,230,220,220,220, 0, 0,230, 0, 0,230, 0, - 0, 0, 0, 7, 0, 1, 1, 1, 1,220,230,230,230,220,220,230, - 230,220,230,230,220,230, 0, 0,230,230,220, 0, 0, 0, 9, 9, - 0,220, 0, 0, 0, 0, 0, 9, 9, 0, 9, 7, 0, 1,220,220, - 220,220,220,220,230,230,230,220,220,230,220,220,230,230,220,230, - 230,220,230,220,230,230,230, 0,230, 0,220,220,220,220,220, 0, - 0, 9, 9, 0, 0, 1, 0, 0, 0, 0, 0, 0,220,230, 0,230, - 230, 0, 0,220,220, 0, 0,230,220, 0, 0, 9, 7,220,220,220, - 0,230,232,220,220,220,220,232,216,220,202,202,220,220,220,220, - 202,202,220,220,220,230,240,230,220,230,220,220, 0,232,220,220, - 230,233,234,234,233,234,234,233,230, 0,220,230,230,230,230,222, - 220,230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, - 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, - 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230, 35, 0, 0, - 0,230, 0,220,230, 0, 36, 0, 0,220,220,230,220,220,230,230, - 0,230,230, 0,220, 27, 28, 29,230, 0,230,220,230, 0, 84, 91, - 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122, - 122, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, 0, - 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, 9, 0,230, - 230, 0, 0,220, 0, 0,228, 0, 0, 0,222,230,220,230, 0, 0, - 220,230,220, 0,220,230,230,230,234,230, 0, 1, 1,230,234,214, - 220,202,230,230,230,230,230,232,228,228,220,218,230,233,220,230, - 220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, - 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,220, 0, 0, - 230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230,220, - 0, 0, 7, 9, 0, 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, - 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,232,232,220, - 230,230,230, 7, 0, 1, 0, 0, 32, 0, 48, 0, 0, 84, 96,135, - 144, 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,176, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 40, - 0, 0, 0, 0, 0, 48, 56, 64, 0, 0, 0, 0, 0, 72, 80, 88, - 96,104, 0, 0, 0, 0, 0, 0, 0, 0,112, 0,120, 0, 0, 0, - 0, 0, 0,128,136,144,152,160,168, 0, 0, 0,176,184,192, 0, - 0, 0, 0, 0, 0,200, 0, 0, 0, 0, 0, 0, 0, 0,208, 0, - 0,216,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16, 0, 36, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 0, 0, - 64, 0, 68, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 72, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 0, - 0, 0, 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 76, 80, 84, 88, - 0, 0, 12, 92, 96, 28, 0,100,104, 4, 4, 4,108, 44,112,116, - 120, 4,124, 0,128,132, 4, 4, 48,136,140, 0, 32, 0, 0, 0, - 40, 0, 0, 0, 0, 0, 0, 0, 4, 48, 0, 52,144, 20,148,152, - 4, 0, 0,156,160,164,168,172, 4, 0,176, 56, 60,180, 32, 0, - 16,184, 56, 0, 0, 0, 0, 0, 52, 12, 12, 0, 0, 0, 0, 12, - 0, 0,188, 8, 8, 8, 8,192,196, 8, 8, 8, 8,200,204,208, - 212, 60, 44, 0, 0, 0, 0, 0, 0, 0,216, 28,220, 0, 12, 4, - 16, 0, 0, 0, 0,224,228, 0, 0, 0, 0, 0, 4,232, 32, 0, - 0, 0, 0, 0, 0, 0,236, 12, 0, 0, 0, 0, 16, 0, 36, 0, - 0, 0, 24, 0, 0, 0,240,244, 0, 0, 0, 0, 2, 2, 2, 2, - 4, 4, 4, 4, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 6, 8, - 0, 10, 12, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 14, 16, - 6, 8, 0, 0, 4, 8, 0, 0, 2, 2, 2, 0, 0, 6, 4, 8, - 2, 0, 2, 0, 0, 0, 0, 6, 0, 20, 0, 0, 0, 22, 0, 0, - 0, 6, 8, 0, 24, 26, 28, 0, 0, 0, 30, 0, 0, 0, 0, 32, - 34, 36, 38, 0, 0, 40, 42, 0, 0, 0, 18, 0, 0, 0, 2, 2, - 2, 2, 0, 2, 2, 2, 0, 6, 44, 0, 0, 0, 0, 2, 0, 46, - 48, 50, 0, 0, 52, 0, 0, 0, 6, 4, 54, 0, 2, 0, 0, 2, - 2, 56, 58, 60, 0, 62, 64, 18, 2, 10, 12, 0, 0, 0, 66, 8, - 0, 2, 2, 2, 0, 6, 4, 4, 4, 4, 68, 2, 70, 4, 4, 4, - 8, 72, 0, 0, 74, 76, 2, 0, 78, 0, 0, 0, 4, 8, 2, 0, - 0, 0, 80, 0, 6, 4, 4, 4, 4, 8, 0, 2, 2, 2, 2, 6, - 4, 4, 4, 8, 0, 0, 0, 82, 0, 84, 86, 0, 0, 0, 2, 88, - 0, 0, 0, 90, 6, 8, 2, 0, 0, 0, 6, 4, 4, 4, 8, 0, - 2, 0, 2, 2, 6, 4, 4, 8, 0, 10, 12, 6, 8, 2, 0, 0, - 4, 5, 6, 7, 8, 9, 10, 1, 1, 11, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 12, 13, 2, 2, 2, 2, 14, 0, 0, 0, 0, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 25, 26, 3, 3, - 3, 27, 0, 0, 0, 28, 29, 30, 0, 31, 32, 33, 34, 35, 36, 37, + 12, 21, 10, 2, 2, 21, 2, 9, 7, 21, 26, 12, 8, 8, 2, 5, + 7, 6, 10, 7, 5, 2, 25, 26, 2, 15, 26, 25, 12, 26, 15, 2, + 6, 7, 21, 7, 2, 26, 7, 26, 21, 26, 20, 19, 2, 6, 9, 25, + 5, 25, 21, 6, 15, 26, 25, 22, 18, 21, 26, 21, 5, 7, 6, 24, + 6, 5, 26, 23, 21, 12, 6, 12, 26, 7, 2, 1, 29, 29, 26, 15, + 21, 17, 25, 21, 15, 21, 11, 11, 21, 23, 12, 6, 6, 2, 10, 21, + 17, 17, 9, 26, 7, 15, 29, 21, 21, 9, 24, 5, 25, 9, 17, 6, + 1, 12, 17, 21, 11, 12, 8, 24, 26, 9, 21, 22, 23, 26, 25, 2, + 14, 2, 26, 10, 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, 5, 22, + 25, 18, 24, 26, 26, 24, 9, 8, 8, 5, 5, 21, 15, 7, 2, 23, + 21, 15, 17, 7, 5, 6, 5, 24, 2, 24, 22, 20, 21, 20, 19, 21, + 21, 16, 16, 21, 18, 6, 23, 2, 7, 5, 5, 26, 14, 15, 18, 25, + 7, 14, 17, 22, 24, 6, 6, 21, 12, 15, 21, 14, 25, 0, 7, 20, + 25, 1, 24, 15, 7, 19, 9, 21, 6, 26, 17, 12, 1, 21, 12, 1, + 24, 7, 29, 7, 7, 22, 18, 2, 14, 7, 9, 24, 24, 2, 29, 1, + 27, 28, 1, 29, 21, 29, 1, 2, 15, 6, 12, 11, 26, 5, 14, 9, + 5, 14, 26, 22, 18, 26, 5, 12, 22, 21, 18, 17, 26, 6, 18, 18, + 26, 14, 14, 6, 12, 24, 11, 21, 24, 9, 6, 9, 6, 10, 7, 25, + 17, 16, 16, 22, 16, 16, 25, 17, 25, 24, 12, 17, 24, 12, 21, 1, + 2, 25, 10, 1, 10, 26, 7, 13, 13, 2, 23, 15, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, + 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, + 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, + 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, + 0, 36, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, + 0, 0, 0, 9, 0, 0, 0, 10, 11, 12, 13, 0, 14, 15, 16, 0, + 17, 18, 19, 20, 21, 1, 22, 1, 23, 1, 2, 1, 2, 1, 2, 0, + 2, 1, 24, 1, 2, 25, 2, 0, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, + 0, 0, 0, 0, 0, 38, 0, 0, 39, 0, 0, 40, 0, 41, 0, 0, + 0, 42, 43, 44, 45, 46, 47, 48, 49, 50, 0, 0, 51, 0, 0, 0, + 52, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 3, 0, + 55, 56, 0, 57, 0, 0, 0, 0, 0, 0, 58, 59, 60, 0, 0, 0, + 0, 61, 0, 0, 62, 63, 64, 4, 65, 0, 0, 66, 67, 0, 0, 0, + 68, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 72, 0, 73, 0, + 0, 74, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 76, 77, 0, + 0, 0, 0, 78, 79, 0, 80, 81, 0, 0, 82, 5, 0, 83, 4, 0, + 84, 85, 0, 0, 86, 87, 88, 0, 89, 0, 90, 0, 91, 0, 0, 3, + 92, 3, 0, 93, 0, 94, 0, 0, 0, 5, 0, 0, 0, 95, 96, 0, + 97, 98, 99,100, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,101,102, + 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 0, 0,104, 0, 0, + 0, 0, 0, 0,105, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0,108,109,110, + 0, 0,111,112, 0, 0, 0, 0, 0,113, 0,114, 0, 6, 0, 0, + 0, 0, 0,115,116, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, + 118, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0,120, 0,121, 0, + 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 4, 0, + 0, 0, 11, 0, 0, 0, 15, 0, 0, 0, 17, 3, 18, 19, 20, 21, + 22, 23, 0, 24, 0, 0, 0, 0, 25, 26, 27, 28, 0, 0, 0, 0, + 29, 0, 0, 30, 31, 0, 32, 0, 33, 34, 0, 0, 35, 0, 36, 37, + 0, 0, 0, 0, 0, 38, 39, 0, 40, 41, 0, 0, 42, 0, 0, 0, + 43, 0, 0, 44, 45, 46, 47, 1, 48, 0, 0, 1, 0, 0, 7, 1, + 49, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 0, 0, 0, 52, 53, + 0, 0, 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 56, 0, 57, 0, + 0, 0, 58, 59, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 61, 12, + 0, 0, 0, 0, 62, 0, 0, 0, 63, 0, 5, 0, 64, 0, 0, 0, + 0, 65, 0, 0, 0, 0, 66, 0, 67, 0, 0, 0, 0, 6, 68, 0, + 0, 0, 69, 70, 71, 72, 13, 0, 0, 0, 73, 5, 0, 74, 75, 0, + 0, 76, 0, 0, 0, 77, 78, 0, 0, 0, 79, 0, 80, 81, 82, 83, + 84, 3, 85, 0, 86, 87, 13, 0, 0, 8, 9, 0, 0, 3, 3, 0, + 0, 88, 0, 0, 89, 0, 0, 0, 0, 8, 90, 0, 91, 0, 0, 0, + 0, 0, 9, 10, 0, 92, 0, 5, 0, 3, 9, 0, 0, 93, 0, 0, + 94, 0, 0, 6, 0, 0, 0, 0, 0, 0, 95, 96, 0, 0, 10, 0, + 0, 1, 0, 0, 97, 0, 0, 0, 0, 98, 0, 0, 0, 0, 12, 0, + 0, 14, 0, 0, 0, 0, 99,100, 0, 0,101, 0, 0,102, 0, 0, + 0,103, 0, 0, 0,104, 0, 0, 0,105, 0,106, 0, 0,107,108, + 14, 0, 0,109, 0, 0, 0, 10, 0, 0,110,111, 0, 0,112,113, + 0, 0, 0, 0, 0, 0,114, 0, 0,115, 0, 0, 0, 0,116, 1, + 0,117,118,119, 6, 0, 0,120, 7, 0, 0,121, 0, 0, 0,122, + 0, 0, 0, 0, 0, 0,123, 0, 0,124, 0, 0, 0, 0,125, 11, + 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 5, 16, 0, 0, 0, 0, + 126, 0, 0,127, 0, 0, 0, 0, 16, 0, 0,128, 0, 0, 0, 0, + 0, 4, 0, 0, 0, 0,129, 0, 0, 0,130, 0,131, 0, 0, 0, + 0,132, 0, 0, 0,133,134,135, 0,136, 0,137,138, 0, 0,139, + 0, 0, 0,140,141,142, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, + 0,143, 0, 0, 0,144, 0, 0, 0,145, 0, 0, 0,146,147, 0, + 148, 0, 0,149, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 9, + 1, 1, 1, 1, 0, 0, 0, 2, 0, 3, 0, 0, 3, 0, 0, 0, + 0, 0, 0, 21, 0, 0, 0, 5, 11, 0, 0, 0, 0, 14, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 19, 10, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 35, 0, 0, 2, 0, 0, 1, 12, 0, 0, 1, 49, 50, 6, + 51, 52, 53, 6, 6, 25, 36, 26, 1, 54, 17, 55, 16, 27, 56, 57, + 58, 1, 1, 1, 5, 1, 0, 0, 59, 7, 60, 1, 18, 6, 7, 61, + 62, 63, 64, 65, 66, 67, 68, 0, 1, 1, 69, 0, 0, 0, 70, 71, + 72, 37, 1, 28, 73, 0, 0, 0, 0, 8, 1, 29, 16, 29, 74, 38, + 75, 0, 0, 0, 30, 28, 76, 31, 7, 31, 77, 0, 0, 0, 5, 1, + 7, 0, 0, 19, 0, 8, 39, 1, 1, 13, 13, 11, 0, 0, 40, 0, + 0, 5, 20, 1, 0, 0, 8, 16, 6, 1, 1, 1, 78, 7, 30, 20, + 79, 7, 37, 1, 80, 10, 0, 0, 0, 81, 0, 0, 0, 0, 2, 3, + 0, 0, 14, 0, 0, 0, 82, 0, 0, 0, 83, 0, 0, 0, 84, 0, + 0, 0, 85, 0, 0, 0, 41, 0, 0, 86, 87, 0, 88, 89, 90, 91, + 92, 93, 0, 0, 0, 94, 0, 0, 0, 15, 32, 0, 0, 0, 0, 13, + 0, 42, 0, 0, 14, 0, 0, 22, 0, 0, 95, 0, 0, 0, 96, 0, + 0, 5, 23, 0, 0, 13, 1, 97, 1, 20, 27, 98, 28, 26, 7, 1, + 1, 1, 1, 30, 1, 7, 99, 18, 0, 9, 0, 0, 0, 0, 5, 26, + 1, 0, 0, 0, 0, 0, 33, 0, 0, 24, 0, 0, 33, 0, 0, 0, + 0, 15, 0, 0, 12, 36, 17, 6,100, 25, 43, 19, 0, 10, 11, 0, + 7, 1, 7,101,102, 1, 1, 1, 1,103,104,105,106, 1,107, 10, + 22,108,109, 6, 0, 0,110,111, 0, 0,112, 0, 0, 1, 1, 11, + 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 34, 41, 2, 0, 0, 0, + 44,113, 10, 8, 22, 0, 0, 0, 0, 0, 0,114, 1, 16, 6, 17, + 0, 8, 12, 0, 0, 0, 0,115, 0, 0,116, 2, 0,117, 0, 0, + 0, 1, 0, 0, 0, 0, 13, 11, 0, 0, 5, 10, 0, 0, 5, 17, + 27, 31, 18, 40, 0,118, 16, 20, 45, 38, 0, 0, 3, 0, 0, 2, + 12, 0, 0, 0, 2, 3, 0, 0, 3, 0, 24, 0, 0, 35, 0, 0, + 0, 0,119, 0, 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, + 0, 0, 0, 33, 14, 24, 0, 0, 46, 0, 0, 0, 9, 0, 0, 0, + 0, 46, 0, 0, 0, 0, 2, 0, 0, 0, 0, 32, 0, 0, 4, 0, + 24, 42, 0, 0, 32, 0, 0, 0, 25, 43, 0, 0,120, 0, 0, 0, + 0, 0, 0,121, 0, 34, 23, 0, 0,122,123,124, 47, 0, 34, 6, + 48, 13, 18, 0, 0, 0, 8, 11, 8, 10, 0, 0, 47, 0,125,126, + 127, 0, 0, 0, 1, 12, 1, 1, 1, 1, 29, 1, 39, 44, 12, 0, + 0, 0, 0, 1, 0, 0, 0,128, 0, 0, 0, 45, 5, 21, 0, 8, + 0, 22, 0, 0, 6, 48, 0, 0, 0, 1,129, 0, 0, 0, 0,230, + 230,230,230, 0, 0, 0, 9, 9, 0, 0, 0, 0, 9, 0, 0, 0, + 0, 0,230,220,220,220,220,230,230,220,230, 0, 0,230,230, 7, + 0, 0, 0,230, 0, 0, 0,230,230, 0, 0,230,230,230, 0, 0, + 230,230,230, 0, 0, 9, 0, 0, 0, 0, 7,230,230,230,220,220, + 220,230,230,230,230,220,220, 0,220, 0, 0,230,220,220,220, 0, + 0,230, 0, 0,230, 0, 0,220, 0, 0, 0, 0, 0, 7, 0, 1, + 1, 1, 1,220,230,230,230,220,220,220,230,220,230,230,220,230, + 0, 0,230,230,220,230,230,220,230,220,230, 0, 9, 9, 0, 0, + 0, 9, 9, 0, 0, 0,220, 0, 9, 7, 0, 1,220,220,220,230, + 220,220,230,230,220, 0, 0,230,230, 0,230, 0,220,220,220,220, + 220, 0, 0, 9, 9, 0, 0, 1, 0, 0, 0,230, 0,230,230, 0, + 0,230,220, 0, 0, 9, 7,216,216,216, 0,220,220,220, 0,230, + 232,220,220,220,220,232,216,220,202,202,220,220,220,220,202,202, + 220,220,220,230,240,230,220,230,220,220, 0,232,220,220,230,233, + 234,234,233,234,234,233,230, 0,220,230,230,230,230,222,220,230, + 222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, + 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 10, 21, 0, 0, 30, + 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230, 35, + 0, 0, 0,230, 0,220,230, 0, 36, 0, 0,220,220,230,220,220, + 230,230, 0,230,230, 0,220, 27, 28, 29,230, 0,230,220,230, 0, + 84, 91, 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0,122, + 122,122,122, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,132, + 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, 9, + 0,230,230, 0, 0,220, 0, 0,228, 0, 0, 0,222,230,220,230, + 0, 0,220,230,220, 0,220,230,230,230,234,230, 0, 1, 1,230, + 234,214,220,202,230,230,230,230,230,232,228,228,220,218,230,233, + 220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220, + 230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,220, + 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0, + 230,220, 0, 0, 0,220,220, 0, 7, 9, 0, 6, 6, 0, 0, 0, + 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216, 0, + 0, 0, 1, 1, 0, 0,216,216,216, 0, 0,232,232,220,230,230, + 230, 7, 0, 1, 32, 48, 0, 84,118, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,144, 0, 0, 0, 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, 8, 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 32, 0, 0, 40, + 48, 0, 0, 56, 64, 72, 0, 0, 0, 0, 0, 0, 0, 80, 88, 0, + 0, 0, 96,104,112, 0,120, 0, 0, 0, 0,128, 0, 0, 0,136, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,144, 0,152, 0, 0, + 0, 0, 0, 0, 0,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 16, 0, 12, 0, 12, 0, 0, 40, 44, 0, 0, 0, 0, 0, 0, + 0, 48, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 20, 56, 0, 0, 24, 24, 0, 0, 0, 0, 0, 0, 0, 60, 64, + 68, 28, 72, 76, 80, 84, 88, 92, 96,100,104,108,112,116,120, 0, + 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,124, 0, 0, + 0, 0,128,132,136, 0,140,144,148,152,156,160, 8,164, 0, 0, + 168,172, 0, 0, 36,176, 4, 4,180, 4, 4,184,188,192, 0, 0, + 0, 0, 0, 0, 0,196,200, 28,204, 0, 0,208,212, 0, 32,216, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 36, 0, 8, 16, + 0, 12, 0,224,228, 0,232,236, 0, 0, 0, 0, 0, 0, 12, 12, + 12, 12, 0, 0, 8, 0, 0, 0, 32, 36, 0, 0, 0, 44, 0, 0, + 28, 0, 0, 0, 0, 28, 0, 0, 0, 8, 0, 0, 4, 4, 0, 8, + 0, 0, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 16, 8, 0, 0, + 24, 48, 0, 28, 0, 0, 0, 0, 60, 64, 0, 68, 0, 72, 76, 80, + 0, 0, 84, 88, 0, 92, 16, 8, 0, 0, 0, 4, 4, 16, 4, 4, + 4, 4, 4, 4, 4, 24, 20, 0, 96, 0, 16,100,104, 0, 4, 4, + 108, 0, 0, 0, 40,112, 8, 16, 4, 4, 4, 4, 4, 8,116,120, + 124,128, 0, 0, 4, 0, 4, 8, 0, 0, 24, 20,132, 36, 0, 28, + 0,136, 16, 4, 4, 4, 24, 12, 12,140,144, 12,148, 0,152, 8, + 4, 4, 0, 0,156, 0, 8, 8, 0, 24, 20, 8, 4, 0, 0,160, + 8, 8, 0, 0, 24, 20, 0, 8, 0, 8, 0, 0, 40, 12, 20, 16, + 4,164, 12, 20, 0,168,172,176, 0,180, 0, 24, 20, 0, 0, 0, + 0,184, 16, 8, 28, 8, 4, 4, 8, 0, 0, 40, 12, 48, 16, 0, + 0, 0, 8, 4, 4, 0, 0, 0, 40, 20, 0, 0, 32,188,192, 0, + 0, 0, 24, 20, 8, 0,196, 0, 0, 0, 19, 19, 19, 19, 20, 18, + 20, 18, 20, 18, 19, 19, 18, 20, 18, 20, 19, 19, 20, 18, 18, 20, + 18, 19, 19, 19, 19, 20, 19, 20, 18, 19, 19, 19, 19, 21, 19, 17, + 19, 19, 19, 20, 18, 20, 21, 19, 17, 19, 18, 19, 19, 19, 19, 19, + 19, 25, 19, 19, 19, 13, 22, 22, 22, 16, 16, 16, 19, 19, 19, 32, + 19, 19, 19, 38, 19, 37, 31, 29, 30, 19, 36, 19, 19, 19, 19, 19, + 19, 26, 19, 23, 19, 19, 15, 19, 19, 19, 28, 19, 19, 19, 19, 19, + 33, 19, 35, 34, 19, 34, 27, 19, 19, 19, 18, 12, 19, 19, 20, 18, + 24, 24, 24, 19, 23, 23, 19, 19, 14, 14, 14, 15, 15, 19, 20, 18, + 19, 21, 11, 20, 18, 19, 18, 22, 20, 18, 16, 20, 18, 20, 18, 19, + 19, 9, 8, 19, 19, 7, 10, 19, 19, 19, 19, 6, 19, 19, 20, 18, + 19, 20, 19, 19, 5, 19, 19, 19, 19, 4, 3, 4, 19, 19, 20, 18, + 2, 19, 19, 19, 1, 19, 19, 17, 19, 20, 18, 19, 20, 18, 0, 19, + 19, 19, 4, 5, 6, 7, 8, 1, 1, 1, 1, 1, 9, 2, 2, 10, + 0, 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 28, 29, 1, + 30, 31, 1, 32, 1, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 3, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 15, 10, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 2, 31, 32, 11, 11, 33, 34, 35, 36, 37, 38, 39, + 40, 10, 41, 42, 43, 6, 6, 44, 6, 6, 6, 45, 6, 6, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 38, 1, 1, 39, 1, 40, 1, 1, 1, 41, 0, 42, - 1, 1, 43, 1, 1, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 20, 21, 8, 8, 8, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 2, 2, 51, 52, 53, 54, 9, 9, 9, 9, 9, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 8, 8, 70, - 71, 72, 73, 74, 75, 5, 5, 5, 5, 76, 5, 5, 5, 5, 5, 5, - 5, 15, 15, 5, 5, 5, 5, 77, 5, 78, 79, 80, 81, 82, 83, 1, - 84, 85, 86, 87, 88, 89, 90, 91, 5, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 92, 1, 1, 1, - 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 93, 16, 16, 94, 95, 96, - 97, 98, 99,100,101,102,103,104,105, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 106, 0, 0, 1, 1,107,108,109, 13, 13, 13,110,111,112,113,114, - 115,116,117,118,119, 0,120,121,122,123,124,125,126, 17, 17,127, - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154, 0,155,156,157,158, - 0,159,160,161,162,163,164,165,166,167,168,169,170, 0,171,172, - 173, 7, 7, 7, 7, 7, 7, 7,174,175, 7,176, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 177, 4, 4, 4, 4, 4, 4, 4, 4,178, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4,179, 11, 11, 11, 11,180, 0, 0, - 0, 0, 0,181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 12, 12, 12, 12,182,183,184,185, 0, 0,186, 0,187,188,189, - 190, 3, 3, 3, 3, 3, 3, 14, 14, 14,191,192,193, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 194,195,196,197, 18, 18,198, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,199,200, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,201, 5, 5, 5,202,203, - 204, 5,205,206,207,208,209,210, 0,211,212,213, 5, 5,214, 5, - 215, 10, 10, 10, 10, 10,216, 0, 0, 0, 0, 0, 0, 0, 0,217, - 0,218,219,220, 0, 0,221, 0, 0, 0,222, 0,223, 0,224, 0, - 225,226,227,228, 0, 0, 0, 0, 0,229,230,231, 0,232,233, 0, - 0,234,235, 5,236,237, 0, 5, 5, 5, 5, 5, 5, 5,238, 5, - 239,240,241, 5, 5,242,243, 5,244, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,245, 1, - 1,246, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,247, 1, - 1, 1, 1, 1, 1, 1, 1, 1,248, 1, 1, 1, 1,249, 0, 0, - 0, 1, 1, 1, 1,250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1,251, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1,252, 0, 0, 0, 0, 0, 0, - 0,253, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 13, 13, 13, 13, 12, 12, 12, 12, 0, 0, 0, - 0,136,136,136,136, 80, 80, 80, 80, 19, 19, 19, 19, 3, 3, 3, - 3, 63, 63, 63, 63, 39, 39, 39, 39, 28, 28, 28, 28,131,131,131, - 131, 79, 79, 79, 79, 1, 1, 1, 1,127,127,127,127, 6, 6, 6, - 6,155,155,155,155, 9, 9, 9, 9, 30, 30, 30, 30,139,139,139, - 139, 15, 15, 15, 15,110,110,110,110, 77, 77, 77, 77, 17, 17, 17, - 17, 27, 27, 27, 27, 33, 33, 33, 33,113,113,113,113, 49, 49, 49, - 49, 25, 25, 25, 25, 29, 29, 29, 29, 7, 7, 7, 7, 8, 8, 8, - 8, 32, 32, 32, 32, 99, 99, 99, 99, 31, 31, 31, 31,105,105,105, - 105, 55, 55, 55, 55, 62, 62, 62, 62, 56, 56, 56, 56, 91, 91, 91, - 91,119,119,119,119, 14, 14, 14, 14, 94, 94, 94, 94, 20, 20, 20, - 20,100,100,100,100,130,130,130,130,157,157,157,157,137,137,137, - 137, 97, 97, 97, 97,123,123,123,123,133,133,133,133,146,146,146, - 146, 84, 84, 84, 84,159,159,159,159,132,132,132,132, 4, 4, 4, - 4, 36, 36, 36, 36, 24, 24, 24, 24, 30, 30, 30, 2, 35, 35, 35, - 35, 40, 40, 40, 40,124,124,124,124,125,125,125,125,140,140,140, - 140, 37, 37, 37, 37, 58, 58, 58, 58, 0, 0, 2, 2, 75, 75, 75, - 75, 68, 68, 68, 68,114,114,114,114,163,163,163,163, 22, 22, 22, - 22, 23, 23, 23, 23, 76, 76, 76, 76, 0, 0, 0, 2, 26, 26, 26, - 26, 87, 87, 87, 87,135,135,135,135, 89, 89, 89, 89,141,141,141, - 141, 70, 70, 70, 70, 92, 92, 92, 92, 96, 96, 96, 96, 5, 5, 5, - 5, 18, 18, 18, 18, 48, 48, 48, 48, 85, 85, 85, 85,109,109,109, - 109,102,102,102,102,151,151,151,151, 16, 16, 16, 16, 0, 2, 2, - 2,165,165,165,165,108,108,108,108,171,171,171,171,142,142,142, - 142,150,150,150,150,134,134,134,134,138,138,138,138, 64, 64, 64, - 64, 90, 90, 90, 90, 21, 21, 21, 21, 93, 93, 93, 93, 61, 61, 61, - 61, 65, 65, 65, 65, 78, 78, 78, 78,126,126,126,126,154,154,154, - 154,121,121,121,121,166,166,166,166,167,167,167,167,152,152,152, - 152, 10, 10, 10, 10, 2, 0, 0, 0,104,104,104,104,170,170,170, - 170, 57, 57, 57, 57,107,107,107,107,175,175,175,175, 38, 38, 38, - 38, 73, 73, 73, 73, 86, 86, 86, 86, 67, 67, 67, 67, 59, 59, 59, - 59, 51, 51, 51, 51,161,161,161,161,144,144,144,144,143,143,143, - 143,172,172,172,172,174,174,174,174, 60, 60, 60, 60, 69, 69, 69, - 69, 47, 47, 47, 47,112,112,112,112,118,118,118,118,106,106,106, - 106,156,156,156,156,147,147,147,147,148,148,148,148,169,169,169, - 169,164,164,164,164,168,168,168,168, 11, 11, 11, 11, 74, 74, 74, - 74, 42, 42, 42, 42, 50, 50, 50, 50,116,116,116,116,111,111,111, - 111,115,115,115,115, 52, 52, 52, 52, 13, 13, 2, 2,120,120,120, - 120, 98, 98, 98, 98, 88, 88, 88, 88,117,117,117,117,101,101,101, - 101,103,103,103,103, 19, 19, 19, 0, 95, 95, 95, 95, 30, 30, 2, - 2, 34, 34, 34, 34, 54, 54, 54, 54, 0, 2, 0, 0, 71, 71, 71, - 71, 53, 53, 53, 53, 81, 81, 81, 81, 66, 66, 66, 66, 83, 83, 83, - 83,153,153,153,153,160,160,160,160, 2, 2, 22, 22, 30, 2, 30, - 30, 9, 9, 2, 2, 2, 2, 0, 0, 41, 41, 41, 41, 72, 72, 72, - 72,173,173,173,173, 82, 82, 82, 82,158,158,158,158,129,129,129, - 129,145,145,145,145, 2, 3, 3, 3, 23, 2, 23, 23, 16, 2, 16, - 16, 2, 2, 2, 0, 45, 45, 45, 45, 44, 44, 44, 44, 43, 43, 43, - 43,128,128,128,128,122,122,122,122,149,149,149,149, 0, 19, 19, - 19, 0, 0, 19, 0, 9, 2, 9, 9, 5, 2, 2, 5, 2, 10, 10, - 10, 10, 10, 2, 10, 2, 21, 21, 21, 21, 2, 2, 21, 22, 22, 22, - 2, 22, 22, 2, 2, 20, 2, 20, 20, 2, 30, 30, 30, 12, 12, 12, - 2, 19, 19, 19, 2, 2, 2, 12, 12,161,161, 2,161, 3, 3, 3, - 2,107, 2, 2,107, 2, 3, 2, 3, 19, 0, 0, 0, 2, 2, 9, - 9, 9, 9, 9, 2, 2, 4, 4, 4, 2, 11, 11, 11, 11, 11, 11, - 2, 11, 2, 11, 11, 10, 10, 2, 2, 22, 2, 22, 22, 2, 2, 2, - 22, 23, 23, 2, 2, 2, 36, 36, 36, 2, 2, 36, 36, 2, 25, 25, - 25, 46, 46, 46, 46, 31, 31, 2, 2, 91, 91, 2, 2, 1, 0, 0, - 0, 1, 1, 0, 0, 0, 17, 17, 17, 49, 49, 49, 2,161,161,161, - 2, 2,107,107,107,107, 2, 2, 2,171,171, 2,171, 0, 0, 2, - 0, 2, 3, 3, 2, 3, 2, 2, 3, 4, 4, 4, 2, 2, 14, 14, - 14, 14, 14, 14, 2, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, - 0, 37, 37, 37, 2, 3, 3, 2, 2, 2, 2, 2, 3, 2, 2, 5, - 5, 5, 5, 5, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 2, - 2, 10, 2, 10, 10, 21, 2, 21, 21, 21, 21, 2, 2, 22, 2, 2, - 2, 2, 16, 16, 16, 16, 16, 2, 2, 36, 36, 36, 2, 36, 2, 2, - 2, 18, 18, 18, 2, 18, 18, 2, 2, 25, 2, 25, 25, 8, 8, 2, - 8, 2, 8, 2, 2, 29, 29, 2, 2, 46, 2, 46, 46, 32, 2, 2, - 2, 1, 1, 2, 2, 1, 1, 1, 0, 19, 19, 9, 9, 2, 9, 2, - 9, 0, 0, 0, 19, 19, 2, 2, 2, 0, 0, 19, 19, 2, 2, 2, - 61, 15, 15, 15, 2, 17, 17, 17, 0, 2, 19, 19, 19, 75, 75, 2, - 2, 12, 2, 2, 2, 68, 68, 2, 2, 87, 87, 2, 2, 49, 49, 2, - 2, 50, 50, 2, 2, 2, 57, 57, 57, 57, 2, 2, 2,112,112,112, - 2, 2,122,122,122,130,130,130, 2,165,165, 2, 2,156,156, 2, - 2, 2, 2, 3, 3, 94, 94, 2, 2,129,129, 2,129,107, 2,107, - 107,123,123, 2, 2,102,102, 2, 2,126,126,126, 2,154,154,154, - 2, 2, 2,150,150,169,169, 2, 2,138,138,138, 2,138,138, 2, - 138,143,143, 2,143,163,163,163, 2,103,103, 2, 2,119,119, 2, - 119, 2, 2, 2, 99, 13, 13, 13, 2,136,136,136, 2,105, 2, 2, - 2, 0, 0, 0, 1, 56, 56, 56, 2,151,151, 2, 2, 3, 3, 2, - 3, 0, 0, 26, 26, 0, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, - 0, 9, 9, 2, 9, 9, 9, 55, 55, 6, 1, 1, 6, 2, 2, 2, - 14, 14, 2, 2, 2, 3, 3, 3, 1, 1, 1, 3, 3, 1, 3, 3, - 3, 37, 37, 2, 37, 2, 37, 37, 37, 38, 38, 2, 2, 64, 64, 64, - 2, 2, 64, 64, 64, 90, 90, 2, 2, 90, 90, 90, 2, 2, 2, 95, - 2, 3, 3, 0, 3, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, - 7, 2, 5, 5, 5, 5, 2, 5, 5, 5, 2, 5, 2, 5, 5, 2, - 2, 2, 2, 2, 5, 5, 5, 2, 5, 2, 11, 11, 2, 2, 11, 2, - 2, 11, 2, 11, 2, 2, 2, 11, 11, 10, 2, 2, 2, 2, 2, 10, - 10, 21, 21, 2, 21, 2, 2, 21, 21, 2, 22, 22, 22, 2, 22, 22, - 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 2, 23, 23, 2, 2, 2, - 23, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 16, 16, 2, 2, 20, - 20, 36, 36, 2, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, - 36, 36, 2, 36, 2, 2, 24, 24, 24, 24, 24, 24, 2, 2, 18, 18, - 2, 18, 2, 18, 18, 2, 18, 2, 18, 18, 2, 18, 2, 25, 2, 2, - 2, 25, 0, 0, 0, 0, 25, 25, 2, 8, 8, 8, 0, 30, 2, 2, - 2, 34, 2, 2, 2, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2, 2, - 2, 45, 45, 2, 2, 2, 2, 2, 45, 44, 0, 0, 2, 32, 32, 0, - 0, 32, 0, 32, 32, 32, 32, 2, 2, 32, 32, 32, 2, 28, 28, 2, - 2, 48, 48, 48, 2, 48, 2, 2, 2, 52, 52, 2, 2, 52, 2, 2, - 2, 58, 58, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 2, 2, 54, - 54, 91, 91, 91, 2, 91, 2, 2, 91, 62, 2, 62, 62, 2, 2, 2, - 70, 70, 70, 2, 2, 2, 70, 70, 70, 6, 6, 6, 2, 8, 8, 8, - 2, 2, 8, 8, 8, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, - 2, 9, 9, 9, 6, 19, 9, 9, 9, 9, 9, 19, 19, 9, 9, 9, - 19, 6, 19, 19, 19, 19, 19, 19, 9, 2, 9, 9, 9, 0, 19, 2, - 2, 1, 2, 2, 2, 0, 0, 9, 0, 2, 55, 55, 55, 61, 2, 2, - 2, 13, 13, 2, 13, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, - 1, 1, 1, 12, 12, 2, 15, 15, 15, 2, 1, 1, 0, 0, 15, 15, - 15, 2, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 0, 39, 2, 2, - 2, 39, 39, 39, 2, 60, 2, 2, 2, 2, 2, 75, 75, 69, 69, 0, - 69, 2, 2, 2, 74, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, - 84, 33, 33, 33, 2, 68, 68, 68, 2, 92, 92, 92, 2, 2, 2, 2, - 92, 87, 87, 87, 2, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, - 12, 2, 2, 2, 4, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, - 14, 3, 3, 0, 0, 1, 1, 6, 6, 3, 2, 3, 3, 3, 2, 2, - 0, 0, 0, 17, 17, 17, 17, 0, 0, 2, 49, 49, 49, 49, 49, 2, - 49, 9, 2, 2, 2, 0, 1, 2, 2, 71, 2, 2, 2, 67, 2, 2, - 2, 2, 42, 42, 42, 41, 41, 41, 2,118,118,118, 2, 53, 53, 2, - 53, 59, 59, 2, 2, 2, 2, 2,104,161, 2, 2, 2,110,110,110, - 2,110,110, 2, 2, 19, 19, 2, 19, 19, 2, 19, 19, 47, 47, 2, - 2, 47, 2, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, - 47, 81, 81, 2, 81,116,116,116, 2, 2, 2, 2,116,128,128,128, - 2,128,128, 2, 2, 2, 2, 2,128, 2, 2, 2, 66, 72, 72, 2, - 2, 2, 2, 2, 72,173,173, 2, 2, 2, 2, 97, 97, 2, 57, 57, - 2, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 2, 2, 2, - 112, 78, 78, 2, 2, 2, 78, 78, 78, 83, 83, 2, 2, 82, 82, 82, - 2,122,122, 2, 2,122, 2, 2, 2, 89, 2, 2, 2, 2, 2,130, - 130,144,144, 2, 2, 2,165,165,165, 2, 2,165,165,156,156, 2, - 156, 3, 2, 2, 2,148,148, 2, 2,158,158, 2, 2,149,149,149, - 2, 2, 2, 94, 94, 2, 2, 2, 94, 85, 85, 85, 2, 2, 85, 2, - 2,101, 2, 2, 2,101,101, 2, 2, 96, 2, 96, 96,111,111,111, - 2,108,108, 2,108,108,108, 2, 2,129,129,129, 2,129, 2,129, - 129,129,129, 2, 2,109,109,109, 2,109,109, 2, 2,107,107, 2, - 1,107,107, 2, 2, 2, 2, 2,107, 2, 2,107,107, 2, 2,171, - 2,171, 2,171, 2, 2,171, 2,171,171,171,171, 2,171, 2, 2, - 2, 2,171,171, 2, 2,137,137,137,137,137, 2, 2,124,124, 2, - 2,114, 2, 2, 2,114,114, 2, 2, 2,126,126,126,125,125,125, - 2, 2, 2, 2,125, 2,154, 2, 2, 2,154,154, 2,154,154, 2, - 154,154, 2, 2,154,154,154, 2, 2,150, 2, 2, 2,140,140,140, - 2,121, 2, 2, 2, 7, 7, 2, 2,133, 2,133,133,133,133,133, - 2,133,133, 2, 2,133, 2, 2, 2, 2, 2,134,134, 2,134,134, - 134,134,134,134, 2, 2, 2,138, 2,138,138, 2, 2,143, 2,143, - 143,143,143,143, 2,143, 2, 2, 2,143,143, 2, 2,175,175, 2, - 2,145, 2, 2, 2,163, 2,163,163, 2, 2,163,163, 86, 2, 2, - 2, 63, 63, 2, 2, 63, 63, 63, 2, 63, 2, 2, 2,157,157,157, - 2, 80, 80, 2, 2, 80, 80, 80, 2,127,127,127, 2,166,166, 2, - 2, 79, 2, 2, 2,115,115,115, 2,115,115, 2, 2, 2, 2,115, - 115,159,159,159, 2,159,159, 2, 2,119,119, 2, 2, 2,119,119, - 119,167,167, 2, 2,146,146,146, 2,172, 2, 2,172, 99, 99, 99, - 2,136,139, 13, 13,155, 2, 2, 2,155,155, 2, 2, 2, 2, 2, - 155, 2, 17, 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 17, 17, 17, - 2, 2, 2, 15, 2, 2, 17, 2, 2,105,105,105, 2,105,105, 2, - 2, 1, 1, 1, 2, 0, 1, 1, 1, 0, 0, 1, 1, 2, 2, 0, - 2, 2, 0, 0, 2, 0, 2, 0, 2, 2, 2, 2,131, 2,131,131, - 131, 56, 2, 2, 56, 56, 56, 2, 56, 56, 2, 56, 56, 6, 6, 2, - 2, 2, 2, 2, 6,151, 2, 2, 2, 2, 2,151,151,160,160,160, - 2,152,152, 2, 2, 2, 2, 2,152,164,164, 2, 2,168,168,168, - 2, 2, 2, 2,168,174,174,174, 2,174,174, 2, 2, 2, 2,174, - 174, 2, 30, 30, 2,113, 2, 2,113,113,113,113, 2,132,132, 2, - 2, 2, 2,132,132, 2, 2, 3, 2, 3, 2, 3, 2, 15, 0, 0, - 2, 0, 2, 2, 0, 13, 2, 2, 2, 2, 0, 2, 2, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 10, 0, 11, 12, 13, 0, - 0, 0, 14, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 0, 0, 0, 0, 18, - 0, 0, 0, 0, 0, 19, 20, 21, 0, 22, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 1, 1, 7, 7, 7, 7, 56, 57, 58, 59, 60, 61, 62, 63, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 65, 66, 67, + 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, + 100,101,102, 8, 8, 8,103, 8,104,105, 0, 0, 0, 0, 0, 0, + 0, 0,106, 5, 5, 5, 5,107, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5,108, 12, 12,109, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,110, 0, 0, 0, 0, 0, 0, 13, 13,111,112, 0, + 113,114,115, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,116,117, + 118, 9, 9, 9,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,120,121,122,123, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,125, + 6,126,127,128,129,130,131,132,133,134,135, 14, 14,136,137, 0, + 0, 0,138,139,140,141, 0,142,143,144,145,146,147, 0, 0,148, + 149,150, 0,151,152,153, 6, 6, 6,154,155,156, 6,157,158, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1,159, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,160, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1,161, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,162, 1, + 1,163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,164, 0, 0, + 0, 0, 0, 1, 1, 1,165, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1,166, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,167, + 0, 0, 0,168,169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, + 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12,178,178,178,178,178, + 178,178,178, 0, 0, 0, 0, 0, 0, 0, 0,136,136,136,136,136, + 136,136,136, 80, 80, 80, 80, 80, 80, 80, 80, 19, 19, 19, 19, 19, + 19, 19, 19, 63, 63, 63, 63, 63, 63, 63, 63, 3, 3, 3, 3, 3, + 3, 3, 3, 39, 39, 39, 39, 39, 39, 39, 39,176,176,176,176,176, + 176,176,176, 28, 28, 28, 28, 28, 28, 28, 28, 79, 79, 79, 79, 79, + 79, 79, 79,131,131,131,131,131,131,131,131, 1, 1, 1, 1, 1, + 1, 1, 1,127,127,127,127,127,127,127,127, 6, 6, 6, 6, 6, + 6, 6, 6,155,155,155,155,155,155,155,155,139,139,139,139,139, + 139,139,139, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, + 15, 15, 15, 30, 30, 30, 30, 30, 30, 30, 30,110,110,110,110,110, + 110,110,110, 77, 77, 77, 77, 77, 77, 77, 77, 17, 17, 17, 17, 17, + 17, 17, 17, 27, 27, 27, 27, 27, 27, 27, 27, 33, 33, 33, 33, 33, + 33, 33, 33,113,113,113,113,113,113,113,113, 49, 49, 49, 49, 49, + 49, 49, 49, 25, 25, 25, 25, 25, 25, 25, 25, 29, 29, 29, 29, 29, + 29, 29, 29,177,177,177,177,177,177,177,177, 7, 7, 7, 7, 7, + 7, 7, 7, 32, 32, 32, 32, 32, 32, 32, 32, 8, 8, 8, 8, 8, + 8, 8, 8, 99, 99, 99, 99, 99, 99, 99, 99, 31, 31, 31, 31, 31, + 31, 31, 31, 30, 30, 30, 30, 30, 30, 30, 2,105,105,105,105,105, + 105,105,105, 55, 55, 55, 55, 55, 55, 55, 55, 62, 62, 62, 62, 62, + 62, 62, 62, 0, 0, 0, 0, 2, 2, 2, 2, 56, 56, 56, 56, 56, + 56, 56, 56, 91, 91, 91, 91, 91, 91, 91, 91,100,100,100,100,100, + 100,100,100,119,119,119,119,119,119,119,119, 14, 14, 14, 14, 14, + 14, 14, 14,130,130,130,130,130,130,130,130, 94, 94, 94, 94, 94, + 94, 94, 94,157,157,157,157,157,157,157,157,137,137,137,137,137, + 137,137,137,146,146,146,146,146,146,146,146, 4, 4, 4, 4, 4, + 4, 4, 4, 20, 20, 20, 20, 20, 20, 20, 20, 35, 35, 35, 35, 35, + 35, 35, 35, 84, 84, 84, 84, 84, 84, 84, 84, 40, 40, 40, 40, 40, + 40, 40, 40, 97, 97, 97, 97, 97, 97, 97, 97,124,124,124,124,124, + 124,124,124,123,123,123,123,123,123,123,123,125,125,125,125,125, + 125,125,125,140,140,140,140,140,140,140,140,159,159,159,159,159, + 159,159,159,132,132,132,132,132,132,132,132, 37, 37, 37, 37, 37, + 37, 37, 37, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 24, + 24, 24, 24, 58, 58, 58, 58, 58, 58, 58, 58, 76, 76, 76, 76, 76, + 76, 76, 76, 0, 0, 0, 0, 0, 0, 2, 2, 26, 26, 26, 26, 26, + 26, 26, 26, 75, 75, 75, 75, 75, 75, 75, 75, 89, 89, 89, 89, 89, + 89, 89, 89,114,114,114,114,114,114,114,114,141,141,141,141,141, + 141,141,141,133,133,133,133,133,133,133,133,163,163,163,163,163, + 163,163,163, 70, 70, 70, 70, 70, 70, 70, 70, 0, 0, 0, 0, 0, + 2, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 92, 92, 92, 92, 92, + 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 0, 0, 0, 0, 0, + 0, 0, 2,135,135,135,135,135,135,135,135, 85, 85, 85, 85, 85, + 85, 85, 85, 96, 96, 96, 96, 96, 96, 96, 96,109,109,109,109,109, + 109,109,109,102,102,102,102,102,102,102,102, 64, 64, 64, 64, 64, + 64, 64, 64, 0, 0, 2, 2, 2, 2, 2, 2, 61, 61, 61, 61, 61, + 61, 61, 61, 65, 65, 65, 65, 65, 65, 65, 65,108,108,108,108,108, + 108,108,108,142,142,142,142,142,142,142,142,121,121,121,121,121, + 121,121,121,166,166,166,166,166,166,166,166,167,167,167,167,167, + 167,167,167,151,151,151,151,151,151,151,151,152,152,152,152,152, + 152,152,152, 38, 38, 38, 38, 38, 38, 38, 38, 90, 90, 90, 90, 90, + 90, 90, 90, 23, 23, 23, 23, 23, 23, 23, 23, 36, 36, 36, 36, 36, + 36, 36, 36, 30, 2, 30, 30, 30, 30, 2, 2, 48, 48, 48, 48, 48, + 48, 48, 48, 93, 93, 93, 93, 93, 93, 93, 93, 73, 73, 73, 73, 73, + 73, 73, 73, 9, 9, 9, 9, 9, 9, 2, 2, 86, 86, 86, 86, 86, + 86, 86, 86, 2, 0, 0, 0, 0, 0, 0, 0, 67, 67, 67, 67, 67, + 67, 67, 67, 51, 51, 51, 51, 51, 51, 51, 51,104,104,104,104,104, + 104,104,104,170,170,170,170,170,170,170,170, 78, 78, 78, 78, 78, + 78, 78, 78,144,144,144,144,144,144,144,144,165,165,165,165,165, + 165,165,165,171,171,171,171,171,171,171,171,126,126,126,126,126, + 126,126,126,150,150,150,150,150,150,150,150,134,134,134,134,134, + 134,134,134,138,138,138,138,138,138,138,138,175,175,175,175,175, + 175,175,175, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, + 2, 0, 0, 13, 13, 13, 13, 13, 13, 2, 2, 60, 60, 60, 60, 60, + 60, 60, 60, 69, 69, 69, 69, 69, 69, 69, 69,118,118,118,118,118, + 118,118,118, 59, 59, 59, 59, 59, 59, 59, 59,106,106,106,106,106, + 106,106,106,156,156,156,156,156,156,156,156,147,147,147,147,147, + 147,147,147,148,148,148,148,148,148,148,148,169,169,169,169,169, + 169,169,169,172,172,172,172,172,172,172,172,164,164,164,164,164, + 164,164,164,168,168,168,168,168,168,168,168,174,174,174,174,174, + 174,174,174, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, + 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 21, 21, 21, 21, 21, + 21, 21, 21, 16, 16, 16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 12, + 12, 12, 2, 74, 74, 74, 74, 74, 74, 74, 74, 42, 42, 42, 42, 42, + 42, 42, 42, 50, 50, 50, 50, 50, 50, 50, 50,161,161,161,161,161, + 161,161,161, 47, 47, 47, 47, 47, 47, 47, 47,120,120,120,120,120, + 120,120,120,116,116,116,116,116,116,116,116, 98, 98, 98, 98, 98, + 98, 98, 98, 57, 57, 57, 57, 57, 57, 57, 57, 88, 88, 88, 88, 88, + 88, 88, 88,117,117,117,117,117,117,117,117,112,112,112,112,112, + 112,112,112,101,101,101,101,101,101,101,101,111,111,111,111,111, + 111,111,111,154,154,154,154,154,154,154,154,143,143,143,143,143, + 143,143,143,115,115,115,115,115,115,115,115, 0, 0, 19, 0, 0, + 0, 0, 0, 95, 95, 95, 95, 95, 95, 95, 95, 11, 11, 11, 11, 11, + 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 22, 22, 22, 2, 2, + 2, 22, 22, 2, 25, 25, 25, 25, 25, 25, 25, 34, 34, 34, 34, 34, + 34, 34, 34, 52, 52, 52, 52, 52, 52, 52, 52, 54, 54, 54, 54, 54, + 54, 54, 54, 0, 0, 0, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, + 30, 30, 2, 2, 2, 12, 12, 12, 12, 12, 12, 71, 71, 71, 71, 71, + 71, 71, 71, 41, 41, 41, 41, 41, 41, 41, 41, 53, 53, 53, 53, 53, + 53, 53, 53, 81, 81, 81, 81, 81, 81, 81, 81, 66, 66, 66, 66, 66, + 66, 66, 66, 72, 72, 72, 72, 72, 72, 72, 72,173,173,173,173,173, + 173,173,173, 83, 83, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, + 82, 82, 82,158,158,158,158,158,158,158,158,153,153,153,153,153, + 153,153,153,145,145,145,145,145,145,145,145,103,103,103,103,103, + 103,103,103, 0, 2, 2, 2, 2, 2, 2, 2,160,160,160,160,160, + 160,160,160, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3, 3, 2, 3, + 3, 3, 3, 19, 19, 19, 19, 19, 19, 19, 0, 3, 3, 3, 3, 3, + 0, 3, 3, 5, 5, 5, 5, 5, 2, 2, 5, 11, 11, 11, 2, 2, + 2, 2, 11, 10, 10, 10, 10, 10, 10, 2, 10, 21, 21, 21, 21, 21, + 2, 2, 21, 22, 2, 22, 22, 22, 22, 2, 2, 23, 23, 23, 23, 23, + 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, + 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, + 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 36, 36, 36, 36, 36, + 36, 36, 2, 25, 25, 25, 25, 25, 2, 25, 25, 8, 8, 8, 8, 8, + 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 29, 29, 29, 29, 29, + 29, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 44, 44, 44, 44, 44, + 44, 44, 44, 43, 43, 43, 43, 43, 43, 43, 43, 31, 31, 2, 2, 2, + 2, 2, 2, 48, 48, 48, 48, 2, 2, 2, 2, 91, 91, 2, 2, 2, + 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 9, 9, 9, 9, 9, + 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 2, + 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 61, 0, 17, 17, 17, 17, + 17, 17, 17, 12, 12, 12, 12, 2, 2, 2, 2, 13, 13, 2, 2, 2, + 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 0, 0, 0, 2, 0, + 0, 0, 0, 49, 49, 49, 49, 49, 49, 2, 2, 0, 0, 0, 0, 2, + 2, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0,135,135,135,135, 2, + 2, 2, 2,161,161,161, 2,161,161,161,161,161,161, 2,161,161, + 161,161,161,128,128,128,128,128,128,128,128, 57, 2, 2, 2, 2, + 2, 2, 2,112,112,112,112,112,112,112, 2,122,122,122,122,122, + 122,122,122,130,130,130, 2, 2, 2, 2, 2,165,165,165,165,165, + 165, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, + 3, 3, 3,149,149,149,149,149,149,149,149, 94, 94, 94, 94, 94, + 94, 2, 2,129,129,129,129,129,129,129,129,107,107,107,107,107, + 2, 2,107,107,107,107,107,107,107,107,107,107,107,107,107,107, + 2, 2, 2,171,171,171,171,171,171, 2,171,123,123,123,123,123, + 123, 2, 2,102,102, 2, 2, 2, 2, 2, 2,154,154,154,154,154, + 154,154, 2, 2, 2,150,150,150,150,150,150,169,169, 2, 2, 2, + 2, 2, 2,138,138,138,138,138,138,138, 2,103,103,103,103,103, + 103, 2, 2,119,119, 2,119,119,119,119,119, 13, 13, 13, 13, 13, + 13, 13, 2, 17, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 2, 0, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 2, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, + 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 9, 9, 9, 9, 0, + 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, + 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9, 2, 9, 9, + 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, + 1, 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, 2, + 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, + 2, 2, 2, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, + 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, + 3, 3, 3, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, + 37, 37, 37, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64, 64, 2, 2, + 64, 64, 64, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, + 90, 90, 2, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, + 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 0, 3, 3, + 3, 3, 3, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, + 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 2, 2, 5, 5, + 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, + 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, + 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, + 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 2, 2, 11, 11, + 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, + 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, + 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, + 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 2, 10, 10, + 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, + 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, + 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, + 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, + 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 2, 2, 21, 21, + 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, + 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, + 21, 2, 2, 2, 2, 2, 21, 21, 21, 21, 21, 2, 2, 2, 2, 21, + 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, + 22, 22, 22, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, + 2, 2, 2, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, + 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, + 2, 2, 2, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, + 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 23, + 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, + 2, 2, 23, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, + 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, + 16, 16, 2, 2, 2, 2, 2, 16, 16, 16, 2, 16, 16, 16, 16, 2, + 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 20, + 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, + 36, 36, 36, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, + 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, + 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, + 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, + 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, + 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, + 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, + 2, 2, 2, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, + 2, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 30, 30, 30, 2, 2, + 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, + 2, 2, 2, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35, 35, 0, 0, + 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, + 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, + 0, 0, 2, 43, 43, 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, + 2, 2, 2, 31, 31, 31, 31, 31, 31, 2, 2, 32, 32, 0, 0, 32, + 0, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, + 2, 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, + 28, 2, 2, 48, 48, 48, 48, 48, 48, 48, 2, 48, 2, 2, 2, 48, + 48, 48, 48, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, + 2, 2, 2, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, + 2, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 2, + 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, + 2, 2, 91, 91, 91, 91, 91, 91, 91, 2, 2, 62, 62, 62, 62, 62, + 2, 62, 62, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, + 93, 93, 93, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, + 70, 70, 70, 6, 6, 6, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, + 8, 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, + 19, 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, + 19, 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 9, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 2, + 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, + 2, 9, 9, 0, 0, 0, 0, 1, 1, 0, 0, 0, 19, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, + 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 55, 55, 55, 55, 2, + 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 2, 2, 2, 2, + 2, 2, 2, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, + 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13, 13, 13, 0, + 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 17, 17, 17, 0, 0, + 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 2, 12, 12, 12, 12, + 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 0, 12, 12, 12, 12, 12, + 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39, 39, 39, 39, + 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 77, 77, 77, 77, 2, + 2, 2, 2, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 19, 2, 2, + 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, + 2, 2, 2, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, + 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, + 69, 0, 69, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, + 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, + 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, + 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, 92, 2, 2, + 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, + 87, 87, 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 9, 19, 19, 19, 19, 0, 0, 19, 19, 2, 2, 87, 87, 87, 87, 87, + 87, 2, 2, 87, 87, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, + 12, 12, 12, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, + 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, 3, 3, 3, + 3, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 3, 3, 3, 3, 3, + 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, + 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 2, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, + 49, 2, 49, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, + 2, 2, 0, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, + 1, 2, 2, 71, 71, 71, 71, 71, 2, 2, 2, 67, 2, 2, 2, 2, + 2, 2, 2, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 42, 42, 42, 41, 41, 41, 2, 2, 2, 2, 2,118,118,118, 2, 2, + 2, 2, 2, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 2, + 2, 2, 2, 59, 59, 59, 59, 59, 59, 2, 2, 50, 50, 50, 50, 50, + 50, 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,104,104,104,104, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,104,161,161,161, 2,161, + 161, 2,161,161,161, 2,161,161, 2, 2, 2,170,170,170,170, 2, + 2, 2, 2,110,110,110,110,110,110,110, 2,110,110,110,110,110, + 110, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2, 19, 19, 19, + 19, 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, + 2, 2, 47, 81, 81, 81, 81, 81, 81, 2, 81,116,116,116,116,116, + 116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,128,128,128, 2,128, + 128, 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66, 66, 66, 2, + 2, 2, 66, 72, 72, 2, 2, 2, 2, 2, 72,173,173, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, + 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2, 2, 2, 57, + 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, + 2, 2, 57, 2, 2, 2,112,112,112,112,112, 78, 78, 78, 78, 78, + 78, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, + 83, 2, 2, 82, 82, 82, 2, 2, 2, 2, 2,122,122, 2, 2, 2, + 2, 2, 2, 2,122,122,122,122, 2, 2, 2, 2,122,122,122,122, + 122,122,122, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2,130,130,130, + 130,130,130,144,144, 2, 2, 2, 2, 2, 2, 2,165,165,165,165, + 165,165,165, 2, 2, 2, 2, 2, 2,165,165,156,156, 2,156,156, + 156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3,148,148, 2, 2, 2, 2, 2, 2,158,158, 2, 2, 2, + 2, 2, 2,153,153,153,153, 2, 2, 2, 2,149,149,149,149,149, + 149,149, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, + 2, 2, 94, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 85, 2, 2,101, 2, 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, + 2, 2, 2, 96, 96, 96, 96, 96, 2, 96, 96,111,111,111,111,111, + 111,111, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 2, 2, 2,108,108, 2,108,108,108,108,108,108,108, 2, 2, 2, + 2, 2, 2,129,129,129,129,129,129,129, 2,129, 2,129,129,129, + 129, 2,129,129,129,129,129,129,129, 2,129,129,129, 2, 2, 2, + 2, 2, 2,109,109,109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, + 2, 2, 2,107,107,107,107, 2,107,107,107,107, 2, 2,107,107, + 107,107,107,107, 2,107,107,107,107,107,107,107, 2,107,107, 2, + 107,107,107,107,107, 2, 1,107,107,107,107,107, 2, 2,107,107, + 107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2, + 107,107,107,107,107,107,107, 2, 2,107,107,171,171, 2,171, 2, + 2,171, 2,171, 2,171, 2, 2,171, 2,171,171,171,171, 2,171, + 171,171,171,171, 2, 2, 2, 2, 2, 2, 2, 2,171,171, 2, 2, + 2, 2, 2,137,137,137,137, 2,137,137,137,137,137, 2, 2, 2, + 2, 2, 2,124,124, 2, 2, 2, 2, 2, 2,114,114,114,114,114, + 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, + 2, 2, 2, 33, 33, 33, 33, 2, 2, 2, 2,126,126,126, 2, 2, + 126,126,126,126,126,126,126, 2, 2, 2, 2,126,126,126,126,126, + 126,126, 2,142,142,142,142, 2, 2, 2, 2,125,125,125, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125, 2,154, 2, 2,154, + 154,154,154,154,154,154,154, 2,154,154, 2,154,154,154,154,154, + 154, 2,154,154, 2, 2,154,154,154,154,154,154,154, 2, 2, 2, + 2, 2, 2,150,150,150,150,150, 2, 2, 2,140,140,140, 2, 2, + 2, 2, 2,121, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 2, 2, + 2, 2, 2,133, 2,133,133,133,133,133,133,133,133,133,133,133, + 133,133, 2,133,133,133,133,133,133, 2, 2,133,133,133,133,133, + 2, 2, 2, 2, 2,134,134,134,134,134,134, 2,134,134,134,134, + 134,134,134,134,134,134,134,134,134,134, 2,138,138, 2,138,138, + 138,138,138, 2, 2,138, 2,138,138, 2,138,138,138, 2, 2, 2, + 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2,143,143,143, + 143,143,143,143,143,143,143,143,143,143, 2,143,143, 2,143,143, + 143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, + 2, 2, 2,175,175,175,175, 2, 2, 2, 2,175,175, 2, 2, 2, + 2, 2, 2, 5, 5, 2, 2, 2, 2, 2, 2,145, 2, 2, 2, 2, + 2, 2, 2,163, 2,163,163,163,163,163,163,163,163,163, 2, 2, + 2,163,163,163,163,163, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, + 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 22, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 2, + 2, 2, 2,177,177,177,177, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 2,157,157,157, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, + 80, 2, 2, 80, 80, 80, 2, 2, 2, 2, 2,127,127,127,127,127, + 127,127, 2,166,166, 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, + 2, 2, 2,115,115,115,115,115,115,115, 2,115,115, 2, 2, 2, + 2,115,115,159,159,159,159,159,159,159, 2,159,159, 2, 2, 2, + 2, 2, 2,119,119,119,119,119,119, 2, 2, 2, 2, 2, 2, 2, + 119,119,119,167,167, 2, 2, 2, 2, 2, 2,146,146,146, 2, 2, + 2, 2, 2,172, 2, 2,172,172,172,172,172,172,172,172,172, 2, + 2, 2, 2, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, + 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,155,155,155, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,155,136, 2, 2, 2, 2, + 2, 2, 2,136,136,136, 2, 2, 2, 2, 2,176,176, 2, 2, 2, + 2, 2, 2,176,176,176, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, + 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, + 15, 15, 15, 17, 17, 17, 15, 17, 17, 17, 17, 2, 2, 15, 2, 2, + 2, 2, 2, 15, 15, 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, + 17, 17, 17,139,139,139,139, 2, 2, 2, 2,105,105,105, 2, 2, + 2, 2, 2,105,105,105,105,105, 2, 2, 2,105, 2, 2, 2, 2, + 2, 2, 2,105,105, 2, 2,105,105,105,105, 0, 2, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 2, 2, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0,131,131,131,131, 2, + 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131,131,131,131, + 131,131,131, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 19, 19, 19, 19, 19, 19, 9, 9, 19, 19, 19, 56, 56, 56, 56, 56, + 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, + 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, + 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151,151,151,151,151, + 2, 2, 2,151,151,151,151,151,151, 2, 2,151,151, 2, 2, 2, + 2,151,151,160,160,160,160,160,160,160, 2,152,152, 2, 2, 2, + 2, 2,152,164,164, 2, 2, 2, 2, 2, 2,168,168,168, 2, 2, + 2, 2,168,174,174,174,174,174,174,174, 2,174,174,174,174,174, + 174, 2, 2, 2, 2, 2, 2, 2, 2,174,174, 30, 30, 30, 30, 2, + 30, 30, 2,113,113,113,113,113, 2, 2,113,113,113,113,113,113, + 113,113, 2,132,132,132,132, 2, 2, 2, 2,132,132, 2, 2, 2, + 2,132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, + 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, + 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, + 2, 3, 2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, + 2, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, + 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, + 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 0, 0, 0, 10, 0, 11, 12, 13, 0, 0, 0, + 14, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 16, 17, 0, 0, 0, 0, 18, 0, 0, + 0, 0, 0, 19, 20, 21, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, + 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 27, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, - 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 27, 0, 0, 0, 0, 0, + 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, + 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, + 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, + 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, + 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, + 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, - 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, - 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, - 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, - 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, - 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, - 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, - 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, - 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,100,101,102,103, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, + 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0,111, + 112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,120, + 121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,100,101,102,103, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, - 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, - 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132,133,134, + 135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150, + 151,152,153,154,155,156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118, - 119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132, - 133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148, - 149,150,151,152,153,154,155,156,157, 0, 0, 0,158,159,160,161, + 0, 0, 0, 0, 0,162, 0,163, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,164,165, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, + 0,168,169, 0, 0,170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,162, 0,163, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,164,165, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, - 0, 0, 0,168,169, 0, 0,170, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,171, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,172, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,173, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,174, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,176,177, + 0, 0, 0, 0,178,179, 0, 0, 0,180,181,182,183,184,185,186, + 187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202, + 203,204,205,206,207,208,209,210,211,212,213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 176,177, 0, 0, 0, 0,178,179, 0, 0, 0,180,181,182,183,184, - 185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200, - 201,202,203,204,205,206,207,208,209,210,211,212,213, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 uint16_t _hb_ucd_u16[10877]= +static const uint16_t _hb_ucd_u16[9777]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 224, 224, 768, 424, 432, 440, 448, 776, 224, 224, 784, 792, 72, 800, 40, 808, - 48, 48, 48, 816, 824, 48, 48, 832, 840, 848, 856, 864, 872, 880, 48, 888, - 48, 48, 48, 896, 904, 40, 40, 40, 40, 912, 40, 96, 920, 928, 936, 456, - 64, 64, 64, 64, 64, 64, 64, 944, 952, 960, 968, 40, 976, 984, 48, 992, - 72, 72, 72, 40, 40, 40, 48, 48,1000, 48, 48, 48,1008, 48, 48, 48, - 48, 48, 48,1016, 72,1024, 40, 40,1032, 464, 64,1040,1048, 8,1056,1064, - 1072,1080, 8, 8,1088, 64,1096,1104, 8, 8, 8, 8, 8,1112,1120,1128, - 1136,1144, 8, 64,1152, 8, 8, 8, 8, 8, 472,1160, 232, 8,1168,1176, - 8,1184,1192,1200, 8,1208, 176, 8,1216,1224, 8, 8,1232, 64,1240, 64, - 480, 8, 8,1248,1256,1264,1272,1280,1288, 240, 128,1296,1304,1312, 144,1320, - 1328, 240, 128,1336,1344,1352, 304,1360,1368, 488, 128,1376,1384, 248, 144,1392, - 1400, 240, 128,1408,1416,1424, 144,1432,1440,1448,1456,1464,1472,1480, 304,1488, - 1496, 256, 128,1504,1512,1520, 144,1528,1536, 256, 128,1544,1552,1560, 144,1568, - 1576, 256, 8,1584,1592,1600, 144,1608,1616,1624, 8,1632,1640,1648, 304,1656, + 232, 232, 776, 416, 424, 432, 440, 784, 232, 232, 792, 800, 72, 808, 40, 816, + 64, 64, 64, 824, 832, 64, 64, 840, 848, 856, 864, 872, 880, 888, 64, 896, + 64, 64, 64, 904, 912, 40, 40, 40, 40, 920, 40, 104, 928, 936, 944, 448, + 48, 48, 48, 48, 48, 48, 48, 952, 960, 968, 976, 40, 984, 992, 64,1000, + 72, 72, 72, 40, 40, 40, 64, 64,1008, 64, 64, 64,1016, 64, 64, 64, + 64, 64, 64,1024, 72,1032, 40, 40,1040, 456, 48,1048,1056, 8,1064,1072, + 1080,1088, 8, 8,1096, 48,1104,1112, 8, 8, 8, 8, 8,1120,1128,1136, + 1144,1152, 8, 48,1160, 8, 8, 8, 8, 8, 464, 472, 240, 8,1168,1176, + 8,1184,1192,1200, 8,1208, 152, 8,1216,1224, 8, 8,1232, 48,1240, 48, + 480, 8, 8,1248,1256,1264,1272,1280,1288, 248, 128,1296,1304,1312, 160,1320, + 1328, 248, 128,1336,1344,1352, 304,1360,1368, 488, 128,1376,1384, 192, 160,1392, + 1400, 248, 128,1408,1416,1424, 160,1432,1440,1448,1456,1464,1472,1480, 304,1488, + 1496, 256, 128,1504,1512,1520, 160,1528,1536, 256, 128,1544,1552,1560, 160,1568, + 1576, 256, 8,1584,1592,1600, 160,1608,1616,1624, 8,1632,1640,1648, 304,1656, 312, 8, 8,1664,1672,1680, 0, 0,1688, 8,1696,1704,1712,1720, 0, 0, - 1728,1736, 320,1744,1752, 8, 152,1760,1768,1776, 64,1784,1792,1800, 0, 0, + 1728,1736, 320,1744,1752, 8, 168,1760,1768,1776, 48,1784,1792,1800, 0, 0, 8, 8,1808,1816, 496,1824,1832,1840,1848,1856, 72, 72,1864, 40, 40,1872, 8, 8, 8, 8, 504,1880, 8, 8, 504, 8, 8,1888, 512, 520, 8, 8, - 8, 512, 8, 8, 8,1896,1904, 528, 8, 264, 72, 72, 72, 72, 72,1912, + 8, 512, 8, 8, 8,1896,1904, 528, 8, 328, 72, 72, 72, 72, 72,1912, 536, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,1920, 8,1928,1936, 8, 8, 8, 8,1944,1952, - 8,1960, 8,1968, 8,1976,1984,1992, 8, 8, 8,2000,2008,2016, 80,2024, - 2032, 80, 8, 8,2040, 8, 8, 160,2048, 8,2056, 8, 8, 8, 8, 328, - 8, 120,2064,2072,2080, 8, 112,2088, 8, 8, 184, 8, 192,2096, 24, 24, - 8,2104, 8, 8, 8,2112,2120,2128, 80, 80,2136,2144, 64, 544,2152, 0, - 2160, 8, 8,2168,2176, 496,2184,2192, 336, 8,2200, 232, 8, 8,2208,2216, - 8, 8,2224,2232,2240, 232, 8, 552,2248, 72, 72,2256,2264,2272,2280,2288, - 40, 40,2296, 96, 96, 96,2304,2312, 40,2320, 96, 96, 64, 64, 64, 64, - 48, 48, 48, 48, 48, 48, 48, 48, 48,2328, 48, 48, 48, 48, 48, 48, - 168, 560, 168, 168, 560,2336, 168,2344, 344, 344, 344,2352,2360,2368,2376,2384, - 2392,2400,2408,2416,2424,2432,2440,2448,2456,2464, 568, 568,2472,2480,2488,2496, - 2504,2512,2520,2528,2536, 88, 104, 104,2544,2552,2560, 24,2568,2576, 24,2584, - 2592, 24,2600, 24, 24, 24, 24,2608, 24,2616, 56,2624, 24,2632,2640, 24, - 24, 24, 264, 0, 576, 0, 88, 88, 88,2648, 24, 24, 24, 24,2656, 88, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,2664,2672, 24, 24,2680, - 24, 24, 24, 24, 24, 24,2688, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24,2696,2704, 88,2712, 24, 24,2720, 56,2728, 56, - 56, 56, 56, 56, 56, 56, 56, 56,2736,2744, 56, 56, 56,2752, 56,2760, - 24, 24, 24, 56,2768, 24, 24,2776, 24, 24, 24, 24, 24, 24, 24, 24, - 72, 72, 72, 40, 40, 40,2784,2792, 48, 48, 48, 48, 48, 48,2800,2808, - 40, 40,2816, 8, 8, 8,2824,2832, 8, 200, 208, 208, 208, 208, 64, 64, - 2840,2848,2856,2864,2872,2880, 0, 0, 24,2888, 24, 24, 24, 24, 24, 352, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 272, 0, 24, - 2896,2904,2912,2920, 312, 8, 8, 8, 8,2928, 536, 8, 8, 8, 8,2936, - 2944, 8, 8, 312, 8, 8, 8, 8, 120,2952, 8, 8, 24, 24,2960, 8, - 24, 584, 592, 24,2968, 600, 24, 24, 592, 24, 24, 600, 24, 24, 24, 24, + 8,1960, 8,1968, 8,1976,1984,1992, 8, 8, 8,2000,2008,2016, 88,2024, + 2032, 88, 8, 8,2040, 8, 8, 136,2048, 8,2056, 8, 8, 8, 8, 544, + 8, 112,2064,2072,2080, 8, 120,2088, 8, 8, 200, 8, 208,2096, 24, 24, + 8,2104, 8, 8, 8,2112,2120,2128, 88, 88,2136,2144, 48, 48, 48, 552, + 2152, 8, 8,2160,2168, 496,2176,2184, 336, 8,2192, 240, 8, 8,2200,2208, + 8, 8,2216,2224,2232, 240, 8, 560,2240, 72, 72,2248,2256,2264,2272,2280, + 40, 40,2288, 104, 104, 104,2296,2304, 40,2312, 104, 104, 48, 48, 48, 48, + 64, 64, 64, 64, 64, 64, 64, 64, 64,2320, 64, 64, 64, 64, 64, 64, + 176, 568, 176, 176, 568,2328, 176,2336, 344, 344, 344,2344,2352,2360,2368,2376, + 2384,2392,2400,2408,2416,2424,2432,2440,2448, 104, 576, 576,2456,2464,2472, 552, + 2480,2488,2496,2504,2512, 96, 80, 80,2520,2528,2536, 24,2544,2552, 24,2560, + 2568, 24,2576, 24, 24, 24, 24,2584, 24,2592, 56,2600, 24,2608,2616, 24, + 24, 24, 328, 0, 584, 0, 96, 96, 96,2624, 24, 24, 24, 24,2632, 96, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,2640,2648, 24, 24,2656, + 24, 24, 24, 24, 24, 24,2664, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24,2672,2680, 96,2688, 24, 24,2696, 56,2704, 56, + 56, 56, 56, 56, 56, 56, 56, 56,2712,2720, 56, 56, 56,2728, 56,2736, + 24, 24, 24, 56,2744, 24, 24,2752, 24, 24, 24, 24, 24, 24, 24, 24, + 72, 72, 72, 40, 40, 40,2760,2768, 64, 64, 64, 64, 64, 64,2776,2784, + 40, 40,2792, 8, 8, 8,2800,2808, 8, 216, 224, 224, 224, 224, 48, 48, + 2816,2824,2832,2840,2848,2856,2864, 0, 24,2872, 24, 24, 24, 24, 24, 352, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 264, 0, 24, + 2880,2888,2896,2904, 312, 8, 8, 8, 8,2912, 536, 8, 8, 8, 8,2920, + 2928, 8, 8, 312, 8, 8, 8, 8, 112,2936, 8, 8, 24, 24,2944, 8, + 24, 360, 592, 24,2952, 600, 24, 24, 592, 24, 24, 600, 24, 24, 24, 24, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, - 8,2976, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 152, 24, 24, 24, 608, 8, 8, 552, - 2984, 8,2992, 0, 48, 48,3000,3008, 48,3016, 8, 8, 8, 8,3024,3032, - 456,3040,3048,3056, 48, 48, 48,3064,3072,3080,3088,3096,3104,3112, 0,3120, - 3128, 8,3136,3144, 8, 8, 8,3152,3160, 8, 8,3168,3176, 80, 64,3184, - 232, 8,3192, 8,3200,3208, 8, 152, 480, 8, 8,3216,3224, 360,3232,3240, - 8, 8,3248,3256,3264,3272, 8,3280, 8, 8, 8,3288,3296,3304,3312,3320, - 3328,3336, 208, 40, 40,3344,3352, 40, 40, 40, 40, 40, 8, 8,3360, 80, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 368, 8,3368, 8, 8, 184, - 8, 8, 8, 8, 8, 8, 112, 8, 8, 8, 8, 8, 8, 192, 0, 0, - 3376,3384,3392,3400,3408, 8, 8, 8, 8, 8, 8,3416,3424,3432, 8, 8, - 8, 8, 8,3440, 24, 8, 8, 8, 8,3448, 8, 8,3456, 0, 0,3464, - 64,3472, 64,3480,3488,3496,3504,3512, 8, 8, 8, 8, 8, 8, 8,3520, - 3528, 424, 432, 440, 448,3536,3544,3552, 8,3560, 8, 120,3568,3576,3584,3592, - 3600, 8, 520,3608, 112, 112, 0, 0, 8, 8, 8, 8, 8, 8, 8, 176, - 3616, 88, 88,3624, 104, 104, 104,3632,3640, 280, 376, 0, 0, 24, 24,3648, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 152, 8, 8, 8, 248,3656,3664, - 8, 8,3672, 8,3680, 8, 8,3688, 8,3696, 8, 8,3704,3712, 0, 0, - 72, 72,3720, 40, 40, 8, 8, 8, 8, 112, 80, 72, 72,3728, 40,3736, - 8, 8, 616, 8, 8, 8,3744, 624, 624,3752,3760,3768, 8, 8, 8, 368, - 8, 8, 8, 200, 8, 328, 616, 0,3776, 96, 96,3784, 0, 0, 0, 0, - 3792, 8, 8,3800, 8,3808, 8,3816, 8, 120,3824, 0, 0, 0, 8,3832, - 8,3840, 8,3848, 8, 192, 0, 0, 8, 8, 8,3856, 88, 632, 88, 88, - 3864,3872, 8,3880, 640,3888, 8,3896, 8, 648, 0, 0,3904, 8,3912,3920, - 8, 8, 8,3928, 8,3936, 8,3944, 8,3952,3960, 0, 0, 0, 0, 0, - 8, 8, 8, 8, 160, 0, 0, 0, 72, 72, 72,3968, 40, 40, 40,3976, - 8, 8,3984, 80,3992, 72,4000, 40,4008, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 88,4016, 8, 8,4024, 656,4032,4040, 0,4048, - 8, 648,4056, 8, 472,4064, 0, 8,4072, 0, 0, 8,4080, 0, 8, 200, - 4088, 8, 8,4096,4104, 632,4112,4120, 336, 8, 8,4128,4136, 8, 160, 80, - 4144, 8,4152,4160,4168, 8, 8,4176, 336, 8, 8,4184,4192,4200, 384,4208, - 8, 488, 664,4216,4224, 0, 0, 0,4232,4240,4248, 8, 8,4256,4264, 80, - 4272, 240, 128,4280,4288,4296,4304,4312,4320, 8, 8,4328,4336,4344,4352, 0, - 8, 8, 8,4360,4368,4376, 656, 0, 8, 8, 8,4384,4392, 80, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 672,4400,4408,4416, 0, 0, - 8, 8, 8,4424,4432, 80,4440, 0, 8, 8,4448,4456, 80, 288,4464, 0, - 8,4472,4480,4488, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 664,4496, 0, 0, 0, 0, 0, 0, 72, 72, 40, 40, 320,4504, - 4512,4520, 8,4528,4536, 80, 0, 0, 0, 0,4544, 8, 8,4552,4560, 0, - 4568, 8, 8,4576,4584,4592, 8, 8,4600,4608,4616, 8, 8, 8, 8, 160, - 4624, 0, 0, 0, 0, 0,4632, 0, 0, 0, 0, 0, 8, 8,4640, 80, - 128, 8, 672,4648,4656, 320, 528,4664, 8,4672,4680,4688, 0, 0, 0, 0, - 4696, 8, 8,4704,4712, 80,4720, 8,4728,4736, 80, 8, 8,4744, 80, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,4752, - 4760, 256, 8,4768,4776,4784, 0, 0, 0, 0, 0, 248, 88,4792,4800,4808, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 192, 0, 0, 0, 0, 0, 0, - 104, 104, 104, 104, 104, 104,4816,4824, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8,4832, - 8, 8, 8, 136,4840,4848, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 176, - 8, 8, 8, 8, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 680,4856, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 8, 160, 8, 120, 360, 8, 8, 8, 8, 120, 80, 8, 112,4864, - 8, 8, 8,4872,4880,4888,4896,4904, 8, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,4912, 8,4920, 80, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 72, 72, 40, 40, 88,4928, 72,4936, 40,4944, 0, 0, - 8, 8, 8, 8,4952,4960, 688, 688,4968,4976, 0, 0, 0, 0,4984,4992, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 328, 0,5000, - 8, 120, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 696, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5008, - 8, 8, 696,5016, 0,5024,5032, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 184, - 8, 8, 8, 8, 8, 8, 176, 152, 160,5040,5048, 0, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5056, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5064, 24, 376, 24,5072, - 64, 64, 544, 64, 704, 24, 24, 24, 24, 24, 24, 24, 352, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 272, - 24, 24,5080, 24, 24, 24,5088,5096,5104, 24,5112, 24, 24, 24, 576, 0, - 24, 24, 24, 24,5120, 0, 0, 0, 0, 0, 0, 0, 88, 712, 88, 712, - 24, 24, 24, 24, 24, 608, 88, 640, 0, 0, 0, 0, 0, 0, 0, 0, - 72, 296, 40, 720, 728,5128, 168, 72, 392,5136,5144,5152,5160, 72, 296, 40, - 5168,5176, 40,5184,5192,5200, 736, 72, 744, 40, 72, 296, 40, 720, 728, 40, - 168, 72, 392, 736, 72, 744, 40, 72, 296, 40,5208, 72,5216,5224,5232,5240, - 40,5248, 72,5256,5264,5272,5280, 40,5288, 72,5296, 40,5304, 288, 288, 288, - 64, 64, 64,5312, 64, 64,5320,5328,5336,5344, 464, 0, 0, 0, 0, 0, - 5352,5360,5368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5376,5384,5392, 96, 96, 96,5400, 0,5408, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 152,5416,5424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5432, 0, 8, 8,5440,5448, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5456, 80, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 680,5464, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120,5472,5480, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5488, 120, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,5496, 704, 0, 0, - 72, 72, 392, 40,5504, 360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 384, 88, 88,5512,5520, 0, 0, 0, 0, - 384, 88,5528,5536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5544, 8,5552,5560,5568,5576,5584,5592,5600, 184,5608, 184, 0, 0, 0,5616, - 24, 24, 216, 24, 24, 24, 24, 24, 24, 352, 584, 400, 400, 400, 24, 272, - 5624, 24, 24, 24, 24, 24, 24, 24, 24, 24, 408, 0, 0, 0,5632, 24, - 5640, 24, 24, 216, 752, 760, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5648, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5656, 280, 280, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 264, 216, 376, - 216, 24, 24, 24, 416, 264, 24, 24, 416, 24, 408, 216, 760,5664, 0, 0, - 24, 24, 24, 24, 24, 416, 408, 280,5672, 24, 24, 24,5680,5688,5696, 752, - 24, 24, 24, 24, 24, 24, 24, 24, 24,5704, 24, 24, 24, 24, 24,5712, + 8,2960, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 168, 24, 24, 24, 608, 8, 8, 560, + 2968, 8,2976, 0, 64, 64,2984,2992, 64,3000, 8, 8, 8, 8,3008,3016, + 448,3024,3032, 616, 64, 64, 64,3040,3048,3056,3064,3072,3080,3088,3096,3104, + 3112, 8,3120,3128, 8, 8, 8,3136,3144, 8, 8,3152,3160, 88, 48,3168, + 240, 8,3176, 8,3184,3192, 8, 168, 480, 8, 8,3200,3208, 368,3216,3224, + 8, 8,3232,3240,3248,3256, 8,3264, 8, 8, 8,3272,3280,3288,3296,3304, + 3312,3320, 224, 40, 40,3328,3336, 40, 40, 40, 40, 40, 8, 8,3344, 88, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 376, 8,3352, 8, 8, 200, + 8, 8, 8, 8, 8, 8, 120, 8, 8, 8, 8, 8, 8, 208, 0, 0, + 624,3360,3368,3376,3384, 8, 8, 8, 8, 8, 8,3392,3400,3408, 8, 8, + 8, 8, 8,3416, 24, 8, 8, 8, 8,3424, 8, 8,3432, 0, 0,3440, + 48,3448, 48,3456,3464,3472,3480,3488, 8, 8, 8, 8, 8, 8, 8,3496, + 3504, 416, 424, 432, 440,3512,3520,3528, 8,3536, 8, 112,3544,3552,3560,3568, + 3576, 8, 520,3584, 120, 120, 0, 0, 8, 8, 8, 8, 8, 8, 8, 152, + 3592, 96, 96,3600, 80, 80, 80,3608,3616, 272,3624, 0, 0, 24, 24,3632, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 168, 8, 8, 8, 192,3640,3648, + 8, 8,3656, 8,3664, 8, 8,3672, 8,3680, 8, 8,3688,3696, 0, 0, + 72, 72,3704, 40, 40, 8, 8, 8, 8, 120, 88, 72, 72,3712, 40,3720, + 8, 8, 632, 8, 8, 8,3728, 640, 640,3736,3744,3752, 8, 8, 8, 376, + 8, 8, 8, 216, 8, 544, 632, 0,3760, 104, 104,3768, 0, 0, 0, 0, + 3776, 8, 8,3784, 8,3792, 8,3800, 8, 112,3808, 0, 0, 0, 8,3816, + 8,3824, 8,3832, 8, 208, 0, 0, 8, 8, 8,3840, 96, 648, 96, 96, + 3848,3856, 8,3864, 656,3872, 8,3880, 8, 664, 0, 0,3888, 8,3896,3904, + 8, 8, 8,3912, 8,3920, 8,3928, 8,3936,3944, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 136, 0, 0, 0, 72, 72, 72,3952, 40, 40, 40,3960, + 8, 8,3968, 88,3976, 72,3984, 40,3992, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 96,4000, 8, 8,4008, 280,4016,4024, 112, 48, + 8, 664,4032, 8, 464,4040, 0, 8,4048, 0, 0, 8,4056, 0, 8, 216, + 4064, 8, 8,4072,4080, 648,4088,4096, 336, 8, 8,4104,4112, 8, 136, 88, + 4120, 8,4128,4136,4144, 8, 8,4152, 336, 8, 8,4160,4168,4176, 384,4184, + 8, 488, 672,4192,4200, 0, 0, 0,4208,4216,4224, 8, 8,4232,4240, 88, + 4248, 248, 128,4256,4264,4272,4280,4288,4296, 8, 8,4304,4312,4320,4328, 0, + 8, 8, 8,4336,4344,4352, 280, 0, 8, 8, 8,4360,4368, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 680,4376,4384,4392, 0, 0, + 8, 8, 8,4400,4408, 88,4416, 0, 8, 8,4424,4432, 88, 288,4440, 0, + 8,4448,4456,4464, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 672,4472, 0, 0, 0, 0, 0, 0, 72, 72, 40, 40, 320,4480, + 4488,4496, 8,4504,4512, 88, 0, 0, 0, 0,4520, 8, 8,4528,4536, 0, + 4544, 8, 8,4552,4560,4568, 8, 8,4576,4584,4592, 8, 8, 8, 8, 136, + 4600, 0, 0, 0, 0, 0,4608, 0, 0, 0, 0, 0, 8, 8,4616, 88, + 128, 8, 680,4624,4632, 320, 528,4640, 8,4648,4656,4664, 0, 0, 0, 0, + 4672, 8, 8,4680,4688, 88,4696, 8,4704,4712, 88, 8, 8,4720, 88, 472, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,4728, + 4736, 256, 8,4744,4752,4760, 0, 0, 0, 0, 0, 192, 96,4768,4776,4784, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 208, 0, 0, 0, 0, 0, 0, + 80, 80, 80, 80, 80, 80, 80,4792, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 376, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80,4800, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8,4808, + 8, 8, 8, 144,4816,4824, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 152, + 8, 8, 8, 8, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 688,4832, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 136, 8, 112, 368, 8, 8, 8, 8, 112, 88, 8, 120,4840, + 8, 8, 8,4848,4856,4864,4872,4880, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,4888, 8,4896, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 72, 72, 40, 40, 96,4904, 72,4912, 40,4920, 0, 0, + 8, 8, 8, 8,4928,4936, 696, 696,4944,4952, 0, 0, 0, 0,4960,4968, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 152, 0,4976, + 8, 8, 192, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 704, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 280, 8, 8, 8, 704, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,4984, + 8, 8, 136,4992, 0,5000,5008, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 200, + 8, 8, 8, 8, 8, 8, 152, 168, 136,5016,5024, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5032, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5040, 24,5048, 24,5056, + 48, 48,5064, 48, 712, 24, 24, 24, 24, 24, 24, 24, 352, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 264, + 24, 24,5072, 24, 24, 24,5080,5088,5096, 24,5104, 24, 24, 24, 24, 24, + 24, 24, 24, 24,5112,5120, 24, 24,5128, 0, 0, 0, 96, 720, 96, 720, + 24, 24, 24, 24, 24, 608, 96, 656, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 296, 40, 728, 736,5136, 176, 72, 392,5144,5152,5160,5168, 72, 296, 40, + 5176,5184, 40,5192,5200,5208, 744, 72, 752, 40, 72, 296, 40, 728, 736, 40, + 176, 72, 392, 744, 72, 752, 40, 72, 296, 40,5216, 72,5224,5232,5240,5248, + 40,5256, 72,5264,5272,5280,5288, 40,5296, 72,5304, 40,5312, 288, 288, 288, + 48, 48, 48,5320, 48, 48,5328,5336,5344,5352, 456, 0, 0, 0, 0, 0, + 56,5360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5368, 40, 40, 40,5376,5384,5392, 616, 280, 624, 0, 0,5400, 104, 104, 104, + 5408,5416,5424, 104, 104, 104,5432, 0,5440, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 168,5448,5456, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5464, 0, 8, 8,5472,5480, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5488, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 688,5496, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 112,5504,5512, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5520, 112, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,5528, 712, 0, 0, + 72, 72, 392, 40,5536, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 384, 96, 96,5544,5552, 0, 0, 0, 0, + 384, 96,5560,5568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5576, 8,5584,5592,5600,5608,5616,5624,5632, 200,5640, 200, 0, 0, 0,5648, + 24, 24, 184, 24, 24, 24, 24, 24, 24, 352, 360, 400, 400, 400, 24, 264, + 5656, 24, 24, 24, 24, 24, 24, 24, 24, 24, 360, 0, 0, 0,5664, 24, + 5672, 24, 24, 184,5680, 760, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5688, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5696, 272, 272, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 184, 184, 24, + 184, 24, 24, 24, 408, 328, 24, 24, 408, 24, 768, 184, 760,5704, 0, 0, + 24, 24, 24, 24, 24, 408, 768, 272, 24, 24, 24, 24,5712,5720,5728, 584, + 24, 24, 24, 24, 24, 24, 24, 24, 24,5736, 24, 24, 24, 24, 24,5744, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 8, 112, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 112, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 248, 8, - 8, 8, 8, 8, 8, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 8, 8, 8, 176, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 192, 0, 0, 0, 0, 0, 0, 0, 0, - 5720, 0, 136, 136, 136, 136, 136, 136, 0, 0, 0, 0, 0, 0, 0, 0, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,5728, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 120, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 192, 8, + 8, 8, 8, 8, 8, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 152, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 208, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5752, 0, 144, 144, 144, 144, 144, 144, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,5760, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, - 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, - 20, 20, 20, 20, 20, 20, 20, 20, 12, 12, 12, 12, 12, 12, 12, 12, - 24, 24, 24, 24, 24, 24, 24, 24, 28, 28, 28, 28, 28, 28, 28, 28, - 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 48, 48, 48, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, - 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 36, - 64, 64, 64, 64, 64, 64, 64, 64, 92, 92, 92, 92, 92, 92, 92, 92, - 84, 84, 84, 84, 84, 84, 84, 84, 80, 80, 80, 80, 80, 80, 80, 80, - 68, 68, 68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, - 12, 12, 12, 12, 228, 232, 228, 232, 12, 12, 468, 468, 32, 472, 32, 472, - 32, 32, 32, 692, 12, 12, 696, 12, 56, 56, 56, 56, 56, 56, 56, 700, - 704, 72, 708, 72, 72, 72, 712, 72, 60, 60, 60, 60, 60, 60, 60, 60, - 716, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 720, 308, 724, 308, 308, - 728, 732, 236, 236, 736, 236, 740, 744, 748, 752, 36, 36, 756, 760, 36, 764, - 36, 36, 36, 36, 36, 768, 36, 36, 772, 312, 312, 312, 776, 36, 36, 36, - 316, 316, 316, 780, 320, 320, 320, 784, 476, 476, 788, 792, 796, 800, 804, 36, - 36, 808, 36, 36, 36, 36, 812, 36, 112, 112, 112, 112, 112, 816, 820, 112, - 824, 828, 832, 836, 840, 844, 848, 852, 856, 860, 864, 868, 872, 876, 880, 884, - 888, 892, 896, 900, 904, 908, 912, 916, 920, 924, 928, 932, 936, 940, 944, 948, - 952, 956, 960, 964, 968, 972, 976, 980, 984, 988, 992, 996,1000,1004,1008,1012, - 1016,1020,1024,1028,1032,1036,1040,1044,1048,1052, 324, 324,1056,1060,1064, 324, - 1068,1072,1076,1080,1084,1088,1092,1096,1100, 328, 328,1104, 328,1108, 0, 0, - 1112,1116,1120,1124,1128,1132, 0, 0, 128, 128, 128, 128, 480, 128,1136,1140, - 128, 480, 128, 484, 484,1144, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 116, 116, 488, 116, 116,1148, 88, 88, 88, 88, 492,1152, 88, 88, - 492, 88, 88,1156, 496,1160, 88, 88, 88, 496, 88, 88, 88,1164, 88,1168, - 88,1172, 108, 108, 108, 108, 108,1176,1180,1184, 240, 240, 240, 240,1188,1192, - 1196,1200,1204,1208,1212,1216,1220,1224, 132, 132, 132, 132, 132,1228, 500, 500, - 1232,1236, 136, 136, 136, 136, 136,1240, 136, 136,1244, 40, 40, 40, 40,1248, - 1252,1256, 504, 504,1260,1264,1268,1272, 332, 332,1276, 332,1280,1284, 132, 132, - 1288,1292, 244, 244, 244,1296, 244,1300, 508, 508,1304, 56, 56, 512,1308, 0, - 140, 140, 140, 140,1312, 140, 140, 140, 248, 248, 248, 248, 336, 336, 336,1316, - 340, 340, 340,1320,1324, 344, 344, 344,1328, 116, 116,1332,1336,1340,1344,1348, - 32, 32,1352, 32, 32,1356,1360,1364, 32, 32, 32,1368, 56, 56, 56, 56, - 72, 516, 72, 72, 516,1372, 72,1376, 72, 72, 72, 520, 520,1380, 72,1384, - 1388, 12, 12, 12, 12, 12, 524,1392, 528, 532, 12, 12, 348, 56, 56,1396, - 12, 12,1400,1404,1408, 12, 32, 32,1412, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 176, 0, 352, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12,1416, - 148, 148, 148, 148, 148, 148, 32, 32, 144, 144, 144, 144, 144, 144, 144,1420, - 116, 116, 488, 356, 356, 356,1424,1428, 88,1432, 180, 180, 180, 180, 60, 60, - 12, 12, 12, 12, 12, 184, 0, 0, 4,1436, 4, 4, 4, 4, 4,1440, - 4, 4, 4, 4, 4,1444, 0, 12,1448, 12,1452,1456,1460, 76, 76, 76, - 76,1464, 536, 100, 100, 100, 100,1468,1472, 252, 252,1476, 8, 8, 8, 8, - 360, 12, 252, 252, 12, 12,1480, 100, 8, 360, 12, 12, 12, 12, 8,1484, - 12, 12, 12, 12, 12, 100, 100,1488, 100, 100, 100, 100, 100,1492, 12, 12, - 4, 4, 4, 4, 12, 12, 12, 12,1496, 24, 24, 24,1500, 364, 364, 364, - 84, 84,1504, 0, 60, 60, 60, 60, 60, 60, 44, 44, 44, 44, 44,1508, - 12, 12,1512, 32, 32, 32, 32, 32,1516, 32, 32, 32, 32, 532, 0,1520, - 540, 540,1524, 176, 368, 368, 368,1528, 256, 256, 256, 256,1532,1536, 112, 112, - 544, 544,1540, 548, 548,1544, 8,1548, 260, 260, 260, 260,1552,1556, 96,1560, - 372, 372, 372,1564,1568,1572, 96, 96, 264, 264, 264, 264,1576,1580, 376,1584, - 1588,1592, 180, 32, 32,1596,1600, 108, 108, 108, 108, 108, 376, 376,1604,1608, - 8, 8,1612, 8,1616, 8, 8,1620, 4, 4, 4, 4, 4, 4, 188, 4, - 4, 4, 4, 4, 4, 552, 0, 0,1624,1628, 236,1632,1636, 36, 36, 36, - 36, 36, 36,1640, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 0, 36, - 56, 176,1644, 12, 12, 556,1648,1652, 36, 36, 36, 36, 36, 36, 36,1656, - 152, 12, 228, 232, 228, 232,1660, 536, 100,1664, 8, 360,1668,1672,1676,1680, - 1684, 120,1688,1692, 560, 560, 0, 0, 120, 120, 120, 120, 120, 120, 120,1696, - 1700, 12, 12,1704, 72, 72, 72, 72,1708, 192,1712, 0, 0, 12, 12,1716, - 1720,1724, 380, 380, 380,1728,1732, 156, 564, 564,1736,1740,1744, 568, 568,1748, - 1752,1756, 572, 572,1760,1764, 0, 0, 196, 196, 196, 196, 196, 384, 384, 384, - 1768,1772,1776, 388, 388,1780, 388,1784, 576, 576,1788, 392, 392, 392,1792, 580, - 580,1796,1800,1804, 396, 396, 396,1808, 80, 80, 80,1812, 80,1816,1820, 0, - 1824, 32, 32,1828, 0, 0, 0, 0,1832, 584, 584,1836,1840,1844, 588, 588, - 1848,1852,1856, 0, 0, 0,1860,1864,1868,1872,1876,1880,1884,1888, 0, 0, - 592, 592, 268,1892, 268,1896, 268, 268,1900,1904,1908,1912, 596, 596, 600, 600, - 604, 604, 0, 0, 608, 608,1916,1920, 400, 400, 400,1924,1928,1932,1936,1940, - 1944,1948,1952, 0, 0, 0, 0, 0, 272, 272, 272, 272,1956, 0, 0, 0, - 160, 160, 160,1960, 160, 160, 160,1964, 612, 612,1968,1972, 404, 404,1976, 404, - 1980, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36,1984, - 616, 616,1988,1992,1996,2000, 0,2004, 620, 620,2008, 624, 624,2012, 0,2016, - 2020, 0, 0,2024,2028, 0,2032,2036, 200, 200, 200, 200,2040,2044, 200,2048, - 276, 276, 276, 276,2052,2056,2060,2064, 408, 408, 408,2068,2072, 628, 628,2076, - 164, 164, 164, 164, 164, 164,2080,2084, 412,2088, 412, 412,2092, 0, 0, 0, - 2096,2100,2104, 416, 416, 416,2108,2112,2116,2120,2124,2128,2132,2136,2140,2144, - 2148, 632, 632,2152,2156,2160,2164, 0, 204, 204, 204, 204, 204,2168,2172, 0, - 280, 280, 280, 280,2176,2180, 0, 0, 284, 284, 284,2184, 284,2188, 0, 0, - 288, 288, 288, 288,2192,2196,2200, 0, 420, 420, 420, 636, 636, 96,2204, 0, - 640,2208,2212, 640,2216, 0, 0, 0, 424, 424, 424,2220, 0, 0, 0, 0, - 0, 0, 208, 208, 208, 208, 208,2224,2228,2232,2236,2240,2244,2248, 0, 0, - 0, 0, 644, 648, 648, 644,2252, 0, 292, 292, 292, 292,2256, 212, 212, 212, - 212, 212,2260, 40, 428, 428, 428,2264,2268, 0, 0, 0, 0, 0,2272, 0, - 0, 0, 0, 0, 652, 652,2276,2280,2284, 432, 432,2288,2292, 432,2296, 656, - 656,2300,2304,2308, 0, 0, 0, 0,2312, 660, 660,2316,2320,2324,2328,2332, - 2336,2340,2344, 664, 664,2348,2352, 0, 0, 0, 0, 0, 0, 0,2356,2360, - 436,2364, 436,2368, 436,2372, 0, 0, 0, 0, 0,2376, 440, 440, 440,2380, - 28,2384, 0, 0, 0, 0, 0, 0, 28, 28, 28, 28, 28, 28,2388,2392, - 28, 28, 28, 28,2396, 0, 0, 0, 0, 168, 168, 168, 168, 168, 168,2400, - 20, 20, 20, 20, 20,2404, 20, 20, 20, 20, 20, 20, 20, 20, 20,2408, - 52, 52, 52, 52,2412, 0, 0, 0, 444, 444, 444,2416, 0, 0, 0, 0, - 44, 44, 44,2420,2424,2428,2432, 296, 296, 296, 296,2436,2440,2444,2448,2452, - 216, 216, 216, 216,2456,2460,2464,2468, 216, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 448, 448, 448,2472, 0, 0, 0, 0, 220, 220, 220, 220, - 220,2476, 668,2480, 668,2484, 0, 0, 124, 124, 124, 124,2488, 124, 124, 124, - 2492, 124, 0, 0, 0, 0,2496,2500, 64, 64, 64, 64, 64,2504, 0,2508, - 16,2512, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16,2516, - 0, 0, 0, 0, 0, 0, 0,2520,2524, 76, 76, 76, 76, 76, 76, 76, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,2528,2532, 0,2536,2540, 68, - 68, 68, 68, 68, 68, 68, 68,2544, 172, 172, 172, 172, 172, 172,2548,2552, - 2556,2560, 224, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 12, 192, - 12, 12, 12,2564, 12, 452, 12, 452, 56, 56, 512, 56,2568, 12, 12, 12, - 12, 12, 12, 12, 224, 0, 0, 0, 12, 12, 12, 12, 12, 12, 12, 456, - 12, 12,2572, 12, 12, 12,2576,2580,2584, 12,2588, 12, 12, 12, 352, 0, - 72, 72, 72, 72,2592, 0, 0, 0, 0, 0, 0, 0, 12, 224, 12, 224, - 12, 12, 12, 12, 12,2596, 12, 300, 12, 12, 12, 12, 12, 524, 12, 12, - 12,2600,2604,2608,2612, 12, 12, 12,2616,2620, 12,2624,2628,2632, 12, 12, - 12, 12,2636, 12, 12, 12, 12, 12, 12, 12, 12, 12,2640, 12, 12, 12, - 2644,2648,2652, 0, 0, 0, 0, 0, 32,2656,2660, 0, 0, 0, 0, 0, - 2664,2668,2672, 60, 60, 60,2676, 0,2680, 0, 0, 0, 0, 0, 0, 0, - 672, 672,2684,2688,2692, 0, 0, 0, 0,2696,2700, 0, 460, 460, 460,2704, - 0, 0, 0, 0, 0, 676, 676,2708, 0, 0, 0, 0, 0, 680, 680,2712, - 0, 0, 0, 0, 684,2716, 684,2720, 0, 0, 0, 0, 0, 0,2724,2728, - 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,2732,2736, 0, 0, - 304, 304, 304, 304,2740,2744, 0, 0, 0, 0, 0, 0, 0, 0, 0, 152, - 12, 12, 12,2748, 0, 0, 0, 0, 152, 12, 12, 184, 0, 0, 0, 0, - 2752, 36,2756,2760,2764,2768,2772,2776,2780, 688,2784, 688, 0, 0, 0,2788, - 12, 12, 156, 12, 12, 12, 12, 12, 12, 224, 528, 152, 152, 152, 12, 456, - 12, 12, 184, 0, 0, 0,2792, 12,2796, 12, 12, 156, 300, 348, 456, 0, - 12, 12, 12, 12, 12,2800, 192, 192, 12, 12, 12, 12, 12, 176, 156, 452, - 156, 12, 12, 12, 464, 176, 12, 12, 464, 12, 184, 156, 348, 300, 0, 0, - 12, 12, 12, 12, 12, 464, 184, 192,2804, 12, 12, 12,2808,2812,2816, 300, - 12, 556, 12, 12, 12, 12, 12, 352, 4, 4, 4, 4, 4, 4, 0, 0, - 4, 188, 4, 4, 4, 4, 4, 4, 4, 4, 188, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4,2820, 4, 4, 4, 4, 4, 4, 188, 0, 0, - 4, 188, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,2824, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 552,2828, 0, 12, 12, 12, 12, 12, 12, - 0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, - 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36, 32, 32, 32, 32, - 24, 24, 24, 24, 28, 28, 28, 28, 40, 40, 40, 40, 48, 48, 48, 48, - 44, 44, 44, 44, 56, 56, 56, 56, 52, 52, 52, 52, 60, 60, 60, 60, - 64, 64, 64, 64, 76, 76, 76, 76, 68, 68, 68, 68, 80, 80, 80, 80, - 84, 84, 84, 84, 88, 88, 88, 88, 72, 72, 72, 72, 96, 96, 96, 96, - 100, 100, 100, 100, 92, 92, 92, 92, 104, 104, 104, 104, 116, 116, 116, 116, - 120, 120, 120, 120, 124, 124, 124, 124, 108, 108, 108, 108, 132, 132, 132, 132, - 112, 112, 112, 112, 136, 136, 136, 136, 128, 128, 128, 128, 148, 148, 148, 148, - 144, 144, 144, 144, 152, 152, 152, 152, 452, 12, 12, 12, 12, 12, 12, 0, - 180, 180, 180, 180, 176, 176, 176, 176, 184, 184, 184, 184, 140, 140, 140, 140, - 12, 12, 264, 0, 72, 232, 72, 232, 12, 12, 12, 264, 4, 4, 4, 600, - 12, 12, 12, 364, 240, 240, 240, 240, 168, 168, 168, 168, 188, 188, 188, 188, - 248, 248, 248, 248, 252, 252, 252, 252, 160, 160, 160, 160, 204, 204, 204, 204, - 12, 0, 0, 0, 764, 24, 24, 24, 24, 24, 628, 12, 164, 164, 164, 164, - 236, 236, 236, 236, 156, 156, 156, 156, 292, 292, 292, 292, 300, 300, 300, 300, - 268, 268, 268, 268, 208, 208, 208, 208, 324, 324, 324, 324, 192, 192, 192, 192, - 312, 312, 312, 312, 344, 344, 344, 344, 244, 244, 244, 244, 196, 196, 196, 196, - 276, 276, 276, 276, 316, 316, 316, 316, 212, 212, 212, 212, 12, 12, 364, 0, - 216, 216, 216, 216, 220, 220, 220, 220, 256, 256, 256, 256, 476, 476, 476, 476, - 396, 396, 396, 396, 172, 172, 172, 172, 228, 228, 228, 228, 260, 260, 260, 260, - 408, 408, 408, 408, 320, 320, 320, 320, 480, 480, 480, 480, 264, 0, 0, 0, - 12, 12, 296, 0, 412, 412, 412, 412, 8, 8, 8, 812, 484, 484, 484, 484, - 416, 416, 416, 416, 272, 272, 272, 272, 304, 304, 304, 304, 488, 488, 488, 488, - 496, 496, 496, 496, 308, 308, 308, 308, 456, 456, 456, 456, 460, 460, 460, 460, - 420, 420, 420, 420, 368, 368, 368, 368, 328, 328, 328, 328, 372, 372, 372, 372, - 348, 348, 348, 348, 352, 352, 352, 352, 380, 380, 380, 380, 432, 432, 432, 432, - 200, 200, 200, 200, 280, 280, 280, 280, 284, 284, 284, 284, 436, 436, 436, 436, - 440, 440, 440, 440, 364, 0, 0, 0, 12, 264, 0, 0, 444, 444, 444, 444, - 12, 12, 0, 0, 12, 12, 768, 12, 24, 628, 24, 24, 400, 400, 400, 400, - 112, 112, 892, 112, 112, 112, 112,1048, 124,1052, 0,1056, 72, 72, 684, 636, - 684, 636, 72, 72, 136, 136, 900, 0, 340, 340, 340, 0, 156, 156, 904, 0, - 52, 52, 52,1072, 68, 688, 68, 688, 68, 772, 68, 68, 12, 648, 12, 12, - 12, 12, 12, 296, 24, 24, 24,1092, 916, 92, 92, 92, 520, 520, 520, 520, - 524, 524, 524, 524, 572, 572, 572, 572, 4, 4, 600, 0, 296, 12, 12, 12, - 108, 108, 108,1132, 576, 576, 576, 576, 536, 536, 536, 536, 492, 492, 492, 492, - 540, 540, 540, 540, 500, 500, 924, 500, 528, 528, 528, 528, 604, 604, 604, 604, - 608, 608, 608, 608, 464, 464,1144, 0, 612, 612, 612, 612, 616, 616, 616, 616, - 532, 532, 532, 532, 504, 504, 504, 504, 544, 544, 544, 544, 548, 548, 548, 548, - 552, 552, 552, 552, 588, 588, 588, 588, 376, 376, 376, 376, 352, 352,1188, 0, - 424, 424, 424, 424, 384, 384,1200, 384, 384, 384, 384, 384, 556, 556, 556, 556, - 388, 388, 388, 388, 392, 392, 392, 392, 472, 472, 472, 472, 512, 512, 512, 512, - 356, 356, 356, 356, 560, 560, 560, 560, 564, 564, 564, 564, 516, 516, 516, 516, - 28, 28, 28, 0, 24, 24, 840, 12, 24, 840,1264, 12, 68,1268, 844,1272, - 0,1276, 848, 772,1280, 68, 68, 68,1284, 144, 144, 144, 60,1288, 60, 60, - 852, 220, 220, 220, 220, 952, 852, 220, 220, 220, 952, 852, 956, 164, 164, 164, - 164, 164, 0, 0, 164, 164, 960,1292, 164,1296, 0, 0, 28, 964, 28, 968, - 28, 28, 972, 972, 968, 28,1300, 52, 52,1304, 28, 28,1308, 28, 28, 28, - 28, 28, 28, 964, 256, 256, 256,1312, 256, 256, 976,1316,1320, 0, 0, 0, - 396, 396,1324,1328, 400, 400, 400,1332, 400, 400, 400,1336, 632, 632, 632, 632, - 632, 632, 632,1340, 256, 256, 976, 0, 980, 984, 28, 28,1344, 28, 28, 28, - 1348,1352, 120, 120, 120,1356, 120, 120, 332,1360, 332, 776, 776, 332, 332, 332, - 332, 332,1364, 332,1368, 988,1372, 332, 332, 776, 776, 992, 0,1376, 0,1380, - 332, 988, 332, 332, 332, 332, 332, 992, 856, 856, 860, 996,1000, 568, 568, 568, - 568, 568, 864, 568, 864,1384,1004, 864, 860, 996,1000,1004,1388, 0, 856,1392, - 0,1396, 568, 568, 568, 860, 0, 0, 780, 780, 448, 784, 784, 448, 448, 448, - 448, 448,1008, 448,1008, 780, 868, 448, 448, 784, 784, 868,1400, 0, 0, 0, - 448,1404, 448, 448, 868, 0, 780, 448, 788, 788, 404, 792, 792, 404, 404, 404, - 404, 404,1012, 404,1012, 788,1016, 404, 404, 792, 792,1016, 0, 788, 0,1408, - 404,1412, 404, 404, 404, 404, 0, 0, 680,1416, 796, 680, 872, 800,1420, 872, - 876,1020, 796, 680, 284, 284, 800, 680, 796, 680, 872, 800,1020, 876, 0, 0, - 0, 680, 284, 284, 284, 284, 796, 0, 288, 288, 288, 728, 728, 288, 288, 288, - 288, 288, 728, 288, 288, 288, 880, 288, 288, 728, 728, 880, 0,1424,1428, 880, - 288,1432, 288, 288, 0,1436, 288, 288, 360, 360, 360, 732, 732, 360, 360, 360, - 360, 360, 732, 360, 360,1024,1028, 360, 360, 732, 732,1028, 0,1440, 0,1444, - 360,1448, 360, 360,1024, 0, 0, 0, 172, 172, 172, 804, 804, 172, 172, 172, - 172, 804, 804, 172, 0, 172, 172, 172, 172,1452, 172, 172, 884, 884, 224, 224, - 224,1032, 888, 224, 224, 224, 224, 224,1456, 224, 224,1460, 224,1032,1464,1468, - 224,1472, 224, 224, 0, 888, 224, 224, 888,1036, 0, 0,1476, 228, 228, 228, - 228, 228,1480, 736, 228, 228, 228, 0,1484,1488,1040, 336, 336, 336, 336, 336, - 336,1492, 336, 336, 336, 336, 336,1044, 336,1496, 336,1040, 336, 336,1044, 336, - 112, 112, 112,1500, 892, 112, 112, 112, 112,1504,1508, 0, 124, 124,1512, 124, - 72, 232, 684, 636, 684, 636, 72, 232, 72, 232, 72, 72, 72, 72, 232, 808, - 72, 72, 72,1516, 72, 72, 636, 0, 116,1060, 116,1060, 640, 640, 640, 640, - 640, 640, 640,1520, 236, 236,1524,1528, 236, 236,1532, 0, 740, 740, 740, 740, - 740,1536, 0,1540, 744, 744, 744, 744, 744,1544, 0, 0, 748, 748, 748, 748, - 748, 0, 0, 0, 896, 896, 896,1064,1064, 0, 0, 0, 136, 136, 136, 900, - 1548,1552, 128, 128, 128, 128,1556, 0, 128, 128,1068, 0, 128, 128,1560, 0, - 40,1564, 0, 0, 340, 340, 340, 340, 340, 340, 340,1568,1572, 340, 340, 340, - 596, 596, 596, 596, 596, 596, 596,1576, 596,1580, 0, 0, 260, 260, 260, 0, - 260, 260,1584, 0, 260, 260,1588,1592, 644, 644, 644, 644, 644, 644, 644,1596, - 156, 156, 156,1600, 156, 156, 156,1604, 156, 156, 156, 904, 52, 52, 52, 0, - 148, 148, 148,1608, 408, 0, 0, 408, 320, 320,1612, 320, 320, 320,1616,1620, - 60, 60,1624, 0, 124, 124,1628,1632, 292, 292, 0, 0,1076, 52, 52, 52, - 1636, 52, 908,1640, 12, 908,1644, 0, 24,1080,1648, 24, 24, 24, 24,1652, - 1656,1080,1660, 24, 24, 24,1664, 24, 24, 24, 24,1668, 68, 68,1084,1084, - 68, 68, 68, 688, 68, 844, 68,1672, 844, 772, 68, 848, 12, 12, 12, 912, - 1676, 12, 12,1088,1680, 0, 0, 0, 12,1684,1096, 12, 768, 12, 12, 12, - 12, 12, 12, 768, 24, 24, 840, 0, 12, 692, 12, 12, 144, 0,1688, 144, - 412, 412, 0,1100,1692, 0, 0,1100, 72, 232, 0, 0, 4, 4,1696, 4, - 4, 0, 0, 0, 4, 600, 0, 0, 12,1700, 12, 12,1704, 4,1708,1712, - 12, 12, 4, 12,1716, 80, 80, 80, 80,1104,1720,1724, 92, 92,1108, 916, - 0,1728, 300, 300,1732, 8, 8, 8, 12, 264, 0, 736, 8, 8, 8,1736, - 92, 92, 92,1108, 92, 92, 12, 12, 36, 36, 36,1740, 36,1744, 0, 0, - 88, 88, 88, 0, 48, 48, 0, 0,1096, 24, 24, 24, 24, 24,1088, 24, - 1112, 24, 24, 24, 520, 520, 520,1748, 416, 416, 0, 0, 268,1116, 0,1752, - 268, 268,1116, 0, 524, 524, 524,1756, 572, 0, 0,1760, 8, 8, 8,1120, - 208, 208, 208,1764, 208, 208,1768,1772, 100, 100, 100,1776, 272,1780, 0, 0, - 272, 272, 272,1124, 272, 272,1124, 272,1784, 0, 0, 0, 0, 0,1788, 324, - 304,1792, 0, 0, 808, 232, 808, 232, 808, 232, 0, 0, 24, 24, 628, 24, - 24,1796,1800, 0, 304, 304, 304,1128, 304, 304,1128, 0, 8, 0, 0, 0, - 8, 812,1804, 8, 8, 8, 8, 0, 24, 816, 0, 0,1808, 220, 0, 956, - 164, 960, 164,1812,1816,1820, 164, 164, 28, 28, 28,1824, 52, 52, 52,1828, - 12, 296, 12, 0, 28,1832, 28, 28, 28, 28, 28,1836, 12,1840, 92, 92, - 92, 92, 92,1844, 820, 8, 820, 8, 820, 8, 820,1120, 12, 296, 12, 296, - 0, 0, 452, 264, 108, 108, 108,1848, 108, 920, 108, 108, 108, 108, 920,1852, - 108, 108, 920, 0, 296, 736, 12, 12, 12, 736, 12, 12, 68, 68, 68, 848, - 1856, 0, 0, 0, 12, 12, 12,1860, 652, 652, 652, 652, 652, 652, 652,1864, - 1868, 0, 0, 0, 908, 12, 12, 12, 576, 0, 0,1872, 696, 696, 696, 696, - 696, 696,1876, 0, 536, 536,1880, 0, 656, 656, 656, 656, 656, 656, 656,1884, - 492, 0, 492, 492, 492,1888, 0, 0, 580, 580, 580, 580, 580, 580, 580,1136, - 580, 580,1136, 0, 308, 0, 308, 308, 308, 308, 308, 0, 540, 540, 0, 0, - 456, 0, 0,1892, 924, 824, 500, 500, 824, 500, 500, 500, 824, 500, 824,1896, - 460, 0, 0, 0, 84,1900, 0, 0, 84,1904, 0, 0, 84, 84, 0, 0, - 24,1908, 24, 24,1912, 24, 816, 0, 528,1916,1920, 528, 528,1924,1928,1932, - 660, 660, 660, 660, 660,1936, 660, 660, 584, 584, 584, 584, 584, 584, 584,1940, - 0,1944, 584, 584, 752, 752, 752, 752,1948,1952,1956, 752, 664, 664, 664, 664, - 664, 664, 664,1960, 700, 700, 700, 700, 700, 700,1964,1968, 704, 704, 704, 704, - 704, 704,1972, 0, 192, 192, 0, 192,1976, 192, 192, 192, 464,1980, 0, 464, - 464,1140,1140, 464, 464, 464, 464, 464, 464,1984,1988,1992, 532,1148,1996, 532, - 532,1148, 0, 0, 420,2000,2004, 420, 668, 668, 668, 668, 668,2008, 668, 668, - 708, 708, 708, 708,2012, 0, 708, 708, 756, 756, 756, 756,2016, 0,1152,2020, - 0, 0,1152, 756, 312, 312,2024, 0,1156, 0, 0, 0,1156, 0,2028, 180, - 504, 504, 0, 0, 504, 504,2032, 0, 368,1160,2036, 368, 368,1160, 0,2040, - 28, 28, 28, 828, 544, 544,2044,1164,1164, 0, 0, 0,1168, 28, 0, 0, - 28, 28,2048, 0, 0, 0,1168, 28, 548, 548, 0, 0, 552, 552,2052, 0, - 712, 712, 712, 712, 712, 712,2056, 0, 672, 672, 672, 672, 672, 672, 672, 0, - 760, 760, 760, 760, 760,2060, 0, 0, 168, 168, 168,1172,2064, 168, 168, 168, - 168,1172, 0,2068,2072, 0, 0,2076, 620, 620, 620, 620, 620, 620,2080, 0, - 620, 620,2084, 0, 328,2088, 328, 328, 328, 328, 0, 0, 588,2092, 0, 0, - 884, 224, 224, 224, 224,1036, 0, 0,2096, 372, 372, 372,2100, 0, 0, 0, - 716,2104,2108,1176, 716, 716, 716,1176, 716, 716,2112, 0, 348, 348,2116, 0, - 348, 348,2120, 0, 468, 928, 468, 832, 832, 468, 468, 468, 468, 468,1180, 468, - 1180, 928,2124, 468, 468, 832, 832,2128, 932,2132, 0, 928, 468,2136, 468, 932, - 468, 932, 0, 0, 376, 376, 936,2140, 376, 936, 376, 376,2144,2148,2152, 376, - 376, 936,2156, 0,2160, 0, 0, 0, 188, 188, 188,2164,2168, 0, 0, 0, - 244, 244, 0, 0, 244, 244,2172, 0, 196,1184, 196, 196, 196, 196, 196,1184, - 276,2176, 0, 0, 276, 276,2180, 0, 128, 128, 128,1068, 100, 0, 0, 0, - 424, 424,1192,2184, 424, 424, 424, 0, 424,1192, 0, 0, 380, 380, 380, 0, - 2188, 0, 0,2192, 428,1196,2196, 428, 428,2200, 428, 428, 428, 428, 428, 428, - 428,2204,2208, 428, 428,1196, 0, 0, 428, 428,2212, 0, 384,2216, 0, 0, - 316, 316, 0, 0,2220, 0, 0, 0, 432, 432,2224, 0, 120, 120,2228, 0, - 176, 176, 0, 0,1204, 0, 0, 0, 556, 556,1204, 0, 200, 200,2232, 200, - 200,2236, 200, 200, 200,2240, 0, 0, 200, 200, 200,2244,2248, 388, 388, 388, - 388, 388,2252, 388, 388,2256, 0, 0, 392,1208,1212, 392, 392,1208,2260,1212, - 392, 392, 0, 0, 392, 392,2264, 0, 508,1216,2268, 508, 508, 508, 508, 508, - 508, 508, 508,2272,1216, 508,2276, 0, 508, 508,2280, 0, 472, 472, 472, 0, - 472, 472,2284, 0, 720, 720, 720, 720, 720, 720,2288, 0,2292, 280, 280, 280, - 280, 280,1220,2296, 280, 280,1220, 0,2300, 0, 0, 0, 800, 0, 0, 876, - 32, 32,2304, 0, 32, 32, 32,2308, 32,2312, 0, 0, 32, 0, 0, 0, - 2316, 0, 0, 0, 20,2320, 0, 0, 20, 20,2324, 0, 56,2328, 0, 0, - 436, 436,2332, 0, 48, 48,2336, 0, 592, 592, 592, 592, 592, 592, 592,2340, - 592, 592,2344,2348, 212, 212, 212,2352, 212, 212,2356, 0, 624, 624, 624, 624, - 624, 624, 624,1224, 624,1224, 0, 0, 160,2360, 0, 0, 160, 160,1228, 160, - 1228, 160, 160, 160, 160, 160, 0,2364, 440, 440,2368, 0, 204, 204,2372, 0, - 512, 512,2376, 512, 512, 0, 0, 0, 132, 132,2380,1232, 132, 132, 0,1232, - 2384,2388, 0, 0, 4,1236, 0, 0, 64,2392, 0, 0, 0, 0, 0,2396, - 16, 16, 16,1240,1240, 0, 0, 0, 92,2400, 92,2404,2408, 80, 80, 80, - 2412, 0, 0, 0,2416, 0, 0, 0,1104,2420, 0, 0, 0, 92, 0, 0, - 76, 76, 76, 0, 140, 140,2424, 0, 140, 140, 140,1244, 140, 140,1244, 0, - 140, 140,2428, 140, 12, 0, 692, 12, 52,2432, 0, 0, 12, 296, 452, 12, - 12,1248, 912, 12, 12, 12,1248, 52,1076,2436, 52, 12, 12, 12,2440, 912, - 68, 688, 0, 0, 12, 296, 0, 0, 12, 12, 12, 648,2444,2448, 452, 648, - 12, 12, 940, 452, 12, 452, 12, 12, 12, 940, 296, 452, 12, 648, 12, 648, - 12, 12, 940, 296, 12,2452, 692, 12, 648, 12, 12, 12, 12, 264, 12, 12, - 12, 12, 12, 692, 44, 44, 44, 0, 0, 0,2456, 44,2460, 44, 44, 44, - 24, 24, 24, 816, 0,1112, 816, 0, 152,1252, 152, 152, 152, 152,2464, 152, - 2468,2472,1252, 0, 60, 60, 60,2476, 0, 0, 0,2480, 356, 356, 356,2484, - 356, 356, 356,1256, 356, 356,1256,2488, 676, 676, 676, 676, 676, 676, 676,2492, - 444, 444,2496,2500, 560, 560,2504, 0, 564, 564,2508,2512, 516, 516, 516,2516, - 516,2520, 0,2524, 72, 232, 72,2528, 72, 72, 72, 232, 104,2532, 104, 104, - 104,2536, 0, 0, 216, 216, 216, 0, 216, 216,2540,2544, 12, 364, 0, 0, - 28, 724, 28, 28, 944, 948, 724, 28, 828, 28, 836, 0,2548, 984, 836, 724, - 944, 948, 836, 836, 944, 948, 828, 28, 828, 28, 724,2552, 28, 28,1260, 28, - 724, 724,1260, 28, 980, 0, 0, 0, 0, 692, 12, 12,2556, 0, 0, 0, - 12, 12, 364, 12, 12, 12, 296, 692, 12, 296, 364, 452, 12, 12, 12,2560, - 12, 12, 296, 736,2564, 0, 0, 0, 4, 4,1236, 0,2568, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, - 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040, - 1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126, - 1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226, - 1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944, - 1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973, - 1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993, - 1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, - 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0, - 1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, - 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077, - 1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096, - 1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236, - 1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323, - 1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, - 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951, - 1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062, - 1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, - 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113, - 1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, - 10,1425, 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, 1, 0, 0, 0, 0, - 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0, - 1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0, - 1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0, - 1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, - 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524, - 1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533, - 1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541, - 1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606, - 1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, - 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0, - 1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, - 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, - 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0, - 1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, - 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, - 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0, - 1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955, - 1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967, - 1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995, - 1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019, - 1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030, - 1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383, - 1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070, - 1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095, - 1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102, - 1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122, - 1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947, - 1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373, - 1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328, - 1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330, - 1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399, - 1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109, - 1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701, - 1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729, - 1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737, - 1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765, - 1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777, - 1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785, - 1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794, - 1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, - 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709, - 1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745, - 1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802, - 1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822, - 1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823, - 1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, - 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, - 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824, - 1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, - 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, - 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, - 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, - 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, - 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865, - 1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, - 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, - 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0, - 1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, - 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, - 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, - 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0, - 1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, - 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, - 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, - 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, - 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, - 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, - 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, - 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, - 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, - 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, - 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, - 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, - 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, - 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, - 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, - 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, - 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, - 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, - 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, - 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, - 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, - 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, - 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, - 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, - 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, - 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, - 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, - 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, - 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, - 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, - 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, - 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579, - 1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0, - 1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1936, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1938, 0,1939, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1940, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1943,1944, 0, 0, 0, 0, 0, 0, - 1945, 0,1946, 0, 0, 0, 0, 0, 0, 0, 0,1947, 0, 0,1948, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,1950, 0,1949,1951, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1953,1952, 0,1954, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,1955,1956, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1957, 0, 0, 0, 0, 0, 0, 0, 0,1958,1961, - 1959,1965,1960,1962,1964,1963, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1967,1966,1968, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1969,1970,1971,1972,1973, - 1974,1975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1976,1977,1978,1980,1979,1981, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, - 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, - 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, - 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, - 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, - 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, - 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, - 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, - 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, - 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, - 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, - 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, - 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, - 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, - 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, - 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, - 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, - 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, - 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, - 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, - 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, - 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, - 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, - 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, - 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, - 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, - 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, - 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, - 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, - 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, - 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, - 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, - 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, - 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, - 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, + 20, 20, 20, 20, 20, 20, 20, 20, 24, 24, 24, 24, 24, 24, 24, 24, + 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, + 28, 28, 28, 28, 28, 28, 28, 28, 40, 40, 40, 40, 40, 40, 40, 40, + 36, 36, 36, 36, 36, 36, 36, 36, 48, 48, 48, 48, 48, 48, 48, 48, + 60, 60, 60, 60, 60, 60, 60, 60, 56, 56, 56, 56, 56, 56, 56, 56, + 52, 52, 52, 52, 52, 52, 52, 52, 16, 16, 112, 112, 16, 324, 184, 184, + 36, 36, 36, 36, 36, 328, 16, 332, 64, 64, 64, 336, 340, 344, 96, 348, + 72, 72, 72, 72, 352, 72, 72, 72, 72, 356, 360, 364, 368, 372, 376, 380, + 384, 44, 388, 392, 44, 44, 396, 44, 400, 404, 408, 44, 412, 416, 420, 424, + 428, 432, 436, 440, 444, 44, 44, 448, 124, 124, 452, 456, 460, 464, 468, 472, + 476, 480, 484, 488, 492, 496, 500, 504, 508, 512, 516, 520, 524, 528, 532, 536, + 540, 544, 548, 552, 556, 560, 564, 568, 572, 576, 580, 584, 588, 592, 596, 600, + 604, 608, 612, 0, 616, 620, 624, 0, 188, 188, 628, 632, 636, 640, 644, 0, + 100, 100, 100, 100, 100, 192, 648, 652, 108, 108, 656, 108, 660, 664, 668, 108, + 672, 108, 676, 680, 684, 116, 116, 688, 48, 48, 48, 48, 692, 196, 196, 696, + 700, 704, 708, 712, 128, 128, 716, 720, 724, 132, 132, 728, 132, 732, 48, 736, + 740, 744, 748, 752, 756, 760, 764, 128, 768, 772, 776, 780, 784, 788, 64, 200, + 136, 136, 792, 136, 204, 204, 796, 800, 804, 808, 812, 816, 820, 824, 828, 832, + 36, 836, 840, 844, 36, 848, 64, 64, 852, 96, 856, 860, 96, 864, 868, 872, + 876, 16, 16, 880, 884, 16, 888, 200, 16, 892, 896, 36, 900, 16, 16, 16, + 16, 904, 908, 16, 16, 16, 16, 16, 92, 92, 92, 92, 92, 92, 92, 92, + 16, 16, 16, 912, 16, 16, 16, 16, 140, 140, 140, 36, 144, 144, 144, 916, + 192, 920, 924, 928, 932, 208, 208, 72, 16, 16, 148, 152, 936, 4, 4, 940, + 4, 4, 4, 4, 4, 4, 944, 212, 948, 952, 956, 80, 960, 964, 156, 968, + 972, 976, 8, 8, 980, 984, 16, 988, 216, 16, 16, 992, 16, 16, 996,1000, + 156, 156,1004, 16, 16, 16, 16, 16, 4, 4, 4, 4, 4, 4, 16, 16, + 32, 32, 32, 32,1008, 32,1012,1016, 84, 84, 84, 84, 84, 84, 84, 84, + 84,1020, 72, 72, 72, 56, 56,1024, 16,1028, 36, 36,1032, 36,1036,1040, + 1044,1048,1052,1056, 220, 220,1060, 124,1064,1068,1072,1076, 224, 224,1080,1084, + 1088,1092,1096, 100, 228, 228,1100,1104,1108,1112,1116,1120, 116, 116,1124,1128, + 8, 8, 8, 8, 8,1132,1136,1140, 4, 4, 4, 232, 4, 4, 236, 0, + 1144,1148,1152, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44,1156, 44, 44, 44, 44,1160,1164,1168,1172, 240,1176, 44, 44, 44,1180, + 244, 112, 112,1184,1188, 216,1192,1196,1200,1204,1208, 0, 160, 160, 160,1212, + 1216,1220, 96, 96,1224,1228, 212,1232, 0, 0, 0, 0,1236,1240,1244,1248, + 1252,1256,1260,1264,1268,1272,1276, 0, 248, 248,1280,1284,1288,1292,1296,1300, + 1304,1308,1312,1316,1320,1324,1328,1332, 88, 88, 88, 88, 88, 88, 88, 88, + 88,1336,1340,1344,1348,1352, 0, 0,1356,1360,1364,1368,1372,1376, 0,1380, + 1384,1388,1392, 0,1396,1400,1404,1408,1412,1416,1420,1424,1428, 0,1432,1436, + 1440,1444,1448,1452,1456,1460, 0, 0, 252, 252,1464, 0, 256,1468, 256,1472, + 1476,1480,1484,1488,1492, 0, 0, 0, 0, 0, 0,1496,1500,1504,1508,1512, + 1516,1520,1524,1528,1532,1536,1540,1544, 260, 260,1548,1552, 264, 264,1556,1560, + 1564,1568,1572,1576, 164, 164, 164,1580,1584,1588,1592, 0,1596,1600,1604,1608, + 1612,1616,1620,1624,1628,1632,1636,1640, 268, 268,1644,1648, 272, 272,1652, 0, + 0, 0, 0, 0,1656,1660,1664, 0, 276, 276,1668,1672,1676,1680,1684,1688, + 1692,1696,1700, 0, 0, 0, 0, 0,1704,1708, 0, 0, 0, 280, 280,1712, + 1716,1720,1724, 0, 0,1728,1732,1736, 284, 284,1740, 288, 288,1744,1748,1752, + 1756, 0, 0,1760, 0, 0,1764,1768,1772,1776,1780,1784,1788,1792, 0, 0, + 1796,1800,1804,1808,1812,1816,1820,1824, 0, 0, 0, 0, 0, 0, 0,1828, + 1832,1836,1840, 0, 0,1844,1848,1852, 28, 28, 28, 28,1856, 0, 0, 0, + 28, 28,1860, 28, 28,1864, 120, 120, 120, 120,1868, 28,1872, 0, 0, 0, + 0, 0, 0, 0,1876, 292, 292,1880, 24, 24,1884, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24,1888, 60, 60,1892, 0, 0, 0, 0, 0, + 1896,1900, 0, 0, 0, 0, 0, 0, 56,1904,1908,1912,1916,1920,1924,1928, + 296, 296,1932,1936,1940, 0, 0, 0, 0, 0,1944,1948, 0, 0, 0, 0, + 0, 0, 300, 300,1952,1956,1960, 0, 168, 168,1964, 168,1968, 0, 0,1972, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,1976,1980, + 20,1984, 0, 0, 20, 20, 20,1988, 40, 40, 40, 40,1992, 40,1996, 0, + 0, 0, 0, 0, 0, 0, 0,2000,2004, 80, 80, 80, 80, 80, 80, 80, + 80,2008,2012,2016, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,2020, + 172, 172, 172,2024,2028, 152, 0, 0, 16, 16, 16, 16, 16, 16, 16, 304, + 16, 16, 16, 16, 16,2032,2036, 148, 64,2040,2044, 16, 16, 16, 152, 0, + 16, 16, 16, 16, 16, 16, 16, 308, 16,2048, 16,2052,2056,2060, 16, 16, + 96, 96,2064, 16,2068, 0, 176, 176, 16, 16,2072,2076, 0, 0, 0, 0, + 16, 16,2080, 16,2084,2088,2092, 16,2096,2100,2104, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16,2108, 16, 16, 16, 16, 16, 16, 16, 16,2112, 16, + 52, 52, 52, 52,2116,2120, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, + 36, 36, 36, 36,2124, 0,2128,2132,2136,2140, 72,2144,2148, 0, 0, 0, + 2152,2156,2160, 0, 0, 0, 0, 0, 0, 0, 0, 0,2164,2168,2172,2176, + 0, 0, 0, 0, 0, 0,2180,2184, 0, 0, 0, 0, 0, 0,2188,2192, + 0, 0, 0, 0, 0, 0,2196,2200, 0, 0, 0, 0, 0, 0, 0,2204, + 104, 104, 104, 104, 104, 104,2208, 0, 312, 312,2212, 0, 0, 0, 0, 0, + 0, 0, 0,2216, 16,2220, 0, 0, 244, 148, 0, 0, 0, 0, 0, 0, + 2224,2228,2232,2236,2240,2244, 0,2248, 16, 180, 16, 16, 176,2252,2256, 308, + 16, 16, 16, 16, 16,2260, 0,2264,2268, 316,2272,2276, 0, 0, 0, 0, + 16, 16, 16, 16, 16, 16,2280,2284, 16, 16, 16, 16, 16, 16, 316, 180, + 180, 16,2288, 16,2292,2296,2300, 0, 16, 16,2304,2308, 16, 16,2312,2316, + 16, 16, 16, 16, 240, 16, 16,2320, 4, 4, 4, 4, 4, 4, 4, 0, + 2324, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 232, 4, 4, + 4, 4, 4, 4, 4, 4, 4,2328, 4, 4, 320, 0, 0, 0, 0, 0, + 320, 0, 0, 0, 0, 0, 0, 0, 4, 4,2332, 4, 4, 4, 4, 4, + 4, 4, 4, 236, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, + 2336, 16, 16, 16, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, + 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 16, 24, 24, 24, 24, + 32, 32, 32, 32, 40, 40, 40, 40, 48, 48, 48, 48, 64, 64, 64, 64, + 80, 80, 80, 80, 56, 56, 56, 56, 88, 88, 88, 88, 72, 72, 72, 72, + 96, 96, 96, 96, 112, 112, 112, 112, 104, 104, 104, 104, 128, 128, 128, 128, + 120, 120, 120, 120, 144, 144, 144, 144, 136, 136, 136, 136, 152, 152, 152, 152, + 168, 168, 168, 168, 192, 192, 192, 192, 184, 184, 184, 184, 208, 208, 208, 208, + 160, 160, 160, 160, 216, 216, 216, 216, 224, 224, 224, 224, 176, 176, 176, 176, + 1120, 56, 56,1128, 248, 248, 248, 248, 256, 256, 256, 256, 264, 264, 264, 264, + 296, 296, 296, 296, 272, 272, 272, 272, 328, 328, 328, 328, 344, 344, 344, 344, + 320, 320, 320, 320, 32, 32, 32, 560, 336, 0, 0, 0, 200, 200, 200, 200, + 232, 232, 232, 232, 360, 360, 360, 360, 288, 288, 288, 288, 312, 312, 312, 312, + 32, 32, 336, 0, 32, 336, 32, 32, 56, 56,1536, 56, 240, 240, 240, 240, + 280, 280, 280, 280, 440, 440, 440, 440, 120, 120,1728, 0, 552, 552, 552, 552, + 304, 304, 304, 304, 0, 0, 32, 32, 16, 16, 16,1160, 576, 576, 576, 576, + 448, 448, 448, 448, 648, 648, 648, 648, 8,1008, 8, 8, 8, 8, 8,1784, + 32, 32,1800, 32, 880, 32, 32, 32, 456, 456, 456, 456, 584, 584, 584, 584, + 384, 384, 384, 384, 392, 392, 392, 392, 680, 680, 680, 680, 408, 408, 408, 408, + 472, 472, 472, 472, 592, 592, 592, 592, 488, 488, 488, 488, 600, 600, 600, 600, + 496, 496, 496, 496, 400, 400, 400, 400, 368, 368, 368, 368, 416, 416, 416, 416, + 32, 32, 32, 632, 32, 32, 560, 0, 512, 512, 512, 512, 32, 32, 32, 336, + 8, 8, 8,1008, 32,1304, 32,1304, 56, 56, 56,2096,2104,2112, 32, 32, + 120, 120,2120,2128,2136,2144, 160, 160,2152, 160, 160, 160,2160, 320, 160, 160, + 2168, 136, 136, 136, 136, 136,2176, 424, 424, 424,2184, 424, 424, 424, 424, 424, + 424, 424,2192, 376, 376, 376, 376, 376, 376,2200, 376, 376, 376,2208,2216, 0, + 1544,2224, 72,2232,2240,2248,2256, 72, 72, 72,2264, 72, 72, 72, 72,1544, + 520,2272, 520, 520, 520, 520, 520, 520, 520,2280, 72, 72, 800, 800, 800, 800, + 800, 800,2288, 0, 712, 712, 712, 712, 712, 712, 712,2296, 808, 808, 808, 808, + 808,2304, 808,2312,1312,1312,1312,2320, 520,2328, 72, 72, 72, 72,2336, 72, + 2344, 72, 72, 72, 264, 264,2352, 264,2360, 264, 264, 264,2368,1552,2376,1136, + 1136,2384,2392,2400,1552,2408,2416,2424,2432,1136,1136,2440,2448,1560,2456,1320, + 1320,2464,2472,2480,1560,2488,2496,2504,2512,1320,2520, 0,2528,1568,2536,1328, + 1328,2544,2552,2560,1568,2568,2576, 0,2584,1328,2592,2600,2608,1576,2616,1144, + 1144,2624,2632,2640,1576,2648,2656,2664,2672,1144,1144, 0,2680,1336,1584,2688, + 2696,1336, 528,2704,1336,1584,2712, 0,2720, 528, 528,2728, 816,1592,1600, 816, + 816,1600, 816,2736,1592,2744,2752,2760,2768, 816,2776, 816,1152,1608,1616,1152, + 1152,1616,2784,2792,1608,2800,2808,2816,2824,1152,2832, 0, 432,1624,1632, 432, + 432, 432, 432, 432,1624,1632,2840, 432,2848, 432, 432, 432,2856, 824,1640,2864, + 824, 824,2872,2880,1640,2888,2896, 824,2904, 824,2912, 0,2920, 536, 536, 536, + 536, 536, 536,2928, 536, 536, 536,2936,2944,2952, 992, 992,2960, 992, 992,2968, + 2976,2984, 992,2992, 240,1344, 240, 240, 240,3000,1344, 240, 240, 240, 240,1344, + 240, 240, 240,1648, 240,1648,3008,3016,1656,1664, 280, 280, 280, 280, 280,3024, + 176, 832, 304, 832, 176, 832, 176, 176, 176, 176, 832, 304, 832, 176, 304, 176, + 176, 176, 832, 176, 176, 176, 176,3032, 176, 176, 176,3040, 176, 176, 176,3048, + 248, 248,1672,1672,1352,1352,1352,3056, 440,3064, 440,3072,1680,1680,3080,3088, + 1688,1688,3096, 0,1696,1696,3104, 0,3112,3120,3128, 0, 296, 296, 296,3136, + 296,1704, 296,1704,3144, 272, 272,3152, 272, 272, 272,3160, 272,3168, 96, 96, + 96, 96,3176, 0, 840, 840, 840,3184, 840,1712, 840,1712,3192, 840,1360,1360, + 1360,3200,3208, 0, 544, 544, 544, 544, 544,3216, 544, 544, 544,3224, 544,3232, + 1368,1368,1368,3240, 352, 352, 352, 352, 352, 352, 352,3248, 352, 352, 352,3256, + 352,1720, 352,1720, 352,3264, 120, 120, 328,3272, 328, 328, 848, 848, 848, 848, + 848, 848,3280,3288, 624, 624, 624, 624, 624, 624, 624,3296, 624,3304, 856, 856, + 856, 856, 856, 856, 136,3312, 280, 280, 280, 280, 280,3320, 552, 0,3328, 120, + 3336,3344,3352,3360,3368,3376, 56, 56, 56, 56, 56,3384,3392,3400, 56,3408, + 56, 56, 56,3416, 160, 160, 864, 864, 864, 864, 160,3424, 160, 160, 160, 864, + 160, 160,1736, 160,1736, 160,3432,3440, 160, 160,3448,1744, 32,3456, 32, 32, + 1000, 32,3464,3472, 32, 32, 56, 56, 632, 0, 120, 120,3480,3488,1304, 32, + 32,3496, 32, 32, 56,3504, 32, 32, 32, 720, 0, 0, 32,1376, 0, 0, + 32, 32,1752, 32, 320, 320,3512,3520,1656,1664, 728, 728, 728, 728, 728, 728, + 728,1760,3528,1760, 176, 176, 304, 0, 8, 8, 8,3536, 8, 8,3544, 0, + 8, 8,1008, 0,3552, 32, 32, 32,3560,3568, 32,3576,3584, 168, 168, 168, + 168, 168,3592,3600,1768, 200, 200, 200, 200, 200, 200,3608,3616, 568, 568, 568, + 568, 568,3624, 16, 16,1160, 32, 32, 568, 568, 568, 568, 560,3632, 200, 200, + 16, 16, 16,3640, 32, 32, 200, 200, 200, 200, 200,3648, 200, 200, 200, 32, + 80,3656, 80, 80,3664, 0, 872, 872, 872, 872, 872, 872, 192,3672, 0, 0, + 104, 104, 104, 0,3680, 56, 56, 56, 56,3688, 56, 56, 56, 56, 56,3696, + 3704, 0,3712, 56,1016,1016,1016,1016,1016,3720, 32, 720, 736, 736, 736, 736, + 736, 736, 736, 0,3728,3736, 576,3744,1024,1024,1024,1024,1024,3752,1168,1168, + 1168,1168,3760,3768, 16, 16, 16,3776, 448,3784, 448,3792, 216, 216, 216,3800, + 640, 640, 640, 640, 640, 640,3808, 0, 640,3816, 640,3824,3832, 0, 0,3840, + 656, 656,3848, 0,1384,1384,1384, 0, 304, 304, 56, 56, 56, 56, 56,3856, + 3864,3872, 248, 248, 656, 656, 656, 656, 656,3880, 656,3888,1776, 0, 16, 16, + 1160,3896, 16, 16, 16, 16, 16,1776,1792, 0,3904,3912, 376, 376,3920,3928, + 3936, 376, 72, 72, 72, 72, 72,3944, 72, 72, 0, 0, 0, 0, 72, 72, + 120, 120, 32, 720, 120,3952, 32, 32, 664, 336,3960, 72, 72, 72, 72,3968, + 3976, 200,1768, 200, 200, 200, 200,3984,1392,1392,1392,3992, 664, 664, 0,4000, + 232,4008, 232, 232,4016, 232, 232,4024, 232,1808, 232,1808, 232, 232, 232,4032, + 4040, 32, 32, 32, 32, 32,1816, 32, 160,1744, 32, 632,4048, 0, 0, 0, + 32, 32, 32,4056,1400,1400,1400,4064, 888, 888, 888, 888, 888, 888,4072, 0, + 1824, 32, 32, 336,1176,1176,1176,1176,4080,4088,1408,1408,1408,4096,1032,1032, + 1032,1032,1032,4104,1416,1416,1416,4112,1040,1040,1040,1040,4120,1040,4128, 0, + 456, 456, 896, 896, 896, 896, 896, 896,1184,1184,1184,4136,1184,4144, 672, 672, + 672, 672,1832, 672, 672, 672, 672,1832,1048,1048,1048,1048,1048, 0, 904, 904, + 904, 904, 904, 904,4152,4160,1192,1840,1192,1840,4168,1192,1848,1192,1848,4176, + 912, 912, 912, 912, 912, 912,4184, 0, 184, 184,4192, 0, 184, 184,4200, 0, + 184, 0, 0, 0,4208, 56, 56, 56, 56, 56,4216, 56,4224,4232,1200,1200, + 1200,1200,4240,4248,1424,1424,4256,1424,1208,1208,1208,1208,1216,1216,1216,4264, + 4272,1216, 0, 0,1856,1856,4280,4288,1432,1432,1432,4296,1440,1440,1440,4304, + 1448,1448,1448,4312,1224,1224,1224,1224, 464, 464, 464,4320, 464, 464,4328, 464, + 464, 464, 464, 464,4336,4344,4352,4360,1232,1232,4368,4376,1232,1864,1232,1864, + 1240,1240,1240,1240,1248,1248,1248,1248,1256,1256,1256,1256,1872,4384,1872, 0, + 920, 920, 920, 920, 920, 920,4392,4400,1456,1456,4408,1456,1464,1464,4416,1464, + 1880,1880,4424,4432, 0,4440, 0, 0, 584,4448, 0, 0, 384, 384,1888, 0, + 384, 384,1888,4456, 928, 928, 928, 928, 928, 0, 928,4464, 936, 936, 936, 936, + 1896,4472, 936, 936,1896,4480, 0, 0, 72, 72, 72,1904,1056,1056,1056,1056, + 1056,4488,4496, 0,4504,1912, 72, 72, 72,1904, 72, 72,1064,1064,1064,1064, + 1064, 0,1072,1072,1072,1072,1072,4512, 0, 0,1472,1472,1472,4520, 0, 0, + 0, 0,1480,1480,1480,4528, 0, 0,1920,1920,4536, 0, 392,1928,4544, 392, + 392, 392,1928,4552,4560,4568,1264,1264,1264,4576,1264,4584, 688, 688, 688, 688, + 688, 688,4592, 688, 688, 0,1272,1272,1272,1272,4600, 0,4608, 824,4616, 0, + 744, 744,4624, 744, 744, 744, 744, 744,4632, 0, 0, 0,4640,4648,1936,4656, + 1936,4664, 696, 696, 696, 696, 696, 696, 696,4672, 696,4680,4688,1944,4696,1952, + 1952,4704,4712,4720,1944,4728,4736,4744,4752,1960,1960, 0, 944,4760, 944, 944, + 944, 944,1968, 944,4768,4776,1968,4784,4792, 0, 0, 0, 408, 408, 408,4800, + 4808, 0, 0, 0, 472, 0, 472,4816, 480, 480, 480, 480, 480, 480,1976, 480, + 480, 480, 480,1976,4824, 0, 592,4832, 272,4840, 0, 0, 704, 704, 704, 704, + 704, 704, 704,1984, 704,1984, 216, 216,4848, 0, 0, 0, 952, 952, 952,4856, + 952,4864, 952, 952,4872, 0, 0, 0, 752, 752, 752, 752, 752, 752, 752,4880, + 488, 488,4888,4896,1992,4904,4912,1280,1280,1280,4920,4928,1992, 0,1280,4936, + 960,2000, 960, 960, 960, 960, 960,2000,4944, 0, 0, 0, 600, 0, 496, 496, + 4952, 0, 96, 96, 760, 760, 760, 760, 760, 760, 760,4960, 264,4968, 0, 0, + 360, 0, 0, 0,1080,1080,1080,1080,2008, 0,1080,2008, 608,4976, 608, 608, + 608, 608,4984, 608,4992, 0, 608, 608, 608,5000, 968, 968, 968, 968,5008, 968, + 968,5016,5024, 0,2016,5032, 976, 976, 976, 976,2016,5040, 976, 0, 976,5048, + 5056,5064,1288,1288,1288,5072,5080,5088,1288,5096, 984, 984, 984, 984, 984,5104, + 984,5112,5120, 0,1488,1488,1488,5128, 616, 616,5136, 616, 616, 616, 616,5144, + 616, 616, 616,5152, 0, 0,5160, 0, 528, 528, 528, 528, 528, 528,5168,5176, + 64, 64, 64,5184,5192, 0, 64, 64, 64, 256, 256, 256, 256,5200, 64, 64, + 5208, 0, 0, 0, 0, 0, 400, 400, 400, 400,5216, 0, 48, 48,5224, 0, + 48, 48, 48,5232,5240, 0, 0, 0, 768, 768, 768, 768, 768, 768, 768,5248, + 104, 104, 104,5256,1296,1296,1296,5264,1296,5272, 504, 504, 504, 504, 504, 504, + 504, 504, 504,5280, 504,5288,1496,1496,1496,2024,2024, 0,5296, 0, 368,2032, + 2032, 368, 368,5304, 368, 368, 0, 0, 776, 776, 776, 776, 776, 776, 776,5312, + 416, 416, 416,5320,1088,1088,1088,5328,1088,1088,5336, 0, 288,5344, 288, 288, + 288,5352, 288, 288,5360, 0,2040, 0, 144, 144, 144,5368, 0, 0, 0,5376, + 5384, 0, 0, 0, 40, 40,5392, 0, 88, 88,5400, 0, 88, 88,5408, 0, + 0, 0,5416,5424,5432, 168, 168, 168,5440,2048,5448, 0, 0, 0,5456, 0, + 5464,2048, 152, 152, 152, 152, 152,5472, 312,5480, 312,5488, 312,5496, 312,5504, + 32, 32, 336,2056, 32, 32,5512,5520, 120,5528, 120, 120,5536, 0, 32, 32, + 2064,1824, 32, 32,2064,5544, 32,5552,5560,5568, 32, 32, 32,5576, 32, 32, + 864, 0, 32,5584, 720, 0, 0, 0, 32, 32, 664, 0, 32, 32, 32,1504, + 32, 32,1000, 32, 32, 32, 32,1000,5592,5600, 32,5608,5616, 32, 32, 32, + 2072,5624,1000,1000, 32, 32, 32,5632,5640,2056,5648, 32, 664, 32, 32, 32, + 32,1752, 32, 32, 112,5656, 0,5664,5672, 112, 0, 0,5680, 0,1792, 0, + 0,5688, 56, 56, 56, 56,5696, 56,5704, 344, 344,5712,5720,5728, 136, 136, + 136,5736, 0, 0, 0,5744, 0, 0, 784, 784, 784, 784, 784,5752, 784,5760, + 784,5768, 0, 0, 0, 0,1512,1512,1512,5776, 0, 0, 792, 792, 792, 792, + 792, 792, 792,5784, 0, 0,1096,1096,1096,1096,1096,5792, 0, 0,1104,1104, + 1104,1104,1104,5800,1112,1112,1112,5808,1112,1112,5816,5824, 304,5832, 176, 304, + 5840, 224,5848, 0, 512,5856, 512,5864, 0, 0, 880, 32, 32, 32, 632, 0, + 5872, 72, 72, 72,1520,1912,1528,5880,5888,5896,1520,5904,1520,1528,1528,5912, + 72,2080, 72,2088,5920,2080, 72,2088, 0, 0,5928, 0, 32, 664, 880, 32, + 880, 32, 880, 32, 32, 664, 0, 0,5936, 32, 32, 32,5944, 0, 32, 32, + 32,1504, 720, 0, 560, 0, 0, 0, 32, 32, 32,5952, 32, 632, 32, 632, + 32, 0, 32, 720, 32, 0, 32, 32, 32, 560, 32, 336, 720, 0, 32,1504, + 32, 32, 32, 0, 32, 560, 32, 632, 664,5960, 32,2072, 32,1816, 32,1376, + 32, 32, 32,1376, 8, 8, 8,2040,5968, 0, 8, 8, 8,5976, 8, 8, + 5984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003, + 1008, 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, + 0,1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189, + 1193, 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0, + 1303, 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964, + 1149, 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990, + 1175, 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014, + 1199,1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, + 0, 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045, + 1231,1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072, + 1258,1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088, + 1275,1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, + 0,1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1093,1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134, + 1010,1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320, + 1347,1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415, + 1424,1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338, + 1365, 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052, + 1238,1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997, + 1182, 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046, + 1232,1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 9, 0, 10,1425, 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, 1, + 0, 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455, + 1461,1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480, + 1486,1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, + 0, 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, + 0,1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, + 0, 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531, + 1553, 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538, + 1560,1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, + 0, 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, + 0, 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621, + 1622, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0, + 1627, 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, + 0, 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, + 0,1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, + 0, 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, + 0, 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, + 0, 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, + 0, 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, + 0, 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, + 0,1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968, + 1153, 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986, + 1171, 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329, + 1356,1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028, + 1214,1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336, + 1363,1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065, + 1251,1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079, + 1266,1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100, + 1287,1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114, + 1302,1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, + 0, 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371, + 1375,1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326, + 1353,1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048, + 1234,1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398, + 1403,1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407, + 1412,1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, + 0,1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717, + 1721,1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, + 0,1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753, + 1757,1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773, + 1776,1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, + 0,1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0, + 1793,1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810, + 1814,1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, + 0,1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727, + 1728,1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763, + 1764,1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820, + 1821,1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, + 0, 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827, + 1828,1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832, + 1833,1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, + 3, 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, + 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839, + 1838, 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, + 0, 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, + 0, 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, + 938,1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, + 0,1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869, + 1870,1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, + 0,1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, + 0,1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, + 0,1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, + 0, 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, + 0,1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, + 0,1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, + 0,1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, + 0, 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, + 0, 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, + 601, 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, + 662, 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, + 168, 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, + 758, 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, + 585, 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, + 259, 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, + 697, 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, + 170, 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, + 330, 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, + 473, 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, + 603, 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, + 411, 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, + 583, 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, + 269, 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, + 510, 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, + 156, 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, + 0, 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, + 0, 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, + 773, 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, + 329, 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, + 548, 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, + 651, 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, + 0, 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, + 243, 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, + 362, 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, + 490, 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, + 586, 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, + 706, 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, + 848, 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0, + 1605, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574, + 1575,1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, + 0,1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0,1939, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1940, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941, + 1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1943,1944, 0, 0, + 0, 0, 0, 0,1945, 0,1946, 0, 0, 0, 0, 0, 0, 0, 0,1947, + 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1950, 0,1949,1951, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1953,1952, 0,1954, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1957, 0, 0, 0, 0, 0, 0, + 0, 0,1958,1961,1959,1965,1960,1962,1964,1963, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1967,1966,1968, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1969, + 1970,1971,1972,1973,1974,1975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1976,1977,1978,1980, + 1979,1981, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, + 131, 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, + 37, 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, + 179, 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, + 195, 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, + 216, 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, + 244, 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, + 259, 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, + 276, 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, + 934, 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, + 312, 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, + 334, 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, + 361, 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, + 381, 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, + 399, 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, + 417, 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, + 433, 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, + 460, 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, + 870, 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, + 505, 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, + 64, 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, + 538, 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, + 567, 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, + 592, 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, + 611, 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, + 627, 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, + 651, 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, + 83, 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, + 85, 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, + 696, 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, + 728, 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, + 90, 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, + 787, 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, + 807, 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, + 0, }; -static const int16_t _hb_ucd_i16[92]= +static const int32_t _hb_ucd_palette[39]= { - 0, 0, 1, -1, -1, 1, 0, 1, -1, 0, 0, 2, 0, -2, 2, 0, - -2, 0, -7, 0, 0, 16, 0, -16, 3, 3, 3, -3, -3, -3, 0, 2016, - 0, 2527, 1923, 1914, 1918, 0, 2250, 0, 0, 138, 0, 7, 1824, 0, 2104, 0, - 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8, - -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0, - 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0, + -112883, -2527, -2250, -2108, -2106, -2104, -2016, -1923, + -1918, -1914, -1824, -1316, -138, -16, -8, -7, + -3, -2, -1, 0, 1, 2, 3, 7, + 8, 16, 138, 1316, 1824, 1914, 1918, 1923, + 2016, 2104, 2106, 2108, 2250, 2527, 112883, }; static inline uint8_t _hb_ucd_gc (unsigned u) { /* packtab: [2^8,2^4,2^4,2^3,2^1] */ - return u<1114110u ? (uint8_t)(_hb_ucd_u8[6536u+((_hb_ucd_u8[800u+_hb_ucd_u16[((_hb_ucd_u8[272u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>4))>>4)])<<4)+((((((((u)>>1))>>3))>>4))&15)])<<4)+((((((u)>>1))>>3))&15)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; + return u<1114110u ? (uint8_t)(_hb_ucd_u8[6600u+((_hb_ucd_u8[832u+_hb_ucd_u16[((_hb_ucd_u8[272u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>4))>>4)])<<4)+((((((((u)>>1))>>3))>>4))&15)])<<4)+((((((u)>>1))>>3))&15)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; } static inline uint8_t _hb_ucd_ccc (unsigned u) { /* packtab: [2^8,2^3,2^2,2^2,2^2] */ - return u<125259u ? (uint8_t)(_hb_ucd_u8[8589u+((_hb_ucd_u8[8006u+((_hb_ucd_u8[7529u+((_hb_ucd_u8[7163u+((_hb_ucd_u8[6918u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)]) : 0; + return u<125259u ? (uint8_t)(_hb_ucd_u8[8683u+((_hb_ucd_u8[8084u+((_hb_ucd_u8[7599u+((_hb_ucd_u8[7233u+((_hb_ucd_u8[6988u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)]) : 0; } static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) { return (a[i>>1]>>((i&1)<<2))&15; } -static inline int16_t _hb_ucd_bmg (unsigned u) +static inline int32_t _hb_ucd_bmg (unsigned u) { - /* packtab: [2^4,2^3,2^3,2^2,2^1] */ - return u<65380u ? (int16_t)(_hb_ucd_i16[_hb_ucd_u8[9480u+_hb_ucd_u8[9251u+_hb_ucd_u8[9157u+((_hb_ucd_b4(_hb_ucd_u8+9093u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)]+((((((u)>>1))>>2))&7)]+((((u)>>1))&3)]+((u)&1)]) : 0; + /* packtab: [2^4,2^3,2^3,2^2,2^2] palette[39] */ + return u<121617u ? (int32_t)(_hb_ucd_palette[_hb_ucd_u8[9754u+_hb_ucd_u8[9514u+_hb_ucd_u8[9350u+_hb_ucd_u8[9263u+((_hb_ucd_b4(_hb_ucd_u8+9203u,((((((((u)>>2))>>2))>>3))>>3)))<<3)+((((((((u)>>2))>>2))>>3))&7)]+((((((u)>>2))>>2))&7)]+((((u)>>2))&3)]+((u)&3)]]) : 0; } static inline uint8_t _hb_ucd_sc (unsigned u) { - /* packtab: [2^8,2^4,2^3,2^2,2^2] */ - return u<918000u ? (uint8_t)(_hb_ucd_u8[10913u+_hb_ucd_u16[4624u+_hb_ucd_u16[2592u+((_hb_ucd_u8[10177u+((_hb_ucd_u8[9728u+((((((((u)>>2))>>2))>>3))>>4)])<<4)+((((((((u)>>2))>>2))>>3))&15)])<<3)+((((((u)>>2))>>2))&7)]+((((u)>>2))&3)]+((u)&3)]) : 2; + /* packtab: [2^8,2^4,2^3,2^2,2^3] */ + return u<918000u ? (uint8_t)(_hb_ucd_u8[10755u+_hb_ucd_u16[4016u+_hb_ucd_u16[2656u+((_hb_ucd_u8[10179u+((_hb_ucd_u8[9954u+((((((((u)>>3))>>2))>>3))>>4)])<<4)+((((((((u)>>3))>>2))>>3))&15)])<<3)+((((((u)>>3))>>2))&7)]+((((u)>>3))&3)]+((u)&7)]) : 2; } static inline uint16_t _hb_ucd_dm (unsigned u) { /* packtab: [2^8,2^5,2^4] */ - return u<195102u ? (uint16_t)(_hb_ucd_u16[7453u+((_hb_ucd_u8[13867u+((_hb_ucd_u8[13485u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; + return u<195102u ? (uint16_t)(_hb_ucd_u16[6353u+((_hb_ucd_u8[17129u+((_hb_ucd_u8[16747u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; } @@ -4390,16 +4557,16 @@ static inline uint16_t _hb_ucd_dm (unsigned u) #include -static const uint8_t _hb_ucd_u8[13905]= +static const uint8_t _hb_ucd_u8[14455]= { - 4, 5, 6, 7, 8, 9, 10, 2, 2, 11, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 12, 13, 2, 2, 2, 2, 2, 14, 1, 1, 1, 15, - 16, 17, 18, 19, 20, 21, 22, 2, 3, 0, 0, 0, 23, 24, 2, 2, - 2, 25, 0, 0, 0, 26, 27, 28, 0, 29, 30, 31, 32, 33, 34, 35, + 5, 6, 7, 8, 9, 10, 11, 2, 2, 12, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 13, 14, 2, 2, 2, 2, 2, 15, 1, 1, 1, 16, + 17, 18, 19, 20, 21, 22, 23, 2, 3, 0, 0, 0, 24, 25, 2, 2, + 2, 2, 26, 0, 0, 27, 28, 29, 0, 30, 31, 32, 33, 34, 35, 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 36, - 2, 2, 2, 2, 2, 2, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 37, + 2, 2, 2, 2, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -4427,1202 +4594,1286 @@ static const uint8_t _hb_ucd_u8[13905]= 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 2, 2, 2, 2, 45, 46, 47, 2, 2, 2, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 5, 5, 72, 73, 8, 74, 3, 75, 76, 3, 77, 78, - 3, 3, 5, 79, 5, 5, 80, 3, 81, 82, 83, 84, 85, 3, 3, 3, - 86, 87, 2, 88, 89, 90, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 2, 2, - 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 2, 2, 94, 95, 96, 97, - 98, 99,100,101,102,103,104,105, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 1, 1, 1, 1, 46, 47, 48, 1, 1, 1, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 5, 5, 73, 74, 8, 75, 3, 76, 77, 3, 78, 79, + 3, 3, 5, 80, 5, 5, 81, 3, 82, 83, 84, 85, 86, 3, 3, 3, + 87, 88, 1, 89, 90, 91, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 92, 1, 1, 1, 1, + 93, 1, 1, 1, 1, 1, 1, 1, 1, 94, 1, 1, 95, 96, 97, 98, + 99,100,101,102,103,104,105,106, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 1, 2, 2, 2, 2,106,107, 2, 2,108,109,110,111,112,113, - 2, 2,114,115, 0,116,117,118,119,120,121,122, 2, 2, 2, 9, - 123,124,125,126,127,128,129,130, 2,131,132,133, 6,134,135,136, - 137,138,139,140,141,142,143,144,145,146, 0,147,148,149,150, 0, - 151,152,153,154,155,156,157,158,159,160,161,162, 0,163,164,165, - 2, 2, 2, 2, 2, 2, 2, 2,166, 2, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, - 2, 2, 2, 2, 2, 2, 2, 2,168, 2, 2, 2, 2, 2, 2, 2, - 0, 0,169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2,170,171,172, 2, 0, 0,173, 0,174,175,176,177, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 2, 2, 1, 1, 1, 1,107,108, 1, 1,109,110,111,112,113,114, + 1, 1,115,116, 0,117,118,119,120,121,122,123, 1, 1, 1, 9, + 124,125,126,127,128,129,130,131, 1,132,133,134, 10,135,136,137, + 138,139,140,141,142,143,144,145,146,147, 0,148,149,150,151, 0, + 152,153,154,155,156,157,158,159,160,161,162,163, 0,164,165,166, + 1, 1, 1, 1, 1, 1, 1, 1,167, 1,168, 6, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,169, + 1, 1, 1, 1, 1, 1, 1, 1,170, 1, 1, 1, 1, 1, 1, 1, + 0, 0,171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1,172,173,174, 1, 0, 0,175, 0,176,177,178,179, + 1, 1, 1, 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, 9, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2,178, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 10, 3, 3, 3,179,180, 3, - 3, 3,181,182,183, 6, 8, 0,184,185,186,187,188,189,190,191, - 3, 3, 3, 3,192,193, 0, 0, 0, 0, 0, 0, 0, 0,194, 0, - 195, 7,196, 0, 0,197, 0, 0, 0,198, 0,199, 0,200, 0, 2, - 2,201,202, 0, 0, 0, 0, 0, 6,203,204, 0, 2,205, 0, 0, - 3, 3,206, 3, 3, 0, 3,207, 3, 3, 3, 3, 3, 3, 3, 3, - 3,208, 3, 3, 3, 3, 3, 10, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, - 209, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1,180, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 11, 3, 3, 3,181,182, 3, + 3, 3,183,184,185,186, 8, 0,187,188,189,190,191,192,193,194, + 3, 3, 3, 3,195,196, 5, 0, 0, 0, 0, 0, 0, 0,197,198, + 199, 7,200, 0, 0,201, 0, 0, 0,202, 0,203, 0,204, 0, 1, + 1,205,206, 0, 0, 0, 0, 0, 10,207,208, 0, 1,209, 0, 0, + 3, 3,210, 3, 3, 0, 3,211, 3, 3, 3, 3, 3, 3, 3, 3, + 3,212, 3, 3, 3, 3, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 213, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 11, 11, 11, 11, 11, 11, 11, 11, - 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, - 9, 9, 9, 9, 9, 9, 9, 9, 13, 13, 13, 13, 13, 13, 13, 13, - 10, 10, 10, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 15, 15, 15, + 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11, 11, 11, 11, + 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, + 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16, 16, 16, 6, 6, 6, 6, 8, 8, 8, 8, - 9, 9, 9, 9, 9, 1, 1, 1, 1, 4, 4, 9, 9, 9, 9, 9, - 25, 25, 25, 25, 25, 25, 25, 25, 14, 14, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 10, 10, 10, 10, 10, 1, 1, 1, + 1, 4, 4, 10, 10, 10, 10, 10, 25, 25, 25, 25, 25, 25, 25, 25, 8, 8, 8, 8, 8, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, - 1, 1, 1, 4, 4, 4, 4, 4, 4, 14, 30, 1, 1, 1, 1, 1, - 9, 9, 9, 9, 9, 10, 10, 10, 9, 9, 9, 9, 9, 7, 7, 7, - 8, 8, 8, 8, 6, 6, 6, 6, 1, 4, 4, 4, 4, 4, 4, 4, - 4, 30, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 32, 32, 32, 32, - 24, 24, 24, 24, 24, 24, 24, 24, 9, 9, 9, 9, 9, 9, 9, 10, - 1, 1, 1, 1, 1, 1, 1, 29, 21, 4, 4, 4, 4, 4, 4, 4, - 1, 1, 1, 1, 29, 10, 10, 10, 29, 10, 10, 10, 10, 10, 10, 10, - 1, 1, 1, 1, 1, 1, 1, 4, 6, 6, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 8, 8, - 8, 8, 8, 6, 6, 6, 6, 6, 9, 9, 9, 9, 9, 10, 11, 65, - 73, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 86, 87, 88, - 74, 6, 6, 6, 6, 6, 6, 6, 20, 20, 20, 20, 20, 20, 20, 20, - 19, 8, 8, 8, 8, 8, 8, 8, 22, 1, 1, 1, 1, 1, 1, 1, - 21, 1, 1, 1, 1, 1, 1, 1, 4, 17, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 22, 14, 4, 17, 30, 1, 1, 1, 1, 1, + 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, + 4, 15, 29, 1, 1, 1, 1, 1, 10, 10, 10, 10, 10, 12, 12, 12, + 10, 10, 10, 10, 10, 7, 7, 7, 8, 8, 8, 8, 6, 6, 6, 6, + 1, 4, 4, 4, 4, 4, 4, 4, 4, 29, 1, 1, 1, 1, 1, 1, + 6, 6, 6, 6, 33, 33, 33, 33, 24, 24, 24, 24, 24, 24, 24, 24, + 10, 10, 10, 10, 10, 10, 10, 12, 1, 1, 1, 1, 1, 1, 1, 28, + 20, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 28, 12, 12, 12, + 28, 12, 12, 12, 12, 12, 12, 12, 1, 1, 1, 1, 1, 1, 1, 4, + 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, + 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, + 10, 10, 10, 10, 10, 12, 9, 66, 73, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 89, 90, 91, 74, 6, 6, 6, 6, 6, 6, 6, + 21, 21, 21, 21, 21, 21, 21, 21, 19, 8, 8, 8, 8, 8, 8, 8, + 20, 1, 1, 1, 1, 1, 1, 1, 4, 17, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 22, 15, 4, 17, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 18, 4, 22, 1, 1, 1, 1, 1, 1, - 14, 14, 14, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 21, 22, 14, - 10, 10, 10, 10, 60, 7, 7, 7,100, 1, 1, 1, 1, 1, 1, 1, - 14, 18, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 13, 13, 13, 10, - 20, 6, 6, 6, 8, 8, 79, 20, 6, 6, 6, 6, 8, 8,103, 20, - 26, 26, 26, 26, 26, 26, 26, 26, 7, 7, 7, 7, 7, 3, 3, 3, - 63, 7, 7, 7, 7, 7, 7, 7, 1, 1, 34, 1, 1, 1, 1, 1, - 1, 1, 1, 46, 7, 7, 7, 7, 1, 1, 1, 1, 4, 4, 4, 4, - 1, 1, 1, 1, 1, 1, 46, 7, 1, 1, 1, 1, 7, 7, 7, 7, - 1, 1, 1, 1, 1, 1, 14, 18, 1, 1, 1, 1, 1, 1, 1, 21, - 1, 1, 1, 1, 1, 1, 1, 27, 9, 9, 9, 9, 9, 3, 3, 3, - 72, 10, 84, 10, 23, 85, 64, 10, 6, 6, 6, 6, 6, 89, 90,119, - 72, 24, 24, 47, 91,120,121, 92, 36, 7, 74, 10,122,123, 7, 54, - 8, 8, 8, 48, 8, 8, 8, 12, 6, 6, 6, 49, 6, 6, 6, 6, - 12, 12, 12, 12, 19, 19, 19, 19, 19, 19, 19, 19, 6, 12, 12, 12, - 12, 12, 12, 12, 8, 19, 19, 6, 19, 12, 12, 8, 19, 8, 6, 8, - 8, 19, 12, 8, 12, 6, 8, 19, 12, 12, 12, 8, 19, 6, 12, 8, - 19, 8, 19, 19, 12, 50, 12, 6, 1, 1, 93, 19, 94, 93, 19, 19, - 19, 19, 19, 19, 19, 19, 6, 12, 19, 94, 12, 8, 12, 12, 12, 12, - 12, 12, 6, 6, 6, 8, 19, 12, 19, 19, 8, 12, 12, 12, 12, 12, - 6, 6, 1, 6, 6, 6, 6, 6, 13, 20, 20, 13, 13, 13, 13, 13, - 13, 20, 20, 20, 20, 20, 20, 20, 13, 13, 55, 20, 20, 20, 55, 55, - 12, 12, 55, 12, 6, 56, 6, 73, 20, 20, 20,124, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 19, - 6, 8, 12, 6, 12, 12, 12, 12, 6, 6, 12, 75, 19, 12, 19, 8, - 12, 33, 4, 4, 66, 12, 12, 12, 8, 19, 19, 19, 19, 19, 19, 6, - 8, 8, 8, 8, 95, 10, 10, 10, 6, 6, 6, 6, 76, 26,125, 57, - 126, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,127, - 37, 31, 4, 37, 4, 4, 4, 4, 1, 29, 10, 10, 10, 10, 10, 10, - 15, 15, 15, 11, 65, 67, 10, 3, 4, 4, 4, 4, 4, 31,128, 10, - 38, 1, 1, 1, 1, 21, 4, 4, 9, 9, 9, 9, 9, 10, 10, 1, - 1, 1, 39, 4, 4, 4, 96, 33, 4, 4, 68, 51, 40, 4, 4, 1, - 9, 9, 9, 9, 9, 1, 41, 58, 10, 10, 10, 10, 10, 10, 10, 97, - 4, 4, 4, 4, 4, 4, 22, 1, 1, 1, 1, 1, 1, 21, 4, 4, - 4, 4, 13, 47, 10, 13, 51, 24, 1, 1, 1, 4, 4, 51, 4, 4, - 4, 4, 51, 4, 51, 4, 4, 4, 1, 1, 1, 1, 21, 4, 4, 10, - 1, 1, 1, 1,129, 1, 1, 1, 15, 15, 15, 69, 4, 4, 4, 4, - 1, 1, 1, 1, 34, 4, 4, 4, 4, 69, 4, 4, 4, 4, 4, 4, - 1, 1, 1, 1, 1, 17, 22, 14, 18, 4, 4, 4, 17, 14, 18, 14, - 21, 4, 4, 4, 1, 1, 1, 1, 1, 4, 10, 9, 9, 9, 9, 9, - 42, 1, 1, 1, 1, 1, 1, 1, 21, 14, 30, 1, 1, 1, 1, 1, - 18, 4, 4, 17, 14, 14, 18, 1, 1, 1, 1, 27, 14, 14, 1, 1, - 1, 24, 7, 7, 7, 57, 29, 4, 1, 1, 1, 1, 1, 1, 4, 14, - 18, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 22, 1, 1, 1, - 1, 1, 1, 9, 9, 9, 9, 9, 4, 1, 21, 10, 10, 10, 10, 10, - 18, 4, 4, 4, 17, 14, 18, 4, 67, 24, 24, 24,130, 4, 4, 4, - 18, 4, 4, 17, 14, 14, 18, 4, 4, 4, 4, 17, 14, 14, 1, 1, - 58, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 14, - 17, 14, 14, 14, 14, 14, 18, 4, 1, 1, 1, 27, 14, 14, 14, 14, - 7, 43, 3, 3, 57, 3, 3, 3, 17, 14, 22, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 22, 4, 17, 14, 14, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 1, 1, 1, 1, 9, 9, 9, 98, 7, 7, 7, 43, - 21, 14, 39, 1, 1, 1, 1, 1, 14, 14, 14, 17, 14, 14, 4, 4, - 4, 4, 17, 14, 14, 14, 1, 1, 99, 27, 14, 14, 14, 14, 14, 14, - 4, 14, 1, 1, 1, 1, 1, 1, 18, 4, 4, 14, 14, 14, 18, 41, - 3, 3, 1, 27, 7, 7, 7, 59, 7, 7, 7, 7, 43, 1, 1, 1, - 1, 1, 1, 1, 1, 4, 4, 17, 14, 4, 4, 4, 14, 14, 14, 14, - 9, 14, 10, 10, 10, 10, 10, 10, 21, 1, 4, 4, 4, 4, 4,131, - 1, 1, 1, 51, 4, 4, 4, 31, 21, 1, 4, 4, 4, 4, 22, 1, - 1, 1, 1, 13, 4, 4, 4, 4, 9, 9, 9, 9, 9, 9, 1, 1, - 41, 3, 10, 10, 10, 10, 10, 10, 10, 44, 44, 3, 4, 3, 3, 3, - 7, 7, 33, 33, 33, 23, 23, 14, 21, 4, 4, 4, 4, 4, 4, 17, - 4, 4, 31, 4, 1, 1, 21, 4, 4, 4, 4, 4, 4, 4, 4, 3, - 3, 3, 3, 40, 3, 3, 3, 3, 10, 10, 44, 3, 47, 10, 10, 10, - 1, 1, 1, 1, 1, 27, 18, 4, 17, 4, 4, 4, 18, 17, 18, 22, - 1, 1, 1, 14, 4, 1, 1, 4, 22, 14, 30, 27, 14, 14, 14, 1, - 21, 4, 22, 1, 1, 1, 1, 1, 1, 17, 18, 17, 14, 14, 18, 27, - 9, 9, 9, 9, 9, 14, 18, 3, 6, 6, 6, 6, 6, 76, 56, 6, - 1, 1, 1, 1, 1, 1, 21, 4, 1, 1, 1, 1, 1, 1, 41, 39, - 132, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,133, 70, 70, - 1, 1, 1, 1, 1, 29, 10, 16,134, 1, 1, 1, 1, 1, 1, 1, - 1, 4, 17, 14, 14, 14, 14, 30, 1, 4, 61, 10, 10, 10, 10, 10, - 1, 1, 4, 18, 4, 4, 4, 14, 14, 14, 14, 17, 18, 4, 4, 4, - 4, 4, 10, 42, 10, 67, 21, 4, 10, 10, 10, 77, 10, 37, 4, 69, - 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 21, 22, 1, 1, 1, 1, - 1, 1, 1, 1, 21, 1, 1, 1, 4, 17, 14, 18, 17, 14, 14, 14, - 14, 17, 14, 14, 18, 4, 4, 4, 3, 3, 10, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 7, 7, 3, 1, 1, 1, 21, 17, 18, 4, 10, - 1, 1, 27, 17, 4, 4, 4, 4, 17, 17, 18, 4, 4, 4, 17, 14, - 10, 10, 10, 42, 10, 10, 10, 10, 4, 4, 4, 4, 4, 4, 4, 78, - 4, 4, 30, 1, 1, 1, 1, 1, 1, 1, 17, 4, 4, 17, 17, 14, - 14, 17, 30, 1, 1, 1, 1, 10, 44, 3, 3, 3, 3, 33, 4, 4, - 4, 4, 3, 3, 3, 3, 47, 10, 27, 4, 4, 14, 4, 18, 4, 1, - 1, 1, 1, 17, 4, 14, 18, 18, 4, 14, 14, 14, 14, 14, 10, 10, - 1, 1, 14, 14, 14, 14, 4, 4, 4, 4, 14, 4, 4, 31, 10, 10, - 9, 9, 9, 9, 9, 9, 99, 1, 6, 6, 6, 6, 19, 6, 6, 6, - 4, 31, 4, 4, 4, 4, 4, 4, 17, 4, 4, 4, 22, 1, 21, 1, - 1, 1, 22, 27, 4, 1, 1, 1, 6, 6, 6, 6, 6, 6, 13, 13, - 13, 13, 13, 13, 13, 56, 6, 6, 6, 6, 6, 6, 56, 6, 6, 6, - 6, 6, 6, 6, 6,101, 13, 13, 12, 12, 12, 6, 6, 6, 6, 12, - 6, 6, 6, 6, 19, 8, 8, 8, 6, 6, 6, 6, 8, 8, 79,102, - 62, 62, 62, 62, 62,135, 15, 15, 26, 26, 26, 10, 45,104, 45,104, - 10, 10, 10, 10,136, 15, 15,137, 10, 10, 10, 10,105,106, 10,107, - 108, 10, 52, 53, 10, 10, 10, 10, 10, 65,108, 10, 10, 10, 10,138, - 139, 13, 7, 7, 7, 11, 52,140, 7, 7, 7, 7, 7, 11, 52, 70, - 4, 4, 4, 4, 4, 4,141, 66, 78, 66, 78, 4, 4, 4, 4, 4, - 3, 71, 3, 80, 3, 19, 8, 6, 8, 12, 80, 3, 75, 8, 8, 3, - 3, 3, 71, 71, 71, 8, 8,142, 8, 8, 50, 1,109, 3, 6, 8, - 11, 11, 75, 6, 6, 36, 3,110, 16,143,144, 16,111, 3, 3, 3, - 11, 11, 35, 3, 3, 11, 3, 3, 35, 36, 3, 35, 3, 3, 3, 35, - 3, 3, 3, 3, 3, 3, 3, 11, 3, 35, 35, 3, 3, 3, 3, 3, - 3, 3, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3, 23, 23, 3, 3, - 11, 3, 3, 3,145,146, 3, 3, 3, 3, 3, 3, 3, 3, 35, 3, - 3, 3, 3, 3, 3, 36, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, - 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, - 3, 3, 3, 36, 3, 3, 3, 3, 36, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 36, - 3, 3, 3, 3, 23, 23, 23, 23, 23, 23, 23, 7, 7, 7, 7, 7, - 7, 7, 3, 3, 3, 3, 3, 3, 11, 11, 52,112, 11, 11, 11, 11, - 11, 11, 11, 23, 23, 23, 23, 23, 11, 52, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28,112, 11, 11, 11, 11, 11, 11, 11, 23, 23, 11, 11, - 11, 11, 11, 11, 11, 11, 23, 11, 11, 11, 35, 36, 11, 11, 35, 3, - 12, 8, 12, 19, 19, 19, 19, 8, 12, 12, 19, 6, 6, 6, 13, 8, - 12, 12,110, 3, 3, 80, 19,147, 4, 12, 6, 6, 76, 10, 60, 10, - 1, 1, 1, 1, 1, 1, 1, 34, 10, 10, 10, 10, 10, 10, 10, 37, - 10, 45, 45, 10,105,106, 45, 10, 10, 10, 10, 64, 10, 77, 45, 10, - 45, 23, 23, 23, 23, 10, 10, 42, 10, 10, 10, 10, 10, 26, 10, 10, - 77,148, 10, 10, 10, 10, 10, 10, 3, 10, 81, 28, 28, 28,149, 26, - 72, 10,150,113, 23, 23, 23, 23, 23, 3, 23, 23, 23, 23,114, 70, - 151, 16, 16, 16, 16, 4, 4, 14,115, 13, 13, 3, 16,152, 29, 3, - 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21,153,116, 38, - 1, 1, 1, 1, 1, 29, 13, 38, 3, 7, 7, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1,117, 10, - 12, 12, 12, 12, 12, 12, 12, 21, 66,154, 4, 4, 4, 4, 4, 42, - 12, 12, 12, 12, 12, 12, 13, 4, 1, 1, 1, 16, 16, 16, 16, 16, - 4, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20,116, 13, 13, 13, 13, - 20, 12, 12, 12, 12, 12, 12, 12, 6, 12, 12, 12, 12, 12, 12, 12, - 56, 6, 6, 6, 19, 19, 19, 12, 12, 12, 12, 12, 55,155, 19, 50, - 12, 12, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 8, 8, 12, - 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 8, 8, 19, 19, 12, 12, - 12, 12, 12, 12, 12, 12, 8, 8, 95, 13,156, 50, 13, 50, 1, 1, - 1, 22, 1, 22, 1, 21, 1, 1, 1, 27, 18, 17, 3, 3, 4, 4, - 7, 7, 7, 3, 82, 3, 3, 3, 1, 1, 10, 10, 10, 10, 10, 10, - 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 14, 14, 14, 14, 14, - 14, 14, 4, 4, 4, 4, 4, 10, 4, 1, 1, 1, 10, 39, 39, 21, - 1, 1, 1, 4, 4, 4, 4, 10, 1, 1, 1, 21, 4, 4, 4, 4, - 4, 14, 14, 14, 14, 14, 14, 61, 1, 21, 14, 4, 4, 14, 4, 14, - 61, 10, 10, 10, 10, 10, 10, 42, 1, 1, 21, 38, 1, 1, 1, 1, - 1, 1, 1, 1, 21, 4, 4, 17, 18, 17, 18, 4, 4, 4, 4, 4, - 1, 21, 1, 1, 1, 1, 17, 14, 9, 9, 9, 9, 9, 9, 10, 10, - 38, 1, 1, 41, 3, 27, 17, 1, 22, 4, 22, 21, 22, 1, 1, 4, - 1, 1, 1, 1, 1, 1, 34, 10, 1, 1, 1, 1, 1, 27, 4, 14, - 10, 34,157, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6,102, 13, 13, - 6, 6, 6, 6,101, 20, 20, 20, 1, 27, 18, 14, 17, 61, 18, 4, - 6, 6, 6, 6, 6, 6, 50, 22, 1, 1, 1, 1,158, 1, 1, 1, - 1, 20, 20, 20, 20, 20, 20, 20, 20, 91, 3, 3, 3, 3, 3, 3, - 3, 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, - 1, 1, 1, 1, 1, 1, 82, 3, 10, 10, 10, 81, 53, 10, 10, 10, - 64,159,160, 28, 28, 28, 28, 28, 28, 28, 53, 81, 53, 10,107,161, - 10, 10, 10, 10,114, 28, 28, 53, 10,162, 11, 11, 67, 10, 10, 10, - 1, 1, 1, 1, 1, 1, 1,163, 10, 10, 84, 10, 23, 85, 64, 10, - 6, 6, 6, 6, 6, 89, 90, 52, 53, 23, 10, 1, 1, 1, 1, 1, - 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, - 24,164, 57, 24, 36, 11, 35, 3, 3, 3, 3, 3,165, 15, 3, 3, - 10, 10, 10, 60, 7, 7, 7, 7, 7, 7, 7, 43, 3, 3, 3, 3, - 16, 16,111, 7, 43, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 3, - 3, 3, 3, 3, 3, 3, 33, 4, 83, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 59, 1,113, 1, 1, 1, 1, 16, 16, 16, - 166, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 12, 6, 6, 6, 6, - 1, 1, 1, 29, 7, 7, 7, 7, 1, 1, 1, 41, 63, 7, 7, 7, - 1, 1, 1, 1, 1, 46, 7, 7, 1, 1, 1, 7, 7, 7, 7, 54, - 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 46, 54, - 1, 1, 1, 1, 58, 1, 1, 1, 1, 1, 21, 4, 4, 83, 7, 7, - 6, 6, 6, 6, 6, 7, 7, 7, 1, 1, 4, 4, 4, 4, 4, 4, - 9, 9, 9, 9, 9, 1, 1, 38, 8, 8, 8, 8,167, 4, 4,115, - 6, 6, 6, 6, 6, 6, 6, 11, 1, 1, 1, 1, 1, 21,168, 26, - 44, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, - 7, 7, 7, 59, 1, 1, 1, 1, 83, 7, 54, 10, 10, 10, 10, 10, - 1, 4, 4, 10, 10, 10, 10, 10, 1, 1, 46, 7, 7, 7, 7, 7, - 18, 30, 1, 1, 1, 1, 1, 1, 4, 4, 4, 31, 10, 10, 10, 10, - 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, - 22, 21, 22, 1, 1, 1, 1, 21, 14, 18, 4, 17, 18, 31, 97, 10, - 10, 4, 4, 4, 4, 4, 96, 15, 1, 1, 1, 21, 4, 4, 18, 4, - 4, 4, 4, 9, 9, 9, 9, 9, 10, 10, 27, 30, 1, 1, 1, 1, - 1, 21, 10, 1, 1, 1, 1, 1, 1, 27, 14, 4, 4, 4, 4, 17, - 30, 1, 29, 10, 37, 4, 31, 18, 9, 9, 9, 9, 9, 29, 29, 10, - 60, 7, 7, 7, 7, 7, 7, 7, 4, 14, 17, 4, 10, 10, 10, 22, - 17, 14, 14, 14, 14, 14, 14, 14, 1, 1, 1, 27, 14, 14, 30, 1, - 1, 14, 14, 4, 4, 4, 4, 4, 1, 1, 1, 1, 14, 18, 4, 4, - 4, 14, 14, 14, 14, 14, 14, 17, 22, 22, 10, 10, 10, 10, 10, 10, - 37, 4, 4, 4, 4, 4, 4, 4, 1, 1, 27, 14, 4, 4, 4, 4, - 14, 4, 17, 22, 1, 29, 10, 10, 9, 9, 9, 9, 9, 10, 10, 22, - 14, 18, 4, 4, 17, 17, 14, 18, 17, 4, 1, 39, 1, 1, 1, 1, - 14, 4, 4, 4, 14, 14, 4, 18, 31, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 1, 1, 4, 4, 14, 18, 4, 4, 4, 17, 18, 18, - 31, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 18, 14, - 4, 4, 4, 18, 29, 10, 10, 10, 1, 1, 1, 1, 1, 1, 21, 18, - 14, 4, 4, 18, 4, 4, 4, 4, 9, 9, 9, 9, 9, 7, 10, 44, - 4, 4, 4, 4, 18, 31, 10, 10, 7, 7, 7, 7, 7, 7, 7, 59, - 14, 14, 14, 14, 14, 18, 17, 22, 30, 18, 10, 10, 10, 10, 10, 10, - 27, 14, 4, 4, 4, 4, 14, 14, 22, 39, 14, 14, 14, 14, 14, 14, - 21, 4, 4, 4, 4, 22, 1, 1, 1, 21, 4, 4, 17, 21, 4, 31, - 10, 10, 10, 37, 4, 4, 4, 4, 21, 4, 4, 17, 18, 4, 1, 1, - 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 17, 4, 10, 39, 10, - 17, 4, 17, 17, 14, 14, 14, 14, 4, 4, 4, 4, 4, 4, 4, 18, - 10, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 17, 4, 4, 4, - 17, 4, 18, 4, 4, 4, 4, 4, 4, 4, 4, 21, 4, 4, 4, 4, - 1, 1, 1, 1, 1, 14, 14, 14, 4, 17, 18, 18, 1, 1, 1, 1, - 1, 1, 1, 1, 34, 1, 1, 1, 1, 21, 17, 61, 10, 10, 10, 10, - 4, 27, 1, 1, 1, 1, 1, 1, 1, 1, 14, 4, 4, 4, 4, 14, - 17, 31, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 4, 4, 4, - 7, 7, 43, 3, 3, 3, 57, 24, 82, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 47, 22, 1, 1, 21, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 14, 18, 4, 4, 4, 31, 10, 10, 10, 10, 10, - 4, 4, 4, 31, 10, 10, 3, 3, 13, 13, 44, 3, 3, 3, 3, 3, - 9, 9, 9, 9, 9,169, 7, 7, 7, 59, 1, 1, 1, 1, 1, 1, - 13, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34,117, 10, - 7, 7, 7, 54, 10, 10, 10, 10, 8, 8, 8, 8, 8, 12, 6, 6, - 27, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, - 4, 68, 13, 13, 13, 13, 13, 13, 13, 42, 4, 4, 4, 4, 4, 4, - 14, 13, 16, 16, 16, 16, 16, 16, 1, 1, 1, 1, 1, 1, 33, 31, - 3, 3,118, 18, 4, 3,118, 14, 14,170, 15, 15, 15, 69, 4, 4, - 4, 40, 33, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, - 3, 4, 40, 3, 3, 3, 3, 3, 48, 6, 6, 6, 6, 6, 6, 6, + 15, 15, 15, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 20, 22, 15, + 12, 12, 12, 12, 61, 7, 7, 7,102, 1, 1, 1, 1, 1, 1, 1, + 15, 18, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 13, 13, 13, 12, + 21, 6, 6, 6, 8, 8, 81, 21, 6, 6, 6, 6, 8, 8,104, 21, + 7, 7, 7, 7, 7, 3, 3, 3, 64, 7, 7, 7, 7, 7, 7, 7, + 6, 11, 11, 11, 11, 11, 11, 11, 1, 1, 1, 46, 7, 7, 7, 7, + 1, 1, 1, 1, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 46, 7, + 1, 1, 1, 1, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 15, 18, + 1, 1, 1, 1, 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 26, + 10, 10, 10, 10, 10, 3, 3, 3, 72, 12, 87, 12, 23, 88, 65, 12, + 6, 6, 6, 6, 6, 92, 93,120, 72, 24, 24, 47, 94,121,122, 95, + 35, 7, 74, 12,123,124, 7, 56, 8, 8, 8, 48, 8, 8, 8, 11, + 6, 6, 6, 49, 6, 6, 6, 6, 11, 11, 11, 11, 19, 19, 19, 19, + 19, 19, 19, 19, 6, 11, 11, 11, 11, 11, 11, 11, 8, 19, 19, 6, + 19, 11, 11, 8, 19, 8, 6, 8, 8, 19, 11, 8, 11, 6, 8, 19, + 11, 11, 11, 8, 19, 6, 11, 8, 19, 8, 19, 19, 11, 50, 11, 6, + 1, 1, 96, 19, 97, 96, 19, 19, 19, 19, 19, 19, 19, 19, 6, 11, + 19, 97, 11, 8, 11, 11, 11, 11, 11, 11, 6, 6, 6, 8, 19, 11, + 19, 19, 8, 11, 11, 11, 11, 11, 6, 6, 1, 6, 6, 6, 6, 6, + 13, 21, 21, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, 21, + 13, 13, 57, 21, 21, 21, 57, 57, 11, 11, 57, 11, 6, 58, 6, 73, + 21, 21, 21,125, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 19, 6, 8, 11, 6, 11, 11, 11, 11, + 6, 6, 11, 75, 19, 11, 19, 8, 11, 32, 4, 4, 67, 11, 11, 11, + 8, 19, 19, 19, 19, 19, 19, 6, 8, 8, 8, 8, 13, 12, 12, 12, + 6, 6, 6, 6, 76, 77,126, 59,127, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4,128, 38, 30, 4, 38, 4, 4, 4, 4, + 1, 28, 12, 12, 12, 12, 12, 12, 16, 16, 16, 9, 66, 68, 12, 3, + 4, 4, 4, 4, 4, 30,129, 12, 39, 1, 1, 1, 1, 20, 4, 4, + 10, 10, 10, 10, 10, 12, 12, 1, 1, 1, 40, 4, 4, 4, 98, 32, + 4, 4, 69, 51, 37, 4, 4, 1, 10, 10, 10, 10, 10, 1, 41, 52, + 12, 12, 12, 12, 12, 12, 12, 99, 4, 4, 4, 4, 4, 4, 22, 1, + 1, 1, 1, 1, 1, 20, 4, 4, 4, 4, 13, 47, 12, 13, 51, 24, + 1, 1, 1, 4, 4, 51, 4, 4, 4, 4, 51, 4, 51, 4, 4, 4, + 1, 1, 1, 1, 20, 4, 4, 12, 1, 1, 1, 1,130, 1, 1, 1, + 16, 16, 16, 70, 4, 4, 4, 4, 1, 1, 1, 1, 34, 4, 4, 4, + 4, 70, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 17, 22, 15, + 18, 4, 4, 4, 17, 15, 18, 15, 20, 4, 4, 4, 1, 1, 1, 1, + 1, 4, 12, 10, 10, 10, 10, 10, 42, 1, 1, 1, 1, 1, 1, 1, + 20, 15, 29, 1, 1, 1, 1, 1, 18, 4, 4, 17, 15, 15, 18, 1, + 1, 1, 1, 26, 15, 15, 1, 1, 1, 24, 7, 7, 7, 59, 28, 4, + 1, 1, 1, 1, 1, 1, 4, 15, 18, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 22, 1, 1, 1, 1, 1, 1, 10, 10, 10, 10, 10, + 4, 1, 20, 12, 12, 12, 12, 12, 18, 4, 4, 4, 17, 15, 18, 4, + 68, 24, 24, 24,131, 4, 4, 4, 18, 4, 4, 17, 15, 15, 18, 4, + 4, 4, 4, 17, 15, 15, 1, 1, 52, 7, 7, 7, 7, 7, 7, 7, + 1, 1, 1, 1, 1, 1, 1, 15, 17, 15, 15, 15, 15, 15, 18, 4, + 1, 1, 1, 26, 15, 15, 15, 15, 7, 43, 3, 3, 59, 3, 3, 3, + 17, 15, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 4, + 17, 15, 15, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, + 10, 10, 10,100, 7, 7, 7, 43, 20, 15, 40, 1, 1, 1, 1, 1, + 15, 15, 15, 17, 15, 15, 4, 4, 4, 4, 17, 15, 15, 15, 1, 1, + 101, 26, 15, 15, 15, 15, 15, 15, 4, 15, 1, 1, 1, 1, 1, 1, + 18, 4, 4, 15, 15, 15, 18, 41, 3, 3, 1, 26, 7, 7, 7, 60, + 7, 7, 7, 7, 43, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 17, + 15, 4, 4, 4, 15, 15, 15, 15, 10, 15, 12, 12, 12, 12, 12, 12, + 20, 1, 4, 4, 4, 4, 4,132, 1, 1, 1, 51, 4, 4, 4, 30, + 20, 1, 4, 4, 4, 4, 22, 1, 1, 1, 1, 13, 4, 4, 4, 4, + 10, 10, 10, 10, 10, 10, 1, 1, 41, 3, 12, 12, 12, 12, 12, 12, + 12, 44, 44, 3, 4, 3, 3, 3, 7, 7, 32, 32, 32, 23, 23, 15, + 20, 4, 4, 4, 4, 4, 4, 17, 4, 4, 30, 4, 1, 1, 20, 4, + 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 37, 3, 3, 3, 3, + 12, 12, 44, 3, 47, 12, 12, 12, 1, 1, 1, 1, 1, 26, 18, 4, + 17, 4, 4, 4, 18, 17, 18, 22, 1, 1, 1, 15, 4, 1, 1, 4, + 22, 15, 29, 26, 15, 15, 15, 1, 20, 4, 22, 1, 1, 1, 1, 1, + 1, 17, 18, 17, 15, 15, 18, 26, 10, 10, 10, 10, 10, 15, 18, 3, + 6, 6, 6, 6, 6, 76, 58, 6, 1, 1, 1, 1, 1, 1, 20, 4, + 1, 1, 1, 1, 1, 1, 41, 40,133, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1,134, 31, 31, 1, 1, 1, 1, 1, 28, 12, 14, + 135, 1, 1, 1, 1, 1, 1, 1, 1, 4, 17, 15, 15, 15, 15, 29, + 1, 4, 62, 12, 12, 12, 12, 12, 1, 1, 4, 18, 4, 4, 4, 15, + 15, 15, 15, 17, 18, 4, 4, 4, 4, 4, 12, 42, 12, 68, 20, 4, + 12, 12, 12, 78, 12, 38, 4, 70, 1, 34, 1, 1, 1, 1, 1, 1, + 1, 1, 20, 22, 1, 1, 1, 1, 1, 1, 1, 1, 20, 1, 1, 1, + 4, 17, 15, 18, 17, 15, 15, 15, 15, 17, 15, 15, 18, 4, 4, 4, + 3, 3, 12, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 7, 3, + 1, 1, 1, 20, 17, 18, 4, 12, 1, 1, 26, 17, 4, 4, 4, 4, + 17, 17, 18, 4, 4, 4, 17, 15, 12, 12, 12, 42, 12, 12, 12, 12, + 4, 4, 4, 4, 4, 4, 4, 79, 4, 4, 29, 1, 1, 1, 1, 1, + 1, 1, 17, 4, 4, 17, 17, 15, 15, 17, 29, 1, 1, 1, 1, 12, + 44, 3, 3, 3, 3, 32, 4, 4, 4, 4, 3, 3, 3, 3, 47, 12, + 26, 4, 4, 15, 4, 18, 4, 1, 1, 1, 1, 17, 4, 15, 18, 18, + 4, 15, 15, 15, 15, 15, 12, 12, 1, 1, 15, 15, 15, 15, 4, 4, + 4, 4, 15, 4, 4, 30, 12, 12, 10, 10, 10, 10, 10, 10,101, 1, + 6, 6, 6, 6, 19, 6, 6, 6, 4, 30, 4, 4, 4, 4, 4, 4, + 17, 4, 4, 4, 22, 1, 20, 1, 1, 1, 22, 26, 4, 1, 1, 1, + 6, 6, 6, 6, 6, 6, 13, 13, 13, 13, 13, 13, 13, 58, 6, 6, + 6, 6, 6, 6, 58, 6, 6, 6, 6, 6, 6, 6, 6, 80, 13, 13, + 11, 11, 11, 6, 6, 6, 6, 11, 6, 6, 6, 6, 19, 8, 8, 8, + 6, 6, 6, 6, 8, 8, 81,103, 63, 63, 63, 63, 63,136, 16, 16, + 53, 53, 53, 12, 45,105, 45,105, 12, 12, 12, 12,137, 16, 16,138, + 12, 12, 12, 12,106,107, 12,108,109, 12, 54, 55, 12, 12, 12, 12, + 12, 66,109, 12, 12, 12, 12,139,140, 13, 7, 7, 7, 9, 54,110, + 7, 7, 7, 7, 7, 9, 54,110, 4, 4, 4, 4, 4, 4,141, 67, + 79, 67, 79, 4, 4, 4, 4, 4, 3, 71, 3, 82, 3, 19, 8, 6, + 8, 11, 82, 3, 75, 8, 8, 3, 3, 3, 71, 71, 71, 8, 8,142, + 8, 8, 50, 1,111, 3, 6, 8, 9, 9, 75, 6, 6, 35, 3,112, + 14,143,144, 14,113, 3, 3, 3, 9, 9, 36, 3, 3, 9, 3, 3, + 36, 35, 3, 36, 3, 3, 3, 36, 3, 3, 3, 3, 3, 3, 3, 9, + 3, 36, 36, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, + 3, 3, 3, 3, 23, 23, 3, 3, 9, 3, 3, 3,145,146, 3, 3, + 3, 3, 3, 3, 3, 3, 36, 3, 3, 3, 3, 3, 3, 35, 9, 9, + 9, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, + 9, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 3, 3, + 3, 3, 3, 3, 3, 7, 7, 7, 3, 3, 3, 35, 3, 3, 3, 3, + 35, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, + 3, 3, 3, 3, 3, 3, 3, 35, 3, 3, 3, 3, 23, 23, 23, 23, + 23, 23, 23, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, + 9, 9, 54,114, 9, 9, 9, 9, 9, 9, 9, 23, 23, 23, 23, 23, + 9, 54, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,114, 9, 9, 9, + 9, 9, 9, 9, 23, 23, 9, 9, 9, 9, 9, 9, 9, 9, 23, 9, + 9, 9, 36, 35, 9, 9, 36, 3, 11, 8, 11, 19, 19, 19, 19, 8, + 11, 11, 19, 6, 6, 6, 13, 8, 11, 11,112, 3, 3, 82, 19,147, + 4, 11, 6, 6, 76, 12, 61, 12, 1, 1, 1, 1, 1, 1, 1, 34, + 12, 12, 12, 12, 12, 12, 12, 38, 12, 45, 45, 12,106,107, 45, 12, + 12, 12, 12, 65, 12, 78, 45, 12, 45, 23, 23, 23, 23, 12, 12, 42, + 12, 12, 12, 12, 12, 53, 12, 12, 78,148, 12, 12, 12, 12, 12, 12, + 3, 12, 83, 27, 27, 27,149, 53, 12, 23, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 72, 12,150,115, 23, 23, 23, 23, + 23, 3, 23, 23, 23, 23,116, 31,151, 14, 14, 14, 14, 4, 4, 15, + 77, 13, 13, 3, 14,152, 28, 3, 52, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 20,153,117, 39, 1, 1, 1, 1, 1, 28, 13, 39, + 3, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, + 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,118, 12, + 11, 11, 11, 11, 11, 11, 11, 20, 67,154, 4, 4, 4, 4, 4, 42, + 11, 11, 11, 11, 11, 11, 13, 4, 1, 1, 1, 14, 14, 14, 14, 14, + 4, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21,117, 13, 13, 13, 13, + 21, 11, 11, 11, 11, 11, 11, 11, 58, 6, 6, 6, 19, 19, 19, 11, + 11, 11, 11, 11, 57,155, 19, 50, 11, 11, 6, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 8, 8, 11, 8, 8, 11, 11, 11, 11, 11, 11, + 11, 11, 8, 8, 19, 19, 11, 11, 11, 11, 11, 11, 11, 11, 8, 8, + 156, 13,157, 50, 13, 50, 1, 1, 1, 22, 1, 22, 1, 20, 1, 1, + 1, 26, 18, 17, 3, 3, 4, 4, 7, 7, 7, 3, 84, 3, 3, 3, + 1, 1, 12, 12, 12, 12, 12, 12, 15, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 4, 4, 4, 4, 4, 12, + 4, 1, 1, 1, 12, 40, 40, 20, 1, 1, 1, 4, 4, 4, 4, 12, + 1, 1, 1, 20, 4, 4, 4, 4, 4, 15, 15, 15, 15, 15, 15, 62, + 1, 20, 15, 4, 4, 15, 4, 15, 62, 12, 12, 12, 12, 12, 12, 42, + 1, 1, 20, 39, 1, 1, 1, 1, 1, 1, 1, 1, 20, 4, 4, 17, + 18, 17, 18, 4, 4, 4, 4, 4, 1, 20, 1, 1, 1, 1, 17, 15, + 10, 10, 10, 10, 10, 10, 12, 12, 39, 1, 1, 41, 3, 26, 17, 1, + 22, 4, 22, 20, 22, 1, 1, 4, 1, 1, 1, 1, 1, 1, 34, 12, + 1, 1, 1, 1, 1, 26, 4, 15, 12, 34,158, 4, 4, 4, 4, 4, + 6, 6, 6, 6, 6,103, 13, 13, 6, 6, 6, 6, 80, 21, 8, 8, + 1, 26, 18, 15, 17, 62, 18, 4, 6, 6, 6, 6, 6, 6, 50, 22, + 1, 1, 1, 1,159, 1, 1, 1, 1, 21, 21, 21, 21, 21, 21, 21, + 21, 94, 3, 3, 3, 3, 3, 3, 3, 52, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 27, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 84, 3, + 12, 12, 12, 83, 55, 12, 12, 12, 65,160,161, 27, 27, 27, 27, 27, + 27, 27, 55, 83, 55, 12,108,162, 12, 12, 12, 12,116, 27, 27, 55, + 12,163, 9, 9, 68, 12, 12, 12, 1, 1, 1, 1, 1, 1, 1,164, + 12, 12, 87, 12, 23, 88, 65, 12, 6, 6, 6, 6, 6, 92, 93, 54, + 55, 23, 12, 1, 1, 1, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 13, 24,165, 59, 24, 35, 9, 36, 3, + 3, 3, 3, 3,166, 16, 3, 3, 12, 12, 12, 61, 7, 7, 7, 7, + 7, 7, 7, 43, 3, 3, 3, 3, 14, 14,113, 7, 43, 3, 3, 3, + 3, 3, 3, 3, 3, 7, 3, 3, 3, 3, 3, 3, 3, 3, 32, 4, + 85, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 60, 1, + 115, 1, 1, 1, 1, 14, 14, 14,119, 14, 14, 14, 14, 14, 14, 14, + 8, 8, 8, 11, 6, 6, 6, 6, 1, 1, 1, 28, 7, 7, 7, 7, + 1, 1, 1, 41, 64, 7, 7, 7, 1, 1, 1, 1, 1, 46, 7, 7, + 1, 1, 1, 7, 7, 7, 7, 56, 1, 1, 1, 1, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 1, 46, 56, 1, 1, 1, 1, 52, 1, 1, 1, + 1, 1, 20, 4, 4, 85, 7, 7, 6, 6, 6, 6, 6, 7, 7, 7, + 1, 1, 4, 4, 4, 4, 4, 4, 10, 10, 10, 10, 10, 1, 1, 39, + 8, 8, 8, 8,167, 4, 4, 77, 6, 6, 6, 6, 6, 6, 6, 9, + 1, 1, 1, 1, 1, 20,168, 53, 1, 1, 34, 1,169,170, 4, 4, + 44, 3, 3, 3, 52, 1, 1, 1, 7, 7, 7, 60, 1, 1, 1, 1, + 85, 7, 56, 12, 12, 12, 12, 12, 1, 4, 4, 12, 12, 12, 12, 12, + 1, 1, 46, 7, 7, 7, 7, 7, 18, 29, 1, 1, 1, 1, 1, 1, + 4, 4, 4, 30, 12, 12, 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 10, 10, 10, 10, 10, 22, 20, 22, 1, 1, 1, 1, 20, + 15, 18, 4, 17, 18, 30, 99, 12, 12, 4, 4, 4, 4, 4, 98, 16, + 1, 1, 1, 20, 4, 4, 18, 4, 4, 4, 4, 10, 10, 10, 10, 10, + 12, 12, 26, 29, 1, 1, 1, 1, 1, 20, 12, 1, 1, 1, 1, 1, + 1, 26, 15, 4, 4, 4, 4, 17, 29, 1, 28, 12, 38, 4, 30, 18, + 10, 10, 10, 10, 10, 28, 28, 12, 61, 7, 7, 7, 7, 7, 7, 7, + 4, 15, 17, 4, 12, 12, 12, 22, 17, 15, 15, 15, 15, 15, 15, 15, + 1, 1, 1, 26, 15, 15, 29, 1, 1, 15, 15, 4, 4, 4, 4, 4, + 1, 1, 1, 1, 15, 18, 4, 4, 4, 15, 15, 15, 15, 15, 15, 17, + 22, 22, 12, 12, 12, 12, 12, 12, 38, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 26, 15, 4, 4, 4, 4, 15, 4, 17, 22, 1, 28, 12, 12, + 10, 10, 10, 10, 10, 12, 12, 22, 15, 18, 4, 4, 17, 17, 15, 18, + 17, 4, 1, 40, 1, 1, 1, 1, 15, 4, 4, 4, 15, 15, 4, 18, + 30, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 1, 1, 4, 4, + 15, 18, 4, 4, 4, 17, 18, 18, 30, 12, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 20, 18, 15, 4, 4, 4, 18, 28, 12, 12, 12, + 1, 1, 1, 1, 1, 1, 20, 18, 15, 4, 4, 18, 4, 4, 4, 4, + 10, 10, 10, 10, 10, 7, 12, 44, 4, 4, 4, 4, 18, 30, 12, 12, + 7, 7, 7, 7, 7, 7, 7, 60, 15, 15, 15, 15, 15, 18, 17, 22, + 29, 18, 12, 12, 12, 12, 12, 12, 26, 15, 4, 4, 4, 4, 15, 15, + 22, 40, 15, 15, 15, 15, 15, 15, 20, 4, 4, 4, 4, 22, 1, 1, + 1, 20, 4, 4, 17, 20, 4, 30, 12, 12, 12, 38, 4, 4, 4, 4, + 20, 4, 4, 17, 18, 4, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 17, 4, 12, 40, 12, 12, 12, 12, 12, 12, 1, 1, 1, + 17, 4, 17, 17, 15, 15, 15, 15, 4, 4, 4, 4, 4, 4, 4, 18, + 12, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 17, 4, 4, 4, + 17, 4, 18, 4, 4, 4, 4, 4, 4, 4, 4, 20, 4, 4, 4, 4, + 1, 1, 1, 1, 1, 15, 15, 15, 4, 17, 18, 18, 1, 1, 1, 1, + 1, 1, 1, 1, 34, 1, 1, 1, 1, 20, 17, 62, 12, 12, 12, 12, + 4, 26, 1, 1, 1, 1, 1, 1, 1, 1, 15, 4, 4, 4, 4, 15, + 17, 30, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 10, 4, 4, 4, + 7, 7, 43, 3, 3, 3, 59, 24, 84, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 47, 12, 12,119, 14, 14, 14, 14, 14, + 22, 1, 1, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 15, 18, 4, + 4, 4, 30, 12, 12, 12, 12, 12, 4, 4, 4, 30, 12, 12, 3, 3, + 13, 13, 44, 3, 3, 3, 3, 3, 10, 10, 10, 10, 10,171, 7, 7, + 7, 60, 1, 1, 1, 1, 1, 1, 13, 39, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 34,118, 12, 7, 7, 7, 56, 12, 12, 12, 12, + 8, 8, 8, 8, 8, 11, 6, 6, 26, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 18, 4, 69, 13, 13, 13, 13, 13, 13, + 13, 42, 4, 4, 4, 4, 4, 4, 15, 13, 14, 14, 14, 14, 14, 14, + 1, 1, 1, 1, 1, 1, 32, 30, 3, 3, 3, 3, 3, 3, 35, 9, + 3, 3, 3, 32, 37, 3, 3, 3, 3, 3, 86, 18, 4, 3, 86, 15, + 15,172, 16, 16, 16, 70, 4, 4, 4, 37, 32, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 37, 3, 3, 3, 3, 3, + 15,173, 3, 3, 3, 32, 37, 86, 48, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 49, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 48, 6, 6, 6, 6, 49, 6, 6, 6, 8, 8, 8, 8, 48, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 49, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 48, 6, 6, 6, 6, 49, 6, 6, 6, 8, 8, 8, 8, 48, 6, 6, 6, - 6, 49, 6, 6, 6, 12, 6, 9, 4, 4, 4, 40, 3, 33, 4, 4, - 4, 4, 4, 4, 4, 4, 40, 3, 3, 3, 33, 3, 3, 3, 3, 3, - 3, 3, 40, 47, 10, 10, 10, 10, 10, 10, 10, 10, 10, 37, 4, 4, - 6, 6, 6, 6, 6,109, 6, 6, 4, 4, 4, 68, 13, 13, 13, 13, - 9, 9, 9, 9, 9, 9, 9, 41, 1, 1, 1, 1, 1, 1, 4, 4, - 9, 9, 9, 9, 9, 9, 9,171, 1, 1, 1, 1, 1, 34, 4, 4, - 172, 9, 9, 9, 9, 9, 9, 98, 1, 21, 1, 22, 1, 1, 1, 4, - 1, 1, 21, 4, 4, 4, 4, 34, 6, 6, 4, 4, 4, 68, 13, 13, - 7, 7, 7, 7, 7, 7, 63, 7,173, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 63, 7, 7, 7, 7, 7, 7, 43, 3, - 3, 3, 3, 3, 3, 92, 20, 20, 2, 2, 7, 7, 3, 3, 26, 26, - 12, 12, 4, 4, 5, 5, 15, 15, 9, 9, 13, 13, 21, 21, 25, 25, - 9, 5, 6, 6, 10, 10, 1, 1, 14, 14, 12, 10, 10, 12, 5, 9, - 24, 24, 7, 12, 12, 7, 22, 18, 23, 23, 0, 0, 17, 17, 7, 10, - 18, 22, 7, 21, 10, 7, 12, 21, 8, 8, 26, 12, 7, 6, 25, 26, - 26, 25, 21, 12, 6, 7, 21, 7, 12, 26, 7, 26, 21, 6, 15, 26, + 6, 49, 6, 6, 6, 11, 6, 10, 4, 4, 4, 37, 3, 32, 4, 4, + 4, 4, 4, 4, 4, 4, 37, 3, 3, 3, 32, 3, 3, 3, 3, 3, + 3, 3, 37, 47, 12, 12, 12, 12, 12, 12, 12, 12, 12, 38, 4, 4, + 6, 6, 6, 6, 6,111, 6, 6, 11, 6, 6, 6, 11, 11, 19, 6, + 19, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 11, 11, 11, 11, + 6, 6, 6, 6, 6, 6, 80, 13, 4, 4, 4, 69, 13, 13, 13, 13, + 10, 10, 10, 10, 10, 10, 10, 41, 1, 1, 1, 1, 1, 1, 4, 4, + 10, 10, 10, 10, 10, 10, 10,174, 1, 1, 1, 1, 1, 34, 4, 4, + 175, 10, 10, 10, 10, 10, 10,100, 1, 20, 1, 22, 1, 1, 1, 4, + 1, 1, 20, 4, 4, 4, 4, 34, 6, 6, 4, 4, 4, 69, 13, 13, + 7, 7, 7, 7, 7, 7, 64, 7,176, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 64, 7, 7, 7, 7, 7, 7, 43, 3, + 3, 3, 3, 3, 3, 95, 21, 21, 2, 2, 7, 7, 3, 3, 26, 26, + 12, 12, 4, 4, 5, 5, 15, 15, 9, 9, 25, 25, 13, 13, 9, 5, + 21, 21, 6, 6, 14, 14, 10, 10, 1, 1, 12, 10, 10, 12, 5, 9, + 7, 12, 24, 24, 12, 7, 22, 18, 23, 23, 0, 0, 7, 10, 18, 22, + 7, 21, 10, 7, 12, 21, 18, 18, 26, 12, 8, 8, 7, 6, 26, 25, + 25, 26, 12, 26, 21, 12, 6, 7, 21, 7, 7, 26, 21, 6, 15, 26, 21, 26, 20, 19, 7, 15, 26, 21, 9, 25, 5, 25, 5, 7, 6, 12, - 25, 22, 18, 21, 15, 21, 6, 24, 6, 5, 26, 23, 26, 7, 15, 7, - 21, 15, 10, 21, 29, 29, 26, 15, 21, 17, 25, 21, 11, 11, 21, 23, - 12, 6, 1, 12, 18, 18, 9, 26, 29, 21, 21, 9, 24, 5, 25, 9, - 5, 21, 17, 21, 11, 12, 8, 24, 26, 9, 21, 22, 23, 26, 12, 15, - 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, 5, 22, 25, 18, 24, 26, - 26, 24, 9, 8, 8, 5, 9, 6, 12, 1, 21, 1, 13, 21, 13, 7, - 17, 7, 5, 6, 5, 24, 9, 24, 22, 20, 21, 20, 19, 21, 21, 16, - 16, 21, 7, 5, 5, 26, 14, 15, 18, 25, 7, 14, 17, 22, 17, 6, - 24, 6, 6, 21, 26, 10, 25, 0, 7, 20, 25, 1, 24, 15, 7, 19, - 9, 21, 17, 26, 23, 12, 17, 12, 1, 21, 24, 7, 23, 7, 12, 23, - 29, 7, 7, 22, 14, 7, 29, 1, 27, 28, 1, 29, 21, 29, 15, 6, - 18, 6, 12, 11, 26, 5, 14, 9, 5, 14, 26, 22, 18, 26, 5, 12, + 26, 7, 17, 17, 25, 22, 18, 21, 15, 21, 6, 24, 6, 5, 26, 23, + 15, 7, 21, 15, 10, 21, 29, 29, 26, 15, 21, 17, 25, 21, 11, 11, + 21, 23, 12, 6, 1, 12, 9, 26, 29, 21, 21, 9, 24, 5, 25, 9, + 5, 21, 17, 6, 17, 21, 11, 12, 5, 6, 8, 24, 26, 9, 21, 22, + 23, 26, 12, 15, 26, 10, 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, + 5, 22, 25, 18, 24, 26, 26, 24, 9, 8, 8, 5, 12, 1, 21, 1, + 13, 21, 13, 7, 17, 7, 5, 24, 9, 24, 22, 20, 21, 20, 19, 21, + 21, 16, 16, 21, 18, 6, 7, 5, 5, 26, 14, 15, 18, 25, 7, 14, + 17, 22, 24, 6, 6, 21, 21, 14, 25, 0, 7, 20, 25, 1, 24, 15, + 7, 19, 9, 21, 6, 26, 23, 12, 17, 12, 1, 21, 24, 7, 23, 7, + 12, 23, 29, 7, 7, 22, 14, 7, 29, 1, 27, 28, 1, 29, 21, 29, + 15, 6, 12, 11, 26, 5, 14, 9, 5, 14, 26, 22, 18, 26, 5, 12, 22, 21, 18, 17, 26, 6, 26, 14, 14, 6, 12, 24, 11, 21, 24, 9, - 6, 9, 6, 10, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 7, 1, - 25, 24, 26, 1, 21, 14, 9, 12, 12, 17, 13, 15, 10, 1, 13, 23, - 7, 13, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, - 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, - 0, 0, 0, 0, 41, 42, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 9, 0, 0, 0, 10, - 11, 12, 13, 0, 14, 15, 16, 0, 17, 18, 19, 20, 21, 1, 22, 1, - 23, 1, 2, 1, 2, 1, 2, 0, 2, 1, 24, 1, 2, 25, 2, 0, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 36, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 38, 0, 0, - 39, 0, 0, 40, 0, 41, 0, 0, 0, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 0, 0, 51, 0, 0, 0, 52, 0, 0, 0, 53, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 3, 0, 55, 56, 0, 57, 0, 0, 0, 0, - 0, 0, 58, 59, 60, 0, 0, 0, 0, 61, 0, 0, 62, 63, 64, 4, - 65, 0, 0, 66, 67, 0, 0, 0, 68, 0, 0, 0, 0, 69, 0, 0, - 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 71, 0, 0, 0, 72, 0, 73, 0, 0, 74, 0, 0, 75, 0, 0, 0, - 0, 0, 0, 0, 0, 76, 77, 0, 0, 0, 0, 78, 79, 0, 80, 81, - 0, 0, 82, 5, 0, 83, 4, 0, 84, 85, 0, 0, 86, 87, 88, 0, - 89, 0, 90, 0, 91, 0, 0, 3, 92, 3, 0, 93, 0, 94, 0, 0, - 0, 5, 0, 0, 0, 95, 96, 0, 97, 98, 99,100, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0,101,102, 0, 0, 0, 0, 0, 0,103, 0, - 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105, 6, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,106, 0, 0,107, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,108,109, 0, 0,110, 0, 0, 0, 0, 0, - 0,111, 0,112, 0, 6, 0, 0, 0, 0, 0,113,114, 0, 0, 0, - 0, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,117, 0, 0, 0, - 0, 0, 0, 0,118, 0,119, 0, 0, 0, 0, 0, 0, 0, 2, 1, - 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 11, 0, 0, 0, 14, 0, - 0, 0, 16, 3, 17, 18, 19, 20, 21, 22, 0, 23, 0, 0, 0, 0, - 24, 25, 26, 27, 0, 0, 0, 0, 28, 0, 0, 29, 30, 0, 31, 0, - 32, 33, 0, 0, 34, 0, 35, 36, 0, 0, 0, 0, 0, 37, 38, 0, - 39, 40, 0, 0, 41, 0, 0, 0, 42, 0, 0, 43, 44, 45, 46, 1, - 47, 0, 0, 1, 0, 0, 7, 1, 48, 0, 0, 0, 0, 0, 49, 50, - 0, 0, 0, 0, 0, 0, 51, 52, 0, 0, 0, 0, 0, 0, 53, 54, - 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 57, 58, 0, 0, 0, 59, - 0, 0, 0, 0, 0, 0, 60, 12, 0, 0, 0, 0, 61, 0, 0, 0, - 62, 0, 5, 0, 63, 0, 0, 0, 0, 64, 0, 0, 0, 0, 65, 0, - 66, 0, 0, 0, 0, 6, 67, 0, 0, 0, 68, 69, 70, 71, 0, 0, - 0, 0, 72, 5, 0, 73, 74, 0, 0, 75, 0, 0, 0, 76, 77, 0, - 0, 0, 78, 0, 79, 80, 81, 82, 83, 3, 84, 0, 85, 86, 87, 0, - 0, 8, 9, 0, 0, 3, 3, 0, 0, 88, 0, 0, 89, 0, 0, 0, - 0, 8, 90, 0, 91, 0, 0, 0, 0, 0, 9, 10, 0, 92, 0, 5, - 0, 3, 9, 0, 0, 93, 0, 0, 94, 0, 0, 6, 0, 0, 0, 0, - 0, 0, 95, 96, 0, 0, 10, 0, 0, 1, 0, 0, 97, 0, 0, 0, - 0, 98, 0, 0, 0, 0, 12, 0, 0, 13, 0, 0, 0, 0, 99,100, - 0, 0,101, 0, 0,102, 0, 0, 0,103, 0, 0, 0,104, 0, 0, - 0,105, 0, 0, 0, 0,106,107, 13, 0, 0,108, 0, 0, 0, 10, - 0, 0,109,110, 0, 0,111,112, 0, 0, 0, 0, 0, 0,113, 0, - 0,114, 0, 0, 0, 0,115, 1, 0,116,117,118, 6, 0, 0,119, - 7, 0, 0,120, 0, 0, 0,121, 0, 0, 0, 0, 0, 0,122, 0, - 0,123, 0, 0, 0, 0,124, 11, 0, 0, 0, 0, 0, 6, 0, 0, - 0, 0, 5, 15, 0, 0, 0, 0,125, 0, 0,126, 0, 0, 0, 0, - 15, 0, 0,127, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,128, 0, - 0, 0,129, 0,130, 0, 0, 0, 0,131,132,133, 0,134, 0,135, - 0, 0, 0,136,137,138, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, - 0,139, 0, 0, 0,140, 0, 0, 0,141, 0, 0, 0,142,143, 0, - 144, 0, 0,145, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 9, - 1, 1, 1, 1, 0, 0, 0, 2, 0, 3, 0, 0, 3, 0, 0, 0, - 0, 0, 0, 19, 0, 0, 0, 6, 11, 0, 0, 0, 0, 14, 0, 0, - 15, 0, 0, 0, 0, 0, 0, 17, 29, 0, 0, 0, 0, 0, 31, 0, - 0, 2, 0, 0, 1, 12, 0, 0, 1, 49, 50, 5, 51, 52, 53, 5, - 5, 22, 32, 23, 1, 54, 24, 55, 16, 33, 56, 57, 58, 1, 1, 1, - 6, 1, 0, 0, 59, 7, 60, 1, 34, 5, 7, 61, 62, 63, 64, 65, - 66, 67, 0, 0, 1, 1, 68, 0, 0, 0, 69, 70, 71, 35, 1, 25, - 72, 0, 0, 0, 0, 8, 1, 26, 16, 26, 73, 27, 74, 0, 0, 0, - 36, 25, 75, 37, 7, 37, 76, 0, 0, 0, 6, 1, 7, 0, 0, 17, - 0, 8, 38, 1, 1, 13, 13, 11, 0, 0, 39, 0, 0, 6, 18, 1, - 0, 0, 8, 16, 5, 1, 1, 1, 77, 7, 36, 18, 78, 7, 35, 1, - 79, 10, 0, 0, 0, 80, 0, 0, 0, 0, 2, 3, 0, 0, 14, 0, - 0, 0, 81, 0, 0, 0, 82, 0, 0, 0, 83, 0, 0, 0, 84, 0, - 0, 0, 40, 0, 0, 85, 86, 0, 87, 88, 89, 90, 91, 92, 0, 0, - 0, 93, 0, 0, 0, 15, 28, 0, 0, 0, 0, 13, 0, 41, 0, 0, - 14, 0, 0, 20, 0, 0, 94, 0, 0, 0, 95, 0, 0, 6, 29, 0, - 0, 13, 1, 96, 1, 18, 33, 97, 25, 23, 7, 1, 1, 1, 1, 27, - 1, 7, 98, 0, 0, 9, 0, 0, 0, 0, 6, 23, 1, 0, 0, 0, - 0, 0, 30, 0, 0, 21, 0, 0, 30, 0, 0, 0, 0, 15, 0, 0, - 12, 32, 24, 5, 99, 22, 42, 17, 0, 10, 11, 0, 7, 1, 7,100, - 101, 1, 1, 1, 1,102,103,104,105, 1,106, 10, 20,107,108, 5, - 10, 0, 0, 0, 0, 0,109,110, 0, 0,111, 0, 0, 1, 1, 11, - 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 43, 40, 2, 0, 0, 0, - 44,112, 10, 8, 20, 0, 0, 0, 0, 0, 0,113, 1, 16, 5, 24, - 0, 8, 12, 0, 0, 0, 0,114, 0, 0,115, 2, 0,116, 0, 0, - 0, 1, 0, 0, 0, 0, 13, 11, 0, 0, 6, 10, 0, 0, 45, 39, - 0, 45, 16, 18, 46, 27, 0, 0, 3, 0, 0, 2, 12, 0, 0, 0, - 2, 3, 0, 0, 3, 0, 21, 0, 0, 31, 0, 0, 0, 0,117, 0, - 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, 0, 0, 0, 30, - 14, 21, 0, 0, 47, 0, 0, 0, 9, 0, 0, 0, 0, 47, 0, 0, - 0, 0, 2, 0, 0, 0, 0, 28, 0, 0, 4, 0, 21, 41, 0, 0, - 28, 0, 0, 0, 22, 42, 0, 0,118, 0, 0, 0, 0, 0, 0,119, - 0,120,121,122,123, 0, 43, 5, 48, 13, 34, 0, 0, 0, 8, 11, - 8, 10, 0, 0, 1, 12, 1, 1, 1, 1, 26, 1, 38, 44, 12, 0, - 0, 0, 0, 1, 0, 0, 0,124, 0, 0, 0, 46, 6, 19, 0, 8, - 0, 20, 0, 0, 5, 48, 0, 0, 0, 1,125, 0, 0, 0, 0,230, - 230,230,230, 0, 0, 0, 9, 9, 0, 0, 0, 0, 9, 0, 0,220, - 220,220,220, 0, 0, 0,230,230,230,220,230, 0, 0,230,230, 7, - 0, 0, 0,230, 0, 0, 0,230,230, 0, 0,230,230,230, 0, 0, - 230,230,230, 0, 0, 9, 0, 0, 0, 0, 7,230,230,230,220, 0, - 220, 0, 0,230,220,220,220, 0, 0,230, 0, 0,230, 0, 0, 0, - 0, 7, 0, 1, 1, 1, 1,220,230,230,230,220,220,230,230,220, - 230,230,220,230, 0, 0,230,230,220, 0, 0, 0, 9, 9, 0,220, - 0, 0, 0, 0, 0, 9, 9, 0, 9, 7, 0, 1,220,220,220,220, - 220,220,230,230,230,220,220,230,220,220,230,230,220,230,230,220, - 230,220,230,230,230, 0,230, 0,220,220,220,220,220, 0, 0, 9, - 9, 0, 0, 1, 0, 0, 0, 0, 0, 0,220,230, 0,230,230, 0, - 0,220,220, 0, 0,230,220, 0, 0, 9, 7,220,220,220, 0,230, - 232,220,220,220,220,232,216,220,202,202,220,220,220,220,202,202, - 220,220,220,230,240,230,220,230,220,220, 0,232,220,220,230,233, - 234,234,233,234,234,233,230, 0,220,230,230,230,230,222,220,230, - 222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, - 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, - 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230, 35, 0, 0, 0,230, - 0,220,230, 0, 36, 0, 0,220,220,230,220,220,230,230, 0,230, - 230, 0,220, 27, 28, 29,230, 0,230,220,230, 0, 84, 91, 0,103, - 103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122, 0, - 220, 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, - 0,130,130,130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, - 0,220, 0, 0,228, 0, 0, 0,222,230,220,230, 0, 0,220,230, - 220, 0,220,230,230,230,234,230, 0, 1, 1,230,234,214,220,202, - 230,230,230,230,230,232,228,228,220,218,230,233,220,230,220,230, - 230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, - 0,218,228,232,222,224,224, 0, 8, 8, 0,220, 0, 0,230, 0, - 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, 0, - 7, 9, 0, 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, - 1, 0, 0, 0,226,216,216,216,216,216, 0,232,232,220,230,230, - 230, 7, 0, 1, 0, 0, 32, 0, 48, 0, 0, 84, 96,135,144, 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,176, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 40, 0, 0, - 0, 0, 0, 48, 56, 64, 0, 0, 0, 0, 0, 72, 80, 88, 96,104, - 0, 0, 0, 0, 0, 0, 0, 0,112, 0,120, 0, 0, 0, 0, 0, - 0,128,136,144,152,160,168, 0, 0, 0,176,184,192, 0, 0, 0, - 0, 0, 0,200, 0, 0, 0, 0, 0, 0, 0, 0,208, 0, 0,216, - 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, - 36, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 0, 0, 64, 0, - 68, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 72, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 0, 0, 0, - 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 76, 80, 84, 88, 0, 0, - 12, 92, 96, 28, 0,100,104, 4, 4, 4,108, 44,112,116,120, 4, - 124, 0,128,132, 4, 4, 48,136,140, 0, 32, 0, 0, 0, 40, 0, - 0, 0, 0, 0, 0, 0, 4, 48, 0, 52,144, 20,148,152, 4, 0, - 0,156,160,164,168,172, 4, 0,176, 56, 60,180, 32, 0, 16,184, - 56, 0, 0, 0, 0, 0, 52, 12, 12, 0, 0, 0, 0, 12, 0, 0, - 188, 8, 8, 8, 8,192,196, 8, 8, 8, 8,200,204,208,212, 60, - 44, 0, 0, 0, 0, 0, 0, 0,216, 28,220, 0, 12, 4, 16, 0, - 0, 0, 0,224,228, 0, 0, 0, 0, 0, 4,232, 32, 0, 0, 0, - 0, 0, 0, 0,236, 12, 0, 0, 0, 0, 16, 0, 36, 0, 0, 0, - 24, 0, 0, 0,240,244, 0, 0, 0, 0, 2, 2, 2, 2, 4, 4, - 4, 4, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 6, 8, 0, 10, - 12, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 14, 16, 6, 8, - 0, 0, 4, 8, 0, 0, 2, 2, 2, 0, 0, 6, 4, 8, 2, 0, - 2, 0, 0, 0, 0, 6, 0, 20, 0, 0, 0, 22, 0, 0, 0, 6, - 8, 0, 24, 26, 28, 0, 0, 0, 30, 0, 0, 0, 0, 32, 34, 36, - 38, 0, 0, 40, 42, 0, 0, 0, 18, 0, 0, 0, 2, 2, 2, 2, - 0, 2, 2, 2, 0, 6, 44, 0, 0, 0, 0, 2, 0, 46, 48, 50, - 0, 0, 52, 0, 0, 0, 6, 4, 54, 0, 2, 0, 0, 2, 2, 56, - 58, 60, 0, 62, 64, 18, 2, 10, 12, 0, 0, 0, 66, 8, 0, 2, - 2, 2, 0, 6, 4, 4, 4, 4, 68, 2, 70, 4, 4, 4, 8, 72, - 0, 0, 74, 76, 2, 0, 78, 0, 0, 0, 4, 8, 2, 0, 0, 0, - 80, 0, 6, 4, 4, 4, 4, 8, 0, 2, 2, 2, 2, 6, 4, 4, - 4, 8, 0, 0, 0, 82, 0, 84, 86, 0, 0, 0, 2, 88, 0, 0, - 0, 90, 6, 8, 2, 0, 0, 0, 6, 4, 4, 4, 8, 0, 2, 0, - 2, 2, 6, 4, 4, 8, 0, 10, 12, 6, 8, 2, 0, 0, 50, 84, - 118,152, 17,161, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 5, 16, 17, 18, 1, 1, 1, 1, 1, 1, 19, 1, + 9, 6, 6, 9, 6, 10, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, + 7, 1, 25, 24, 26, 1, 9, 12, 12, 17, 7, 24, 24, 12, 13, 15, + 10, 1, 10, 26, 13, 23, 7, 13, 23, 15, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, + 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, + 0, 9, 0, 0, 0, 10, 11, 12, 13, 0, 14, 15, 16, 0, 17, 18, + 19, 20, 21, 1, 22, 1, 23, 1, 2, 1, 2, 1, 2, 0, 2, 1, + 24, 1, 2, 25, 2, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 39, 0, 0, 40, 0, 41, 0, 0, 0, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 0, 0, 51, 0, 0, 0, 52, 0, + 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 3, 0, 55, 56, + 0, 57, 0, 0, 0, 0, 0, 0, 58, 59, 60, 0, 0, 0, 0, 61, + 0, 0, 62, 63, 64, 4, 65, 0, 0, 66, 67, 0, 0, 0, 68, 0, + 0, 0, 0, 69, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 72, 0, 73, 0, 0, 74, + 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 76, 77, 0, 0, 0, + 0, 78, 79, 0, 80, 81, 0, 0, 82, 5, 0, 83, 4, 0, 84, 85, + 0, 0, 86, 87, 88, 0, 89, 0, 90, 0, 91, 0, 0, 3, 92, 3, + 0, 93, 0, 94, 0, 0, 0, 5, 0, 0, 0, 95, 96, 0, 97, 98, + 99,100, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,101,102, 0, 0, + 0, 0, 0, 0,103, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, + 0, 0,105, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,106, 0, + 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0,108,109,110, 0, 0, + 111,112, 0, 0, 0, 0, 0,113, 0,114, 0, 6, 0, 0, 0, 0, + 0,115,116, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0,118, 0, + 0, 0,119, 0, 0, 0, 0, 0, 0, 0,120, 0,121, 0, 0, 0, + 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, + 11, 0, 0, 0, 15, 0, 0, 0, 17, 3, 18, 19, 20, 21, 22, 23, + 0, 24, 0, 0, 0, 0, 25, 26, 27, 28, 0, 0, 0, 0, 29, 0, + 0, 30, 31, 0, 32, 0, 33, 34, 0, 0, 35, 0, 36, 37, 0, 0, + 0, 0, 0, 38, 39, 0, 40, 41, 0, 0, 42, 0, 0, 0, 43, 0, + 0, 44, 45, 46, 47, 1, 48, 0, 0, 1, 0, 0, 7, 1, 49, 0, + 0, 0, 0, 0, 50, 51, 0, 0, 0, 0, 0, 0, 52, 53, 0, 0, + 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 56, 0, 57, 0, 0, 0, + 58, 59, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 61, 12, 0, 0, + 0, 0, 62, 0, 0, 0, 63, 0, 5, 0, 64, 0, 0, 0, 0, 65, + 0, 0, 0, 0, 66, 0, 67, 0, 0, 0, 0, 6, 68, 0, 0, 0, + 69, 70, 71, 72, 13, 0, 0, 0, 73, 5, 0, 74, 75, 0, 0, 76, + 0, 0, 0, 77, 78, 0, 0, 0, 79, 0, 80, 81, 82, 83, 84, 3, + 85, 0, 86, 87, 13, 0, 0, 8, 9, 0, 0, 3, 3, 0, 0, 88, + 0, 0, 89, 0, 0, 0, 0, 8, 90, 0, 91, 0, 0, 0, 0, 0, + 9, 10, 0, 92, 0, 5, 0, 3, 9, 0, 0, 93, 0, 0, 94, 0, + 0, 6, 0, 0, 0, 0, 0, 0, 95, 96, 0, 0, 10, 0, 0, 1, + 0, 0, 97, 0, 0, 0, 0, 98, 0, 0, 0, 0, 12, 0, 0, 14, + 0, 0, 0, 0, 99,100, 0, 0,101, 0, 0,102, 0, 0, 0,103, + 0, 0, 0,104, 0, 0, 0,105, 0,106, 0, 0,107,108, 14, 0, + 0,109, 0, 0, 0, 10, 0, 0,110,111, 0, 0,112,113, 0, 0, + 0, 0, 0, 0,114, 0, 0,115, 0, 0, 0, 0,116, 1, 0,117, + 118,119, 6, 0, 0,120, 7, 0, 0,121, 0, 0, 0,122, 0, 0, + 0, 0, 0, 0,123, 0, 0,124, 0, 0, 0, 0,125, 11, 0, 0, + 0, 0, 0, 6, 0, 0, 0, 0, 5, 16, 0, 0, 0, 0,126, 0, + 0,127, 0, 0, 0, 0, 16, 0, 0,128, 0, 0, 0, 0, 0, 4, + 0, 0, 0, 0,129, 0, 0, 0,130, 0,131, 0, 0, 0, 0,132, + 0, 0, 0,133,134,135, 0,136, 0,137,138, 0, 0,139, 0, 0, + 0,140,141,142, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, 0,143, + 0, 0, 0,144, 0, 0, 0,145, 0, 0, 0,146,147, 0,148, 0, + 0,149, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 9, 1, 1, + 1, 1, 0, 0, 0, 2, 0, 3, 0, 0, 3, 0, 0, 0, 0, 0, + 0, 21, 0, 0, 0, 5, 11, 0, 0, 0, 0, 14, 0, 0, 15, 0, + 0, 0, 0, 0, 0, 19, 10, 0, 0, 0, 23, 0, 0, 0, 0, 0, + 35, 0, 0, 2, 0, 0, 1, 12, 0, 0, 1, 49, 50, 6, 51, 52, + 53, 6, 6, 25, 36, 26, 1, 54, 17, 55, 16, 27, 56, 57, 58, 1, + 1, 1, 5, 1, 0, 0, 59, 7, 60, 1, 18, 6, 7, 61, 62, 63, + 64, 65, 66, 67, 68, 0, 1, 1, 69, 0, 0, 0, 70, 71, 72, 37, + 1, 28, 73, 0, 0, 0, 0, 8, 1, 29, 16, 29, 74, 38, 75, 0, + 0, 0, 30, 28, 76, 31, 7, 31, 77, 0, 0, 0, 5, 1, 7, 0, + 0, 19, 0, 8, 39, 1, 1, 13, 13, 11, 0, 0, 40, 0, 0, 5, + 20, 1, 0, 0, 8, 16, 6, 1, 1, 1, 78, 7, 30, 20, 79, 7, + 37, 1, 80, 10, 0, 0, 0, 81, 0, 0, 0, 0, 2, 3, 0, 0, + 14, 0, 0, 0, 82, 0, 0, 0, 83, 0, 0, 0, 84, 0, 0, 0, + 85, 0, 0, 0, 41, 0, 0, 86, 87, 0, 88, 89, 90, 91, 92, 93, + 0, 0, 0, 94, 0, 0, 0, 15, 32, 0, 0, 0, 0, 13, 0, 42, + 0, 0, 14, 0, 0, 22, 0, 0, 95, 0, 0, 0, 96, 0, 0, 5, + 23, 0, 0, 13, 1, 97, 1, 20, 27, 98, 28, 26, 7, 1, 1, 1, + 1, 30, 1, 7, 99, 18, 0, 9, 0, 0, 0, 0, 5, 26, 1, 0, + 0, 0, 0, 0, 33, 0, 0, 24, 0, 0, 33, 0, 0, 0, 0, 15, + 0, 0, 12, 36, 17, 6,100, 25, 43, 19, 0, 10, 11, 0, 7, 1, + 7,101,102, 1, 1, 1, 1,103,104,105,106, 1,107, 10, 22,108, + 109, 6, 0, 0,110,111, 0, 0,112, 0, 0, 1, 1, 11, 0, 0, + 0, 8, 0, 0, 0, 3, 0, 0, 34, 41, 2, 0, 0, 0, 44,113, + 10, 8, 22, 0, 0, 0, 0, 0, 0,114, 1, 16, 6, 17, 0, 8, + 12, 0, 0, 0, 0,115, 0, 0,116, 2, 0,117, 0, 0, 0, 1, + 0, 0, 0, 0, 13, 11, 0, 0, 5, 10, 0, 0, 5, 17, 27, 31, + 18, 40, 0,118, 16, 20, 45, 38, 0, 0, 3, 0, 0, 2, 12, 0, + 0, 0, 2, 3, 0, 0, 3, 0, 24, 0, 0, 35, 0, 0, 0, 0, + 119, 0, 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, 0, 0, + 0, 33, 14, 24, 0, 0, 46, 0, 0, 0, 9, 0, 0, 0, 0, 46, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 32, 0, 0, 4, 0, 24, 42, + 0, 0, 32, 0, 0, 0, 25, 43, 0, 0,120, 0, 0, 0, 0, 0, + 0,121, 0, 34, 23, 0, 0,122,123,124, 47, 0, 34, 6, 48, 13, + 18, 0, 0, 0, 8, 11, 8, 10, 0, 0, 47, 0,125,126,127, 0, + 0, 0, 1, 12, 1, 1, 1, 1, 29, 1, 39, 44, 12, 0, 0, 0, + 0, 1, 0, 0, 0,128, 0, 0, 0, 45, 5, 21, 0, 8, 0, 22, + 0, 0, 6, 48, 0, 0, 0, 1,129, 0, 0, 0, 0,230,230,230, + 230, 0, 0, 0, 9, 9, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, + 230,220,220,220,220,230,230,220,230, 0, 0,230,230, 7, 0, 0, + 0,230, 0, 0, 0,230,230, 0, 0,230,230,230, 0, 0,230,230, + 230, 0, 0, 9, 0, 0, 0, 0, 7,230,230,230,220,220,220,230, + 230,230,230,220,220, 0,220, 0, 0,230,220,220,220, 0, 0,230, + 0, 0,230, 0, 0,220, 0, 0, 0, 0, 0, 7, 0, 1, 1, 1, + 1,220,230,230,230,220,220,220,230,220,230,230,220,230, 0, 0, + 230,230,220,230,230,220,230,220,230, 0, 9, 9, 0, 0, 0, 9, + 9, 0, 0, 0,220, 0, 9, 7, 0, 1,220,220,220,230,220,220, + 230,230,220, 0, 0,230,230, 0,230, 0,220,220,220,220,220, 0, + 0, 9, 9, 0, 0, 1, 0, 0, 0,230, 0,230,230, 0, 0,230, + 220, 0, 0, 9, 7,216,216,216, 0,220,220,220, 0,230,232,220, + 220,220,220,232,216,220,202,202,220,220,220,220,202,202,220,220, + 220,230,240,230,220,230,220,220, 0,232,220,220,230,233,234,234, + 233,234,234,233,230, 0,220,230,230,230,230,222,220,230,222,228, + 230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, + 23, 0, 24, 25, 0,230,220, 0, 18, 10, 21, 0, 0, 30, 31, 32, + 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230, 35, 0, 0, + 0,230, 0,220,230, 0, 36, 0, 0,220,220,230,220,220,230,230, + 0,230,230, 0,220, 27, 28, 29,230, 0,230,220,230, 0, 84, 91, + 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122, + 122, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, 0, + 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, 9, 0,230, + 230, 0, 0,220, 0, 0,228, 0, 0, 0,222,230,220,230, 0, 0, + 220,230,220, 0,220,230,230,230,234,230, 0, 1, 1,230,234,214, + 220,202,230,230,230,230,230,232,228,228,220,218,230,233,220,230, + 220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, + 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,220, 0, 0, + 230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230,220, + 0, 0, 0,220,220, 0, 7, 9, 0, 6, 6, 0, 0, 0, 0, 1, + 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216, 0, 0, 0, + 1, 1, 0, 0,216,216,216, 0, 0,232,232,220,230,230,230, 7, + 0, 1, 32, 48, 0, 84,118, 8, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 144, 0, 0, 0, 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, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 32, 0, 0, 40, 48, 0, + 0, 56, 64, 72, 0, 0, 0, 0, 0, 0, 0, 80, 88, 0, 0, 0, + 96,104,112, 0,120, 0, 0, 0, 0,128, 0, 0, 0,136, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,144, 0,152, 0, 0, 0, 0, + 0, 0, 0,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, + 0, 12, 0, 12, 0, 0, 40, 44, 0, 0, 0, 0, 0, 0, 0, 48, + 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, + 56, 0, 0, 24, 24, 0, 0, 0, 0, 0, 0, 0, 60, 64, 68, 28, + 72, 76, 80, 84, 88, 92, 96,100,104,108,112,116,120, 0, 20, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,124, 0, 0, 0, 0, + 128,132,136, 0,140,144,148,152,156,160, 8,164, 0, 0,168,172, + 0, 0, 36,176, 4, 4,180, 4, 4,184,188,192, 0, 0, 0, 0, + 0, 0, 0,196,200, 28,204, 0, 0,208,212, 0, 32,216, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 36, 0, 8, 16, 0, 12, + 0,224,228, 0,232,236, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, + 0, 0, 8, 0, 0, 0, 32, 36, 0, 0, 0, 44, 0, 0, 28, 0, + 0, 0, 0, 28, 0, 0, 0, 8, 0, 0, 4, 4, 0, 8, 0, 0, + 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 16, 8, 0, 0, 24, 48, + 0, 28, 0, 0, 0, 0, 60, 64, 0, 68, 0, 72, 76, 80, 0, 0, + 84, 88, 0, 92, 16, 8, 0, 0, 0, 4, 4, 16, 4, 4, 4, 4, + 4, 4, 4, 24, 20, 0, 96, 0, 16,100,104, 0, 4, 4,108, 0, + 0, 0, 40,112, 8, 16, 4, 4, 4, 4, 4, 8,116,120,124,128, + 0, 0, 4, 0, 4, 8, 0, 0, 24, 20,132, 36, 0, 28, 0,136, + 16, 4, 4, 4, 24, 12, 12,140,144, 12,148, 0,152, 8, 4, 4, + 0, 0,156, 0, 8, 8, 0, 24, 20, 8, 4, 0, 0,160, 8, 8, + 0, 0, 24, 20, 0, 8, 0, 8, 0, 0, 40, 12, 20, 16, 4,164, + 12, 20, 0,168,172,176, 0,180, 0, 24, 20, 0, 0, 0, 0,184, + 16, 8, 28, 8, 4, 4, 8, 0, 0, 40, 12, 48, 16, 0, 0, 0, + 8, 4, 4, 0, 0, 0, 40, 20, 0, 0, 32,188,192, 0, 0, 0, + 24, 20, 8, 0,196, 0, 0, 0, 19, 19, 19, 19, 20, 18, 20, 18, + 20, 18, 19, 19, 18, 20, 18, 20, 19, 19, 20, 18, 18, 20, 18, 19, + 19, 19, 19, 20, 19, 20, 18, 19, 19, 19, 19, 21, 19, 17, 19, 19, + 19, 20, 18, 20, 21, 19, 17, 19, 18, 19, 19, 19, 19, 19, 19, 25, + 19, 19, 19, 13, 22, 22, 22, 16, 16, 16, 19, 19, 19, 32, 19, 19, + 19, 38, 19, 37, 31, 29, 30, 19, 36, 19, 19, 19, 19, 19, 19, 26, + 19, 23, 19, 19, 15, 19, 19, 19, 28, 19, 19, 19, 19, 19, 33, 19, + 35, 34, 19, 34, 27, 19, 19, 19, 18, 12, 19, 19, 20, 18, 24, 24, + 24, 19, 23, 23, 19, 19, 14, 14, 14, 15, 15, 19, 20, 18, 19, 21, + 11, 20, 18, 19, 18, 22, 20, 18, 16, 20, 18, 20, 18, 19, 19, 9, + 8, 19, 19, 7, 10, 19, 19, 19, 19, 6, 19, 19, 20, 18, 19, 20, + 19, 19, 5, 19, 19, 19, 19, 4, 3, 4, 19, 19, 20, 18, 2, 19, + 19, 19, 1, 19, 19, 17, 19, 20, 18, 19, 20, 18, 0, 19, 19, 19, + 6, 7, 8, 9, 10, 11, 12, 1, 1, 13, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 14, 15, 2, 2, 2, 2, 2, 0, 0, 0, 0, 16, + 17, 18, 19, 20, 21, 22, 5, 5, 23, 0, 0, 0, 24, 25, 4, 4, + 4, 26, 27, 0, 0, 28, 29, 30, 0, 31, 32, 33, 34, 35, 36, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 20, 21, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 0, 35, 4, 4, 4, 4, 4, 36, 0, 0, 0, - 0, 0, 0, 37, 0, 38, 39, 3, 3, 3, 3, 3, 3, 40, 41, 0, - 0, 0, 0, 0, 0, 0, 42, 43, 0, 0, 44, 0, 0, 0, 45, 46, - 5, 47, 48, 49, 50, 51, 52, 53, 5, 5, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 6, 0, 0, 6, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 54, 0, 0, 55, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, - 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, - 3, 3, 3, 1, 1, 1, 1, 1, 0, 0, 0, 26, 27, 8, 8, 8, - 28, 29, 30, 19, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 2, 2, 13, - 13, 13, 56, 11, 11, 11, 11, 11, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 8, 8, 16, 16, 72, 73, 74, 75, 3, - 3, 3, 3, 20, 20, 3, 3, 3, 3, 3, 3, 76, 77, 78, 79, 3, - 1, 1, 80, 81, 82, 83, 84, 85, 86, 87, 3, 1, 1, 1, 88, 1, - 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 89, 21, 21, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, 0, 0, 1, 1, 1, - 1,102, 9, 9, 9,103, 9,104,105,106,107, 22, 22,108,109, 0, - 110,111,112,113,114,115,116, 17, 17, 17, 8,117,118,119,120,121, - 122,123,124,125,126,127,128, 9,129,130,131,132,133,134,135,136, - 137,138,139,140,141, 0,142,143,144,145, 0,146,147,148,149,150, - 151,152,153,154,155,156,157, 0,158,159,160, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,161, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0,162, 0, 0, - 0, 0, 0, 14, 14, 14, 14,163,164, 23, 23, 0, 0,165, 0,166, - 167,168,169, 4, 4, 4, 4, 4, 4, 15, 15, 15, 15, 4, 4, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,170,171,172,173, 18, 18, - 18, 0, 0,174,175, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, - 3,176, 3, 3, 3,177,178, 16, 3, 3, 0, 10, 10, 10, 10, 10, - 10, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0,179, 19,180, 0, 0, - 181, 0, 0, 0,182, 0,183, 0,184, 0, 13, 24, 24,185, 0, 0, - 0, 0, 0, 3, 3, 3, 0, 9, 9, 0, 0, 3, 3, 3, 3,186, - 0, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 25, 25, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, - 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 8, - 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 7, - 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 10, - 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 16, - 16, 16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 12, 12, 12, 12, 13, - 13, 13, 13, 13, 13, 13, 13, 18, 18, 18, 18, 18, 18, 18, 18, 17, - 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 19, - 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 15, 15, 15, 15, 15, 25, - 25, 25, 25, 25, 25, 25, 25, 23, 23, 23, 23, 23, 23, 23, 23, 26, - 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, - 28, 28, 28, 28, 28, 28, 28, 14, 14, 14, 14, 14, 14, 14, 14, 3, - 3, 3, 3,118,119,118,119, 3, 3,156,156, 7,157, 7,157, 7, - 7, 7,158, 3, 3,180, 3, 14, 14, 14, 14, 14, 14, 14,181,182, - 17, 17, 17, 17, 17,183, 17,184, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15,185,100,100,100,100,100,186, 40, 40, 40, 40, 40, 40,187, - 188, 6, 6,189,190, 6,191, 6, 6, 6, 6, 6,192, 6, 6, 85, - 85, 85, 85, 85, 6, 6, 6,120,120,120,120,121,121,121,121,122, - 122,122,122,159,159, 85, 6, 6, 6, 6, 6, 6, 6,193, 6, 30, - 30, 30, 30, 30,194,195, 30, 45, 45, 45, 45, 45, 45, 45, 45, 46, - 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 48, - 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 49, - 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51, - 51, 51, 51, 51, 51, 51, 51, 41, 41, 41, 41, 41, 41, 41, 41, 81, - 81, 81,196, 81, 81, 81, 81, 52, 52, 52, 52, 52, 52, 52, 52, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,197, 29, 29, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 35, 35, 35, 35, 35,198, 12, - 12, 36, 36, 36, 36, 36, 36,160,160,101,101,101,101,199,101,161, - 161,200,201,162,162,163,163, 37, 37, 37, 37, 37, 37, 37, 37,202, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 11, 11, 11, 11, 11,102, - 102,102,102,102,140,140,140, 86, 86, 86, 86, 86, 86, 37, 37,164, - 164, 42, 42, 42, 42, 42, 42, 42, 42, 42, 14, 14, 14, 14, 14, 53, - 53, 53, 53, 53, 53, 53, 53,103,103,103,103,123,123,123,123,104, - 104,104,104,104,141,141,141, 15, 35, 35, 35,103,203,204,205, 7, - 7,206, 7, 7,207,208,209, 7, 7, 7,210, 14, 14, 14, 14,211, - 3, 3, 3, 3, 3, 3,212, 3, 7, 3, 3, 3, 14, 14, 14, 3, - 3,213,214,215, 3, 7, 7,158, 3, 3, 3, 3, 3, 3, 3, 43, - 43, 43, 43, 43, 43, 7, 7, 54, 54, 54, 54, 54, 54, 54, 54, 35, - 35, 35,105,105,105,105,105, 12, 12, 12, 12, 12, 12, 15, 15, 1, - 1, 1, 1, 1, 1, 1, 3,216, 3,217,218,219, 22, 22, 22, 22, - 220,165, 21, 21, 21, 21,221,106,106,106,222, 2, 2, 2, 2, 2, - 3,106,106, 3, 3, 3, 21, 2, 2, 3, 3, 3, 3, 2,223, 3, - 3, 3, 3, 3, 21, 21,224, 21, 21, 21, 21, 21,225, 3, 3, 1, - 1, 1, 1, 3, 3, 3, 3, 9, 9, 9, 9, 9, 82, 82, 82, 23, - 23, 23, 23, 15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 3, - 3,226, 7, 7, 7, 7, 7,227, 7, 7, 7, 7, 7, 7, 7,142, - 142,142, 3,124,124,124,124, 87, 87, 87, 87, 87, 87, 30, 30,166, - 166,228,143,143,143, 2, 2,107,107,107,107,229,107, 24, 24, 88, - 88, 88, 88, 88, 88, 24, 24, 89, 89, 89, 89, 89, 89, 90, 90, 12, - 12, 12, 7, 7,230,231, 36, 36, 36, 36, 36, 90, 90, 90, 90, 7, - 232, 40, 40, 40, 6, 6, 6, 6, 6, 6,233, 6, 6, 6, 6, 14, - 3,234, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6,235, 3, - 3,118,119,118,119,236,165, 21,237, 2, 2, 2, 2, 3, 3, 3, - 3, 3, 3, 17, 17, 17, 17, 17, 3, 17, 17, 17, 3, 3,238,167, - 167,125,125,125,125,239, 3,144,144,144,168,168,145,145,145,169, - 169, 91, 91, 91, 91, 91, 91,108,108,108,108,108,146,146,146,147, - 147,147,109,109,109,109,109,148,148,148,126,126,126,126,110,110, - 110,110,110,127,127,127,127,128,128,128,128,170,170,171,171, 92, - 92, 92, 92, 92, 92,172,172,173,173,174,174,129,129,129,129,175, - 175, 93, 93, 93, 93, 93, 93, 94, 94, 94, 94, 94, 94,176,176,130, - 130,130,130,131,131,131,131,132,132,132,132,177,177,178,178, 55, - 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 57, - 57, 57, 57, 57, 57, 57, 57,133,133,133,133, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34,134,134,134,134,240, 6, 6, 6,149, - 149,149,135,135,135,135,136,136,136,136,150,150,150,179,179, 58, - 58, 58, 58, 58, 58, 58, 58,111,111,111,111,111,151,151,151,112, - 112,112,112,112,152,152,152, 59, 59, 59, 59, 59, 59,241, 41, 60, - 60, 60, 60, 60, 60, 60, 60,153,153,153,113,113,113,113,113, 83, - 83, 83,242, 83, 83, 83, 83, 61, 61, 61, 61, 61, 61, 61, 61, 62, - 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 64, - 64, 64, 64, 64, 64, 64, 64, 95, 95, 95, 95, 95, 95, 33, 33,114, - 114,114,114,114, 24, 24, 24, 65, 65, 65, 65, 65, 65, 65, 65, 66, - 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 68, - 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69,115, - 115,115,115,115, 96, 96, 96, 96, 96, 96, 11,137,137,137,137, 30, - 30, 30, 30, 30, 30, 59, 59, 70, 70, 70, 70, 70, 70, 70, 70, 84, - 84, 84, 84, 84, 84, 84, 44, 44, 44, 44, 44, 44, 44, 44, 44, 97, - 97, 97, 97, 97, 97,116,116,116,116,116,117,117,117,117,117, 71, - 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 72, 72, 82, - 82, 82, 82, 32, 32, 32, 32, 73, 73, 73, 73, 73, 73, 73, 73, 74, - 74, 74, 74, 74, 74, 74, 74, 13, 13, 13, 13,154,154,154, 98, 98, - 98, 98, 98, 98,155,155,155, 75, 75, 75, 75, 75, 75, 75, 75, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 99, 99, 99, 99, 99, 99, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,243, 1, 21, - 21, 21, 21, 21, 21, 21, 21,244, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 21,245, 22,246, 21, 19, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 3, 3, 3, 3, 3, 3, 14, - 14, 14, 14, 14, 3, 3, 3, 3, 3, 3, 3, 3, 3,247,248,249, - 3,250, 3, 3, 3, 3, 3, 43, 43, 43, 15, 15, 15, 15, 15, 76, - 76, 76, 76, 76, 76, 76, 76,138,138,138,138,139,139,139,139, 77, - 77, 77, 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 79, - 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, 80,251, - 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 1, 1, 1, 1, 2, - 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, - 10, 10, 10, 11, 11, 11, 11, 13, 13, 13, 13, 14, 14, 14, 14, 12, - 12, 12, 12, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, - 18, 18, 18, 21, 21, 21, 21, 22, 22, 22, 22, 19, 19, 19, 19, 20, - 20, 20, 20, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, - 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, - 30, 30, 30, 31, 31, 31, 31, 33, 33, 33, 33, 32, 32, 32, 32, 34, - 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, - 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, - 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 46, 46, 46, 46, 47, - 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, - 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 45, - 45, 45, 45, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, - 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, - 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, - 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, - 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, - 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, - 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 83, - 83, 83, 83, 82, 82, 82, 82, 84, 84, 84, 84, 86, 86, 86, 86, 87, - 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, - 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, - 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 98, 98, 98, 98, 99, - 99, 99, 99,100,100,100,100, 85, 85, 85, 85,102,102,102,102,103, - 103,103,103,104,104,104,104,105,105,105,105,106,106,106,106,107, - 107,107,107,101,101,101,101,108,108,108,108,109,109,109,109,110, - 110,110,110,111,111,111,111,112,112,112,112,113,113,113,113,114, - 114,114,114,115,115,115,115,116,116,116,116,117,117,117,117,175, - 7, 7, 7, 7, 7,174, 3,118,118,118,118,119,119,119,119,120, - 120,120,120,121,121,121,121,122,122,122,122,123,123,123,123,124, - 124,124,124,125,125,125,125,126,126,126,126,127,127,127,127,128, - 128,128,128,129,129,129,129,130,130,130,130,131,131,131,131,132, - 132,132,132,133,133,133,133,134,134,134,134,135,135,135,135,136, - 136,136,136,137,137,137,137,138,138,138,138,139,139,139,139,140, - 140,140,140,141,141,141,141,142,142,142,142,143,143,143,143,144, - 144,144,144,145,145,145,145,146,146,146,146,147,147,147,147,148, - 148,148,148,149,149,149,149,150,150,150,150,151,151,151,151,152, - 152,152,152,153,153,153,153, 3, 3,177, 3, 7,174, 7, 7, 7, - 7,179, 3,155,155,155,155,156,156,156,156,157,157,157,157,158, - 158,158,158,159,159,159,159,160,160,160,160,182, 19, 19, 19,154, - 154,154,154,161,161,161,161,162,162,162,162,163,163,163,163,164, - 164,164,164,165,165,165,165,166,166,166,166,167,167,167,167,168, - 168,168,168,169,169,169,169,170,170,170,170,171,171,171,171,172, - 172,172,172,173,173,173,173, 7,179,194, 3, 17,195, 17,196, 17, - 197, 17, 17,198, 45, 45, 45, 15,199, 15, 15,200, 85, 85, 85,183, - 40, 40, 40, 6,184, 6,185, 6, 6,180,180,185, 6,201, 12, 12, - 202, 6, 6,203, 6, 6, 6, 6, 6, 6,184,204, 6, 6, 6,205, - 206, 30, 30, 30,207, 30, 30, 81, 81, 81,208, 29,209,210, 29, 35, - 35,211, 35,102,102,212,213,176,176,176,176,176,214, 3, 3,215, - 216, 32, 32,186, 12, 12, 12,217, 12,181,218, 3,181,178, 3, 7, - 187,219, 7, 7, 7, 7,220,221,187,222, 7, 7, 7,223, 7, 7, - 7, 7,224, 3, 3, 3,178,175, 3, 3,188, 3,225,189, 3,177, - 3, 3, 3, 3, 3, 3,177, 3,226, 3, 3,227, 1,228,229, 3, - 3, 1, 3,190, 20, 20, 20, 20, 20,230,190, 19, 19,191,182,231, - 2, 2, 2, 2, 2, 2,232, 19, 19, 19,191, 19, 19, 3, 3,189, - 7, 7, 7, 7, 7,188, 7,154,154,154,233,101,101,101,234, 7, - 7,174, 7, 7,235,236, 3,237, 85, 85,183, 6, 6, 6,238, 12, - 12, 12,239, 6, 6, 6,180, 3,240, 19, 19, 19, 19, 19,241, 3, - 3, 3,192,181, 3, 3, 3,242, 6, 6, 6,243, 41, 41, 41, 82, - 82,244, 82,245, 18, 18, 18,246, 20, 20, 20,247, 20, 20, 20, 20, - 248, 19, 19, 3,193,178, 3, 3, 3,193, 12,186,192, 12, 3, 3, - 3,249,178,250, 3, 3, 3, 2, 2, 2, 2, 13, 13, 13, 13, 12, - 12, 12, 12, 0, 0, 0, 0,136,136,136,136, 80, 80, 80, 80, 3, - 3, 3, 3, 19, 19, 19, 19, 63, 63, 63, 63, 39, 39, 39, 39,131, - 131,131,131, 28, 28, 28, 28, 1, 1, 1, 1, 30, 30, 30, 30, 79, - 79, 79, 79, 6, 6, 6, 6,127,127,127,127, 9, 9, 9, 9,155, - 155,155,155, 17, 17, 17, 17, 15, 15, 15, 15,139,139,139,139,110, - 110,110,110, 77, 77, 77, 77, 33, 33, 33, 33, 27, 27, 27, 27, 49, - 49, 49, 49,119,119,119,119,113,113,113,113, 25, 25, 25, 25, 7, - 7, 7, 7, 99, 99, 99, 99, 32, 32, 32, 32, 22, 22, 22, 22,165, - 165,165,165, 8, 8, 8, 8, 29, 29, 29, 29, 31, 31, 31, 31,146, - 146,146,146,105,105,105,105, 14, 14, 14, 14, 36, 36, 36, 36, 91, - 91, 91, 91, 56, 56, 56, 56,134,134,134,134, 55, 55, 55, 55, 5, - 5, 5, 5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 23, - 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 18, 18, 18, 18, 62, - 62, 62, 62,122,122,122,122, 89, 89, 89, 89,130,130,130,130, 94, - 94, 94, 94,100,100,100,100,108,108,108,108,171,171,171,171,137, - 137,137,137,124,124,124,124,123,123,123,123,126,126,126,126,142, - 142,142,142,125,125,125,125,154,154,154,154,150,150,150,150,169, - 169,169,169,145,145,145,145,163,163,163,163,157,157,157,157,166, - 166,166,166,167,167,167,167,151,151,151,151,164,164,164,164,168, - 168,168,168,174,174,174,174,132,132,132,132, 24, 24, 24, 24,107, - 107,107,107, 86, 86, 86, 86,133,133,133,133, 4, 4, 4, 4, 37, - 37, 37, 37, 58, 58, 58, 58, 75, 75, 75, 75, 68, 68, 68, 68, 92, - 92, 92, 92, 87, 87, 87, 87, 59, 59, 59, 59,116,116,116,116, 97, - 97, 97, 97, 57, 57, 57, 57,114,114,114,114,140,140,140,140,138, - 138,138,138,159,159,159,159,172,172,172,172, 84, 84, 84, 84, 35, - 35, 35, 35, 48, 48, 48, 48, 76, 76, 76, 76, 70, 70, 70, 70, 61, - 61, 61, 61, 26, 26, 26, 26, 40, 40, 40, 40,135,135,135,135,161, - 161,161,161, 85, 85, 85, 85, 96, 96, 96, 96,109,109,109,109,102, - 102,102,102,141,141,141,141,143,143,143,143,175,175,175,175, 38, - 38, 38, 38, 64, 64, 64, 64, 90, 90, 90, 90, 93, 93, 93, 93, 65, - 65, 65, 65, 67, 67, 67, 67,104,104,104,104,170,170,170,170, 47, - 47, 47, 47,173,173,173,173,117,117,117,117,112,112,112,112, 78, - 78, 78, 78,144,144,144,144,156,156,156,156,148,148,148,148,158, - 158,158,158,121,121,121,121,160,160,160,160,152,152,152,152, 52, - 52, 52, 52, 73, 73, 73, 73, 60, 60, 60, 60, 74, 74, 74, 74, 42, - 42, 42, 42,118,118,118,118, 51, 51, 51, 51, 50, 50, 50, 50,106, - 106,106,106,147,147,147,147,153,153,153,153,101,101,101,101,111, - 111,111,111,129,129,129,129,115,115,115,115,103,103,103,103, 69, - 69, 69, 69, 95, 95, 95, 95, 34, 34, 34, 34, 45, 45, 45, 45, 43, - 43, 43, 43, 46, 46, 46, 46, 54, 54, 54, 54, 71, 71, 71, 71, 41, - 41, 41, 41, 53, 53, 53, 53, 81, 81, 81, 81,120,120,120,120,128, - 128,128,128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 88, - 88, 88, 88, 83, 83, 83, 83, 82, 82, 82, 82,149,149,149,149, 19, - 19, 19, 0, 0, 19, 19, 19, 44, 44, 44, 44, 0, 0, 19, 0, 1, - 1, 0, 0, 19, 0, 0, 0, 3, 3, 3, 0, 1, 0, 0, 0, 0, - 17, 17, 17, 4, 14, 14, 14, 3, 0, 3, 3, 0, 3, 3, 3, 1, - 1, 1, 0, 19, 19, 9, 9, 0, 0, 0, 19, 0, 0, 19, 19, 0, - 15, 15, 15, 17, 17, 17, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, - 0, 26, 26, 0, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 0, 9, - 9, 55, 55, 6, 1, 1, 6, 6, 4, 4, 4, 3, 3, 3, 1, 1, - 1, 3, 3, 1, 3, 3, 3, 3, 3, 0, 3, 7, 1, 1, 1, 1, - 7, 7, 7, 0, 0, 7, 7, 24, 24, 24, 0, 25, 0, 0, 0, 0, - 25, 25, 25, 8, 8, 8, 0, 35, 35, 35, 0, 0, 0, 35, 35, 44, - 0, 0, 0, 32, 32, 0, 0, 32, 0, 32, 32, 1, 0, 1, 1, 0, - 1, 0, 0, 9, 9, 9, 6, 19, 9, 9, 9, 9, 9, 19, 19, 9, - 9, 9, 19, 6, 19, 19, 19, 19, 19, 19, 9, 0, 0, 9, 0, 0, - 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 15, - 1, 1, 0, 26, 12, 12, 12, 12, 12, 12, 0, 69, 69, 0, 69, 84, - 84, 84, 0, 19, 9, 19, 19, 19, 19, 0, 0, 19, 19, 19, 4, 3, - 3, 0, 0, 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0,156, - 156, 3, 3,100, 36, 36, 36,107,107,107, 1,136,139, 13, 13, 17, - 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17, 0, 0, 1, 1, 15, - 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, - 10, 0, 11, 12, 13, 0, 0, 0, 14, 0, 0, 15, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, - 17, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 19, 20, 21, 0, 22, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 23, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, - 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, - 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, - 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, - 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, - 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, - 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 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,100,101, - 102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, - 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, - 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, 0, - 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 38, 0, 39, + 1, 1, 1, 1, 1, 1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 41, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142, - 143,144,145,146,147,148,149,150,151,152,153,154,155,156,157, 0, - 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162, 0,163, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,164,165, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 28, 29, 10, 10, 10, 30, 31, 32, 20, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 2, 2, 15, 15, 15, 58, 13, 13, 13, 13, 13, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 10, 10, 21, + 21, 74, 75, 76, 77, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 22, 22, 4, 4, 4, 4, 4, 4, 78, 79, 80, 81, 4, 1, 1, + 82, 83, 84, 85, 86, 87, 88, 89, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 90, 1, 1, 1, + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 91, 23, 23, 92, 93, 94, + 95, 96, 97, 98, 99,100,101,102,103, 2, 2, 2, 2, 2, 2, 2, + 2, 0, 0, 1, 1, 1, 1,104, 11, 11, 11,105, 11,106,107,108, + 109, 24, 24,110,111, 0,112,113,114,115,116,117,118, 18, 18, 18, + 10,119,120,121,122,123,124,125,126,127,128,129,130, 11,131,132, + 133,134,135,136,137,138,139,140,141,142,143, 0,144,145,146,147, + 0,148,149,150,151,152,153,154,155,156,157,158,159, 0,160,161, + 162, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,163,164, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 165, 6, 6, 6, 6, 6, 6, 6, 6, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 16, 16, 16, 16,167,168, 25, 25, 0, 0,169, 0,170,171,172, + 173, 5, 5, 5, 5, 5, 5, 17, 17, 17, 17, 5, 5, 9, 9, 9, + 9, 9, 9, 9, 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, + 174,175,176,177, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,178,179, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4,180, + 4, 4, 4,181,182,183, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, + 4, 12, 12, 12, 12, 12, 12, 4, 0, 0, 0, 0, 0, 0, 0, 10, + 184,185, 20,186, 0, 0,187, 0, 0, 0,188, 0,189, 0,190, 0, + 15, 26, 26,191, 0, 0, 0, 0, 0, 4, 4, 4, 0, 11, 11, 0, + 0, 4, 4, 4, 4,192, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, + 0, 4, 0, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, + 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, + 6, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, + 12, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16, 18, 18, 18, 18, 18, 18, 18, + 18, 14, 14, 14, 14, 14, 14, 14, 14, 17, 17, 17, 17, 17, 17, 17, + 17, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, + 19, 24, 24, 24, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, 23, 23, + 23, 25, 25, 25, 25, 25, 25, 25, 25, 22, 22, 22, 22, 22, 22, 22, + 22, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, + 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, + 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, + 31, 21, 21, 21, 21, 21, 21, 21, 21, 33, 33, 33, 33, 33, 33, 33, + 33, 32, 32, 32, 32, 32, 32, 32, 32, 35, 35, 35, 35, 35, 35, 35, + 35, 36, 36, 36, 36, 36, 36, 36, 36, 38, 38, 38, 38, 38, 38, 38, + 38, 40, 40, 40, 40, 40, 40, 40, 40, 34, 34, 34, 34, 34, 34, 34, + 34, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, + 42,178, 7, 7, 7, 7, 7,177, 4, 43, 43, 43, 43, 43, 43, 43, + 43, 45, 45, 45, 45, 45, 45, 45, 45, 50, 50, 50, 50, 50, 50, 50, + 50, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, + 52, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, + 54, 55, 55, 55, 55, 55, 55, 55, 55, 44, 44, 44, 44, 44, 44, 44, + 44, 56, 56, 56, 56, 56, 56, 56, 56, 37, 37, 37, 37, 37, 37, 37, + 37, 46, 46, 46, 46, 46, 46, 46, 46, 57, 57, 57, 57, 57, 57, 57, + 57, 47, 47, 47, 47, 47, 47, 47, 47, 49, 49, 49, 49, 49, 49, 49, + 49, 58, 58, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, + 59, 60, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 61, 61, + 61, 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, + 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, + 65, 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, + 67, 68, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, + 69, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, + 71, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, + 73, 48, 48, 48, 48, 48, 48, 48, 48, 74, 74, 74, 74, 74, 74, 74, + 74, 75, 75, 75, 75, 75, 75, 75, 75, 39, 39, 39, 39, 39, 39, 39, + 39, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, + 77, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, + 79, 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, + 81, 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, + 83, 84, 84, 84, 84, 84, 84, 84, 84, 90, 90, 90, 90, 90, 90, 90, + 90, 86, 86, 86, 86, 86, 86, 86, 86, 91, 91, 91, 91, 91, 91, 91, + 91, 92, 92, 92, 92, 92, 92, 92, 92, 93, 93, 93, 93, 93, 93, 93, + 93, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, 95, 95, 95, 95, + 95, 96, 96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, + 97, 98, 98, 98, 98, 98, 98, 98, 98, 85, 85, 85, 85, 85, 85, 85, + 85, 99, 99, 99, 99, 99, 99, 99, 99, 87, 87, 87, 87, 87, 87, 87, + 87,101,101,101,101,101,101,101,101,103,103,103,103,103,103,103, + 103, 7, 7, 7, 7, 7,177, 7, 7, 88, 88, 88, 88, 88, 88, 88, + 88, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 8, 8, 8, + 8,120,120,120,120,120,120,120,120,121,121,121,121,121,121,121, + 121,122,122,122,122,122,122,122,122,105,105,105,105,105,105,105, + 105,106,106,106,106,106,106,106,106,107,107,107,107,107,107,107, + 107,123,123,123,123,123,123,123,123,108,108,108,108,108,108,108, + 108,109,109,109,109,109,109,109,109,110,110,110,110,110,110,110, + 110, 4, 4, 4, 4, 21, 21, 21, 21,124,124,124,124,124,124,124, + 124,104,104,104,104,104,104,104,104, 14, 14, 14, 14, 4, 4, 4, + 4, 19, 19, 19, 19, 4, 4, 4, 4,125,125,125,125,125,125,125, + 125,111,111,111,111,111,111,111,111,112,112,112,112,112,112,112, + 112,113,113,113,113,113,113,113,113,127,127,127,127,127,127,127, + 127,128,128,128,128,128,128,128,128,129,129,129,129,129,129,129, + 129,130,130,130,130,130,130,130,130,131,131,131,131,131,131,131, + 131,132,132,132,132,132,132,132,132,133,133,133,133,133,133,133, + 133,134,134,134,134,134,134,134,134,114,114,114,114,114,114,114, + 114,115,115,115,115,115,115,115,115,116,116,116,116,116,116,116, + 116,117,117,117,117,117,117,117,117,118,118,118,118,118,118,118, + 118,100,100,100,100,100,100,100,100,137,137,137,137,137,137,137, + 137,119,119,119,119,119,119,119,119,102,102,102,102,102,102,102, + 102,139,139,139,139,139,139,139,139,140,140,140,140,140,140,140, + 140, 4, 4,181, 4, 4, 4,181, 4, 7, 7, 7, 7, 7, 7,184, + 4, 7,184,198, 4, 4, 4, 4, 4, 14, 14, 14, 14, 19,199, 19, + 200, 19,201, 19, 19, 19, 19, 19, 19,202, 49, 49, 49, 19, 19, 19, + 19, 17,203, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,204, 88, 88, + 88, 88, 88, 88, 88,187, 43, 43, 43, 8,188, 8,189, 8, 8,185, + 185,189, 8,205, 14, 14,206, 8, 8, 8, 8, 8, 8,207, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8,188,158,158,158,158,158,158,158, + 158,208, 8, 8, 8, 8, 8, 8, 8, 32, 32, 32, 32,209,210, 32, + 32, 32,211, 32, 32, 32, 32, 32, 32, 84, 84, 84, 84, 84, 84, 84, + 212, 31, 31, 31, 31, 31,213,214, 31, 37, 37, 37, 37, 37, 37,215, + 37,159,159,159,159,159,159,159,159,105,105,216,217,105,105,105, + 105,160,160,160,160,160,160,160,160,179,179,179,179,179,218, 4, + 4,161,161,161,161,161,161,161,161,162,162,162,162,162,162,162, + 162,219,220, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 13, 13, 13, + 13,106,106,106,106,141,141,141,141,141,141,141,141,141,141,141, + 141,163,163,163,163,163,163,163,163, 46, 46, 46, 46, 14, 14, 14, + 14,108,108,108,108,142,142,142,142,142,142,142,142,142,142,142, + 142, 17, 17, 17, 17, 37, 37, 37, 37,107,107,107,107,190, 14, 14, + 14,221, 14,180,222, 4,180,182, 4, 7,191,223, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7,224,225,191,226, 7, 7, 7,227, + 7, 7, 7, 7, 7, 7, 7, 7,192, 4, 4, 4,182, 4, 4, 4, + 4, 4, 4, 4, 4,178, 4, 4,193, 4, 4, 4, 4, 7, 7, 7, + 7, 4, 4, 4, 4, 14, 14, 14, 14, 4,228,194, 4,181, 4, 4, + 4, 4, 4, 4,181, 4, 4, 4, 4, 7, 7,184, 4, 4, 4, 4, + 4, 37, 37, 37, 37,109,109,109,109, 1, 1, 1, 1, 4, 4, 4, + 4, 4,229, 4, 4, 4, 4, 4, 4,230, 1,231,232, 4, 4, 1, + 4,195, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,233, + 195,186, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,196, + 186,110,110,110,110,234, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2,235, 21, 21, 21, 21, 21, 21, 21, + 196, 21, 21, 21, 21, 21, 21, 4, 4, 10, 10, 10, 10, 86, 86, 86, + 86,194, 7, 7, 7, 7, 7, 7, 7, 7, 7,193, 7, 7, 7, 7, + 7,143,143,143,143,143,143,143,143,143,143,143,143, 4, 4, 4, + 4,157,157,157,157,157,157,157,157,157,157,157,236,144,144,144, + 144,144,144,144,144,144,144,144,144,104,104,104,237,104,104,104, + 104, 15, 15, 15, 15, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,177, + 7, 7,238,239, 7, 38, 38, 38, 38, 7, 7, 7, 7,240, 88, 88, + 187, 43, 43, 43, 43, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 241, 14, 14, 14,242, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8,185, 4,243, 21, 21,186, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21,244, 4, 4, 4, 4, 4, 4, 4, + 197,164,164,164,164,164,164,164,164,180, 4, 4, 4, 4, 4, 4, + 4,145,145,145,145,145,145,145,145,145,145,145,145,165,165,165, + 165,165,165,165,165,146,146,146,146,146,146,146,146,146,146,146, + 146,166,166,166,166,166,166,166,166,111,111,111,111,147,147,147, + 147,147,147,147,147,147,147,147,147,148,148,148,148,148,148,148, + 148,148,148,148,148,112,112,112,112,149,149,149,149,149,149,149, + 149,149,149,149,149,126,126,126,126,126,126,126,126,126,126,126, + 126,126,126,126,126,113,113,113,113,167,167,167,167,167,167,167, + 167,168,168,168,168,168,168,168,168,169,169,169,169,169,169,169, + 169,170,170,170,170,170,170,170,170,171,171,171,171,171,171,171, + 171,172,172,172,172,172,172,172,172,173,173,173,173,173,173,173, + 173,174,174,174,174,174,174,174,174,175,175,175,175,175,175,175, + 175,245, 8, 8, 8, 8, 8, 8, 8,150,150,150,150,150,150,150, + 150,150,150,150,150,135,135,135,135,135,135,135,135,135,135,135, + 135,135,135,135,135,136,136,136,136,136,136,136,136,136,136,136, + 136,136,136,136,136,151,151,151,151,151,151,151,151,151,151,151, + 151,176,176,176,176,176,176,176,176,114,114,114,114,152,152,152, + 152,152,152,152,152,152,152,152,152,115,115,115,115,153,153,153, + 153,153,153,153,153,153,153,153,153,246, 44, 44, 44, 44, 44, 44, + 44,154,154,154,154,154,154,154,154,154,154,154,154,116,116,116, + 116, 85, 85, 85, 85, 85, 85,247, 85,117,117,117,117, 26, 26, 26, + 26,118,118,118,118,100,100,100,100,100,100,100,100, 13, 13, 13, + 13, 87, 87, 87, 87, 48, 48, 48, 48,119,119,119,119,138,138,138, + 138,138,138,138,138,138,138,138,138,138,138,138,138, 45, 45, 45, + 45, 9, 9, 39, 39, 39, 39, 39, 39, 39, 39, 39, 9, 9, 9, 9, + 9,155,155,155,155,155,155,155,155,155,155,155,155,102,102,102, + 102,102,102,102,102,156,156,156,156,156,156,156,156,156,156,156, + 156,248, 20, 20, 20, 1, 1, 1, 1,249, 22, 22, 22, 22, 22, 22, + 22,250, 21, 21, 21,251, 22, 22, 22, 22, 22, 22, 22, 22,252, 21, + 21, 21, 21, 21, 21, 23, 23, 23, 23, 4,183,180, 4, 4, 4, 4, + 4, 4,183,182, 4, 4, 4,183, 14,190,197, 14, 4, 4, 4, 4, + 4, 4, 4,253,182, 4, 4, 4, 4, 19, 19, 19, 19, 4, 4,183, + 180, 7, 7, 7, 7,192,254, 7, 7, 47, 47, 47, 47, 17, 17, 17, + 17,255, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 13, 13, 13, + 13, 12, 12, 12, 12,178,178,178,178, 0, 0, 0, 0,136,136,136, + 136, 80, 80, 80, 80, 19, 19, 19, 19, 3, 3, 3, 3, 63, 63, 63, + 63, 39, 39, 39, 39,176,176,176,176,131,131,131,131, 28, 28, 28, + 28, 1, 1, 1, 1, 30, 30, 30, 30, 79, 79, 79, 79, 6, 6, 6, + 6,127,127,127,127, 9, 9, 9, 9,155,155,155,155, 17, 17, 17, + 17, 15, 15, 15, 15,139,139,139,139,110,110,110,110, 77, 77, 77, + 77, 33, 33, 33, 33, 27, 27, 27, 27, 49, 49, 49, 49,119,119,119, + 119,113,113,113,113, 25, 25, 25, 25, 7, 7, 7, 7, 99, 99, 99, + 99, 32, 32, 32, 32, 22, 22, 22, 22,165,165,165,165, 8, 8, 8, + 8, 29, 29, 29, 29,177,177,177,177, 31, 31, 31, 31,146,146,146, + 146,105,105,105,105, 14, 14, 14, 14, 36, 36, 36, 36, 5, 5, 5, + 5, 91, 91, 91, 91, 56, 56, 56, 56,134,134,134,134, 55, 55, 55, + 55, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 23, 23, 23, + 23, 16, 16, 16, 16, 20, 20, 20, 20, 18, 18, 18, 18, 62, 62, 62, + 62,122,122,122,122, 89, 89, 89, 89,130,130,130,130, 94, 94, 94, + 94,100,100,100,100,108,108,108,108,171,171,171,171,137,137,137, + 137,124,124,124,124,123,123,123,123,126,126,126,126,142,142,142, + 142,125,125,125,125,154,154,154,154,150,150,150,150,169,169,169, + 169,145,145,145,145,163,163,163,163,157,157,157,157,166,166,166, + 166,167,167,167,167,151,151,151,151,164,164,164,164,168,168,168, + 168,174,174,174,174,132,132,132,132, 24, 24, 24, 24,107,107,107, + 107, 86, 86, 86, 86,133,133,133,133, 4, 4, 4, 4, 37, 37, 37, + 37, 58, 58, 58, 58, 75, 75, 75, 75, 68, 68, 68, 68, 92, 92, 92, + 92, 87, 87, 87, 87, 59, 59, 59, 59,116,116,116,116, 97, 97, 97, + 97, 57, 57, 57, 57,114,114,114,114,140,140,140,140,138,138,138, + 138,159,159,159,159,172,172,172,172, 84, 84, 84, 84, 35, 35, 35, + 35, 48, 48, 48, 48, 76, 76, 76, 76, 70, 70, 70, 70, 61, 61, 61, + 61, 26, 26, 26, 26, 40, 40, 40, 40,135,135,135,135,161,161,161, + 161, 85, 85, 85, 85, 96, 96, 96, 96,109,109,109,109,102,102,102, + 102,141,141,141,141,143,143,143,143, 38, 38, 38, 38, 64, 64, 64, + 64, 90, 90, 90, 90, 93, 93, 93, 93, 65, 65, 65, 65, 67, 67, 67, + 67,104,104,104,104,170,170,170,170, 47, 47, 47, 47,173,173,173, + 173,117,117,117,117,112,112,112,112, 78, 78, 78, 78,144,144,144, + 144,156,156,156,156,148,148,148,148,158,158,158,158,121,121,121, + 121,175,175,175,175,160,160,160,160,152,152,152,152, 52, 52, 52, + 52, 73, 73, 73, 73, 60, 60, 60, 60, 74, 74, 74, 74, 42, 42, 42, + 42,118,118,118,118, 51, 51, 51, 51, 50, 50, 50, 50,106,106,106, + 106,147,147,147,147,153,153,153,153,101,101,101,101,111,111,111, + 111,129,129,129,129,115,115,115,115,103,103,103,103, 69, 69, 69, + 69, 95, 95, 95, 95, 34, 34, 34, 34, 45, 45, 45, 45, 43, 43, 43, + 43, 46, 46, 46, 46, 54, 54, 54, 54, 71, 71, 71, 71, 41, 41, 41, + 41, 53, 53, 53, 53, 81, 81, 81, 81,120,120,120,120,128,128,128, + 128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 88, 88, 88, + 88, 83, 83, 83, 83, 82, 82, 82, 82,149,149,149,149, 19, 19, 19, + 0, 0, 19, 19, 19, 44, 44, 44, 44, 1, 0, 0, 0, 0, 0, 19, + 0, 1, 1, 0, 0, 0, 0, 0, 1, 19, 0, 0, 0, 3, 3, 3, + 0, 0, 17, 17, 17, 4, 14, 14, 14, 3, 0, 3, 3, 0, 3, 3, + 3, 1, 1, 1, 0, 19, 19, 9, 9, 19, 19, 19, 9, 0, 0, 0, + 19, 0, 0, 19, 19, 0, 15, 15, 15, 17, 17, 17, 0, 0, 1, 1, + 1, 0, 0, 26, 26, 0, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, + 0, 9, 9, 55, 55, 6, 1, 1, 6, 6, 4, 4, 4, 3, 3, 3, + 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 0, 3, 7, 1, 1, + 1, 1, 7, 7, 7, 0, 0, 7, 7, 24, 24, 24, 0, 25, 0, 0, + 0, 0, 25, 25, 25, 8, 8, 8, 0, 35, 35, 35, 0, 0, 0, 35, + 35, 44, 0, 0, 0, 32, 32, 0, 0, 32, 0, 32, 32, 1, 0, 1, + 1, 0, 1, 0, 0, 9, 9, 9, 6, 19, 9, 9, 9, 9, 9, 19, + 19, 9, 9, 9, 19, 6, 19, 19, 19, 0, 0, 9, 0, 0, 13, 0, + 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 15, 1, 1, + 0, 26, 12, 12, 12, 12, 12, 12, 0, 69, 69, 0, 69, 84, 84, 84, + 0, 19, 9, 19, 19, 19, 19, 0, 0, 19, 19, 19, 4, 3, 3, 0, + 0, 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0,156,156, 3, + 3,100, 36, 36, 36,107,107,107, 1,136,139, 13, 13, 17, 15, 15, + 15, 17, 17, 17, 15, 17, 17, 15, 15, 15, 17, 17, 17, 0, 0, 1, + 1, 9, 19, 19, 19, 15, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 0, 0, 0, 10, 0, 11, 12, 13, 0, 0, 0, 14, 0, + 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 16, 17, 0, 0, 0, 0, 18, 0, 0, 0, 0, + 0, 19, 20, 21, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, + 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, + 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, + 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, + 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, + 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, + 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, + 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 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,100,101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, + 105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, + 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0, + 122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,167, 0, 0, 0,168,169, 0, 0,170, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,171, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,172, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132,133,134,135,136, + 137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, + 153,154,155,156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,162, 0,163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 164,165, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0,168, + 169, 0, 0,170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,176,177, 0, 0, 0, 0,178,179, 0, 0, - 0,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194, - 195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210, - 211,212,213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,175, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,176,177, 0, 0, + 0, 0,178,179, 0, 0, 0,180,181,182,183,184,185,186,187,188, + 189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204, + 205,206,207,208,209,210,211,212,213, 0, 0, 0, 0, 0, 0, 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 uint16_t _hb_ucd_u16[5104]= +static const uint16_t _hb_ucd_u16[5908]= { - 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, - 8, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, 24, 24, 24, 24, - 32, 32, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, - 56, 56, 56, 56, 56, 56, 56, 56, 40, 40, 40, 40, 40, 40, 40, 40, - 24, 24, 24, 24, 24, 24, 56, 56, 96, 96, 96, 96, 96, 96, 96, 96, - 24, 24, 24, 24, 24, 24, 24, 592, 152, 152, 600, 336, 344, 352, 360, 608, - 152, 152, 616, 624, 72, 632, 48, 640, 80, 80, 80, 648, 656, 80, 80, 664, - 672, 680, 688, 696, 704, 712, 80, 720, 80, 80, 80, 728, 736, 48, 48, 48, - 48, 744, 48, 96, 752, 760, 768, 368, 40, 40, 40, 40, 40, 40, 40, 776, - 784, 376, 792, 48, 800, 808, 80, 816, 72, 72, 72, 48, 48, 48, 80, 80, - 824, 80, 80, 80, 832, 80, 80, 80, 80, 80, 80, 376, 72, 840, 48, 48, - 848, 856, 40, 864, 872, 8, 8, 880, 888, 896, 8, 8, 904, 40, 912, 384, - 8, 8, 8, 8, 8, 920, 928, 936, 944, 392, 8, 40, 952, 8, 8, 8, - 8, 8, 184, 384, 136, 8, 960, 968, 8, 976, 984, 104, 8, 992, 8, 8, - 1000,1008, 8, 8,1016, 40,1024, 40, 400, 8, 8,1032,1040,1048,1056,1064, - 1072, 8, 8, 408,1080,1088, 144,1096, 416, 8, 8,1104,1112,1120,1128,1136, - 416, 8, 8, 408,1144, 8, 144,1152, 192, 8, 8, 424,1160,1168, 144,1176, - 432, 8, 8,1184,1192,1200, 440,1208,1216, 8, 8,1224,1232,1240, 144,1248, - 1256, 8, 8, 424,1264,1272, 144,1280,1288, 8, 8, 448,1296,1304, 144,1312, - 192, 8, 8, 8,1320,1328, 440,1336, 8, 8, 8,1344,1352, 200, 104, 104, - 8, 8, 8,1360,1368,1376, 8, 8,1384,1392, 208,1400, 8, 8, 8,1408, - 1416, 40, 40,1424,1432,1440, 104, 104, 8, 8,1448,1456, 200,1464,1472,1480, - 1488,1496, 72, 72, 72, 48, 48,1504, 8, 8, 8, 8, 8,1512, 456, 56, - 8, 24, 72, 72, 72, 72, 72, 216, 464, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8,1520, 8,1528,1536, 8, 8, 8, 8,1544,1552, - 8,1560, 8,1568, 8, 224, 8, 224, 8, 8, 8,1576,1584,1592, 88, 56, - 1600, 88, 8, 8,1608, 8, 8, 8,1616, 8,1624, 8, 8, 8, 8, 8, - 8, 8,1632,1640,1648, 8, 8, 8, 8, 8, 8, 8, 8,1656, 24, 24, - 8,1664, 8, 8, 8,1672,1680, 472, 88, 88,1688,1696, 40, 40, 40, 40, - 1704, 8, 8,1712,1720, 200,1728,1736, 232, 8,1744, 136, 8, 8,1752,1760, - 8, 8,1768,1776,1784, 136, 8, 480,1792, 72, 72, 72, 104,1800,1808,1816, - 48, 48,1824, 96, 96, 96,1832,1840, 48,1848, 96, 96, 40, 40, 40, 40, - 80, 80, 80, 80, 80, 80, 80, 80, 80,1856, 80, 80, 80, 80, 80, 80, - 128, 128, 128, 128, 128,1864, 128, 48, 240, 240, 240,1872, 488, 496, 496, 488, - 1880,1888,1896,1904,1912,1920, 112,1928,1936, 96, 248, 248, 248,1944,1952, 40, - 1960,1968,1976,1984,1992, 56, 120, 120,2000,2008,2016, 24,2024,2032, 24,2040, - 2048, 24,2056, 24, 24, 24, 24,2064, 24,2072, 64,2080, 24,2088,2096, 24, - 56,2104, 24, 24, 24, 24,2112, 56, 24, 24, 24,2120,2128, 24, 24,2136, - 24, 24, 24, 24, 24, 24,2144, 24, 24, 24, 24, 24, 24, 24,2152,2160, - 56,2168, 24, 24,2176, 64,2184, 64,2192,2200, 64, 64, 64,2208, 64,2216, - 24, 24, 24, 64,2224, 24, 24, 24, 72, 72, 72, 48, 48, 48,2232,2240, - 80, 80, 80, 80, 80, 80,2248,2256, 48, 48, 48, 8, 8, 8,2264,2272, - 8, 8, 8, 8, 8, 8, 40, 40,2280,2288,2296,2304,2312,2320, 504, 504, - 2328,2336,2344,2352,2360, 8, 8, 8, 8,2368, 464, 8, 8, 8, 8,2376, - 8,2384, 8, 8, 24, 24, 24, 8, 24, 24, 512, 24,2392, 520, 24, 24, - 512, 24, 24, 520, 24, 24, 24, 24, 8, 8, 8, 8, 24, 24, 24, 24, - 8, 528, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, 8, 8, 480, - 2400, 8, 136, 8, 80, 80,2408,2416, 80,2424, 8, 8, 8, 8,2432,2440, - 368,2448,2456,2464, 80, 80, 80,2472,2480,2488,2496,2504,2512,2520, 72,2528, - 2536, 8,2544,2552, 8, 8, 8,2560,2568, 8, 8,2576,2584, 88, 40,2592, - 136, 8,2600, 8,2608,2616, 8, 8, 400, 8, 8,2624,2632, 256,2640, 136, - 8, 8,2648,2656,2664,2672, 8,2680, 8, 8, 8,2688, 392,2696,2704,2712, - 8, 8, 8, 48, 48,2720,2728, 48, 48, 48, 48, 48, 8, 8,2736, 88, - 48,2744,2752, 8, 8, 8, 8, 8, 8, 8, 8,2760,2768,2776, 8, 8, - 8, 8, 8,2784, 24, 8, 8, 8, 8,2792, 8, 8,2800, 24, 24,2808, - 40,2816, 40,2824,2832,2840,2848, 8, 8, 8, 8, 8, 8, 8, 8,2856, - 2864, 336, 344, 352, 360,2872,2880,2888, 8,2896, 8, 8, 8, 8,2904,2912, - 2920, 56, 56,2928, 120, 120, 120,2936,2944, 24, 24, 24, 24, 24, 24,2952, - 8, 8, 8, 8, 8, 8,2960, 56, 8, 8,2968, 8,2976, 8, 8, 184, - 8, 264, 8, 8, 8,2984, 120, 120, 72, 72, 216, 48, 48, 8, 8, 8, - 8, 8, 88, 72, 72, 216, 48, 48, 8, 8, 8, 8, 8, 8, 264, 72, - 72,2992, 48, 48, 8, 8, 8, 8, 8, 8, 8, 8, 8,3000, 8,3008, - 8, 8, 536, 56, 56, 56, 8,3016, 8,3024, 8, 264, 8, 8, 8, 8, - 8, 8, 8,3032, 56, 56, 56, 56, 272, 8, 8, 544, 56, 104, 8,3040, - 8, 552, 56, 56,3048, 8,3056, 104, 8, 8, 8, 280, 8, 560, 8, 560, - 8, 280, 456, 56, 56, 56, 56, 56, 72, 72, 72, 72, 48, 48, 48,3064, - 8, 8,3072, 88,3080, 72,3088, 48,3096, 64, 64, 64, 64, 64, 64, 64, - 8, 8,3104, 8, 528,3112, 24,3120, 8, 552,3128, 8, 184,3136, 104, 8, - 3144, 104, 104, 8,3152, 56, 8, 8,3160, 8, 8, 544,3168,3176,3184,3192, - 232, 8, 8,3200,3208, 8, 8, 88, 432, 8,3216,3224,3232, 8, 8,3240, - 232, 8, 8,3248,3256,3264,3272, 56, 8, 8, 568,3280, 272, 40, 40, 40, - 8, 8, 280, 8, 8, 576, 472, 88, 192, 8, 8, 448,3288,3296,3304, 40, - 8, 8, 8,3312,3320,3328,3336, 40, 8, 8, 8,3344,3352,3360, 8, 8, - 8, 8, 8,3368,3376, 88, 88, 88, 8, 8, 584,3384,3392,3400, 40, 40, - 8, 8, 8,3408,3416, 88, 104, 104, 8, 8,3424,3432, 88, 88, 88, 88, - 8,3440,3448,3456, 8, 8, 8, 8, 8, 8, 568,3464, 104, 104, 104, 104, - 72, 72, 72, 72, 48, 48, 208,3472, 8, 8, 8,3480,3488, 88, 88, 88, - 8, 8, 8, 8, 8,3496,3504, 160,3512, 8, 8,3520,3528,3536, 8, 8, - 3544,3552, 104, 8, 8, 8, 8, 8, 104, 104, 104, 104, 104, 104,3560, 160, - 8, 8, 8, 8, 8, 8, 288, 88, 8, 8, 584,3568, 288, 208, 56,3576, - 8, 224,3584,3592, 40, 40, 40, 40, 8, 8, 8, 272,3600, 88, 8, 8, - 3608,3616, 88, 8, 8,3624, 88, 88, 8, 8, 8, 8, 8, 8, 8,3632, - 3640, 8, 8,3648,3656,3664, 40, 40, 8, 8, 8, 8, 56,3672,3680,3688, - 120, 120, 120, 120, 120, 120, 120, 104, 8, 8, 8, 8, 8, 8, 8, 288, - 8, 8, 8, 112,3696, 40, 8, 8, 8, 296,3704, 88, 88, 88, 88, 88, - 8, 8, 8, 8, 8, 8, 256, 8, 8, 8, 8, 8, 88, 8, 8,3712, - 8, 8, 8,3720,3728,3736,3744, 8, 96, 96, 96, 96,3752, 8,3760, 88, - 72, 72, 72, 72, 72, 72, 48, 48, 56,3768, 72,3776, 48, 48, 48, 48, - 8, 8, 8, 8, 576,3784, 160, 160,3792,3800, 96, 96, 96, 96,3808,3816, - 8,3824, 112, 112, 112, 112, 112, 112, 24, 24, 24, 24, 24, 24, 24, 64, - 40, 40, 40, 40, 40, 24, 24, 24, 24, 24, 24, 24, 24, 24,3832,3840, - 3848, 24,3856, 24, 24, 24, 24, 24, 24, 24, 24, 24,3864, 24, 24, 24, - 72, 168, 48, 304, 312, 48, 128, 72, 176, 320, 72, 328, 48, 72, 168, 48, - 304, 312, 48, 128, 72, 176, 320, 72, 328, 48, 72, 168, 48, 304, 312, 48, - 128, 72, 176, 320, 72, 328, 48, 72, 168, 48, 128, 72,3872,3880,3888,3896, - 48,3904, 72,3912,3920,3928,3936, 48,3944, 72,3952, 48,3960, 88, 88, 88, - 40, 40, 40,3968, 40, 40,3976,3984,3992,4000, 40, 40, 40, 40, 40, 40, - 4008, 48, 48, 48, 48, 48, 48, 48, 40, 40, 40, 96, 96, 96, 96, 96, - 8, 8, 8,4016,4024, 24, 24, 24, 8, 8, 296, 40, 8, 8,4032,4040, - 8, 8, 8, 8, 8, 8,4048, 88, 8, 8, 8, 8, 8, 8, 296,4056, - 8, 8, 8, 8, 8, 8,4064,4072, 8, 8, 8, 8, 536, 40, 40, 40, - 72, 72, 176, 48,4080, 256, 104, 104, 56, 56,4088,4096, 56, 56, 56, 56, - 56, 56,4104, 56, 56, 56, 56, 56, 8, 8, 8, 8, 8, 8, 8, 64, - 4112, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,4120, - 24, 24, 24, 24, 24, 64, 64, 64, 112, 112, 112, 112, 112, 112, 112, 112, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 56, 56, 56, 56, 56, 56, 56, 56, + 88, 88, 88, 88, 88, 88, 88, 88, 40, 40, 40, 40, 40, 40, 40, 40, + 24, 24, 24, 24, 24, 24, 64, 64, 96, 96, 96, 96, 96, 96, 96, 96, + 64, 64, 64, 64, 64, 64, 64, 64, 24, 24, 24, 24, 24, 24, 24, 584, + 160, 160, 592, 344, 352, 360, 368, 600, 160, 160, 608, 616, 72, 624, 48, 632, + 80, 80, 80, 640, 648, 80, 80, 656, 664, 672, 680, 688, 696, 704, 80, 712, + 80, 80, 80, 720, 728, 48, 48, 48, 48, 736, 48, 96, 744, 752, 760, 376, + 40, 40, 40, 40, 40, 40, 40, 768, 776, 384, 784, 48, 792, 800, 80, 808, + 72, 72, 72, 48, 48, 48, 80, 80, 816, 80, 80, 80, 824, 80, 80, 80, + 80, 80, 80, 384, 72, 832, 48, 48, 840, 848, 40, 856, 864, 8, 8, 872, + 880, 888, 8, 8, 896, 40, 904, 184, 8, 8, 8, 8, 8, 912, 920, 928, + 936, 392, 8, 40, 944, 8, 8, 8, 8, 8, 192, 184, 144, 8, 952, 960, + 8, 968, 976, 112, 8, 984, 8, 8, 992,1000, 8, 8,1008, 40,1016, 40, + 400, 8, 8,1024,1032,1040,1048,1056,1064, 8, 8, 408,1072,1080, 152,1088, + 416, 8, 8,1096,1104,1112,1120,1128, 416, 8, 8, 408,1136, 8, 152,1144, + 200, 8, 8, 424,1152,1160, 152,1168, 432, 8, 8,1176,1184,1192, 440,1200, + 1208, 8, 8,1216,1224,1232, 152,1240,1248, 8, 8, 424,1256,1264, 152,1272, + 1280, 8, 8, 448,1288,1296, 152,1304, 200, 8, 8, 8,1312,1320, 440,1328, + 8, 8, 8,1336,1344, 208, 112, 112, 8, 8, 8,1352,1360,1368, 8, 8, + 1376,1384, 216,1392, 8, 8, 8,1400,1408, 40, 40,1416,1424,1432, 112, 112, + 8, 8,1440,1448, 208,1456,1464,1472,1480,1488, 72, 72, 72, 48, 48,1496, + 8, 8, 8, 8, 8,1504, 456, 64, 8, 24, 72, 72, 72, 72, 72, 224, + 464, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,1512, 8, + 1520,1528, 8, 8, 8, 8,1536,1544, 8,1552, 8,1560, 8, 232, 8, 232, + 8, 8, 8,1568,1576,1584, 104, 64,1592, 104, 8, 8,1600, 8, 8, 8, + 1608, 8,1616, 8, 8, 8, 8, 8, 8, 8,1624,1632,1640, 8, 8, 8, + 8, 8, 8, 8, 8,1648, 24, 24, 8,1656, 8, 8, 8,1664,1672, 472, + 104, 104,1680,1688, 40, 40, 40, 40,1696, 8, 8,1704,1712, 208,1720,1728, + 240, 8,1736, 144, 8, 8,1744,1752, 8, 8,1760,1768,1776, 144, 8, 480, + 1784, 72, 72, 72, 112,1792,1800,1808, 48, 48,1816, 96, 96, 96,1824,1832, + 48,1840, 96, 96, 40, 40, 40, 40, 80, 80, 80, 80, 80, 80, 80, 80, + 80,1848, 80, 80, 80, 80, 80, 80, 128, 128, 128, 128, 128,1856, 128, 48, + 248, 248, 248,1864, 488, 496, 496, 488,1872,1880,1888,1896,1904,1912, 120,1920, + 1928, 96, 256, 256, 256,1936,1944, 40,1952,1960,1968,1976,1984, 64, 88, 88, + 1992,2000,2008, 24,2016,2024, 24,2032,2040, 24,2048, 24, 24, 24, 24,2056, + 24,2064, 56,2072, 24,2080,2088, 24, 64,2096, 24, 24, 24, 24,2104, 64, + 24, 24, 24,2112,2120, 24, 24,2128, 24, 24, 24, 24, 24, 24,2136, 24, + 24, 24, 24, 24, 24, 24,2144,2152, 64,2160, 24, 24,2168, 56,2176, 56, + 2184,2192, 56, 56, 56,2200, 56,2208, 24, 24, 24, 56,2216, 24, 24, 24, + 72, 72, 72, 48, 48, 48,2224,2232, 80, 80, 80, 80, 80, 80,2240,2248, + 48, 48, 48, 8, 8, 8,2256,2264, 8, 8, 8, 8, 8, 8, 40, 40, + 2272,2280,2288,2296,2304,2312,2320,2328,2336,2344,2352,2360,2368, 8, 8, 8, + 8,2376, 464, 8, 8, 8, 8,2384, 8,2392, 8, 8, 24, 24, 24, 8, + 24, 24, 504, 24,2400, 512, 24, 24, 504, 24, 24, 512, 24, 24, 24, 24, + 8, 8, 8, 8, 24, 24, 24, 24, 8,2408, 8, 8, 8, 8, 8, 8, + 8, 24, 24, 24, 24, 8, 8, 480,2416, 8, 144, 8, 80, 80,2424,2432, + 80,2440, 8, 8, 8, 8,2448,2456, 376,2464,2472, 520, 80, 80, 80,2480, + 2488,2496,2504,2512,2520,2528, 72,2536,2544, 8,2552,2560, 8, 8, 8,2568, + 2576, 8, 8,2584,2592, 104, 40,2600, 144, 8,2608, 8,2616,2624, 8, 8, + 400, 8, 8,2632,2640, 264,2648, 144, 8, 8,2656,2664,2672,2680, 8,2688, + 8, 8, 8,2696, 392,2704,2712,2720, 8, 8, 8, 48, 48,2728,2736, 48, + 48, 48, 48, 48, 8, 8,2744, 104, 48,2752,2760, 8, 8, 8, 8, 8, + 8, 8, 8,2768,2776,2784, 8, 8, 8, 8, 8,2792, 24, 8, 8, 8, + 8,2800, 8, 8,2808, 24, 24,2816, 40,2824, 40,2832,2840,2848,2856, 8, + 8, 8, 8, 8, 8, 8, 8,2864,2872, 344, 352, 360, 368,2880,2888,2896, + 8,2904, 8, 8, 8, 8,2912,2920,2928, 64, 64,2936, 88, 88, 88,2944, + 2952, 24, 24, 24, 24, 24, 24,2960, 8, 8, 8, 8, 8, 8,2968, 64, + 8, 8,2976, 8,2984, 8, 8, 192, 8, 272, 8, 8, 8,2992, 88, 88, + 72, 72, 224, 48, 48, 8, 8, 8, 8, 8, 104, 72, 72, 224, 48, 48, + 8, 8, 8, 8, 8, 8, 272, 72, 72,3000, 48, 48, 8, 8, 8, 8, + 8, 8, 8, 8, 8,3008, 8,3016, 8, 8, 528, 64, 64, 64, 8,3024, + 8,3032, 8, 272, 8, 8, 8, 8, 8, 8, 8,3040, 64, 64, 64, 64, + 280, 8, 8, 536, 64, 112, 8,3048, 8, 544, 64, 64,3056, 8,3064, 112, + 8, 8, 8, 288, 8, 552, 8, 552, 8, 288, 456, 64, 64, 64, 64, 64, + 72, 72, 72, 72, 48, 48, 48,3072, 8, 8,3080, 104,3088, 72,3096, 48, + 3104, 56, 56, 56, 56, 56, 56, 56, 8, 8,3112, 8,3120,3128, 8, 40, + 8, 544,3136, 8, 192,3144, 112, 8,3152, 112, 112, 8,3160, 64, 8, 8, + 3168, 8, 8, 536,3176,3184,3192,3200, 240, 8, 8,3208,3216, 8, 8, 104, + 432, 8,3224,3232,3240, 8, 8,3248, 240, 8, 8,3256,3264,3272,3280, 64, + 8, 8, 560,3288, 280, 40, 40, 40, 8, 8, 288, 8, 8, 568, 472, 104, + 200, 8, 8, 448,3296,3304,3312, 40, 8, 8, 8,3320,3328,3336,3344, 40, + 8, 8, 8,3352,3360,3368, 8, 8, 8, 8, 8,3376,3384, 104, 104, 104, + 8, 8, 576,3392,3400,3408, 40, 40, 8, 8, 8,3416,3424, 104, 112, 112, + 8, 8,3432,3440, 104, 104, 104, 104, 8,3448,3456,3464, 8, 8, 8, 8, + 8, 8, 560,3472, 112, 112, 112, 112, 72, 72, 72, 72, 48, 48, 216,3480, + 8, 8, 8,3488,3496, 104, 104, 104, 8, 8, 8, 8, 8,3504,3512, 136, + 3520, 8, 8,3528,3536,3544, 8, 8,3552,3560, 112, 8, 8, 8, 8, 8, + 3568, 8, 8, 8, 8, 8,3576, 136, 8, 8, 8, 8, 8, 8, 296, 104, + 8, 8, 576,3584, 296, 216, 64,3592, 8, 232,3600,3608, 40, 40, 40, 40, + 8, 8, 8, 280,3616, 104, 8, 8,3624,3632, 104, 8, 8,3640, 104, 184, + 8, 8, 8, 8, 8, 8, 8,3648,3656, 8, 8,3664,3672,3680, 40, 40, + 8, 8, 8, 8, 64,3688,3696,3704, 88, 88, 88, 88, 88, 88, 88,3712, + 8, 8, 8, 8, 8, 88, 88, 88, 8, 8, 8, 8, 8, 8, 8, 296, + 8, 8, 8, 120,3720, 40, 8, 8, 8, 304,3728, 104, 104, 104, 104, 104, + 8, 8, 8, 8, 8, 8, 264, 8, 8, 8, 8, 8, 104, 8, 8,3736, + 8, 8, 8,3744,3752,3760,3768, 8, 96, 96, 96, 96,3776, 8,3784, 104, + 72, 72, 72, 72, 72, 72, 48, 48, 64,3792, 72,3800, 48, 48, 48, 48, + 8, 8, 8, 8, 568,3808, 136, 136,3816,3824, 96, 96, 96, 96,3832,3840, + 8,3848, 120, 120, 120, 120, 120, 120, 24, 24, 24, 24, 24,3856, 24, 56, + 40, 40, 40, 40, 40, 24, 24, 24, 24, 24,3864, 24, 24, 24,3872,3880, + 3888, 24,3896, 24, 24, 24, 24, 24, 24, 24, 24, 24,3904,3912, 24, 24, + 136, 136, 136, 136, 64, 64, 64, 64, 72, 168, 48, 312, 320, 48, 128, 72, + 176, 328, 72, 336, 48, 72, 168, 48, 312, 320, 48, 128, 72, 176, 328, 72, + 336, 48, 72, 168, 48, 312, 320, 48, 128, 72, 176, 328, 72, 336, 48, 72, + 168, 48, 128, 72,3920,3928,3936,3944, 48,3952, 72,3960,3968,3976,3984, 48, + 3992, 72,4000, 48,4008, 104, 104, 104, 40, 40, 40,4016, 40, 40,4024,4032, + 4040,4048, 40, 40, 40, 40, 40, 40,4056, 48, 48, 48,4064,4072,4080, 520, + 8, 48, 48, 48,4088, 96, 96, 96, 40, 40, 40, 96, 96, 96, 96, 96, + 8, 8, 8,4096,4104, 24, 24, 24, 8, 8, 304, 40, 8, 8,4112,4120, + 8, 8, 8, 8, 8, 8,4128, 104, 8, 8, 8, 8, 8, 8, 304,4136, + 8, 8, 8, 8, 8, 8,4144,4152, 8, 8, 8, 8, 528, 40, 40, 40, + 72, 72, 176, 48,4160, 264, 112, 112, 64, 64,4168,4176, 64, 64, 64, 64, + 64, 64,4184, 64, 64, 64, 64, 64, 8, 8, 8, 8, 8, 8, 8, 56, + 4192, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,4200, + 24, 24, 24, 24, 24, 56, 56, 56, 120, 120, 120, 120, 120, 120, 120, 120, + 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 16, 24, 24, 24, 24, + 32, 32, 32, 32, 40, 40, 40, 40, 48, 48, 48, 48, 56, 56, 56, 56, + 80, 80, 80, 80, 88, 88, 88, 88, 72, 72, 72, 72, 64, 64, 64, 64, + 96, 96, 96, 96, 104, 104, 104, 104, 128, 128, 128, 128, 112, 112, 112, 112, + 120, 120, 120, 120, 152, 152, 152, 152, 168, 168, 168, 168, 176, 176, 176, 176, + 144, 144, 144, 144, 160, 160, 160, 160, 208, 208, 208, 208, 184, 184, 184, 184, + 216, 216, 216, 216, 224, 224, 224, 224, 232, 232, 232, 232, 136, 136, 136, 136, + 32, 32, 328, 328, 32,1144, 808, 808, 72,1152, 32,1160, 136, 136, 136,1168, + 1176, 160, 160,1184,1192, 144, 144, 144, 144,1200, 816, 816,1208, 336, 336, 336, + 1216, 64,1224,1232, 64, 64,1240, 64, 824, 824, 832, 64, 840, 840, 848, 848, + 856, 856,1248, 832, 64, 64, 64,1256, 264, 264,1264,1272, 344, 344, 344, 344, + 352, 352, 352, 352, 360, 360, 360, 360, 368, 368, 368, 368, 272, 272, 272, 272, + 376, 376, 376, 376, 384, 384, 384, 384, 392, 392, 392, 392, 400, 400, 400, 400, + 680,1280, 680, 680, 408, 408, 408, 408, 240, 240, 240, 240, 240, 240,1288, 240, + 200, 200, 200, 200, 200, 416, 416,1296, 112, 288, 288, 288,1304, 864, 864,1312, + 1320,1328,1336,1344, 296, 296, 296, 296,1352, 304, 304, 304, 304,1360, 104, 104, + 872, 872,1368,1376, 688, 688, 688, 296,1384, 424, 424, 424, 424,1392, 136, 136, + 432, 432, 432, 432, 880, 880, 888, 888, 896, 896,1400,1408,1416, 416,1424,1432, + 72,1440,1448,1456, 72,1464, 136, 136,1472, 32, 32,1480,1488, 32,1496, 136, + 32,1504,1512, 72,1520, 32, 32, 32, 440, 440, 440, 72, 448, 448, 448, 448, + 416,1528, 904, 904, 112, 112, 112, 144, 8, 8, 8,1536,1544,1552,1560, 192, + 1568,1576, 248,1584, 912,1592, 16, 16,1600, 912, 32, 920, 16, 32, 32,1608, + 32, 32, 920,1616, 248, 248,1624, 32, 8, 8, 32, 32, 80, 80,1632, 696, + 184, 184, 144, 144, 144, 120, 120, 120, 32,1640, 72, 72,1648, 72, 72, 72, + 1656,1664, 928, 928, 704, 704, 704, 264,1672,1680,1688, 16, 936, 936,1696, 200, + 712, 712, 712, 200, 720, 720, 720, 728, 112,1704,1712,1720, 288, 288, 728, 728, + 1728, 336,1736, 64, 64,1744, 64, 64, 944,1752, 32,1760, 64, 64, 64,1768, + 32, 328, 328,1776,1784, 16, 16, 32, 32, 32, 160, 160, 952, 160, 952,1792, + 1800, 960, 960,1808,1816,1824,1832,1840,1848, 736, 736, 736, 968, 968,1856,1864, + 1872,1880, 976, 976,1888,1896,1904,1912, 984, 984, 992, 992,1000,1000,1920,1928, + 744, 744, 744,1936,1944,1952,1008,1008,1960, 752, 752, 752, 760, 760, 760,1968, + 1016,1016,1024,1024,1032,1032,1976,1984, 456, 456, 456, 456, 464, 464, 464, 464, + 472, 472, 472, 472,1040,1040, 280, 280, 280, 280, 280, 280,1048,1048,1992, 64, + 2000,2008,2016,2024,2032,2040,2048,2056, 480, 480, 480, 480,1056,1056,2064,2072, + 1064,1064,2080,2088, 488, 488, 488,2096, 496, 496, 496, 496,2104,2112,1072,1072, + 768,2120, 768, 768, 504, 504, 504, 504, 512, 512, 512, 512, 520, 520, 520, 520, + 528, 528, 528, 528, 776, 776, 776, 304,1080,1080,2128, 200, 536, 536, 536, 536, + 544, 544, 544, 544, 552, 552, 552, 552, 560, 560, 560, 560, 568, 568, 568, 568, + 1088,1088,2136,1096,1096,2144,1104,1104, 264, 264, 264, 488, 576, 576, 576, 576, + 784, 784, 784,2152, 584, 584, 584, 584, 792, 792, 792,1112,1112,2160,2168,2176, + 592, 592, 592, 592, 600, 600, 600, 600, 696, 696, 272, 272, 56,2184, 608, 608, + 608, 608,2192, 56, 616, 616, 616, 616, 624, 624, 624, 624, 120, 120,2200,2208, + 1120,1120,2216,2224, 632, 632, 632, 632, 312, 312, 312, 312, 312, 800, 800, 800, + 256, 256, 256, 256, 256, 256, 256,2232, 248, 248, 248, 248,2240, 192, 192, 192, + 192, 192, 192, 192, 192,2248,2256,2264, 320, 320, 320, 320, 320, 32, 32, 32, + 136, 136, 944, 32, 32,2272, 32,2280,2288,2296, 32, 32, 160, 160,2304, 32, + 72, 72, 72,2312, 440,2320, 144, 144, 640, 640, 640, 640,1128,1128,1136,1136, + 648, 648, 648, 648, 656, 656, 656, 656, 664, 664, 664, 664, 672, 672, 672, 672, + 2328, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976, + 1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082, + 1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161, + 1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269, + 1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, + 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, + 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191, + 1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025, + 1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0, + 1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252, + 1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271, + 1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120, + 1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339, + 1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241, + 1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348, + 1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197, + 1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, + 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364, + 1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 9, 0, 10,1425, 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, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0, + 1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458, + 1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503, + 1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0, + 1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, + 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0, + 1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571, + 1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573, + 1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, + 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, + 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617, + 1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628, + 1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, + 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638, + 1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644, + 1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, + 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653, + 1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0, + 1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0, + 1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, + 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0, + 1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0, + 1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, + 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, + 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170, + 1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185, + 1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213, + 1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224, + 1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249, + 1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259, + 1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393, + 1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295, + 1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, + 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345, + 1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, + 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198, + 1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401, + 1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410, + 1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, + 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719, + 1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735, + 1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755, + 1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774, + 1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783, + 1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, + 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812, + 1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28, + 1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724, + 1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760, + 1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817, + 1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12, + 1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14, + 1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, + 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17, + 1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18, + 1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0, + 1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, + 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, + 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872, + 1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0, + 1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, + 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0, + 1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0, + 1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, + 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0, + 1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, + 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, + 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, + 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, + 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, + 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, + 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, + 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, + 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, + 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, + 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, + 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, + 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, + 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, + 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, + 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, + 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, + 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, + 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, + 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, + 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, + 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, + 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, + 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, + 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, + 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, + 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, + 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, + 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, + 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, + 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603, + 1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589, + 1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582, + 1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1937, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, + 1939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1940, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1943, + 1944, 0, 0, 0, 0, 0, 0,1945, 0,1946, 0, 0, 0, 0, 0, 0, + 0, 0,1947, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1950, 0,1949,1951, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1953, + 1952, 0,1954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1957, 0, 0, 0, + 0, 0, 0, 0, 0,1958,1961,1959,1965,1960,1962,1964,1963, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1967,1966,1968, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, - 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, - 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, - 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, - 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, - 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, - 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199, - 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, - 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231, - 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258, - 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275, - 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0, - 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093, - 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010, - 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347, - 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424, - 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, - 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238, - 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, - 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232, - 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 9, 0, 10,1425, 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, 1, 0, - 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461, - 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486, - 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0, - 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0, - 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, - 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, - 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560, - 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, - 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, - 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, - 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, - 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0, - 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, - 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, - 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, - 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, - 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, - 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0, - 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, - 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, - 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356, - 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214, - 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363, - 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251, - 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266, - 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287, - 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302, - 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, - 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375, - 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353, - 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234, - 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403, - 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412, - 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0, - 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721, - 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0, - 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757, - 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776, - 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0, - 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793, - 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814, - 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0, - 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728, - 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764, - 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821, - 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, - 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828, - 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833, - 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, - 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, - 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, - 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, - 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, - 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938, - 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0, - 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870, - 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0, - 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0, - 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0, - 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, - 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0, - 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0, - 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0, - 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, - 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, - 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, - 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, - 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, - 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, - 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, - 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, - 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, - 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, - 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, - 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, - 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, - 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, - 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, - 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, - 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, - 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, - 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, - 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, - 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, - 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, - 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, - 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, - 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, - 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, - 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, - 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, - 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, - 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, - 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, - 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575, - 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0, - 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0,1939, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1940, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1943,1944, 0, 0, 0, - 0, 0, 0,1945, 0,1946, 0, 0, 0, 0, 0, 0, 0, 0,1947, 0, - 0,1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,1950, 0,1949,1951, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1953,1952, 0,1954, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1957, 0, 0, 0, 0, 0, 0, 0, - 0,1958,1961,1959,1965,1960,1962,1964,1963, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1967,1966,1968, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1969,1970, - 1971,1972,1973,1974,1975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1976,1977,1978,1980,1979, - 1981, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, - 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, - 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, - 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, - 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, - 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, - 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, - 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, - 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, - 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, - 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, - 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, - 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, - 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, - 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, - 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, - 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, - 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, - 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, - 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, - 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, - 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, - 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, - 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, - 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, - 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, - 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, - 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, - 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, - 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, - 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, - 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, - 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, - 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, + 0, 0,1969,1970,1971,1972,1973,1974,1975, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1976, + 1977,1978,1980,1979,1981, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, + 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, + 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, + 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, + 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, + 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, + 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, + 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, + 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, + 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, + 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, + 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, + 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, + 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, + 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, + 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, + 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, + 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, + 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, + 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, + 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, + 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, + 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, + 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, + 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, + 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, + 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, + 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, + 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, + 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, + 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, + 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, + 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, + 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, + 821, 935, 0, 0, }; -static const int16_t _hb_ucd_i16[92]= +static const int32_t _hb_ucd_palette[39]= { - 0, 0, 1, -1, -1, 1, 0, 1, -1, 0, 0, 2, 0, -2, 2, 0, - -2, 0, -7, 0, 0, 16, 0, -16, 3, 3, 3, -3, -3, -3, 0, 2016, - 0, 2527, 1923, 1914, 1918, 0, 2250, 0, 0, 138, 0, 7, 1824, 0, 2104, 0, - 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8, - -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0, - 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0, + -112883, -2527, -2250, -2108, -2106, -2104, -2016, -1923, + -1918, -1914, -1824, -1316, -138, -16, -8, -7, + -3, -2, -1, 0, 1, 2, 3, 7, + 8, 16, 138, 1316, 1824, 1914, 1918, 1923, + 2016, 2104, 2106, 2108, 2250, 2527, 112883, }; static inline uint8_t _hb_ucd_gc (unsigned u) { /* packtab: [2^8,2^4,2^3,2^3,2^1] */ - return u<1114112u ? (uint8_t)(_hb_ucd_u8[5288u+((_hb_ucd_u8[1160u+_hb_ucd_u16[((_hb_ucd_u8[544u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>3))>>4)])<<4)+((((((((u)>>1))>>3))>>3))&15)])<<3)+((((((u)>>1))>>3))&7)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; + return u<1114112u ? (uint8_t)(_hb_ucd_u8[5368u+((_hb_ucd_u8[1160u+_hb_ucd_u16[((_hb_ucd_u8[544u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>3))>>4)])<<4)+((((((((u)>>1))>>3))>>3))&15)])<<3)+((((((u)>>1))>>3))&7)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; } static inline uint8_t _hb_ucd_ccc (unsigned u) { /* packtab: [2^8,2^3,2^2,2^2,2^2] */ - return u<125259u ? (uint8_t)(_hb_ucd_u8[7307u+((_hb_ucd_u8[6724u+((_hb_ucd_u8[6247u+((_hb_ucd_u8[5881u+((_hb_ucd_u8[5636u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)]) : 0; + return u<125259u ? (uint8_t)(_hb_ucd_u8[7417u+((_hb_ucd_u8[6818u+((_hb_ucd_u8[6333u+((_hb_ucd_u8[5967u+((_hb_ucd_u8[5722u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)]) : 0; } static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) { return (a[i>>1]>>((i&1)<<2))&15; } -static inline int16_t _hb_ucd_bmg (unsigned u) +static inline int32_t _hb_ucd_bmg (unsigned u) { - /* packtab: [2^4,2^3,2^3,2^2,2^1] */ - return u<65380u ? (int16_t)(_hb_ucd_i16[_hb_ucd_u8[8198u+_hb_ucd_u8[7969u+_hb_ucd_u8[7875u+((_hb_ucd_b4(_hb_ucd_u8+7811u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)]+((((((u)>>1))>>2))&7)]+((((u)>>1))&3)]+((u)&1)]) : 0; + /* packtab: [2^4,2^3,2^3,2^2,2^2] palette[39] */ + return u<121617u ? (int32_t)(_hb_ucd_palette[_hb_ucd_u8[8488u+_hb_ucd_u8[8248u+_hb_ucd_u8[8084u+_hb_ucd_u8[7997u+((_hb_ucd_b4(_hb_ucd_u8+7937u,((((((((u)>>2))>>2))>>3))>>3)))<<3)+((((((((u)>>2))>>2))>>3))&7)]+((((((u)>>2))>>2))&7)]+((((u)>>2))&3)]+((u)&3)]]) : 0; } static inline uint8_t _hb_ucd_sc (unsigned u) { - /* packtab: [2^4,2^4,2^3,2^3,2^2,2^2] */ - return u<918016u ? (uint8_t)(_hb_ucd_u8[11623u+((_hb_ucd_u8[10615u+((_hb_ucd_u8[9119u+((_hb_ucd_u8[8675u+((_hb_ucd_u8[8475u+((_hb_ucd_b4(_hb_ucd_u8+8446u,((((((((((u)>>2))>>2))>>3))>>3))>>4)))<<4)+((((((((((u)>>2))>>2))>>3))>>3))&15)])<<3)+((((((((u)>>2))>>2))>>3))&7)])<<3)+((((((u)>>2))>>2))&7)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)]) : 2; + /* packtab: [2^8,2^4,2^2,2^3,2^2] */ + return u<918016u ? (uint8_t)(_hb_ucd_u8[12153u+((_hb_ucd_u8[9817u+_hb_ucd_u16[1712u+((_hb_ucd_u8[9137u+((_hb_ucd_u8[8688u+((((((((u)>>2))>>3))>>2))>>4)])<<4)+((((((((u)>>2))>>3))>>2))&15)])<<2)+((((((u)>>2))>>3))&3)]+((((u)>>2))&7)])<<2)+((u)&3)]) : 2; } static inline uint16_t _hb_ucd_dm (unsigned u) { /* packtab: [2^8,2^5,2^4] */ - return u<195102u ? (uint16_t)(_hb_ucd_u16[1680u+((_hb_ucd_u8[13009u+((_hb_ucd_u8[12627u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; + return u<195102u ? (uint16_t)(_hb_ucd_u16[2484u+((_hb_ucd_u8[13559u+((_hb_ucd_u8[13177u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh index 7200952547a..7027c3cbbe2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh @@ -7,13 +7,13 @@ * on file with this header: * * # emoji-data.txt - * # Date: 2025-07-25, 17:54:31 GMT - * # © 2025 Unicode®, Inc. + * # Date: 2026-01-30, 22:30:17 GMT + * # © 2026 Unicode®, Inc. * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. * # For terms of use and license, see https://www.unicode.org/terms_of_use.html * # * # Emoji Data for UTS #51 - * # Version: 17.0 + * # Version: 18.0.0 * # * # For documentation and usage, see https://www.unicode.org/reports/tr51 */ @@ -55,14 +55,14 @@ static const uint8_t _hb_emoji_u8[624]= 0, 0, 0, 0, 0, 0, 1, 32, 0, 0,128, 2, 0, 0, 0, 0, 16, 0, 0, 0, 0,240, 0, 0, 0, 0,240,255, 0,128, 1, 0, 1,128, 1, 0, 0, 0,192,255, 0, 0, 0, 0, 0, 0, 3,192, - 0, 64,254, 7, 0,192,255,255,255,255,255,255, 63, 0, 0, 0, + 0, 64,254, 7, 0,128,255,255,255,255,255,255, 63, 0, 0, 0, 254,255, 0, 4, 0,128,252,247, 0,254,255,255,192,255,255,255, 255,255,255,255,243,255,255,255,255,255,207,206,255,255,255,255, 255,255,255,255,255,255,185, 7,255,255,255,255,255,255,255,191, 255,255,255,255,255,255,255, 63, 0,126,255,255,255,128,249, 7, 128, 60, 97, 0, 48, 1, 6, 16, 28, 0, 14,112, 10,129, 8,252, 255,255, 0, 0, 0, 0, 0, 0, 63,248,231,255, 63,250,249,255, - 0, 0, 0,252,255,255,255,255, 0,240, 0, 0, 0, 0, 0, 0, + 0, 0, 0,240,255,255, 1, 0, 0,240, 0, 0, 0, 0, 0, 0, 0,255, 0,252, 0, 0, 0, 0, 0,255, 0, 0, 0,192, 0,240, 252,255, 0,254,255,255,255,255, 0,240,255,255,255,255,255,247, 191,255,255,255,255,255,255,255, 0, 0, 0,255, 0,192,255,255, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh index 9e6f89365fe..660507f18a9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh @@ -176,7 +176,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE case 0x03: return unlikely (ch == 0x034Fu); case 0x06: return unlikely (ch == 0x061Cu); case 0x17: return hb_in_range (ch, 0x17B4u, 0x17B5u); - case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Eu); + case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Fu); case 0x20: return hb_in_ranges (ch, 0x200Bu, 0x200Fu, 0x202Au, 0x202Eu, 0x2060u, 0x206Fu); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh index b0aa842bb23..e4e6a2931af 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh @@ -139,18 +139,23 @@ struct hb_vector_t } HB_ALWAYS_INLINE_VECTOR_ALLOCS void extend (array_t o, bool exact=false) - { - alloc (length + o.length, exact); - if (unlikely (in_error ())) return; - copy_array (o); - } + { extend (c_array_t (o), exact); } HB_ALWAYS_INLINE_VECTOR_ALLOCS void extend (c_array_t o, bool exact=false) { + /* o may point into our own storage, eg. v.extend (v.as_array ()). + * alloc() may move that storage, so find o again afterwards. */ + bool aliased = o.length && in_storage (*o.arrayZ); + unsigned offset = aliased ? o.arrayZ - arrayZ : 0; alloc (length + o.length, exact); if (unlikely (in_error ())) return; + if (unlikely (aliased)) + o = {arrayZ + offset, o.length}; copy_array (o); } + HB_ALWAYS_INLINE_VECTOR_ALLOCS + void extend (const hb_vector_t &o, bool exact=false) + { extend (o.as_array (), exact); } public: int allocated = 0; /* < 0 means allocation failed. */ @@ -231,6 +236,8 @@ struct hb_vector_t hb_vector_t& operator = (const hb_vector_t &o) { + if (this == &o) return *this; + reset (); alloc_exact (o.length); if (unlikely (in_error ())) return *this; @@ -272,7 +279,7 @@ struct hb_vector_t const Type& tail () const { return (*this)[length - 1]; } explicit operator bool () const { return length; } - size_t get_size () const { return length * item_size; } + size_t get_size () const { return hb_unsigned_mul_saturate (length, item_size); } /* Sink interface. */ template @@ -316,11 +323,26 @@ struct hb_vector_t HB_ALWAYS_INLINE_VECTOR_ALLOCS Type *push (Args&&... args) { - if (unlikely ((int) length >= allocated && !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 std::addressof (Crap (Type)); + if (unlikely ((int) length >= allocated)) + { + if (unlikely (in_error ())) + return std::addressof (Crap (Type)); + + /* An argument may live in our own storage, eg. v.push (v[i]). + * alloc() frees that storage, so copy it out first. */ + if (unlikely (in_storage (args...))) + { + Type copy (std::forward (args)...); + if (unlikely (!alloc (length + 1))) + return std::addressof (Crap (Type)); + return push_has_room (std::move (copy)); + } + 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 std::addressof (Crap (Type)); + } return push_has_room (std::forward (args)...); } @@ -339,6 +361,16 @@ struct hb_vector_t return new (p) Type (std::forward (args)...); } + bool in_storage () const { return false; } + template + bool in_storage (const T &v, const Ts &...vs) const + { + uintptr_t p = (uintptr_t) std::addressof (v); + return (arrayZ && + (uintptr_t) arrayZ <= p && p < (uintptr_t) (arrayZ + length)) || + in_storage (vs...); + } + bool is_owned () const { return allocated != 0 && allocated != -1; @@ -635,7 +667,9 @@ struct hb_vector_t HB_ALWAYS_INLINE_VECTOR_ALLOCS bool resize_full (int size_, bool initialize, bool exact) { - unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; + if (unlikely (size_ < 0)) + return false; + unsigned int size = (unsigned int) size_; if (!alloc (size, exact)) return false; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-version.h b/src/java.desktop/share/native/libharfbuzz/hb-version.h index 7ab4a82fd85..9bb79e82a4e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-version.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-version.h @@ -41,13 +41,13 @@ HB_BEGIN_DECLS * * The major component of the library version available at compile-time. */ -#define HB_VERSION_MAJOR 14 +#define HB_VERSION_MAJOR 15 /** * HB_VERSION_MINOR: * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 2 +#define HB_VERSION_MINOR 0 /** * HB_VERSION_MICRO: * @@ -60,7 +60,7 @@ HB_BEGIN_DECLS * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "14.2.0" +#define HB_VERSION_STRING "15.0.0" /** * HB_VERSION_ATLEAST: diff --git a/src/java.desktop/share/native/libharfbuzz/hb.hh b/src/java.desktop/share/native/libharfbuzz/hb.hh index 25565c0caa1..969a3b836ef 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb.hh @@ -151,6 +151,7 @@ #pragma GCC diagnostic ignored "-Wrange-loop-analysis" // https://github.com/harfbuzz/harfbuzz/issues/2834 #pragma GCC diagnostic ignored "-Wstrict-aliasing" #pragma GCC diagnostic ignored "-Wtype-limits" +#pragma GCC diagnostic ignored "-Wunused-template" #pragma GCC diagnostic ignored "-Wc++11-compat" // only gcc raises it #endif @@ -159,7 +160,6 @@ #include "hb-config.hh" -#include "hb-limits.hh" /* @@ -203,6 +203,7 @@ #define HB_OT_H_IN #include "hb-aat.h" #define HB_AAT_H_IN +#define HB_SUBSET_H_IN #include #include @@ -279,7 +280,7 @@ #if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__) #define HB_UNUSED __attribute__((unused)) #elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */ -#define HB_UNUSED __pragma(warning(suppress: 4100 4101)) +#define HB_UNUSED __pragma(warning(suppress: 4100 4101 4189)) #else #define HB_UNUSED #endif @@ -327,6 +328,14 @@ #endif #endif +#ifndef HB_NEVER_INLINE +#if defined(_MSC_VER) +#define HB_NEVER_INLINE __declspec(noinline) +#else +#define HB_NEVER_INLINE __attribute__((noinline)) +#endif +#endif + #ifndef HB_HOT #define HB_HOT __attribute__((hot)) #endif @@ -375,16 +384,13 @@ # define HB_NODISCARD #endif -/* https://github.com/harfbuzz/harfbuzz/issues/1852 */ -#if defined(__clang__) && !(defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))) -/* Disable certain sanitizer errors. */ -/* https://github.com/harfbuzz/harfbuzz/issues/1247 */ -#define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow"))) +/* Like HB_NODISCARD but can be used on structs */ +#if __cplusplus >= 201703L +# define HB_NODISCARD_STRUCT [[nodiscard]] #else -#define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW +# define HB_NODISCARD_STRUCT #endif - #ifdef _WIN32 /* We need Windows Vista for both Uniscribe backend and for * MemoryBarrier. We don't support compiling on Windows XP, @@ -557,6 +563,7 @@ extern "C" void hb_free_impl(void *ptr); /* 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-limits.hh" #include "hb-cplusplus.hh" #include "hb-meta.hh" #include "hb-mutex.hh"