HarfBuzz: Update to version 5.1.0, use new FLAG_SAFE_TO_INSERT_TATWEEL flag to improve justification.

This commit is contained in:
bruvzg 2022-08-04 08:16:56 +03:00
parent ea4b8de2b4
commit 2980c0d60c
No known key found for this signature in database
GPG Key ID: 7960FCF39844EC38
57 changed files with 4029 additions and 3565 deletions

View File

@ -1679,6 +1679,9 @@
<constant name="GRAPHEME_IS_CONNECTED" value="1024" enum="GraphemeFlag" is_bitfield="true">
Grapheme is connected to the previous grapheme. Breaking line before this grapheme is not safe.
</constant>
<constant name="GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL" value="2048" enum="GraphemeFlag" is_bitfield="true">
It is safe to insert a U+0640 before this grapheme for elongation.
</constant>
<constant name="HINTING_NONE" value="0" enum="Hinting">
Disables font hinting (smoother but less crisp).
</constant>

View File

@ -4718,6 +4718,11 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape
if (sd_glyphs[i].font_rid != RID()) {
Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
#if HB_VERSION_ATLEAST(5, 1, 0)
if ((i > 0) && ((sd_glyphs[i - 1].flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL) != GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL)) {
continue;
}
#endif
gl.start = sd_glyphs[i].start;
gl.end = sd_glyphs[i].end;
gl.repeat = 0;
@ -4908,11 +4913,16 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
hb_buffer_clear_contents(p_sd->hb_buffer);
hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
int flags = (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0);
if (p_sd->preserve_control) {
hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0)));
flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;
} else {
hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0)));
flags |= HB_BUFFER_FLAG_DEFAULT;
}
#if HB_VERSION_ATLEAST(5, 1, 0)
flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
#endif
hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags);
hb_buffer_set_script(p_sd->hb_buffer, p_script);
if (p_sd->spans[p_span].language.is_empty()) {
@ -4980,6 +4990,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
gl.flags |= GRAPHEME_IS_CONNECTED;
}
#if HB_VERSION_ATLEAST(5, 1, 0)
if (glyph_info[i].mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) {
gl.flags |= GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL;
}
#endif
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
_ensure_glyph(fd, fss, gl.index);

View File

@ -521,6 +521,7 @@ void TextServer::_bind_methods() {
BIND_BITFIELD_FLAG(GRAPHEME_IS_PUNCTUATION);
BIND_BITFIELD_FLAG(GRAPHEME_IS_UNDERSCORE);
BIND_BITFIELD_FLAG(GRAPHEME_IS_CONNECTED);
BIND_BITFIELD_FLAG(GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL);
/* Hinting */
BIND_ENUM_CONSTANT(HINTING_NONE);

View File

@ -116,6 +116,7 @@ public:
GRAPHEME_IS_PUNCTUATION = 1 << 8, // Punctuation, except underscore (can be used as word break, but not line break or justifiction).
GRAPHEME_IS_UNDERSCORE = 1 << 9, // Underscore (can be used as word break).
GRAPHEME_IS_CONNECTED = 1 << 10, // Connected to previous grapheme.
GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL = 1 << 11, // It is safe to insert a U+0640 before this grapheme for elongation.
};
enum Hinting {

View File

@ -213,7 +213,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 5.0.1 (cbccadba8d1e51d6cc03a891b7c3a17f598e774c, 2022)
- Version: 5.1.0 (f1f2be776bcd994fa9262622e1a7098a066e5cf7, 2022)
- License: MIT
Files extracted from upstream source:

View File

@ -140,6 +140,13 @@ struct CursivePosFormat1
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 %d to glyph at %d",
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);
@ -231,6 +238,13 @@ struct CursivePosFormat1
pos[parent].x_offset = 0;
}
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"cursive attached glyph at %d to glyph at %d",
i, j);
}
buffer->idx++;
return_trace (true);
}

View File

@ -39,6 +39,13 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
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 %d to glyph at %d",
c->buffer->idx, glyph_pos);
}
hb_glyph_position_t &o = buffer->cur_pos();
o.x_offset = roundf (base_x - mark_x);
o.y_offset = roundf (base_y - mark_y);
@ -46,6 +53,13 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
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 %d to glyph at %d",
c->buffer->idx, glyph_pos);
}
buffer->idx++;
return_trace (true);
}
@ -83,7 +97,8 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
}
};
static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
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 */)

View File

@ -217,10 +217,23 @@ struct PairPosFormat2_4
}
bail:
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"kerning glyphs at %d,%d",
c->buffer->idx, skippy_iter.idx);
}
applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"kerned glyphs at %d,%d",
c->buffer->idx, skippy_iter.idx);
}
success:
if (applied_first || applied_second)
buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);

View File

@ -109,12 +109,28 @@ struct PairSet
record_size);
if (record)
{
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"kerning glyphs at %d,%d",
c->buffer->idx, pos);
}
bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"kerned glyphs at %d,%d",
c->buffer->idx, pos);
}
if (applied_first || applied_second)
buffer->unsafe_to_break (buffer->idx, pos + 1);
if (len2)
pos++;
buffer->idx = pos;
return_trace (true);
}

View File

@ -1,6 +1,8 @@
#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
#include "ValueFormat.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {

View File

@ -39,12 +39,10 @@ struct SinglePosFormat1
{
if (!valueFormat.has_device ()) return;
auto it =
+ hb_iter (this+coverage)
| hb_filter (c->glyph_set)
;
hb_set_t intersection;
(this+coverage).intersect_set (*c->glyph_set, intersection);
if (!intersection) return;
if (!it) return;
valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
}
@ -62,8 +60,22 @@ struct SinglePosFormat1
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioning glyph at %d",
c->buffer->idx);
}
valueFormat.apply_value (c, this, values, buffer->cur_pos());
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioned glyph at %d",
c->buffer->idx);
}
buffer->idx++;
return_trace (true);
}

View File

@ -70,10 +70,24 @@ struct SinglePosFormat2
if (likely (index >= valueCount)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioning glyph at %d",
c->buffer->idx);
}
valueFormat.apply_value (c, this,
&values[index * valueFormat.get_len ()],
buffer->cur_pos());
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioned glyph at %d",
c->buffer->idx);
}
buffer->idx++;
return_trace (true);
}

View File

@ -57,8 +57,23 @@ struct AlternateSet
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"replacing glyph at %d (alternate substitution)",
c->buffer->idx);
}
c->replace_glyph (alternates[alt_index - 1]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %d (alternate substitution)",
c->buffer->idx - 1);
}
return_trace (true);
}

View File

@ -64,7 +64,24 @@ struct Ligature
* as a "ligated" substitution. */
if (unlikely (count == 1))
{
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"replacing glyph at %d (ligature substitution)",
c->buffer->idx);
}
c->replace_glyph (ligGlyph);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %d (ligature substitution)",
c->buffer->idx - 1);
}
return_trace (true);
}
@ -85,6 +102,31 @@ struct Ligature
return_trace (false);
}
unsigned pos = 0;
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
unsigned delta = c->buffer->sync_so_far ();
pos = c->buffer->idx;
char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
char *p = buf;
match_end += delta;
for (unsigned i = 0; i < count; i++)
{
match_positions[i] += delta;
if (i)
*p++ = ',';
sprintf (p, "%u", match_positions[i]);
p += strlen(p);
}
c->buffer->message (c->font,
"ligating glyphs at %s",
buf);
}
ligate_input (c,
count,
match_positions,
@ -92,6 +134,14 @@ struct Ligature
ligGlyph,
total_component_count);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"ligated glyph at %d",
pos);
}
return_trace (true);
}

View File

@ -131,7 +131,23 @@ struct ReverseChainSingleSubstFormat1
c->buffer->idx + 1, &end_index))
{
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replacing glyph at %d (reverse chaining substitution)",
c->buffer->idx);
}
c->replace_glyph_inplace (substitute[index]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %d (reverse chaining substitution)",
c->buffer->idx);
}
/* Note: We DON'T decrease buffer->idx. The main loop does it
* for us. This is useful for preventing surprises if someone
* calls us through a Context lookup. */

View File

@ -40,17 +40,58 @@ struct Sequence
* as a "multiplied" substitution. */
if (unlikely (count == 1))
{
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"replacing glyph at %d (multiple substitution)",
c->buffer->idx);
}
c->replace_glyph (substitute.arrayZ[0]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %d (multiple subtitution)",
c->buffer->idx - 1);
}
return_trace (true);
}
/* Spec disallows this, but Uniscribe allows it.
* https://github.com/harfbuzz/harfbuzz/issues/253 */
else if (unlikely (count == 0))
{
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"deleting glyph at %d (multiple substitution)",
c->buffer->idx);
}
c->buffer->delete_glyph ();
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"deleted glyph at %d (multiple substitution)",
c->buffer->idx);
}
return_trace (true);
}
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"multiplying glyph at %d",
c->buffer->idx);
}
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
@ -65,6 +106,26 @@ struct Sequence
}
c->buffer->skip_glyph ();
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
char *p = buf;
for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
{
if (buf < p)
*p++ = ',';
sprintf (p, "%u", i);
p += strlen(p);
}
c->buffer->message (c->font,
"multiplied glyphs at %s",
buf);
}
return_trace (true);
}

View File

@ -45,6 +45,18 @@ struct SingleSubstFormat1_3
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 ((this+coverage).get_population () >= max_before - min_before &&
((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)
@ -82,8 +94,23 @@ struct SingleSubstFormat1_3
glyph_id = (glyph_id + d) & mask;
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"replacing glyph at %d (single substitution)",
c->buffer->idx);
}
c->replace_glyph (glyph_id);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %d (single substitution)",
c->buffer->idx - 1);
}
return_trace (true);
}

View File

@ -68,8 +68,23 @@ struct SingleSubstFormat2_4
if (unlikely (index >= substitute.len)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"replacing glyph at %d (single substitution)",
c->buffer->idx);
}
c->replace_glyph (substitute[index]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %d (single substitution)",
c->buffer->idx - 1);
}
return_trace (true);
}

View File

@ -26,7 +26,9 @@ struct CompositeGlyphRecord
OVERLAP_COMPOUND = 0x0400,
SCALED_COMPONENT_OFFSET = 0x0800,
UNSCALED_COMPONENT_OFFSET = 0x1000,
#ifndef HB_NO_BEYOND_64K
GID_IS_24BIT = 0x2000
#endif
};
public:
@ -34,7 +36,9 @@ struct CompositeGlyphRecord
{
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;
#endif
/* arg1 and 2 are int16 */
if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
/* arg1 and 2 are int8 */
@ -64,9 +68,11 @@ struct CompositeGlyphRecord
void get_anchor_points (unsigned int &point1, unsigned int &point2) const
{
const auto *p = &StructAfter<const HBUINT8> (flags);
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
p += HBGlyphID24::static_size;
else
#endif
p += HBGlyphID16::static_size;
if (flags & ARG_1_AND_2_ARE_WORDS)
{
@ -109,9 +115,11 @@ struct CompositeGlyphRecord
matrix[1] = matrix[2] = 0.f;
const auto *p = &StructAfter<const HBINT8> (flags);
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
p += HBGlyphID24::static_size;
else
#endif
p += HBGlyphID16::static_size;
int tx, ty;
if (flags & ARG_1_AND_2_ARE_WORDS)
@ -158,16 +166,20 @@ struct CompositeGlyphRecord
public:
hb_codepoint_t get_gid () const
{
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
return StructAfter<const HBGlyphID24> (flags);
else
#endif
return StructAfter<const HBGlyphID16> (flags);
}
void set_gid (hb_codepoint_t gid)
{
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
StructAfter<HBGlyphID24> (flags) = gid;
else
#endif
/* TODO assert? */
StructAfter<HBGlyphID16> (flags) = gid;
}

View File

@ -0,0 +1,80 @@
/*
* Copyright © 2022 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger
*/
#include "graph.hh"
#include "../OT/Layout/Common/Coverage.hh"
#ifndef GRAPH_COVERAGE_GRAPH_HH
#define GRAPH_COVERAGE_GRAPH_HH
namespace graph {
struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3<SmallTypes>
{
bool sanitize (graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
}
};
struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes>
{
bool sanitize (graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
}
};
struct Coverage : public OT::Layout::Common::Coverage
{
bool sanitize (graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
switch (u.format)
{
case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
case 2: return ((CoverageFormat2*)this)->sanitize (vertex);
#ifndef HB_NO_BORING_EXPANSION
// Not currently supported
case 3:
case 4:
#endif
default: return false;
}
}
};
}
#endif // GRAPH_COVERAGE_GRAPH_HH

View File

@ -24,6 +24,10 @@
* Google Author(s): Garret Rieger
*/
#include "../hb-set.hh"
#include "../hb-priority-queue.hh"
#include "../hb-serialize.hh"
#ifndef GRAPH_GRAPH_HH
#define GRAPH_GRAPH_HH
@ -76,6 +80,22 @@ struct graph_t
}
}
void remove_real_link (unsigned child_index, const void* offset)
{
for (unsigned i = 0; i < obj.real_links.length; i++)
{
auto& link = obj.real_links[i];
if (link.objidx != child_index)
continue;
if ((obj.head + link.position) != offset)
continue;
obj.real_links.remove (i);
return;
}
}
void remap_parents (const hb_vector_t<unsigned>& id_map)
{
for (unsigned i = 0; i < parents.length; i++)
@ -107,6 +127,10 @@ struct graph_t
return priority >= 3;
}
size_t table_size () const {
return obj.tail - obj.head;
}
int64_t modified_distance (unsigned order) const
{
// TODO(garretrieger): once priority is high enough, should try
@ -204,6 +228,17 @@ struct graph_t
return vertices_[i].obj;
}
/*
* 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 ()
{
if (!positions_invalid) return;
sort_shortest_distance ();
}
/*
* Generates a new topological sorting of graph ordered by the shortest
* distance to each node.
@ -256,12 +291,12 @@ struct graph_t
check_success (!queue.in_error ());
check_success (!sorted_graph.in_error ());
if (!check_success (new_id == -1))
print_orphaned_nodes ();
remap_all_obj_indices (id_map, &sorted_graph);
hb_swap (vertices_, sorted_graph);
if (!check_success (new_id == -1))
print_orphaned_nodes ();
}
/*
@ -310,6 +345,22 @@ struct graph_t
}
}
unsigned index_for_offset(unsigned node_idx, const void* offset) const
{
const auto& node = object (node_idx);
if (offset < node.head || offset >= node.tail) return -1;
for (const auto& link : node.real_links)
{
if (offset != node.head + link.position)
continue;
return link.objidx;
}
return -1;
}
/*
* Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
* Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB
@ -317,6 +368,8 @@ struct graph_t
*/
bool assign_spaces ()
{
update_parents ();
hb_set_t visited;
hb_set_t roots;
find_space_roots (visited, roots);
@ -458,6 +511,21 @@ struct graph_t
find_subgraph (link.objidx, subgraph);
}
size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = -1)
{
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;
for (const auto& link : o.all_links ())
size += find_subgraph_size (link.objidx, subgraph, max_depth - 1);
return size;
}
/*
* Finds the topmost children of 32bit offsets in the subgraph starting
* at node_idx. Found indices are placed into 'found'.
@ -474,6 +542,37 @@ struct graph_t
}
}
/*
* Moves the child of old_parent_idx pointed to by old_offset to a new
* vertex at the new_offset.
*/
template<typename O>
void move_child (unsigned old_parent_idx,
const O* old_offset,
unsigned new_parent_idx,
const O* new_offset)
{
distance_invalid = true;
positions_invalid = true;
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);
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;
auto& child = vertices_[child_id];
child.parents.push (new_parent_idx);
old_v.remove_real_link (child_id, old_offset);
child.remove_parent (old_parent_idx);
}
/*
* duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
* links. index_map is updated with mappings from old id to new id. If a duplication has already
@ -581,6 +680,39 @@ struct graph_t
return true;
}
/*
* Adds a new node to the graph, not connected to anything.
*/
unsigned new_node (char* head, char* tail)
{
positions_invalid = true;
distance_invalid = true;
auto* clone = vertices_.push ();
if (vertices_.in_error ()) {
return -1;
}
clone->obj.head = head;
clone->obj.tail = tail;
clone->distance = 0;
clone->space = 0;
unsigned clone_idx = vertices_.length - 2;
// The last object is the root of the graph, so swap back the root to the end.
// The root's obj idx does change, however since it's root nothing else refers to it.
// all other obj idx's will be unaffected.
hb_swap (vertices_[vertices_.length - 2], *clone);
// Since the root moved, update the parents arrays of all children on the root.
for (const auto& l : root ().obj.all_links ())
vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
return clone_idx;
}
/*
* Raises the sorting priority of all children.
*/

View File

@ -0,0 +1,71 @@
/*
* Copyright © 2022 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger
*/
#include "gsubgpos-graph.hh"
namespace graph {
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 (),
buffers ()
{
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)
{
char* buffer = (char*) hb_calloc (1, size);
if (!buffer)
return -1;
buffers.push (buffer);
return graph.new_node (buffer, buffer + size);
}
unsigned gsubgpos_graph_context_t::num_non_ext_subtables () {
unsigned count = 0;
for (auto l : lookups.values ())
{
if (l->is_extension (table_tag)) continue;
count += l->number_of_subtables ();
}
return count;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright © 2022 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger
*/
#include "graph.hh"
#include "../hb-ot-layout-gsubgpos.hh"
#ifndef GRAPH_GSUBGPOS_CONTEXT_HH
#define GRAPH_GSUBGPOS_CONTEXT_HH
namespace graph {
struct Lookup;
struct gsubgpos_graph_context_t
{
hb_tag_t table_tag;
graph_t& graph;
unsigned lookup_list_index;
hb_hashmap_t<unsigned, graph::Lookup*> lookups;
hb_vector_t<char*> buffers;
HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
graph_t& graph_);
~gsubgpos_graph_context_t ()
{
for (char* b : buffers)
hb_free (b);
}
HB_INTERNAL unsigned create_node (unsigned size);
void add_buffer (char* buffer)
{
buffers.push (buffer);
}
private:
HB_INTERNAL unsigned num_non_ext_subtables ();
};
}
#endif // GRAPH_GSUBGPOS_CONTEXT

View File

@ -0,0 +1,351 @@
/*
* Copyright © 2022 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger
*/
#include "graph.hh"
#include "../hb-ot-layout-gsubgpos.hh"
#include "../OT/Layout/GSUB/ExtensionSubst.hh"
#include "gsubgpos-context.hh"
#include "pairpos-graph.hh"
#ifndef GRAPH_GSUBGPOS_GRAPH_HH
#define GRAPH_GSUBGPOS_GRAPH_HH
namespace graph {
struct Lookup;
template<typename T>
struct ExtensionFormat1 : public OT::ExtensionFormat1<T>
{
void reset(unsigned type)
{
this->format = 1;
this->extensionLookupType = type;
this->extensionOffset = 0;
}
bool sanitize (graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
return vertex_len >= OT::ExtensionFormat1<T>::static_size;
}
unsigned get_lookup_type () const
{
return this->extensionLookupType;
}
unsigned get_subtable_index (graph_t& graph, unsigned this_index) const
{
return graph.index_for_offset (this_index, &this->extensionOffset);
}
};
struct Lookup : public OT::Lookup
{
unsigned number_of_subtables () const
{
return subTable.len;
}
bool sanitize (graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::Lookup::min_size) return false;
return vertex_len >= this->get_size ();
}
bool is_extension (hb_tag_t table_tag) const
{
return lookupType == extension_type (table_tag);
}
bool 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;
}
DEBUG_MSG (SUBSET_REPACK, nullptr,
"Promoting lookup type %u (obj %u) to extension.",
type,
this_index);
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;
}
lookupType = ext_type;
return true;
}
bool 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)
return true;
if (!is_ext && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
return true;
hb_vector_t<unsigned> all_new_subtables;
for (unsigned i = 0; i < subTable.len; i++)
{
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
if (is_ext) {
unsigned ext_subtable_index = subtable_index;
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
c.graph.object (ext_subtable_index).head;
if (!extension->sanitize (c.graph.vertices_[ext_subtable_index]))
continue;
subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
type = extension->get_lookup_type ();
if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
continue;
}
PairPos* pairPos = (PairPos*) c.graph.object (subtable_index).head;
if (!pairPos->sanitize (c.graph.vertices_[subtable_index])) continue;
hb_vector_t<unsigned> new_sub_tables = pairPos->split_subtables (c, subtable_index);
if (new_sub_tables.in_error ()) return false;
+ new_sub_tables.iter() | hb_sink (all_new_subtables);
}
if (all_new_subtables)
add_sub_tables (c, this_index, type, all_new_subtables);
return true;
}
void add_sub_tables (gsubgpos_graph_context_t& c,
unsigned this_index,
unsigned type,
hb_vector_t<unsigned>& subtable_indices)
{
bool is_ext = is_extension (c.table_tag);
auto& v = c.graph.vertices_[this_index];
size_t new_size = v.table_size ()
+ subtable_indices.length * OT::Offset16::static_size;
char* buffer = (char*) hb_calloc (1, new_size);
c.add_buffer (buffer);
memcpy (buffer, v.obj.head, v.table_size());
v.obj.head = buffer;
v.obj.tail = buffer + new_size;
Lookup* new_lookup = (Lookup*) buffer;
new_lookup->subTable.len = subTable.len + subtable_indices.length;
unsigned offset_index = subTable.len;
for (unsigned subtable_id : subtable_indices)
{
if (is_ext)
{
unsigned ext_id = create_extension_subtable (c, subtable_id, type);
c.graph.vertices_[subtable_id].parents.push (ext_id);
subtable_id = ext_id;
}
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].parents.push (this_index);
}
// 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);
}
unsigned create_extension_subtable (gsubgpos_graph_context_t& c,
unsigned subtable_index,
unsigned type)
{
unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
unsigned ext_index = c.create_node (extension_size);
if (ext_index == (unsigned) -1)
return -1;
auto& ext_vertex = c.graph.vertices_[ext_index];
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) ext_vertex.obj.head;
extension->reset (type);
// Make extension point at the subtable.
auto* l = ext_vertex.obj.real_links.push ();
l->width = 4;
l->objidx = subtable_index;
l->position = 4;
return ext_index;
}
bool make_subtable_extension (gsubgpos_graph_context_t& c,
unsigned lookup_index,
unsigned subtable_index)
{
unsigned type = lookupType;
unsigned ext_index = create_extension_subtable(c, subtable_index, type);
if (ext_index == (unsigned) -1)
return false;
auto& lookup_vertex = c.graph.vertices_[lookup_index];
for (auto& l : lookup_vertex.obj.real_links.writer ())
{
if (l.objidx == subtable_index)
// Change lookup to point at the extension.
l.objidx = ext_index;
}
// Make extension point at the subtable.
auto& ext_vertex = c.graph.vertices_[ext_index];
auto& subtable_vertex = c.graph.vertices_[subtable_index];
ext_vertex.parents.push (lookup_index);
subtable_vertex.remap_parent (lookup_index, ext_index);
return true;
}
private:
unsigned extension_type (hb_tag_t table_tag) const
{
switch (table_tag)
{
case HB_OT_TAG_GPOS: return 9;
case HB_OT_TAG_GSUB: return 7;
default: return 0;
}
}
};
template <typename T>
struct LookupList : public OT::LookupList<T>
{
bool sanitize (const graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::LookupList<T>::min_size) return false;
return vertex_len >= OT::LookupList<T>::item_size * this->len;
}
};
struct GSTAR : public OT::GSUBGPOS
{
static GSTAR* graph_to_gstar (graph_t& graph)
{
const auto& r = graph.root ();
GSTAR* gstar = (GSTAR*) r.obj.head;
if (!gstar->sanitize (r))
return nullptr;
return gstar;
}
const void* get_lookup_list_field_offset () const
{
switch (u.version.major) {
case 1: return u.version1.get_lookup_list_offset ();
#ifndef HB_NO_BORING_EXPANSION
case 2: return u.version2.get_lookup_list_offset ();
#endif
default: return 0;
}
}
bool sanitize (const graph_t::vertex_t& vertex)
{
int64_t len = vertex.obj.tail - vertex.obj.head;
if (len < OT::GSUBGPOS::min_size) return false;
return len >= get_size ();
}
void find_lookups (graph_t& graph,
hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
{
switch (u.version.major) {
case 1: find_lookups<SmallTypes> (graph, lookups); break;
#ifndef HB_NO_BORING_EXPANSION
case 2: find_lookups<MediumTypes> (graph, lookups); break;
#endif
}
}
unsigned get_lookup_list_index (graph_t& graph)
{
return graph.index_for_offset (graph.root_idx (),
get_lookup_list_field_offset());
}
template<typename Types>
void find_lookups (graph_t& graph,
hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
{
unsigned lookup_list_idx = get_lookup_list_index (graph);
const LookupList<Types>* lookupList =
(const LookupList<Types>*) graph.object (lookup_list_idx).head;
if (!lookupList->sanitize (graph.vertices_[lookup_list_idx]))
return;
for (unsigned i = 0; i < lookupList->len; i++)
{
unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i]));
Lookup* lookup = (Lookup*) graph.object (lookup_idx).head;
if (!lookup->sanitize (graph.vertices_[lookup_idx])) continue;
lookups.set (lookup_idx, lookup);
}
}
};
}
#endif /* GRAPH_GSUBGPOS_GRAPH_HH */

View File

@ -0,0 +1,299 @@
/*
* Copyright © 2022 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger
*/
#ifndef GRAPH_PAIRPOS_GRAPH_HH
#define GRAPH_PAIRPOS_GRAPH_HH
#include "coverage-graph.hh"
#include "../OT/Layout/GPOS/PairPos.hh"
#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
namespace graph {
struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>
{
bool sanitize (graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
return vertex_len >=
min_size + pairSet.get_size () - pairSet.len.get_size();
}
hb_vector_t<unsigned> 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);
const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
+ coverage_size;
unsigned accumulated = base_size;
hb_vector_t<unsigned> split_points;
for (unsigned i = 0; i < pairSet.len; i++)
{
unsigned pair_set_index = pair_set_graph_index (c, this_index, i);
accumulated += c.graph.find_subgraph_size (pair_set_index, visited);
accumulated += SmallTypes::size; // for PairSet offset.
// TODO(garretrieger): don't count the size of the largest pairset against the limit, since
// it will be packed last in the order and does not contribute to
// the 64kb limit.
if (accumulated > (1 << 16))
{
split_points.push (i);
accumulated = base_size;
visited.clear (); // Pretend node sharing isn't allowed between splits.
}
}
return do_split (c, this_index, split_points);
}
private:
// Split this PairPos into two or more PairPos's. split_points defines
// the indices (first index to include in the new table) to split at.
// Returns the object id's of the newly created PairPos subtables.
hb_vector_t<unsigned> do_split (gsubgpos_graph_context_t& c,
unsigned this_index,
const hb_vector_t<unsigned> split_points)
{
hb_vector_t<unsigned> new_objects;
if (!split_points)
return new_objects;
for (unsigned i = 0; i < split_points.length; i++)
{
unsigned start = split_points[i];
unsigned end = (i < split_points.length - 1) ? split_points[i + 1] : pairSet.len;
unsigned id = clone_range (c, this_index, start, end);
if (id == (unsigned) -1)
{
new_objects.reset ();
new_objects.allocated = -1; // mark error
return new_objects;
}
new_objects.push (id);
}
if (!shrink (c, this_index, split_points[0]))
{
new_objects.reset ();
new_objects.allocated = -1; // mark error
}
return new_objects;
}
bool shrink (gsubgpos_graph_context_t& c,
unsigned this_index,
unsigned count)
{
DEBUG_MSG (SUBSET_REPACK, nullptr,
" Shrinking PairPosFormat1 (%u) to [0, %u).",
this_index,
count);
unsigned old_count = pairSet.len;
if (count >= old_count)
return true;
pairSet.len = count;
c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
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->sanitize (coverage_v))
return false;
auto new_coverage =
+ hb_zip (coverage_table->iter (), hb_range ())
| hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
return p.second < count;
})
| hb_map_retains_sorting (hb_first)
;
return make_coverage (c, new_coverage, coverage_id, coverage_size);
}
// Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
// Returns object id of the new object.
unsigned 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);
unsigned num_pair_sets = end - start;
unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::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;
PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head;
pair_pos_prime->format = this->format;
pair_pos_prime->valueFormat[0] = this->valueFormat[0];
pair_pos_prime->valueFormat[1] = this->valueFormat[1];
pair_pos_prime->pairSet.len = num_pair_sets;
for (unsigned i = start; i < end; i++)
{
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);
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->sanitize (coverage_v))
return false;
auto new_coverage =
+ hb_zip (coverage_table->iter (), hb_range ())
| hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
return p.second >= start && p.second < end;
})
| hb_map_retains_sorting (hb_first)
;
unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr);
auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id];
if (!make_coverage (c, new_coverage, coverage_prime_id, coverage_size))
return -1;
auto* coverage_link = c.graph.vertices_[pair_pos_prime_id].obj.real_links.push ();
coverage_link->width = SmallTypes::size;
coverage_link->objidx = coverage_prime_id;
coverage_link->position = 2;
coverage_prime_vertex.parents.push (pair_pos_prime_id);
return pair_pos_prime_id;
}
template<typename It>
bool make_coverage (gsubgpos_graph_context_t& c,
It glyphs,
unsigned dest_obj,
unsigned max_size) const
{
char* buffer = (char*) hb_calloc (1, max_size);
hb_serialize_context_t serializer (buffer, max_size);
Coverage_serialize (&serializer, glyphs);
serializer.end_serialize ();
if (serializer.in_error ())
{
hb_free (buffer);
return false;
}
hb_bytes_t coverage_copy = serializer.copy_bytes ();
c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
auto& obj = c.graph.vertices_[dest_obj].obj;
obj.head = (char *) coverage_copy.arrayZ;
obj.tail = obj.head + coverage_copy.length;
hb_free (buffer);
return true;
}
unsigned 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]);
}
};
struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
{
bool sanitize (graph_t::vertex_t& vertex) const
{
// TODO(garretrieger): implement me!
return true;
}
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
{
// TODO(garretrieger): implement me!
return hb_vector_t<unsigned> ();
}
};
struct PairPos : public OT::Layout::GPOS_impl::PairPos
{
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
{
switch (u.format) {
case 1:
return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
case 2:
return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
#ifndef HB_NO_BORING_EXPANSION
case 3: HB_FALLTHROUGH;
case 4: HB_FALLTHROUGH;
// Don't split 24bit PairPos's.
#endif
default:
return hb_vector_t<unsigned> ();
}
}
bool sanitize (graph_t::vertex_t& vertex) const
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < u.format.get_size ()) return false;
switch (u.format) {
case 1:
return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
case 2:
return ((PairPosFormat2*)(&u.format2))->sanitize (vertex);
#ifndef HB_NO_BORING_EXPANSION
case 3: HB_FALLTHROUGH;
case 4: HB_FALLTHROUGH;
#endif
default:
// We don't handle format 3 and 4 here.
return false;
}
}
};
}
#endif // GRAPH_PAIRPOS_GRAPH_HH

View File

@ -303,7 +303,7 @@ hb_blob_set_user_data (hb_blob_t *blob,
* Since: 0.9.2
**/
void *
hb_blob_get_user_data (hb_blob_t *blob,
hb_blob_get_user_data (const hb_blob_t *blob,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (blob, key);

View File

@ -135,7 +135,7 @@ hb_blob_set_user_data (hb_blob_t *blob,
HB_EXTERN void *
hb_blob_get_user_data (hb_blob_t *blob,
hb_blob_get_user_data (const hb_blob_t *blob,
hb_user_data_key_t *key);

View File

@ -387,9 +387,11 @@ hb_buffer_t::clear_positions ()
hb_memset (pos, 0, sizeof (pos[0]) * len);
}
void
bool
hb_buffer_t::sync ()
{
bool ret = false;
assert (have_output);
assert (idx <= len);
@ -403,12 +405,39 @@ hb_buffer_t::sync ()
info = out_info;
}
len = out_len;
ret = true;
reset:
have_output = false;
out_len = 0;
out_info = info;
idx = 0;
return ret;
}
int
hb_buffer_t::sync_so_far ()
{
bool had_output = have_output;
unsigned out_i = out_len;
unsigned i = idx;
unsigned old_idx = idx;
if (sync ())
idx = out_i;
else
idx = i;
if (had_output)
{
have_output = true;
out_len = idx;
}
assert (idx <= len);
return idx - old_idx;
}
bool
@ -802,7 +831,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
* Since: 0.9.2
**/
void *
hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_buffer_get_user_data (const hb_buffer_t *buffer,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (buffer, key);
@ -2090,8 +2119,16 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
bool
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
{
assert (!have_output || (out_info == info && out_len == idx));
message_depth++;
char buf[100];
vsnprintf (buf, sizeof (buf), fmt, ap);
return (bool) this->message_func (this, font, buf, this->message_data);
bool ret = (bool) this->message_func (this, font, buf, this->message_data);
message_depth--;
return ret;
}
#endif

View File

@ -142,6 +142,15 @@ typedef struct hb_glyph_info_t {
* shaping, otherwise the buffer flag will not be
* reliably produced.
* Since: 4.0.0
* @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL: In scripts that use elongation (Arabic,
Mongolian, Syriac, etc.), this flag signifies
that it is safe to insert a U+0640 TATWEEL
character *before* this cluster for elongation.
This flag does not determine the
script-specific elongation places, but only
when it is safe to do the elongation without
interrupting text shaping.
Since: 5.1.0
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
*
* Flags for #hb_glyph_info_t.
@ -151,8 +160,9 @@ typedef struct hb_glyph_info_t {
typedef enum { /*< flags >*/
HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
HB_GLYPH_FLAG_UNSAFE_TO_CONCAT = 0x00000002,
HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL = 0x00000004,
HB_GLYPH_FLAG_DEFINED = 0x00000003 /* OR of all defined flags */
HB_GLYPH_FLAG_DEFINED = 0x00000007 /* OR of all defined flags */
} hb_glyph_flags_t;
HB_EXTERN hb_glyph_flags_t
@ -266,7 +276,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_bool_t replace);
HB_EXTERN void *
hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_buffer_get_user_data (const hb_buffer_t *buffer,
hb_user_data_key_t *key);
@ -373,6 +383,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
* glyph-flag should be produced by the shaper. By default
* it will not be produced since it incurs a cost. Since: 4.0.0
* @HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL:
* flag indicating that the @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
* glyph-flag should be produced by the shaper. By default
* it will not be produced. Since: 5.1.0
* @HB_BUFFER_FLAG_DEFINED: All currently defined flags: Since: 4.4.0
*
* Flags for #hb_buffer_t.
@ -388,8 +402,9 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u,
HB_BUFFER_FLAG_VERIFY = 0x00000020u,
HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u,
HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL = 0x00000080u,
HB_BUFFER_FLAG_DEFINED = 0x0000007Fu
HB_BUFFER_FLAG_DEFINED = 0x000000FFu
} hb_buffer_flags_t;
HB_EXTERN void

View File

@ -288,7 +288,8 @@ struct hb_buffer_t
HB_INTERNAL void guess_segment_properties ();
HB_INTERNAL void sync ();
HB_INTERNAL bool sync ();
HB_INTERNAL int sync_so_far ();
HB_INTERNAL void clear_output ();
HB_INTERNAL void clear_positions ();
@ -461,6 +462,17 @@ struct hb_buffer_t
start, end,
true);
}
void safe_to_insert_tatweel (unsigned int start = 0, unsigned int end = -1)
{
if ((flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0)
{
unsafe_to_break (start, end);
return;
}
_set_glyph_flags (HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL,
start, end,
true);
}
void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
{
if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
@ -555,15 +567,11 @@ struct hb_buffer_t
if (likely (!messaging ()))
return true;
message_depth++;
va_list ap;
va_start (ap, fmt);
bool ret = message_impl (font, fmt, ap);
va_end (ap);
message_depth--;
return ret;
#endif
}

View File

@ -130,7 +130,7 @@ template <typename T,
void *,
hb_destroy_func_t,
hb_bool_t),
void * (*_get_user_data) (T *,
void * (*_get_user_data) (const T *,
hb_user_data_key_t *)>
struct vtable_t
{
@ -164,6 +164,27 @@ HB_DEFINE_VTABLE (unicode_funcs);
#undef HB_DEFINE_VTABLE
#ifdef HB_SUBSET_H
#define HB_DEFINE_VTABLE(name) \
template<> \
struct vtable<hb_##name##_t> \
: vtable_t<hb_##name##_t, \
nullptr, \
&hb_##name##_reference, \
&hb_##name##_destroy, \
&hb_##name##_set_user_data, \
&hb_##name##_get_user_data> {}
HB_DEFINE_VTABLE (subset_input);
HB_DEFINE_VTABLE (subset_plan);
#undef HB_DEFINE_VTABLE
#endif
} // namespace hb
/* Workaround for GCC < 7, see:

View File

@ -460,4 +460,9 @@ struct hb_no_trace_t {
#endif
#ifndef HB_BUFFER_MESSAGE_MORE
#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1)
#endif
#endif /* HB_DEBUG_HH */

View File

@ -342,7 +342,7 @@ hb_face_set_user_data (hb_face_t *face,
* Since: 0.9.2
**/
void *
hb_face_get_user_data (hb_face_t *face,
hb_face_get_user_data (const hb_face_t *face,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (face, key);

View File

@ -96,7 +96,7 @@ hb_face_set_user_data (hb_face_t *face,
hb_bool_t replace);
HB_EXTERN void *
hb_face_get_user_data (hb_face_t *face,
hb_face_get_user_data (const hb_face_t *face,
hb_user_data_key_t *key);
HB_EXTERN void

View File

@ -781,7 +781,7 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
* Since: 0.9.2
**/
void *
hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (ffuncs, key);
@ -1897,7 +1897,7 @@ hb_font_set_user_data (hb_font_t *font,
* Since: 0.9.2
**/
void *
hb_font_get_user_data (hb_font_t *font,
hb_font_get_user_data (const hb_font_t *font,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (font, key);

View File

@ -86,7 +86,7 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
HB_EXTERN void *
hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key);
@ -993,7 +993,7 @@ hb_font_set_user_data (hb_font_t *font,
HB_EXTERN void *
hb_font_get_user_data (hb_font_t *font,
hb_font_get_user_data (const hb_font_t *font,
hb_user_data_key_t *key);
HB_EXTERN void

View File

@ -1086,7 +1086,8 @@ hb_ft_font_changed (hb_font_t *font)
}
#endif
_hb_ft_hb_font_check_changed (font, ft_font);
ft_font->advance_cache.clear ();
ft_font->cached_serial = font->serial;
}
/**

View File

@ -145,7 +145,7 @@ hb_map_set_user_data (hb_map_t *map,
* Since: 1.7.7
**/
void *
hb_map_get_user_data (hb_map_t *map,
hb_map_get_user_data (const hb_map_t *map,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (map, key);

View File

@ -74,7 +74,7 @@ hb_map_set_user_data (hb_map_t *map,
hb_bool_t replace);
HB_EXTERN void *
hb_map_get_user_data (hb_map_t *map,
hb_map_get_user_data (const hb_map_t *map,
hb_user_data_key_t *key);

View File

@ -31,7 +31,7 @@
#include "hb.hh"
#line 32 "hb-number-parser.hh"
#line 35 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
46u, 101u, 0
@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
int cs;
#line 132 "hb-number-parser.hh"
#line 139 "hb-number-parser.hh"
{
cs = double_parser_start;
}
#line 135 "hb-number-parser.hh"
#line 144 "hb-number-parser.hh"
{
int _slen;
int _trans;
@ -198,7 +198,7 @@ _resume:
exp_overflow = true;
}
break;
#line 187 "hb-number-parser.hh"
#line 202 "hb-number-parser.hh"
}
_again:

View File

@ -72,10 +72,6 @@ using OT::Layout::MediumTypes;
#define HB_MAX_LANGSYS_FEATURE_COUNT 50000
#endif
#ifndef HB_MAX_FEATURES
#define HB_MAX_FEATURES 750
#endif
#ifndef HB_MAX_FEATURE_INDICES
#define HB_MAX_FEATURE_INDICES 1500
#endif
@ -1337,7 +1333,7 @@ struct Lookup
return_trace (true);
}
private:
protected:
HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
HBUINT16 lookupFlag; /* Lookup qualifiers */
Array16Of<Offset16>

View File

@ -1602,9 +1602,28 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
if (unlikely (buffer->max_ops <= 0))
break;
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
if (buffer->have_output)
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"recursing to lookup %u at %d",
(unsigned) lookupRecord[i].lookupListIndex,
buffer->idx);
}
if (!c->recurse (lookupRecord[i].lookupListIndex))
continue;
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
if (buffer->have_output)
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"recursed to lookup %u",
(unsigned) lookupRecord[i].lookupListIndex);
}
unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
int delta = new_len - orig_len;
@ -4010,6 +4029,11 @@ struct GSUBGPOSVersion1_2
(version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
}
const typename Types::template OffsetTo<LookupList<Types>>* get_lookup_list_offset () const
{
return &lookupList;
}
template <typename TLookup>
bool sanitize (hb_sanitize_context_t *c) const
{

View File

@ -1141,6 +1141,18 @@ hb_propagate_flags (hb_buffer_t *buffer)
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS))
return;
/* If we are producing SAFE_TO_INSERT_TATWEEL, then do two things:
*
* - If the places that the Arabic shaper marked as SAFE_TO_INSERT_TATWEEL,
* are UNSAFE_TO_BREAK, then clear the SAFE_TO_INSERT_TATWEEL,
* - Any place that is SAFE_TO_INSERT_TATWEEL, is also now UNSAFE_TO_BREAK.
*
* We couldn't make this interaction earlier. It has to be done here.
*/
bool flip_tatweel = buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
bool clear_concat = (buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0;
hb_glyph_info_t *info = buffer->info;
foreach_cluster (buffer, start, end)
@ -1148,9 +1160,20 @@ hb_propagate_flags (hb_buffer_t *buffer)
unsigned int mask = 0;
for (unsigned int i = start; i < end; i++)
mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED;
if (mask)
if (flip_tatweel)
{
if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
}
if (clear_concat)
mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
for (unsigned int i = start; i < end; i++)
info[i].mask |= mask;
info[i].mask = mask;
}
}

View File

@ -331,7 +331,7 @@ arabic_joining (hb_buffer_t *buffer)
if (entry->prev_action != NONE && prev != UINT_MAX)
{
info[prev].arabic_shaping_action() = entry->prev_action;
buffer->unsafe_to_break (prev, i + 1);
buffer->safe_to_insert_tatweel (prev, i + 1);
}
else
{
@ -365,7 +365,7 @@ arabic_joining (hb_buffer_t *buffer)
if (entry->prev_action != NONE && prev != UINT_MAX)
{
info[prev].arabic_shaping_action() = entry->prev_action;
buffer->unsafe_to_break (prev, buffer->len);
buffer->safe_to_insert_tatweel (prev, buffer->len);
}
else if (2 <= state && state <= 5) /* States that have a possible prev_action. */
{

View File

@ -90,263 +90,264 @@
#pragma GCC diagnostic pop
static const uint8_t
hb_use_u8[1842] =
hb_use_u8[3083] =
{
0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5,
6, 7, 3, 8, 3, 3, 9, 3, 10, 3, 3, 11, 3, 12, 13, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
14, 0, 0, 1, 1, 2, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10,
1, 11, 12, 1, 1, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 19,
1, 1, 20, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 22,
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, 23, 24, 25, 26, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
27, 28, 1, 1, 1, 1, 1, 29, 1, 1, 1, 1, 30, 31, 1, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 1, 46, 47,
48, 1, 49, 49, 49, 49, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 51, 52, 1, 1,
1, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 49, 54, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 55, 1,
1, 1, 1, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 57, 58, 1, 1, 1, 1, 1, 1, 59, 1, 1, 1, 1,
1, 1, 60, 61, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
60, 60, O, O, O, O, O, GB, O, O, B, B, B, B, B, B,
O, O, GB, O, O, O, O, WJ, O, O, O, O,FMPst,FMPst, O, O,
O, GB, O, O, O, CGJ, B, O, O, O, O, O, B, B, B, B,
B,VMAbv,VMAbv,VMAbv,VMAbv,VMAbv, O, O, B, O, O,VMAbv, O, O, B,CMBlw,
CMBlw,CMBlw,VMAbv,VMAbv,VMAbv,VMPst, B, B, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw,
VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VPst, VPst, VPst, VPst, H, VPre, VPst, O,VMAbv,
VMBlw, O, O, VAbv, VBlw, VBlw, B, B, VBlw, VBlw, GB,VMAbv,VMPst,VMPst, O, B,
B, B, B, O, O, B, B, O, B, B, B, O, B, O, VBlw, O,
O, VPre, VPre, O, O, VPre, VPre, H, O, O, O, O, O, VPst, B, B,
O, B, B, O,FMAbv, O, O,VMAbv,VMAbv,VMPst, B, B, B, O, O, O,
O, B, O, B, B, O,CMBlw, O, VPst, VPre, VPst, VBlw, VBlw, O, O, O,
O, VAbv, VAbv, O, O, VAbv, VAbv, H, O, O, O,VMBlw, O, O,VMAbv,CMAbv,
GB, GB, O, MBlw, O, O, VBlw, VAbv, O, VAbv, VAbv, VAbv, O, VPst, VPst, H,
O, O, O, B,VMAbv,VMAbv,VMAbv,CMAbv,CMAbv,CMAbv, O,VMAbv,VMPst,VMPst,CMBlw, B,
VPst, VAbv, O, VAbv, VAbv, VAbv, O, B, O, O, O, O,VMAbv, O, O, O,
VPst, VPst, VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre,VMAbv,VMPst,
VMPst,VMPst,VMAbv, B, B, B,CMBlw, B, VAbv, VAbv, VPst, O, VAbv, VAbv, VAbv, O,
VAbv, VAbv, O, VAbv, VBlw, O, B,VMAbv,VMPst,VMPst, O, VPst, VPst, O, O, CS,
CS, O,VMAbv,VMAbv,VMPst,VMPst, B, B, B, VAbv, VAbv, B, VPst, VPst, VPst, VPst,
VPst, VBlw, VBlw, O, VPre, VPre, VPre, H, R, O, O, O, HVM, O, VPst, VPst,
VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, VBlw, VBlw,
O, O, O, FBlw, O, FBlw, O,CMAbv, O, O, O, O, VPst, VPre, O,CMBlw,
VBlw, VAbv, VAbv, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw,VMAbv, O, VBlw, VAbv,
VMAbv,VMAbv, VBlw, O,VMAbv,VMAbv, B, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB,
SUB, SUB, SUB, O, O, O, O, O, FBlw, O, B, B, B, VPst, VPst, VAbv,
VAbv, VBlw, VBlw, VPre, VAbv, VAbv, VAbv, VAbv,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw,
MBlw, B, B, B, O, GB, O, O, GB, O, B, B, VPst, VPst, VBlw, VBlw,
B, B, B, B, MBlw, MBlw, MBlw, B, VPst,VMPst,VMPst, B, B, VPst, VPst,VMPst,
VMPst,VMPst,VMPst,VMPst, B, B, B, VAbv, VAbv, VAbv, VAbv, B, B, B, B, B,
MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMPst,VMPst,VMPst,VMPst,VMBlw, B,VMPst, B, B,
VMPst,VMPst, VPst, VAbv, O, O, B, B, VAbv, VBlw, VBlw, VPst, O, O, VPst, O,
O, O, B, O, VAbv, VBlw, CGJ, CGJ, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw,
VPre, VPre, VPre, VPre, VPre, VPre, VPre, VPre,VMAbv,VMPst, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,
FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, O, O, O, O, B, CGJ, CGJ, CGJ,
WJ, CGJ, GB, GB, GB, GB, GB,CMAbv,CMAbv, B, B,CMBlw, B, O, GB, B,
B, B, VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv, SUB, SUB, SUB, FPst, FPst,
VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw,VMAbv,FMBlw,VMPst,VMPst, O, O, VAbv, VPre,
VPst, VAbv, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, SUB, SUB, SUB, O, Sk, VPst,
VAbv, VPst, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre, VPre, VPre, VPre, VAbv,VMAbv,VMAbv,
VAbv,VMAbv,VMAbv, O, O,VMBlw,VMAbv,VMAbv,VMAbv, FAbv,VMPst, B, B, B,CMAbv, VPst,
VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, VPre, VPre, VAbv, VAbv, H, B,
B, B, O, O, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,VMAbv, FAbv,
VMPst, B, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, IS, SUB, SUB, B, B, B, B,
CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv, FAbv, FAbv,CMBlw,CMBlw, SUB, SUB,
VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, FAbv, FAbv, FAbv, FAbv,VMPre,VMPre,
FMAbv,CMBlw,VMAbv,VMAbv,VMAbv, O,VMBlw,VMBlw,VMBlw,VMBlw,VMBlw,VMBlw,VMAbv,VMAbv,VMAbv,VMPst,
VMBlw,VMBlw,VMBlw, O, O, O,VMAbv, CS, CS,VMPst,VMAbv,VMAbv, GB, O, O, O,
O,FMAbv, O, O, O, WJ, ZWNJ, CGJ, WJ, WJ, O, O, WJ, WJ, WJ, WJ,
WJ, O, WJ, WJ, WJ, WJ,FMPst, O, O, O,VMAbv, O, O, O, O, O,
O, H, B, B, VAbv, B, B, B, H, B, VPst, VBlw, VAbv, VPst, VBlw, O,
O, O, MPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, H,VMAbv, O, O,VMAbv,VMAbv,
B, B, O, O, B, VAbv, B, B, VAbv, VAbv, VAbv, VAbv, VAbv,VMBlw,VMBlw,VMBlw,
O, O, B, B, B, VBlw, VBlw, VBlw, VAbv, VBlw, VBlw, VBlw, VBlw, FAbv, FAbv, FAbv,
FPst, VPst,VMAbv,VMAbv, FAbv,VMPst, B, B, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O,
O, O, B, VAbv, O, B, B,VMAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre, VPre, VAbv,
VBlw, MPst, MPre, MAbv, MBlw, O, B, B, B, FAbv, FAbv, FPst, O, O, GB, GB,
GB, O, O, O, B,VMPst,VMAbv,VMPst, B, B, VAbv, B, VAbv, VAbv, VBlw, B,
B, VAbv, B, B, VAbv,VMAbv, B,VMAbv, B, O, B, B, B, VPre, VBlw, VAbv,
VPre, VPst, O,VMPst, IS, O, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O,VMPst, VBlw,
O, O, CGJ, CGJ, CGJ, CGJ, WJ, O, O, O, B, VBlw, VBlw, VBlw, VPst,VMBlw,
VMBlw,VMAbv,CMBlw,CMBlw,CMBlw, O, O, O, O, IS, B,CMBlw,CMBlw, O,VMAbv,VMAbv,
VMAbv,CMAbv, B, B, O, VAbv, VAbv, O, O, O, B, B,VMBlw,VMBlw,VMBlw, B,
B, B, B, B,CMBlw,CMBlw,CMBlw,CMBlw, O, O,VMPst,VMAbv,VMPst, CS, CS, B,
B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O,
N, N, N, N, N, N, N, N, B, B, VAbv, B, B, VAbv, VAbv, B,
O, O, O, O, O, HN,VMAbv,VMAbv,VMPst, B, VPst, VPre, VPst, VBlw, VBlw, VAbv,
VAbv, VPst, VPst, H,CMBlw, O, O, O, VBlw, O,VMAbv,VMAbv,VMAbv, B, VPre, VBlw,
VAbv, VAbv, VBlw, VAbv, VAbv, IS,CMAbv, O, B, B, B, VPst, VPst, B, B, B,
B,CMBlw, VPre, VPst, VBlw, VBlw, H, B, R, R, O,FMBlw,CMBlw, VAbv, VBlw, O,
VPre,VMAbv,VMAbv, H,CMAbv,CMAbv, VAbv,CMBlw, VBlw, O, B, B, O,CMBlw,CMBlw, B,
VPst, VPst, VPst, O, O, VPre, O, O,VMAbv,VMAbv, B, VPst, VPre, VPst, VPst, VPst,
H,VMAbv,VMAbv,VMPst,CMBlw, B, O, O,FMAbv, B, CS, CS, O, O, VBlw, VPre,
VAbv, VPre, VPre, VPst, VPre,VMAbv,VMAbv,VMAbv, H,CMBlw,VMAbv,VMAbv,VMPst, H,CMBlw, O,
O, O, VPst,VMAbv,VMPst, H,VMPst, VAbv, VPre, VPst, VAbv, VAbv, H,CMBlw, O, MBlw,
MPre, MAbv, VBlw, VBlw, VPre, VAbv, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,VMAbv,VMPst, H,
CMBlw, O, VPst, VPre, O, VPre, VPre, O, O,VMAbv,VMAbv, VPst, IS, R, MPst, R,
MPst,CMBlw, O, O, VAbv, VAbv, VPst, VPst,VMPst,VMPst, H, B, O, O, VPre, O,
O, O, B, VAbv, VBlw, VBlw, VAbv, VAbv, VBlw, B, B, B, B,FMBlw, VBlw,VMAbv,
VMAbv,VMAbv,VMAbv,VMPst, R, MBlw, MBlw, MBlw, MBlw, GB, O, GB, O, IS, VAbv, VAbv,
VAbv, VPst, R, R, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw,
VMAbv,VMPst,CMAbv, IS, O, O, VBlw, VBlw, VBlw, O, O, O, SUB, SUB, VBlw, VPre,
VBlw, VAbv, VPst,VMAbv,VMAbv, O, VAbv, VAbv, VBlw, O, O, O, VAbv, O, VAbv, VAbv,
O, VAbv,VMAbv,VMAbv,CMBlw, VAbv, VBlw, IS, R, MBlw, VPst, VPst, VPst, O, VPst,VMAbv,
VMPst, IS, B, B, GB, VAbv, VBlw, VPre, VPst, O, H, H, H, H, H, H,
H, B, O, O, O,CMBlw, O, VBlw, VBlw, VBlw, O, O, O,VMBlw,VMBlw,VMBlw,
VMBlw, O, O,CMBlw,CMBlw, O, B, B,VMAbv, O,CMAbv,CMAbv,CMAbv,CMAbv,CMAbv,CMAbv,
CMAbv, B,
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
14, 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 4, 2, 2,
5, 6, 2, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 2, 2, 17,
18, 19, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 33, 2, 2, 2,
2, 34, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 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, 38, 39, 40, 41, 42, 43, 2, 44, 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, 45, 46, 2,
47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 49, 2, 2, 2,
2, 2, 2, 2, 2, 50, 51, 2, 52, 2, 2, 53, 2, 2, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 2, 64, 65, 2, 66, 67, 68, 69,
2, 70, 2, 71, 72, 73, 74, 2, 2, 75, 76, 77, 78, 2, 79, 2,
2, 80, 80, 80, 80, 80, 80, 80, 80, 81, 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, 82, 83, 2, 2, 2, 2, 2, 2, 2, 84,
85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 80, 80, 80, 86, 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, 87, 88, 2, 2, 2, 2, 2,
2, 2, 2, 89, 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, 90, 2, 2, 91, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 93, 93, 94, 95, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 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, 8, 9, 9, 9, 9, 0, 0, 0, 7, 10,
0, 2, 2, 2, 2, 11, 12, 0, 0, 9, 13, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 14, 15, 16, 17, 18, 19, 20, 14, 21, 22,
23, 10, 24, 25, 18, 2, 2, 2, 2, 2, 18, 0, 2, 2, 2, 2,
2, 0, 2, 2, 2, 2, 2, 2, 2, 26, 27, 28, 2, 2, 2, 7,
28, 7, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2,
2, 7, 7, 0, 2, 2, 0, 15, 16, 17, 18, 29, 30, 31, 30, 32,
0, 0, 0, 0, 33, 0, 0, 2, 28, 2, 0, 0, 0, 0, 0, 7,
34, 10, 13, 28, 2, 2, 7, 0, 28, 7, 2, 28, 7, 2, 0, 35,
16, 17, 29, 0, 25, 36, 25, 37, 0, 38, 0, 0, 0, 28, 2, 7,
7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0,
0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2,
2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22,
0, 0, 0, 0, 0, 28, 9, 39, 42, 10, 27, 28, 2, 2, 2, 7,
28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2,
28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0,
2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0,
2, 2, 2, 2, 2, 2, 0, 0, 21, 14, 45, 0, 46, 31, 46, 32,
0, 0, 0, 0, 33, 0, 0, 0, 0, 13, 27, 47, 2, 2, 2, 7,
2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 15,
20, 14, 21, 45, 20, 36, 20, 37, 0, 0, 0, 25, 29, 2, 7, 0,
0, 8, 27, 28, 2, 2, 2, 7, 2, 2, 2, 28, 2, 2, 0, 15,
43, 0, 0, 33, 45, 0, 0, 0, 7, 48, 49, 0, 0, 0, 0, 0,
0, 9, 27, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 50, 51,
21, 21, 17, 29, 46, 31, 46, 32, 52, 0, 0, 0, 33, 0, 0, 0,
28, 10, 27, 28, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 2, 2,
2, 2, 28, 2, 2, 2, 2, 28, 0, 2, 2, 2, 7, 0, 53, 0,
33, 21, 20, 29, 29, 16, 46, 46, 23, 0, 21, 0, 0, 0, 0, 0,
0, 2, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
0, 2, 2, 54, 54, 55, 0, 0, 16, 2, 2, 2, 2, 28, 2, 2,
2, 2, 2, 2, 2, 2, 2, 7, 0, 56, 19, 57, 20, 20, 18, 18,
44, 19, 9, 29, 9, 2, 2, 58, 59, 59, 59, 59, 59, 60, 59, 59,
59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61,
0, 0, 0, 0, 62, 0, 0, 0, 0, 2, 2, 2, 2, 2, 63, 43,
57, 64, 20, 20, 65, 66, 67, 68, 69, 2, 2, 2, 2, 2, 1, 0,
3, 2, 2, 2, 21, 18, 2, 2, 70, 69, 71, 72, 63, 71, 27, 27,
2, 50, 20, 51, 2, 2, 2, 2, 2, 2, 73, 74, 75, 27, 27, 76,
77, 2, 2, 2, 2, 2, 27, 43, 0, 2, 57, 78, 0, 0, 0, 0,
28, 2, 57, 45, 0, 0, 0, 0, 0, 2, 57, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 7, 2, 7, 57, 0, 0, 0, 0, 0,
0, 2, 2, 79, 43, 20, 57, 18, 46, 46, 46, 46, 13, 80, 81, 82,
83, 84, 85, 0, 0, 0, 0, 86, 0, 7, 0, 0, 28, 0, 87, 79,
88, 2, 2, 2, 2, 7, 0, 0, 0, 40, 40, 89, 90, 2, 2, 2,
2, 2, 2, 2, 2, 11, 7, 0, 0, 91, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 7, 20, 78, 43, 20, 92, 59, 0,
0, 93, 94, 93, 93, 95, 96, 0, 0, 2, 2, 2, 2, 2, 2, 2,
0, 2, 2, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
0, 2, 2, 2, 2, 27, 0, 0, 0, 2, 2, 2, 2, 2, 7, 0,
0, 2, 2, 2, 50, 97, 43, 0, 0, 2, 2, 98, 99, 100, 101, 59,
61, 102, 14, 43, 20, 57, 19, 78, 46, 46, 74, 9, 9, 9, 103, 44,
38, 9, 104, 72, 2, 2, 2, 2, 2, 2, 2, 105, 20, 18, 18, 20,
46, 46, 20, 106, 2, 2, 2, 7, 0, 0, 0, 0, 0, 0, 107, 108,
109, 109, 109, 0, 0, 0, 0, 0, 0, 104, 72, 2, 2, 2, 2, 2,
2, 58, 59, 57, 23, 20, 110, 59, 2, 2, 2, 2, 105, 20, 21, 43,
43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111,
100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28,
2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38,
0, 0, 0, 115, 116, 9, 3, 0, 0, 0, 0, 0, 0, 0, 117, 0,
0, 0, 0, 0, 0, 0, 4, 118, 119, 40, 40, 3, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119,
119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 5, 121, 0, 0, 0, 0,
0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
122, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2,
2, 2, 2, 123, 21, 21, 21, 21, 21, 21, 21, 124, 0, 0, 0, 0,
0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0,
50, 2, 2, 2, 20, 20, 125, 114, 0, 2, 2, 2, 126, 18, 57, 18,
111, 100, 127, 0, 0, 0, 0, 0, 0, 9, 128, 2, 2, 2, 2, 2,
2, 2, 129, 21, 20, 18, 46, 130, 131, 132, 0, 0, 0, 0, 0, 0,
0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57,
97, 74, 133, 134, 135, 0, 0, 0, 0, 2, 136, 2, 2, 2, 2, 137,
0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 138, 50, 51, 2, 2,
103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 139, 19,
23, 0, 0, 140, 141, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 142,
0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0,
4, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7,
0, 126, 18, 25, 29, 0, 0, 143, 144, 2, 2, 28, 2, 28, 2, 2,
2, 2, 2, 2, 0, 12, 35, 0, 145, 2, 2, 11, 35, 0, 28, 2,
2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2,
7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36,
0, 2, 2, 2, 114, 114, 114, 114, 114, 146, 2, 7, 0, 0, 0, 0,
0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2,
2, 28, 2, 7, 0, 28, 2, 0, 0, 147, 148, 149, 2, 2, 2, 2,
2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 132, 0, 0, 0,
0, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 2, 2, 2, 2,
2, 51, 50, 51, 0, 0, 0, 0, 151, 9, 72, 2, 2, 2, 2, 2,
2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0,
0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 126, 18, 20, 152,
20, 19, 153, 154, 2, 2, 2, 2, 2, 0, 0, 63, 155, 0, 0, 0,
0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
20, 106, 156, 0, 0, 157, 158, 29, 159, 28, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 160, 42, 0, 0, 0,
44, 2, 2, 2, 7, 7, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
28, 2, 2, 2, 2, 2, 2, 2, 8, 16, 17, 19, 20, 161, 29, 0,
0, 9, 9, 28, 2, 2, 2, 7, 28, 7, 2, 28, 2, 2, 56, 15,
21, 14, 21, 45, 30, 31, 30, 32, 0, 0, 0, 0, 33, 0, 0, 0,
2, 2, 21, 0, 9, 9, 9, 44, 0, 9, 9, 44, 0, 0, 0, 0,
0, 2, 2, 63, 23, 18, 18, 18, 20, 21, 124, 13, 15, 0, 0, 0,
0, 2, 2, 2, 2, 2, 0, 0, 162, 163, 0, 0, 0, 0, 0, 0,
0, 16, 17, 18, 18, 64, 97, 23, 159, 9, 164, 7, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 2, 63, 23, 18, 18, 0, 46, 46, 9,
165, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 18,
0, 21, 17, 18, 18, 19, 14, 80, 165, 36, 0, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 8, 166, 23, 18, 20, 20, 164, 7, 0, 0,
0, 2, 2, 2, 2, 2, 7, 41, 134, 21, 20, 18, 74, 19, 20, 0,
0, 2, 2, 2, 7, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 16,
17, 18, 19, 20, 103, 165, 35, 0, 0, 2, 2, 2, 7, 28, 0, 2,
2, 2, 2, 28, 7, 2, 2, 2, 2, 21, 21, 16, 30, 31, 10, 167,
168, 169, 170, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2,
2, 63, 23, 18, 18, 0, 20, 21, 27, 106, 0, 31, 0, 0, 0, 0,
0, 50, 18, 20, 20, 20, 138, 2, 2, 2, 171, 172, 9, 13, 173, 70,
174, 0, 0, 1, 145, 0, 0, 0, 0, 50, 18, 20, 14, 17, 18, 2,
2, 2, 2, 156, 156, 156, 175, 175, 175, 175, 175, 175, 13, 176, 0, 28,
0, 20, 18, 18, 29, 20, 20, 9, 165, 0, 59, 59, 59, 59, 59, 59,
59, 64, 19, 80, 44, 0, 0, 0, 0, 2, 2, 2, 7, 2, 28, 2,
2, 50, 20, 20, 29, 0, 36, 20, 25, 9, 158, 177, 173, 0, 0, 0,
0, 2, 2, 2, 28, 7, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21,
45, 20, 33, 80, 66, 0, 0, 0, 0, 2, 178, 64, 45, 0, 0, 0,
0, 179, 179, 179, 106, 7, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
0, 2, 2, 2, 2, 2, 7, 0, 56, 180, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
35, 0, 4, 119, 119, 119, 120, 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,
44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 42, 42, 42, 90, 0,
0, O, O, O, GB, B, B, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B,
O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,
B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre,
VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre,
O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,
CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv,
B, O, CS, CS, O, B, VAbv, VAbv, B, R, O, HVM, O, O, FBlw, O,
CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O, FBlw, O, B,
VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,
VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ,
CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B,
CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst,
FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,
VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw,
FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, CS,VMPst, O,FMAbv, ZWNJ, CGJ, WJ,
WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst,
VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw,
O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,
VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O,
HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, O,FMBlw,CMBlw, VAbv, VPre,
VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv,
VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw,
FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, H, H, O, VBlw,
};
static const uint16_t
hb_use_u16[2056] =
hb_use_u16[768] =
{
0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11,
0, 0, 0, 0, 9, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
13, 9, 9, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 17, 25,
26, 20, 21, 27, 28, 29, 30, 31, 32, 33, 21, 34, 35, 0, 17, 36,
37, 20, 21, 38, 23, 39, 17, 40, 41, 42, 43, 44, 45, 46, 30, 0,
47, 48, 21, 49, 50, 51, 17, 0, 52, 48, 21, 53, 50, 54, 17, 55,
56, 48, 9, 57, 58, 59, 17, 0, 60, 61, 9, 62, 63, 64, 30, 65,
66, 67, 9, 68, 69, 9, 70, 71, 72, 73, 74, 75, 76, 0, 0, 0,
9, 9, 77, 78, 79, 80, 81, 82, 83, 84, 0, 0, 0, 0, 0, 0,
9, 85, 9, 86, 9, 87, 88, 89, 9, 9, 9, 90, 91, 92, 2, 0,
93, 0, 9, 9, 9, 9, 9, 94, 95, 9, 96, 0, 0, 0, 0, 0,
97, 98, 99,100, 30, 9,101,102, 9, 9,103, 9,104,105, 0, 0,
9,106, 9, 9, 9,107,108,109, 2, 2, 0, 0, 0, 0, 0, 0,
110, 9, 9,111,112, 2,113,114,115, 9,116, 9, 9, 9,117,118,
9, 9,119,120,121, 0, 0, 0, 0, 0, 0, 0, 0,122,123,124,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,125,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11,
0, 0, 0, 0, 9, 12, 0, 0, 13, 9, 9, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 17, 25, 26, 20, 21, 27, 28, 29, 30, 31,
32, 33, 21, 34, 35, 0, 17, 36, 37, 20, 21, 38, 23, 39, 17, 40,
41, 42, 43, 44, 45, 46, 30, 0, 47, 48, 21, 49, 50, 51, 17, 0,
52, 48, 21, 53, 50, 54, 17, 55, 56, 48, 9, 57, 58, 59, 17, 0,
60, 61, 9, 62, 63, 64, 30, 65, 66, 67, 9, 68, 69, 9, 70, 71,
72, 73, 74, 75, 76, 0, 0, 0, 9, 9, 77, 78, 79, 80, 81, 82,
83, 84, 0, 0, 0, 0, 0, 0, 9, 85, 9, 86, 9, 87, 88, 89,
9, 9, 9, 90, 91, 92, 2, 0, 93, 0, 9, 9, 9, 9, 9, 94,
95, 9, 96, 0, 0, 0, 0, 0, 97, 98, 99,100, 30, 9,101,102,
9, 9,103, 9,104,105, 0, 0, 9,106, 9, 9, 9,107,108,109,
2, 2, 0, 0, 0, 0, 0, 0,110, 9, 9,111,112, 2,113,114,
115, 9,116, 9, 9, 9,117,118, 9, 9,119,120,121, 0, 0, 0,
0, 0, 0, 0, 0,122,123,124, 0, 0, 0, 0, 0, 0, 0,125,
126,127,128, 0, 0, 0,129,130,131, 0, 0, 0, 0, 0, 0,132,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,133, 0, 0, 0,
0, 0, 0, 9, 9, 9,134,135, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 9, 9, 9,134,135,
136, 9,137, 0, 9, 9, 9,138,139, 9, 9,140,141, 2,142,143,
9, 9,144, 9,145,146, 0, 0,147, 9, 9,148,149, 2,150, 98,
9, 9,151,152,153, 2, 9,154, 9, 9, 9,155,156, 0,157,158,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,159, 2,
160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,161,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,
0, 0, 0, 0, 9, 9,159, 2,160, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,161, 0, 0, 0, 0, 0, 0, 0,162,
0, 0, 0, 0, 0, 0, 0,163,163,164, 33,165, 0, 0, 0, 0,
166,167, 9,168, 94, 0, 0, 0, 0, 0, 0, 0, 69, 9,169, 0,
0, 0, 0, 0, 0, 0, 0, 0, 9,170,171, 0, 0, 0, 0, 0,
9, 9,172, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 9, 9,173,170, 0, 0, 0, 0,
0, 0, 0, 9,174,175, 0, 9,176, 0, 0,177,178, 0, 0, 0,
179, 9, 9,180,181,182,183,184,185, 9, 9,186,187, 0, 0, 0,
188, 9,189,190,191, 9, 9,192,185, 9, 9,193,194,105,195,102,
9, 33,196,197, 0, 0, 0, 0,198,199, 94, 9, 9,200,201, 2,
202, 20, 21,203,204,205,206,207, 0, 0, 0, 0, 0, 0, 0, 0,
9,170,171, 0, 0, 0, 0, 0, 9, 9,172, 2, 0, 0, 0, 0,
9, 9,173,170, 0, 0, 0, 0, 0, 0, 0, 9,174,175, 0, 9,
176, 0, 0,177,178, 0, 0, 0,179, 9, 9,180,181,182,183,184,
185, 9, 9,186,187, 0, 0, 0,188, 9,189,190,191, 9, 9,192,
185, 9, 9,193,194,105,195,102, 9, 33,196,197, 0, 0, 0, 0,
198,199, 94, 9, 9,200,201, 2,202, 20, 21,203,204,205,206,207,
9, 9, 9,208,209,210,211, 0,195, 9, 9,212,213, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 9, 9,214,215,216,217, 0, 0,
9, 9, 9,218,219, 2, 0, 0, 9, 9,220,221, 2, 0, 0, 0,
9,222,223,103,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 9,225,226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
227,228, 9,229,230, 2, 0, 0, 0, 0,231, 9, 9,232,233, 0,
234, 9, 9,235,236,237, 9, 9,238,239, 0, 0, 0, 0, 0, 0,
21, 9,214,240, 7, 9, 70, 18, 9,241, 73,242, 0, 0, 0, 0,
243, 9, 9,244,245, 2,246, 9,247,248, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,249,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 98,250, 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, 0, 0, 0,
9, 9, 9,251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 9,214,215,216,217, 0, 0, 9, 9, 9,218,219, 2, 0, 0,
9, 9,220,221, 2, 0, 0, 0, 9,222,223,103,224, 0, 0, 0,
9, 9,225,226, 0, 0, 0, 0,227,228, 9,229,230, 2, 0, 0,
0, 0,231, 9, 9,232,233, 0,234, 9, 9,235,236,237, 9, 9,
238,239, 0, 0, 0, 0, 0, 0, 21, 9,214,240, 7, 9, 70, 18,
9,241, 73,242, 0, 0, 0, 0,243, 9, 9,244,245, 2,246, 9,
247,248, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,249,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 98,250, 0, 0, 0, 0,
0, 0, 0, 0, 2, 0, 0, 0, 9, 9, 9,251, 0, 0, 0, 0,
9, 9, 9, 9,252,253,254,254,255,256, 0, 0, 0, 0,257, 0,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,258, 0, 0,
9, 9, 9, 9, 9, 9,105, 70, 94,259, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,260, 0, 0, 0, 0, 0, 0, 0, 0,
9, 9, 70,261,262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 9,263, 0, 9, 9,264, 2,
9, 9, 9, 9,265, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
9, 9, 9, 9, 9,258, 0, 0, 9, 9, 9, 9, 9, 9,105, 70,
94,259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,260,
9, 9, 70,261,262, 0, 0, 0, 0, 9,263, 0, 9, 9,264, 2,
9, 9, 9, 9,265, 2, 0, 0,129,129,129,129,129,129,129,129,
160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 0, 4, 0, 0, 5,
6, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0,
0, 0, 10, 2, 2, 2, 2, 2, 2, 2, 11, 12, 12, 0, 13, 14,
2, 2, 15, 0, 16, 2, 2, 2, 2, 2, 17, 18, 19, 20, 21, 22,
23, 24, 2, 2, 25, 10, 2, 2, 10, 2, 2, 2, 26, 27, 2, 28,
28, 2, 2, 2, 2, 2, 29, 2, 30, 10, 3, 18, 19, 31, 32, 33,
0, 34, 0, 35, 3, 0, 0, 36, 37, 27, 38, 39, 29, 40, 3, 41,
42, 43, 44, 45, 46, 0, 27, 30, 0, 10, 2, 2, 47, 48, 0, 0,
37, 27, 2, 35, 35, 2, 2, 2, 29, 27, 3, 18, 19, 49, 50, 51,
0, 0, 52, 53, 54, 27, 2, 28, 29, 27, 3, 55, 0, 56, 0, 35,
57, 0, 0, 0, 58, 27, 38, 10, 29, 3, 40, 29, 39, 9, 38, 10,
2, 2, 3, 59, 60, 61, 62, 33, 0, 34, 0, 0, 63, 64, 2, 29,
29, 2, 2, 2, 2, 2, 3, 65, 21, 66, 67, 45, 0, 68, 38, 0,
69, 27, 2, 29, 2, 27, 3, 55, 0, 70, 0, 13, 71, 0, 0, 0,
72, 2, 2, 29, 2, 2, 73, 74, 75, 76, 62, 77, 0, 34, 0, 39,
54, 27, 2, 2, 2, 38, 10, 2, 35, 2, 2, 57, 2, 38, 78, 34,
79, 80, 81, 82, 59, 0, 0, 0, 3, 38, 0, 0, 0, 0, 83, 0,
2, 84, 85, 86, 2, 2, 27, 2, 2, 2, 2, 9, 87, 88, 89, 90,
91, 92, 2, 93, 94, 94, 95, 94, 94, 94, 94, 94, 94, 94, 94, 96,
0, 97, 0, 0, 2, 2, 98, 99,100,101,102,103, 2, 2,104,105,
2,106,107,108,109,110,111,112,113,114, 2, 2,115,116,117,118,
2, 2,119,120,121,122, 0, 39,121,123, 0, 0,121, 0, 0, 0,
2, 2, 2, 29,124, 0, 0, 0, 2,125,126,127,128,129,130,131,
132, 0, 0,133, 9, 39,134,135, 2, 2, 9, 0,136,137, 2, 2,
2, 2,138, 0,139, 2, 2, 2, 2, 2, 2, 38,140,141,142, 0,
143,144,145, 0, 2, 2, 2, 3, 2, 9, 0, 0, 2, 2, 2, 0,
2, 2,146, 0, 2, 2, 38, 0, 2, 73,147, 0, 2,148,149,150,
151,141,152,153,154, 12,155,156,157,158, 2, 2, 2,159,160,161,
162,163, 2, 9, 0, 0,164,165,166, 0, 0, 0,167, 2, 2, 2,
93,168,169,170, 2,171,172,173,174, 0, 0, 0, 2,175,176,177,
178,179, 0, 0, 2, 2, 3, 27,180,181,182,181,183,181,184, 46,
0,185,186, 0, 0, 0,187, 0, 0, 0,188,189,136, 4, 0, 0,
0, 0,190,191,192,192,192,192, 0,193, 0, 0, 6,193, 0, 0,
194, 0, 0, 0, 0, 0, 0, 9, 2, 2, 0, 39, 0, 0, 0,195,
196,197, 11, 2, 98,198, 0,199, 2, 0, 0, 0,112, 2, 2, 2,
2,200,201,201,201,202, 0, 0, 12, 12, 12, 12,203, 0, 0,204,
2,205,206,207, 2,208,209,210,211, 0, 0, 0,212, 2, 2, 2,
213, 79,127,214,215, 0, 0, 0, 2,216, 2, 2, 2, 2,217,218,
219,220, 0, 0,221, 2, 2,222, 27,223,224,225,226,227,114,228,
229, 0, 0, 0, 2, 2,230,231, 0,232, 0, 0, 98,233,234,235,
236,236,236,236, 0, 0, 0,188,192,192,237, 0, 2, 2, 38, 2,
38, 35, 2, 2, 35, 2, 35, 9,238, 68, 0,239, 2, 27, 27, 2,
2, 3,240,241, 2,242, 39, 2, 3, 0, 0, 0, 0, 0, 27, 38,
2,243, 0, 0, 2, 2,244,245, 2,246,181,181,247, 9, 0, 0,
248,249, 0, 0, 29, 38, 2, 2, 27, 9, 27, 0,250,251, 2, 2,
2, 2,252,160,253,254, 0, 0,255,256,256,256,256,257, 2, 2,
258,259, 0,260,261, 2, 2, 2,262,263,264, 0,265, 0, 0, 0,
266, 2, 2, 2, 2,208,253,267,268,269, 2, 2, 0,270, 0, 0,
271, 0, 0, 0, 98,272,160,252,273, 0,274,275, 27, 2, 2, 2,
2, 2, 2, 75,252,276, 0, 58, 2, 38, 29, 35, 2, 2, 2, 35,
2, 2, 2, 11,262, 20,277, 0, 12, 27, 2, 28, 29, 27,278,279,
21,280, 32, 33, 0, 34, 0, 10,106,281, 12,194, 12,194, 0, 0,
2,282,160,253,283,284, 0, 0, 2, 2, 3,285,286, 0, 0, 0,
262,160,287,288,289, 9, 0, 0, 2, 2, 2, 98,272, 83,128,290,
291, 0, 0, 0, 0, 0, 2, 83, 75,160,263,292,245, 0, 0, 0,
2, 2, 11,293,253,294, 9, 0, 2, 2, 38,295, 79,296, 20, 0,
2, 38, 0, 0, 2, 2, 2,262,297,298,299, 0, 2, 38, 57, 2,
2, 40, 2, 2,201,300,301,302,303, 0, 0, 0, 2, 2, 10, 2,
282,160,304,305,306,307, 0, 0,308,252,309, 2,310,311,312,313,
0,314, 0, 0,308,315, 19, 2, 2,316,317,318,318,319,320, 57,
89,321,252,290,322, 94, 94, 94,323,324, 0, 0, 2, 38, 35, 2,
113,325,326,327,328,329, 0, 0, 2, 35, 29, 2, 2, 2,106,330,
50,331, 0, 0,332,333, 0, 0,334,335, 9, 0, 12,180, 0, 0,
2, 2, 38,336,337,160,160,160,160,160,160,160,160,160, 0,338,
339, 0, 0, 0, 0, 9, 0, 0, 2, 3, 0, 0, 2, 2, 3,340,
188,192,191, 0, 12,266, 2, 3, 2, 2, 3, 10, 2, 2, 2,341,
2, 2, 2, 12, 2,342,343, 0,
};
static inline unsigned
hb_use_b4 (const uint8_t* a, unsigned i)
{
return (a[i>>1]>>((i&1u)<<2))&15u;
}
static inline uint_fast8_t
hb_use_get_category (unsigned u)
{
return u<921600u?hb_use_u8[466+(((hb_use_u16[992+(((hb_use_u16[((hb_use_u8[226+(((hb_use_u8[u>>2>>2>>4>>4])<<4)+((u>>2>>2>>4)&15u))])<<4)+((u>>2>>2)&15u)])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:O;
return u<921600u?hb_use_u8[2721+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
}
#undef B
@ -392,5 +393,26 @@ hb_use_get_category (unsigned u)
#undef VMPre
#ifdef HB_USE_TABLE_MAIN
int main (int argc, char **argv)
{
if (argc != 2)
{
for (unsigned u = 0; u < 0x10FFFFu; u++)
printf ("U+%04X %d\n", u, hb_use_get_category (u));
return 0;
}
hb_codepoint_t u;
sscanf (argv[1], "%x", &u);
printf ("%d\n", hb_use_get_category (u));
return 0;
}
#endif
#endif /* HB_OT_SHAPER_USE_TABLE_HH */
/* == End of generated table == */

View File

@ -29,10 +29,9 @@
#include "hb-open-type.hh"
#include "hb-map.hh"
#include "hb-priority-queue.hh"
#include "hb-serialize.hh"
#include "hb-vector.hh"
#include "graph/graph.hh"
#include "graph/gsubgpos-graph.hh"
#include "graph/serialize.hh"
using graph::graph_t;
@ -42,6 +41,143 @@ using graph::graph_t;
* docs/repacker.md
*/
struct lookup_size_t
{
unsigned lookup_index;
size_t size;
unsigned num_subtables;
static int cmp (const void* a, const void* b)
{
return cmp ((const lookup_size_t*) a,
(const lookup_size_t*) b);
}
static int cmp (const lookup_size_t* a, const lookup_size_t* b)
{
double subtables_per_byte_a = (double) a->num_subtables / (double) a->size;
double subtables_per_byte_b = (double) b->num_subtables / (double) b->size;
if (subtables_per_byte_a == subtables_per_byte_b) {
return b->lookup_index - a->lookup_index;
}
double cmp = subtables_per_byte_b - subtables_per_byte_a;
if (cmp < 0) return -1;
if (cmp > 0) return 1;
return 0;
}
};
static inline
bool _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
// that subtable type).
//
// TODO(grieger): de-dup newly added nodes as necessary. Probably just want a full de-dup
// pass after this processing is done. Not super necessary as splits are
// only done where overflow is likely, so de-dup probably will get undone
// later anyways.
for (unsigned lookup_index : ext_context.lookups.keys ())
{
graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
if (!lookup->split_subtables_if_needed (ext_context, lookup_index))
return false;
}
return true;
}
/*
* Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
* to extension lookups.
*/
static inline
bool _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.
// 2. Select up to 64k of those to remain as non-extension (greedy, highest subtables per byte first)
// 3. Promote the rest.
//
// Advanced Algorithm (v2, not implemented):
// 1. Perform connected component analysis using lookups as roots.
// 2. Compute size of each connected component.
// 3. Select up to 64k worth of connected components to remain as non-extensions.
// (greedy, highest subtables per byte first)
// 4. Promote the rest.
// TODO(garretrieger): support extension demotion, then consider all lookups. Requires advanced algo.
// 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;
hb_vector_t<lookup_size_t> lookup_sizes;
lookup_sizes.alloc (ext_context.lookups.get_population ());
for (unsigned lookup_index : ext_context.lookups.keys ())
{
const graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
hb_set_t visited;
lookup_sizes.push (lookup_size_t {
lookup_index,
ext_context.graph.find_subgraph_size (lookup_index, visited),
lookup->number_of_subtables (),
});
}
lookup_sizes.qsort ();
size_t lookup_list_size = ext_context.graph.vertices_[ext_context.lookup_list_index].table_size ();
size_t l2_l3_size = lookup_list_size; // Lookup List + Lookups
size_t l3_l4_size = 0; // Lookups + SubTables
size_t l4_plus_size = 0; // SubTables + their descendants
// Start by assuming all lookups are using extension subtables, this size will be removed later
// if it's decided to not make a lookup extension.
for (auto p : lookup_sizes)
{
unsigned subtables_size = p.num_subtables * 8;
l3_l4_size += subtables_size;
l4_plus_size += subtables_size;
}
bool layers_full = false;
for (auto p : lookup_sizes)
{
const graph::Lookup* lookup = ext_context.lookups.get(p.lookup_index);
if (lookup->is_extension (ext_context.table_tag))
// already an extension so size is counted by the loop above.
continue;
if (!layers_full)
{
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 remaining_size = p.size - subtables_size - lookup_size;
l2_l3_size += lookup_size;
l3_l4_size += lookup_size + subtables_size;
l3_l4_size -= p.num_subtables * 8;
l4_plus_size += subtables_size + remaining_size;
if (l2_l3_size < (1 << 16)
&& l3_l4_size < (1 << 16)
&& l4_plus_size < (1 << 16)) continue; // this lookup fits within all layers groups
layers_full = true;
}
if (!ext_context.lookups.get(p.lookup_index)->make_extension (ext_context, p.lookup_index))
return false;
}
return true;
}
static inline
bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& overflows,
graph_t& sorted_graph)
@ -157,7 +293,8 @@ template<typename T>
inline hb_blob_t*
hb_resolve_overflows (const T& packed,
hb_tag_t table_tag,
unsigned max_rounds = 20) {
unsigned max_rounds = 20,
bool recalculate_extensions = false) {
graph_t sorted_graph (packed);
sorted_graph.sort_shortest_distance ();
@ -167,13 +304,31 @@ hb_resolve_overflows (const T& packed,
return graph::serialize (sorted_graph);
}
graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
if ((table_tag == HB_OT_TAG_GPOS
|| table_tag == HB_OT_TAG_GSUB)
&& will_overflow)
{
if (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 nullptr;
}
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 nullptr;
}
}
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 ();
}
unsigned round = 0;

View File

@ -145,7 +145,7 @@ hb_set_set_user_data (hb_set_t *set,
* Since: 0.9.2
**/
void *
hb_set_get_user_data (hb_set_t *set,
hb_set_get_user_data (const hb_set_t *set,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (set, key);

View File

@ -77,7 +77,7 @@ hb_set_set_user_data (hb_set_t *set,
hb_bool_t replace);
HB_EXTERN void *
hb_set_get_user_data (hb_set_t *set,
hb_set_get_user_data (const hb_set_t *set,
hb_user_data_key_t *key);

View File

@ -358,7 +358,7 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
* Since: 0.9.7
**/
void *
hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (shape_plan, key);

View File

@ -102,7 +102,7 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
hb_bool_t replace);
HB_EXTERN void *
hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key);

View File

@ -25,18 +25,24 @@
#include "hb-repacker.hh"
#ifdef HB_EXPERIMENTAL_API
/**
* hb_subset_repack_or_fail:
* @table_tag: tag of the table being packed, needed to allow table specific optimizations.
* @hb_objects: raw array of struct hb_object_t, which provides
* object graph info
* @num_hb_objs: number of hb_object_t in the hb_objects array.
*
* Given the input object graph info, repack a table to eliminate
* offset overflows. A nullptr is returned if the repacking attempt fails.
* Table specific optimizations (eg. extension promotion in GSUB/GPOS) may be performed.
* Passing HB_TAG_NONE will disable table specific optimizations.
*
* Since: EXPERIMENTAL
**/
hb_blob_t* hb_subset_repack_or_fail (hb_object_t* hb_objects, unsigned num_hb_objs)
hb_blob_t* hb_subset_repack_or_fail (hb_tag_t table_tag,
hb_object_t* hb_objects,
unsigned num_hb_objs)
{
hb_vector_t<const hb_object_t *> packed;
packed.alloc (num_hb_objs + 1);
@ -44,6 +50,9 @@ hb_blob_t* hb_subset_repack_or_fail (hb_object_t* hb_objects, unsigned num_hb_ob
for (unsigned i = 0 ; i < num_hb_objs ; i++)
packed.push (&(hb_objects[i]));
return hb_resolve_overflows (packed, HB_OT_TAG_GSUB);
return hb_resolve_overflows (packed,
table_tag,
20,
true);
}
#endif

View File

@ -70,7 +70,8 @@ struct hb_object_t
typedef struct hb_object_t hb_object_t;
HB_EXTERN hb_blob_t*
hb_subset_repack_or_fail (hb_object_t* hb_objects,
hb_subset_repack_or_fail (hb_tag_t table_tag,
hb_object_t* hb_objects,
unsigned num_hb_objs);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -24,42 +24,37 @@
#include "hb-unicode.hh"
static const uint8_t
_hb_emoji_u8[544] =
_hb_emoji_u8[464] =
{
16, 17, 17, 17, 50, 20, 21, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,118,152,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 3, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 6, 0, 7, 8,
0, 0, 0, 9, 0, 0, 10, 11, 12, 13, 14, 13, 15, 16, 17, 0,
0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0,
21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0,
13, 13, 13, 13, 23, 24, 25, 26, 27, 28, 13, 13, 13, 13, 13, 29,
13, 13, 13, 13, 30, 31, 13, 13, 13, 32, 13, 13, 0, 33, 0, 34,
35, 36, 37, 13, 38, 39, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 30,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0,
0, 0, 0, 0, 0, 0, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 0, 0, 2, 0, 0,240, 3, 0, 6, 0, 0,
0, 0, 0, 12, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0,128, 0, 0, 0,254, 15, 7, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0, 0, 0, 0,120,
191,255,247,255,255,255,255,255,255,255,255,255,255,255,255,255,
63, 0,255,255,255,255,255,255, 63,255, 87, 32, 2, 1, 24, 0,
144, 80,184, 0,248, 0, 0, 0, 0, 0,224, 0, 2, 0, 1,128,
0, 0, 0, 0, 0, 0, 48, 0,224, 0, 0, 24, 0, 0, 0, 0,
0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32,
0, 0,128, 2, 0, 0, 0, 0, 0,224, 0, 0, 0,128, 0, 0,
0, 0, 0, 0, 0,240, 3,192, 0, 64,254, 7, 0,224,255,255,
255,255,255,255, 63, 0, 0, 0,254,255, 0, 4, 0,128,252,247,
0,254,255,255,255,255,255,255,255,255,255,255,255,255,255, 7,
255,255,255,255,255,255,255, 63,192,255,255,255,255,255,255,255,
255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240,255,
0, 0,224,255,255,255,255,255, 0,240, 0, 0, 0, 0, 0, 0,
0,255, 0,252, 0, 0, 0, 0, 0,255, 0, 0, 0,192,255,255,
0,240,255,255,255,255,255,247,191,255,255,255,255,255,255,255,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 0, 3, 4, 0, 0, 5, 6, 0, 7, 0, 8, 9, 10, 11, 12,
0, 0, 13, 0, 0, 0, 14, 0, 15, 0, 0, 0, 0, 16, 0, 0,
17, 17, 18, 19, 20, 17, 17, 21, 17, 17, 22, 17, 23, 17, 24, 25,
26, 27, 28, 17, 17, 17, 0, 0, 17, 17, 17, 17, 17, 17, 17, 29,
0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 4, 0, 0,
5, 6, 0, 0, 7, 8, 0, 0, 8, 0, 9, 10, 0, 0, 11, 0,
0, 12, 13, 14, 15, 16, 16, 16, 17, 16, 16, 16, 18, 19, 20, 21,
22, 23, 0, 0, 0, 24, 0, 0, 25, 0, 26, 0, 0, 27, 0, 0,
28, 0, 0, 0, 16, 16, 16, 16, 29, 9, 0, 30, 31, 32, 16, 33,
34, 35, 36, 16, 16, 16, 16, 37, 16, 38, 39, 16, 16, 16, 40, 0,
0, 0, 0, 41, 0, 0, 42, 16, 43, 0, 44, 0, 45, 46, 16, 16,
47, 48, 49, 16, 16, 16, 16, 38, 0, 0, 0, 0, 0, 66, 0, 0,
0, 0, 0, 16, 0, 2, 0, 0, 4, 0, 0, 2, 0, 0,240, 3,
0, 6, 0, 0, 0, 0, 0, 12, 0, 1, 0, 0, 0,128, 0, 0,
0,254, 15, 7, 4, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0,
0, 0, 0,120,191,255,247,255,255,255,255,255, 63, 0,255,255,
63,255, 87, 32, 2, 1, 24, 0,144, 80,184, 0,248, 0, 0, 0,
0, 0,224, 0, 2, 0, 1,128, 0, 0, 48, 0,224, 0, 0, 24,
0, 0, 33, 0, 0, 0, 1, 32, 0, 0,128, 2, 0,224, 0, 0,
0,240, 3,192, 0, 64,254, 7, 0,224,255,255, 63, 0, 0, 0,
254,255, 0, 4, 0,128,252,247, 0,254,255,255,255,255,255, 7,
255,255,255, 63,192,255,255,255,255,255, 0, 0, 0, 0,240,255,
0, 0,224,255, 0,240, 0, 0, 0,255, 0,252, 0,255, 0, 0,
0,192,255,255, 0,240,255,255,255,255,255,247,191,255,255,255,
};
static inline unsigned
@ -75,7 +70,7 @@ _hb_emoji_b1 (const uint8_t* a, unsigned i)
static inline uint_fast8_t
_hb_emoji_is_Extended_Pictographic (unsigned u)
{
return u<131070u?_hb_emoji_b1(224+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
return u<131070u?_hb_emoji_b1(264+_hb_emoji_u8,((_hb_emoji_u8[144+(((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>5>>2>>3))<<3)+((u>>5>>2)&7u))])<<2)+((u>>5)&3u))])<<5)+((u)&31u)):0;
}

View File

@ -308,7 +308,7 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
* Since: 0.9.2
**/
void *
hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (ufuncs, key);

View File

@ -317,7 +317,7 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
HB_EXTERN void *
hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key);

View File

@ -47,20 +47,20 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
#define HB_VERSION_MINOR 0
#define HB_VERSION_MINOR 1
/**
* HB_VERSION_MICRO:
*
* The micro component of the library version available at compile-time.
*/
#define HB_VERSION_MICRO 1
#define HB_VERSION_MICRO 0
/**
* HB_VERSION_STRING:
*
* A string literal containing the library version available at compile-time.
*/
#define HB_VERSION_STRING "5.0.1"
#define HB_VERSION_STRING "5.1.0"
/**
* HB_VERSION_ATLEAST: