Merge pull request #103491 from bruvzg/hb1040

Update HarfBuzz to 10.4.0
This commit is contained in:
Thaddeus Crews 2025-03-10 21:05:48 -05:00
commit 3f759f488d
No known key found for this signature in database
GPG key ID: 62181B86FE9E5D84
115 changed files with 5576 additions and 2815 deletions

View file

@ -122,7 +122,7 @@ if env["builtin_harfbuzz"]:
"src/hb-subset-instancer-iup.cc",
"src/hb-subset-instancer-solver.cc",
"src/hb-subset-plan.cc",
"src/hb-subset-repacker.cc",
"src/hb-subset-serialize.cc",
"src/hb-subset.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",

View file

@ -362,7 +362,7 @@ thirdparty_harfbuzz_sources = [
"src/hb-subset-instancer-iup.cc",
"src/hb-subset-instancer-solver.cc",
"src/hb-subset-plan.cc",
"src/hb-subset-repacker.cc",
"src/hb-subset-serialize.cc",
"src/hb-subset.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",

View file

@ -406,7 +406,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 10.1.0 (9ef44a2d67ac870c1f7f671f6dc98d08a2579865, 2024)
- Version: 10.4.0 (3ef8709829a5884517ad91a97b32b9435b2f20d1, 2025)
- License: MIT
Files extracted from upstream source:

View file

@ -941,10 +941,12 @@ struct CBDT
}
}
bool has_data () const { return cbdt.get_length (); }
bool has_data () const { return cbdt->version.major; }
bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
{
if (!has_data ()) return false;
hb_glyph_extents_t extents;
hb_glyph_extents_t pixel_extents;
hb_blob_t *blob = reference_png (font, glyph);

View file

@ -29,11 +29,14 @@
#define OT_COLOR_COLR_COLR_HH
#include "../../../hb.hh"
#include "../../../hb-decycler.hh"
#include "../../../hb-open-type.hh"
#include "../../../hb-ot-var-common.hh"
#include "../../../hb-paint.hh"
#include "../../../hb-paint-extents.hh"
#include "../CPAL/CPAL.hh"
/*
* COLR -- Color
* https://docs.microsoft.com/en-us/typography/opentype/spec/colr
@ -66,11 +69,11 @@ public:
hb_paint_funcs_t *funcs;
void *data;
hb_font_t *font;
unsigned int palette_index;
hb_array_t<const BGRAColor> palette;
hb_color_t foreground;
ItemVarStoreInstancer &instancer;
hb_map_t current_glyphs;
hb_map_t current_layers;
hb_decycler_t glyphs_decycler;
hb_decycler_t layers_decycler;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_MAX_GRAPH_EDGE_COUNT;
@ -85,7 +88,11 @@ public:
funcs (funcs_),
data (data_),
font (font_),
palette_index (palette_),
palette (
#ifndef HB_NO_COLOR
font->face->table.CPAL->get_palette_colors (palette_)
#endif
),
foreground (foreground_),
instancer (instancer_)
{ }
@ -99,12 +106,7 @@ public:
if (color_index != 0xffff)
{
if (!funcs->custom_palette_color (data, color_index, &color))
{
unsigned int clen = 1;
hb_face_t *face = hb_font_get_face (font);
hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color);
}
color = palette[color_index];
*is_foreground = false;
}
@ -1003,7 +1005,7 @@ struct PaintTransform
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
(this+transform).paint_glyph (c);
(this+transform).paint_glyph (c); // This does a push_transform()
c->recurse (this+src);
c->funcs->pop_transform (c->data);
}
@ -2134,12 +2136,16 @@ struct COLR
const ItemVariationStore &get_var_store () const
{ return colr->get_var_store (); }
const ItemVariationStore *get_var_store_ptr () const
{ return colr->get_var_store_ptr (); }
bool has_delta_set_index_map () const
{ return colr->has_delta_set_index_map (); }
const DeltaSetIndexMap &get_delta_set_index_map () const
{ return colr->get_delta_set_index_map (); }
const DeltaSetIndexMap *get_delta_set_index_map_ptr () const
{ return colr->get_delta_set_index_map_ptr (); }
private:
hb_blob_ptr_t<COLR> colr;
@ -2232,9 +2238,13 @@ struct COLR
const DeltaSetIndexMap &get_delta_set_index_map () const
{ return has_delta_set_index_map () && hb_barrier () ? this+varIdxMap : Null (DeltaSetIndexMap); }
const DeltaSetIndexMap *get_delta_set_index_map_ptr () const
{ return has_delta_set_index_map () && hb_barrier () ? &(this+varIdxMap) : nullptr; }
const ItemVariationStore &get_var_store () const
{ return has_var_store () && hb_barrier () ? this+varStore : Null (ItemVariationStore); }
const ItemVariationStore *get_var_store_ptr () const
{ return has_var_store () && hb_barrier () ? &(this+varStore) : nullptr; }
const ClipList &get_clip_list () const
{ return has_clip_list () && hb_barrier () ? this+clipList : Null (ClipList); }
@ -2482,9 +2492,9 @@ struct COLR
* after instancing */
if (!subset_varstore (c, colr_prime)) return_trace (false);
ItemVarStoreInstancer instancer (&(get_var_store ()),
&(get_delta_set_index_map ()),
c->plan->normalized_coords.as_array ());
ItemVarStoreInstancer instancer (get_var_store_ptr (),
get_delta_set_index_map_ptr (),
c->plan->normalized_coords.as_array ());
if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
return_trace (false);
@ -2513,8 +2523,8 @@ struct COLR
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
ItemVarStoreInstancer instancer (&(get_var_store ()),
&(get_delta_set_index_map ()),
ItemVarStoreInstancer instancer (get_var_store_ptr (),
get_delta_set_index_map_ptr (),
hb_array (font->coords, font->num_coords));
if (get_clip (glyph, extents, instancer))
@ -2575,11 +2585,13 @@ struct COLR
bool
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
{
ItemVarStoreInstancer instancer (&(get_var_store ()),
&(get_delta_set_index_map ()),
hb_array (font->coords, font->num_coords));
ItemVarStoreInstancer instancer (get_var_store_ptr (),
get_delta_set_index_map_ptr (),
hb_array (font->coords, font->num_coords));
hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
c.current_glyphs.add (glyph);
hb_decycler_node_t node (c.glyphs_decycler);
node.visit (glyph);
if (version >= 1)
{
@ -2695,19 +2707,16 @@ void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
hb_decycler_node_t node (c->layers_decycler);
for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
{
if (unlikely (c->current_layers.has (i)))
continue;
c->current_layers.add (i);
if (unlikely (!node.visit (i)))
return;
const Paint &paint = paint_offset_lists.get_paint (i);
c->funcs->push_group (c->data);
c->recurse (paint);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
c->current_layers.del (i);
}
}
@ -2715,16 +2724,14 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
if (unlikely (c->current_glyphs.has (gid)))
hb_decycler_node_t node (c->glyphs_decycler);
if (unlikely (!node.visit (gid)))
return;
c->current_glyphs.add (gid);
c->funcs->push_inverse_root_transform (c->data, c->font);
if (c->funcs->color_glyph (c->data, gid, c->font))
{
c->funcs->pop_transform (c->data);
c->current_glyphs.del (gid);
return;
}
c->funcs->pop_transform (c->data);
@ -2747,8 +2754,6 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
if (has_clip_box)
c->funcs->pop_clip (c->data);
c->current_glyphs.del (gid);
}
} /* namespace OT */

View file

@ -187,6 +187,14 @@ struct CPAL
hb_ot_name_id_t get_color_name_id (unsigned int color_index) const
{ return v1 ().get_color_name_id (this, color_index, numColors); }
hb_array_t<const BGRAColor> get_palette_colors (unsigned int palette_index) const
{
if (unlikely (palette_index >= numPalettes))
return hb_array_t<const BGRAColor> ();
unsigned int start_index = colorRecordIndicesZ[palette_index];
hb_array_t<const BGRAColor> all_colors ((this+colorRecordsZ).arrayZ, numColorRecords);
return all_colors.sub_array (start_index, numColors);
}
unsigned int get_palette_colors (unsigned int palette_index,
unsigned int start_offset,
unsigned int *color_count, /* IN/OUT. May be NULL. */

View file

@ -96,6 +96,15 @@ struct Coverage
default:return NOT_COVERED;
}
}
unsigned int get_coverage (hb_codepoint_t glyph_id,
hb_ot_lookup_cache_t *cache) const
{
unsigned coverage;
if (cache && cache->get (glyph_id, &coverage)) return coverage;
coverage = get_coverage (glyph_id);
if (cache) cache->set (glyph_id, coverage);
return coverage;
}
unsigned get_population () const
{
@ -201,6 +210,19 @@ struct Coverage
}
}
unsigned cost () const
{
switch (u.format) {
case 1: hb_barrier (); return u.format1.cost ();
case 2: hb_barrier (); return u.format2.cost ();
#ifndef HB_NO_BEYOND_64K
case 3: hb_barrier (); return u.format3.cost ();
case 4: hb_barrier (); return u.format4.cost ();
#endif
default:return 0u;
}
}
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename set_t>

View file

@ -103,6 +103,8 @@ struct CoverageFormat1_3
intersect_glyphs << glyphArray[i];
}
unsigned cost () const { return hb_bit_storage ((unsigned) glyphArray.len); /* bsearch cost */ }
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{ return glyphs->add_sorted_array (glyphArray.as_array ()); }

View file

@ -157,6 +157,8 @@ struct CoverageFormat2_4
}
}
unsigned cost () const { return hb_bit_storage ((unsigned) rangeRecord.len); /* bsearch cost */ }
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{

View file

@ -103,12 +103,50 @@ struct PairPosFormat1_3
const Coverage &get_coverage () const { return this+coverage; }
bool apply (hb_ot_apply_context_t *c) const
unsigned cache_cost () const
{
return (this+coverage).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
switch (op)
{
case hb_ot_lookup_cache_op_t::CREATE:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
if (likely (cache))
cache->clear ();
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
hb_free (cache);
return nullptr;
}
}
return nullptr;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
#endif
if (index == NOT_COVERED) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset_fast (buffer->idx);
@ -156,7 +194,7 @@ struct PairPosFormat1_3
strip = true;
newFormats = compute_effective_value_formats (glyphset, strip, true);
}
out->valueFormat[0] = newFormats.first;
out->valueFormat[1] = newFormats.second;

View file

@ -123,12 +123,61 @@ struct PairPosFormat2_4 : ValueBase
const Coverage &get_coverage () const { return this+coverage; }
bool apply (hb_ot_apply_context_t *c) const
struct pair_pos_cache_t
{
hb_ot_lookup_cache_t coverage;
hb_ot_lookup_cache_t first;
hb_ot_lookup_cache_t second;
};
unsigned cache_cost () const
{
return (this+coverage).cost () + (this+classDef1).cost () + (this+classDef2).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
switch (op)
{
case hb_ot_lookup_cache_op_t::CREATE:
{
pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t));
if (likely (cache))
{
cache->coverage.clear ();
cache->first.clear ();
cache->second.clear ();
}
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
pair_pos_cache_t *cache = (pair_pos_cache_t *) p;
hb_free (cache);
return nullptr;
}
}
return nullptr;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
#endif
if (index == NOT_COVERED) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset_fast (buffer->idx);
@ -139,8 +188,13 @@ struct PairPosFormat2_4 : ValueBase
return_trace (false);
}
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint, cache ? &cache->first : nullptr);
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint, cache ? &cache->second : nullptr);
#else
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
#endif
if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
{
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);

View file

@ -67,7 +67,7 @@ struct SinglePosFormat1 : ValueBase
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{

View file

@ -66,7 +66,7 @@ struct SinglePosFormat2 : ValueBase
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
if (unlikely (index >= valueCount)) return_trace (false);

View file

@ -74,7 +74,7 @@ struct AlternateSubstFormat1_2
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
return_trace ((this+alternateSet[index]).apply (c));
}

View file

@ -78,12 +78,49 @@ struct LigatureSubstFormat1_2
return lig_set.would_apply (c);
}
bool apply (hb_ot_apply_context_t *c) const
unsigned cache_cost () const
{
return (this+coverage).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
switch (op)
{
case hb_ot_lookup_cache_op_t::CREATE:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
if (likely (cache))
cache->clear ();
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
hb_free (cache);
return nullptr;
}
}
return nullptr;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
#endif
if (index == NOT_COVERED) return_trace (false);
const auto &lig_set = this+ligatureSet[index];
return_trace (lig_set.apply (c));

View file

@ -66,7 +66,7 @@ struct MultipleSubstFormat1_2
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
return_trace ((this+sequence[index]).apply (c));
}

View file

@ -112,7 +112,7 @@ struct ReverseChainSingleSubstFormat1
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
return_trace (false); /* No chaining to this type */

View file

@ -128,7 +128,7 @@ struct SingleSubstFormat1_3
TRACE_APPLY (this);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();

View file

@ -104,7 +104,7 @@ struct SingleSubstFormat2_4
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
if (unlikely (index >= substitute.len)) return_trace (false);

View file

@ -29,6 +29,9 @@
#ifndef OT_LAYOUT_TYPES_HH
#define OT_LAYOUT_TYPES_HH
using hb_ot_lookup_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_ot_lookup_cache_t) == 256, "");
namespace OT {
namespace Layout {

View file

@ -3,7 +3,6 @@
#ifndef HB_NO_VAR_COMPOSITES
#include "../../../hb-draw.hh"
#include "../../../hb-geometry.hh"
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-ot-layout-gdef-table.hh"
@ -133,18 +132,19 @@ VarComponent::get_path_at (hb_font_t *font,
hb_codepoint_t parent_gid,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t total_transform,
hb_ubytes_t total_record,
hb_set_t *visited,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left,
hb_glyf_scratch_t &scratch,
VarRegionList::cache_t *cache) const
{
const unsigned char *end = total_record.arrayZ + total_record.length;
const unsigned char *record = total_record.arrayZ;
auto &VARC = *font->face->table.VARC;
auto &VARC = *font->face->table.VARC->table;
auto &varStore = &VARC+VARC.varStore;
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
#define READ_UINT32VAR(name) \
HB_STMT_START { \
@ -187,22 +187,25 @@ VarComponent::get_path_at (hb_font_t *font,
unsigned conditionIndex;
READ_UINT32VAR (conditionIndex);
const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
}
// Axis values
hb_vector_t<unsigned> axisIndices;
hb_vector_t<float> axisValues;
auto &axisIndices = scratch.axisIndices;
axisIndices.clear ();
auto &axisValues = scratch.axisValues;
axisValues.clear ();
if (flags & (unsigned) flags_t::HAVE_AXES)
{
unsigned axisIndicesIndex;
READ_UINT32VAR (axisIndicesIndex);
axisIndices = (&VARC+VARC.axisIndicesList)[axisIndicesIndex];
axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]);
axisValues.resize (axisIndices.length);
const HBUINT8 *p = (const HBUINT8 *) record;
TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
record += (const unsigned char *) p - record;
record = (const unsigned char *) p;
}
// Apply variations if any
@ -312,26 +315,15 @@ VarComponent::get_path_at (hb_font_t *font,
if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))
transform.scaleY = transform.scaleX;
// Scale the transform by the font's scale
float x_scale = font->x_multf;
float y_scale = font->y_multf;
transform.translateX *= x_scale;
transform.translateY *= y_scale;
transform.tCenterX *= x_scale;
transform.tCenterY *= y_scale;
// Build a transforming pen to apply the transform.
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
hb_transforming_pen_context_t context {transform.to_transform (),
draw_session.funcs,
draw_session.draw_data,
&draw_session.st};
hb_draw_session_t transformer_session {transformer_funcs, &context};
total_transform.transform (transform.to_transform ());
total_transform.scale (font->x_mult ? 1.f / font->x_multf : 0.f,
font->y_mult ? 1.f / font->y_multf : 0.f);
VARC.get_path_at (font, gid,
transformer_session, component_coords,
draw_session, component_coords, total_transform,
parent_gid,
visited, edges_left, depth_left - 1);
decycler, edges_left, depth_left - 1,
scratch);
}
#undef PROCESS_TRANSFORM_COMPONENTS
@ -340,6 +332,72 @@ VarComponent::get_path_at (hb_font_t *font,
return hb_ubytes_t (record, end - record);
}
bool
VARC::get_path_at (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_codepoint_t parent_glyph,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left,
hb_glyf_scratch_t &scratch) const
{
// Don't recurse on the same glyph.
unsigned idx = glyph == parent_glyph ?
NOT_COVERED :
(this+coverage).get_coverage (glyph);
if (idx == NOT_COVERED)
{
// Build a transforming pen to apply the transform.
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
hb_transforming_pen_context_t context {transform,
draw_session.funcs,
draw_session.draw_data,
&draw_session.st};
hb_draw_session_t transformer_session {transformer_funcs, &context};
hb_draw_session_t &shape_draw_session = transform.is_identity () ? draw_session : transformer_session;
if (!font->face->table.glyf->get_path_at (font, glyph, shape_draw_session, coords, scratch))
#ifndef HB_NO_CFF
if (!font->face->table.cff2->get_path_at (font, glyph, shape_draw_session, coords))
if (!font->face->table.cff1->get_path (font, glyph, shape_draw_session)) // Doesn't have variations
#endif
return false;
return true;
}
if (depth_left <= 0)
return true;
if (*edges_left <= 0)
return true;
(*edges_left)--;
hb_decycler_node_t node (*decycler);
if (unlikely (!node.visit (glyph)))
return true;
hb_ubytes_t record = (this+glyphRecords)[idx];
float static_cache[sizeof (void *) * 16];
VarRegionList::cache_t *cache = (this+varStore).create_cache (hb_array (static_cache));
transform.scale (font->x_multf, font->y_multf);
VarCompositeGlyph::get_path_at (font, glyph,
draw_session, coords, transform,
record,
decycler, edges_left, depth_left,
scratch,
cache);
(this+varStore).destroy_cache (cache, hb_array (static_cache));
return true;
}
//} // namespace Var
} // namespace OT

View file

@ -1,6 +1,8 @@
#ifndef OT_VAR_VARC_VARC_HH
#define OT_VAR_VARC_VARC_HH
#include "../../../hb-decycler.hh"
#include "../../../hb-geometry.hh"
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-ot-glyf-table.hh"
#include "../../../hb-ot-cff2-table.hh"
@ -46,10 +48,12 @@ struct VarComponent
hb_codepoint_t parent_gid,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_ubytes_t record,
hb_set_t *visited,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left,
hb_glyf_scratch_t &scratch,
VarRegionList::cache_t *cache = nullptr) const;
};
@ -60,19 +64,21 @@ struct VarCompositeGlyph
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_ubytes_t record,
hb_set_t *visited,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left,
hb_glyf_scratch_t &scratch,
VarRegionList::cache_t *cache = nullptr)
{
while (record)
{
const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
record = comp.get_path_at (font, glyph,
draw_session, coords,
draw_session, coords, transform,
record,
visited, edges_left, depth_left, cache);
decycler, edges_left, depth_left, scratch, cache);
}
}
};
@ -85,79 +91,37 @@ struct VARC
static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
bool
HB_INTERNAL bool
get_path_at (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_codepoint_t parent_glyph = HB_CODEPOINT_INVALID,
hb_set_t *visited = nullptr,
signed *edges_left = nullptr,
signed depth_left = HB_MAX_NESTING_LEVEL) const
{
hb_set_t stack_set;
if (visited == nullptr)
visited = &stack_set;
signed stack_edges = HB_MAX_GRAPH_EDGE_COUNT;
if (edges_left == nullptr)
edges_left = &stack_edges;
// Don't recurse on the same glyph.
unsigned idx = glyph == parent_glyph ?
NOT_COVERED :
(this+coverage).get_coverage (glyph);
if (idx == NOT_COVERED)
{
if (!font->face->table.glyf->get_path_at (font, glyph, draw_session, coords))
#ifndef HB_NO_CFF
if (!font->face->table.cff2->get_path_at (font, glyph, draw_session, coords))
if (!font->face->table.cff1->get_path (font, glyph, draw_session)) // Doesn't have variations
#endif
return false;
return true;
}
if (depth_left <= 0)
return true;
if (*edges_left <= 0)
return true;
(*edges_left)--;
if (visited->has (glyph) || visited->in_error ())
return true;
visited->add (glyph);
hb_ubytes_t record = (this+glyphRecords)[idx];
VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic
(this+varStore).create_cache ()
: nullptr;
VarCompositeGlyph::get_path_at (font, glyph,
draw_session, coords,
record,
visited, edges_left, depth_left,
cache);
(this+varStore).destroy_cache (cache);
visited->del (glyph);
return true;
}
hb_transform_t transform,
hb_codepoint_t parent_glyph,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left,
hb_glyf_scratch_t &scratch) const;
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{ return get_path_at (font, gid, draw_session, hb_array (font->coords, font->num_coords)); }
bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
get_path (hb_font_t *font,
hb_codepoint_t gid,
hb_draw_session_t &draw_session,
hb_glyf_scratch_t &scratch) const
{
funcs->push_clip_glyph (data, gid, font);
funcs->color (data, true, foreground);
funcs->pop_clip (data);
hb_decycler_t decycler;
signed edges = HB_MAX_GRAPH_EDGE_COUNT;
return true;
return get_path_at (font,
gid,
draw_session,
hb_array (font->coords, font->num_coords),
HB_TRANSFORM_IDENTITY,
HB_CODEPOINT_INVALID,
&decycler,
&edges,
HB_MAX_NESTING_LEVEL,
scratch);
}
bool sanitize (hb_sanitize_context_t *c) const
@ -173,6 +137,63 @@ struct VARC
glyphRecords.sanitize (c, this));
}
struct accelerator_t
{
friend struct VarComponent;
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<VARC> (face);
}
~accelerator_t ()
{
auto *scratch = cached_scratch.get_relaxed ();
if (scratch)
{
scratch->~hb_glyf_scratch_t ();
hb_free (scratch);
}
table.destroy ();
}
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{
if (!table->has_data ()) return false;
hb_glyf_scratch_t *scratch;
// Borrow the cached strach buffer.
{
scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
if (unlikely (!scratch))
return true;
}
}
bool ret = table->get_path (font, gid, draw_session, *scratch);
// Put it back.
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_glyf_scratch_t ();
hb_free (scratch);
}
return ret;
}
private:
hb_blob_ptr_t<VARC> table;
hb_atomic_ptr_t<hb_glyf_scratch_t> cached_scratch;
};
bool has_data () const { return version.major != 0; }
protected:
FixedVersion<> version; /* Version identifier */
Offset32To<Coverage> coverage;
@ -184,6 +205,10 @@ struct VARC
DEFINE_SIZE_STATIC (24);
};
struct VARC_accelerator_t : VARC::accelerator_t {
VARC_accelerator_t (hb_face_t *face) : VARC::accelerator_t (face) {}
};
#endif
//}

View file

@ -11,22 +11,48 @@ namespace OT {
struct coord_setter_t
{
coord_setter_t (hb_array_t<const int> coords) :
coords (coords) {}
coord_setter_t (hb_array_t<const int> coords_)
{
length = coords_.length;
if (length <= ARRAY_LENGTH (static_coords))
hb_memcpy (static_coords, coords_.arrayZ, length * sizeof (int));
else
dynamic_coords.extend (coords_);
}
int& operator [] (unsigned idx)
{
if (unlikely (idx >= HB_VAR_COMPOSITE_MAX_AXES))
return Crap(int);
if (coords.length < idx + 1)
coords.resize (idx + 1);
return coords[idx];
if (length <= ARRAY_LENGTH (static_coords))
{
if (idx < ARRAY_LENGTH (static_coords))
{
while (length <= idx)
static_coords[length++] = 0;
return static_coords[idx];
}
else
dynamic_coords.extend (hb_array (static_coords, length));
}
if (dynamic_coords.length <= idx)
{
if (unlikely (!dynamic_coords.resize (idx + 1)))
return Crap(int);
length = idx + 1;
}
return dynamic_coords.arrayZ[idx];
}
hb_array_t<int> get_coords ()
{ return coords.as_array (); }
{ return length <= ARRAY_LENGTH (static_coords) ? hb_array (static_coords, length) : dynamic_coords.as_array (); }
hb_vector_t<int> coords;
private:
hb_vector_t<int> dynamic_coords;
unsigned length;
int static_coords[sizeof (void *) * 8];
};

View file

@ -143,7 +143,7 @@ struct CompositeGlyphRecord
float matrix[4];
contour_point_t trans;
get_transformation (matrix, trans);
if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
if (unlikely (!points.alloc (points.length + 1 + 4))) return false; // For phantom points
points.push (trans);
return true;
}

View file

@ -251,7 +251,8 @@ struct Glyph
composite_contours_p = nullptr;
}
if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
hb_glyf_scratch_t scratch;
if (!get_points (font, glyf, all_points, scratch, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
return false;
// .notdef, set type to empty so we only update metrics and don't compile bytes for
@ -305,6 +306,7 @@ struct Glyph
template <typename accelerator_t>
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */,
hb_glyf_scratch_t &scratch,
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
unsigned *composite_contours = nullptr, /* OUT */
@ -312,7 +314,6 @@ struct Glyph
bool use_my_metrics = true,
bool phantom_only = false,
hb_array_t<const int> coords = hb_array_t<const int> (),
hb_map_t *current_glyphs = nullptr,
unsigned int depth = 0,
unsigned *edge_count = nullptr) const
{
@ -322,10 +323,6 @@ struct Glyph
if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false;
(*edge_count)++;
hb_map_t current_glyphs_stack;
if (current_glyphs == nullptr)
current_glyphs = &current_glyphs_stack;
if (head_maxp_info)
{
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
@ -334,8 +331,7 @@ struct Glyph
if (!coords)
coords = hb_array (font->coords, font->num_coords);
contour_point_vector_t stack_points;
contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
contour_point_vector_t &points = type == SIMPLE ? all_points : scratch.comp_points;
unsigned old_length = points.length;
switch (type) {
@ -388,36 +384,53 @@ struct Glyph
#ifndef HB_NO_VAR
if (coords)
glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
phantom_only && type == SIMPLE);
{
#ifndef HB_NO_BEYOND_64K
if (glyf_accelerator.GVAR->has_data ())
glyf_accelerator.GVAR->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
scratch,
phantom_only && type == SIMPLE);
else
#endif
glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
scratch,
phantom_only && type == SIMPLE);
}
#endif
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
// with child glyphs' points
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
{
if (unlikely (!points_with_deltas->resize (points.length))) return false;
assert (old_length == 0);
*points_with_deltas = points;
}
float shift = 0;
switch (type) {
case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
shift = phantoms[PHANTOM_LEFT].x;
break;
case COMPOSITE:
{
hb_decycler_node_t decycler_node (scratch.decycler);
unsigned int comp_index = 0;
for (auto &item : get_composite_iterator ())
{
hb_codepoint_t item_gid = item.get_gid ();
if (unlikely (current_glyphs->has (item_gid)))
if (unlikely (!decycler_node.visit (item_gid)))
{
comp_index++;
continue;
current_glyphs->add (item_gid);
}
unsigned old_count = all_points.length;
@ -426,6 +439,7 @@ struct Glyph
.get_points (font,
glyf_accelerator,
all_points,
scratch,
points_with_deltas,
head_maxp_info,
composite_contours,
@ -433,14 +447,16 @@ struct Glyph
use_my_metrics,
phantom_only,
coords,
current_glyphs,
depth + 1,
edge_count)))
{
current_glyphs->del (item_gid);
points.resize (old_length);
return false;
}
// points might have been reallocated. Relocate phantoms.
phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
auto comp_points = all_points.as_array ().sub_array (old_count);
/* Copy phantom points from component if USE_MY_METRICS flag set */
@ -455,7 +471,7 @@ struct Glyph
item.get_transformation (matrix, default_trans);
/* Apply component transformation & translation (with deltas applied) */
item.transform_points (comp_points, matrix, points[comp_index]);
item.transform_points (comp_points, matrix, points[old_length + comp_index]);
}
if (item.is_anchored () && !phantom_only)
@ -476,12 +492,11 @@ struct Glyph
if (all_points.length > HB_GLYF_MAX_POINTS)
{
current_glyphs->del (item_gid);
points.resize (old_length);
return false;
}
comp_index++;
current_glyphs->del (item_gid);
}
if (head_maxp_info && depth == 0)
@ -492,9 +507,13 @@ struct Glyph
head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
}
all_points.extend (phantoms);
shift = phantoms[PHANTOM_LEFT].x;
points.resize (old_length);
} break;
case EMPTY:
all_points.extend (phantoms);
shift = phantoms[PHANTOM_LEFT].x;
points.resize (old_length);
break;
}
@ -503,10 +522,9 @@ struct Glyph
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
float v = -phantoms[PHANTOM_LEFT].x;
if (v)
if (shift)
for (auto &point : all_points)
point.x += v;
point.x -= shift;
}
return !all_points.in_error ();

View file

@ -127,19 +127,20 @@ struct SimpleGlyph
hb_array_t<contour_point_t> points_ /* IN/OUT */,
const HBUINT8 *end)
{
auto *points = points_.arrayZ;
unsigned count = points_.length;
for (unsigned int i = 0; i < count;)
{
if (unlikely (p + 1 > end)) return false;
uint8_t flag = *p++;
points_.arrayZ[i++].flag = flag;
points[i++].flag = flag;
if (flag & FLAG_REPEAT)
{
if (unlikely (p + 1 > end)) return false;
unsigned int repeat_count = *p++;
unsigned stop = hb_min (i + repeat_count, count);
for (; i < stop; i++)
points_.arrayZ[i].flag = flag;
points[i].flag = flag;
}
}
return true;
@ -160,10 +161,7 @@ struct SimpleGlyph
if (flag & short_flag)
{
if (unlikely (p + 1 > end)) return false;
if (flag & same_flag)
v += *p++;
else
v -= *p++;
v += (bool(flag & same_flag) * 2 - 1) * *p++;
}
else
{
@ -190,7 +188,7 @@ struct SimpleGlyph
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
unsigned old_length = points.length;
points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
if (unlikely (!points.resize (points.length + num_points, false))) return false;
auto points_ = points.as_array ().sub_array (old_length);
if (!phantom_only)
@ -281,9 +279,9 @@ struct SimpleGlyph
unsigned num_points = all_points.length - 4;
hb_vector_t<uint8_t> flags, x_coords, y_coords;
if (unlikely (!flags.alloc (num_points, true))) return false;
if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
if (unlikely (!flags.alloc_exact (num_points))) return false;
if (unlikely (!x_coords.alloc_exact (2*num_points))) return false;
if (unlikely (!y_coords.alloc_exact (2*num_points))) return false;
unsigned lastflag = 255, repeat = 0;
int prev_x = 0, prev_y = 0;

View file

@ -94,7 +94,7 @@ struct glyf
}
hb_vector_t<unsigned> padded_offsets;
if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true)))
if (unlikely (!padded_offsets.alloc_exact (c->plan->new_to_old_gid_list.length)))
return_trace (false);
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
@ -172,6 +172,9 @@ struct glyf_accelerator_t
glyf_table = nullptr;
#ifndef HB_NO_VAR
gvar = nullptr;
#ifndef HB_NO_BEYOND_64K
GVAR = nullptr;
#endif
#endif
hmtx = nullptr;
#ifndef HB_NO_VERTICAL
@ -187,6 +190,9 @@ struct glyf_accelerator_t
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
#ifndef HB_NO_VAR
gvar = face->table.gvar;
#ifndef HB_NO_BEYOND_64K
GVAR = face->table.GVAR;
#endif
#endif
hmtx = face->table.hmtx;
#ifndef HB_NO_VERTICAL
@ -198,6 +204,13 @@ struct glyf_accelerator_t
}
~glyf_accelerator_t ()
{
auto *scratch = cached_scratch.get_relaxed ();
if (scratch)
{
scratch->~hb_glyf_scratch_t ();
hb_free (scratch);
}
glyf_table.destroy ();
}
@ -206,21 +219,16 @@ struct glyf_accelerator_t
protected:
template<typename T>
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
hb_array_t<const int> coords = hb_array_t<const int> ()) const
hb_array_t<const int> coords,
hb_glyf_scratch_t &scratch) const
{
if (!coords)
coords = hb_array (font->coords, font->num_coords);
if (gid >= num_glyphs) return false;
/* Making this allocfree is not that easy
https://github.com/harfbuzz/harfbuzz/issues/2095
mostly because of gvar handling in VF fonts,
perhaps a separate path for non-VF fonts can be considered */
contour_point_vector_t all_points;
auto &all_points = scratch.all_points;
all_points.resize (0);
bool phantom_only = !consumer.is_consuming_contour_points ();
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
return false;
unsigned count = all_points.length;
@ -229,8 +237,61 @@ struct glyf_accelerator_t
if (consumer.is_consuming_contour_points ())
{
for (auto &point : all_points.as_array ().sub_array (0, count))
consumer.consume_point (point);
auto *points = all_points.arrayZ;
if (false)
{
/* Our path-builder was designed to work with this simple loop.
* But FreeType and CoreText do it differently, so we match those
* with the other, more complicated, code branch below. */
for (unsigned i = 0; i < count; i++)
{
consumer.consume_point (points[i]);
if (points[i].is_end_point)
consumer.contour_end ();
}
}
else
{
for (unsigned i = 0; i < count; i++)
{
// Start of a contour.
if (points[i].flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE)
{
// First point is on-curve. Draw the contour.
for (; i < count; i++)
{
consumer.consume_point (points[i]);
if (points[i].is_end_point)
{
consumer.contour_end ();
break;
}
}
}
else
{
unsigned start = i;
// Find end of the contour.
for (; i < count; i++)
if (points[i].is_end_point)
break;
unsigned end = i;
// Enough to start from the end. Our path-builder takes care of the rest.
if (likely (end < count)) // Can only fail in case of alloc failure *maybe*.
consumer.consume_point (points[end]);
for (i = start; i < end; i++)
consumer.consume_point (points[i]);
consumer.contour_end ();
}
}
}
consumer.points_end ();
}
@ -303,6 +364,7 @@ struct glyf_accelerator_t
HB_ALWAYS_INLINE
void consume_point (const contour_point_t &point) { bounds.add (point); }
void contour_end () {}
void points_end () { bounds.get_extents (font, extents, scaled); }
bool is_consuming_contour_points () { return extents; }
@ -318,7 +380,12 @@ struct glyf_accelerator_t
contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
if (font->num_coords)
success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false));
{
hb_glyf_scratch_t scratch;
success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
hb_array (font->coords, font->num_coords),
scratch);
}
if (unlikely (!success))
return
@ -338,9 +405,11 @@ struct glyf_accelerator_t
if (unlikely (gid >= num_glyphs)) return false;
hb_glyph_extents_t extents;
hb_glyf_scratch_t scratch;
contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false))))
if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false),
hb_array (font->coords, font->num_coords),
scratch)))
return false;
*lsb = is_vertical
@ -366,20 +435,16 @@ struct glyf_accelerator_t
#ifndef HB_NO_VAR
if (font->num_coords)
return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true));
{
hb_glyf_scratch_t scratch;
return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true),
hb_array (font->coords, font->num_coords),
scratch);
}
#endif
return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
}
bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
{
funcs->push_clip_glyph (data, gid, font);
funcs->color (data, true, foreground);
funcs->pop_clip (data);
return true;
}
const glyf_impl::Glyph
glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
{
@ -410,15 +475,52 @@ struct glyf_accelerator_t
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); }
{
if (!has_data ()) return false;
hb_glyf_scratch_t *scratch;
// Borrow the cached strach buffer.
{
scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
if (unlikely (!scratch))
return true;
}
}
bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
hb_array (font->coords, font->num_coords),
*scratch);
// Put it back.
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_glyf_scratch_t ();
hb_free (scratch);
}
return ret;
}
bool
get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session,
hb_array_t<const int> coords) const
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), coords); }
hb_array_t<const int> coords,
hb_glyf_scratch_t &scratch) const
{
if (!has_data ()) return false;
return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
coords,
scratch);
}
#ifndef HB_NO_VAR
const gvar_accelerator_t *gvar;
#ifndef HB_NO_BEYOND_64K
const GVAR_accelerator_t *GVAR;
#endif
#endif
const hmtx_accelerator_t *hmtx;
#ifndef HB_NO_VERTICAL
@ -430,6 +532,7 @@ struct glyf_accelerator_t
unsigned int num_glyphs;
hb_blob_ptr_t<loca> loca_table;
hb_blob_ptr_t<glyf> glyf_table;
hb_atomic_ptr_t<hb_glyf_scratch_t> cached_scratch;
};
@ -439,7 +542,7 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{
OT::glyf_accelerator_t glyf (plan->source);
if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false;
if (!glyphs.alloc_exact (plan->new_to_old_gid_list.length)) return false;
for (const auto &pair : plan->new_to_old_gid_list)
{

View file

@ -42,7 +42,7 @@ struct path_builder_t
{
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
#ifdef HB_NO_CUBIC_GLYF
bool is_cubic = false;
constexpr bool is_cubic = false;
#else
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
#endif
@ -124,58 +124,60 @@ struct path_builder_t
}
}
if (unlikely (point.is_end_point))
{
if (first_offcurve && last_offcurve)
{
optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
first_offcurve2 :
first_offcurve);
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve = optional_point_t ();
}
/* now check the rest */
if (first_offcurve && first_oncurve)
{
if (first_offcurve2)
draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
}
else if (last_offcurve && first_oncurve)
{
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
}
else if (first_oncurve)
draw_session->line_to (first_oncurve.x, first_oncurve.y);
else if (first_offcurve)
{
float x = first_offcurve.x, y = first_offcurve.y;
draw_session->move_to (x, y);
draw_session->quadratic_to (x, y, x, y);
}
/* Getting ready for the next contour */
first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
draw_session->close_path ();
}
}
void contour_end ()
{
if (first_offcurve && last_offcurve)
{
optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
first_offcurve2 :
first_offcurve);
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve = optional_point_t ();
}
/* now check the rest */
if (first_offcurve && first_oncurve)
{
if (first_offcurve2)
draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
}
else if (last_offcurve && first_oncurve)
{
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
}
else if (first_oncurve)
draw_session->line_to (first_oncurve.x, first_oncurve.y);
else if (first_offcurve)
{
float x = first_offcurve.x, y = first_offcurve.y;
draw_session->move_to (x, y);
draw_session->quadratic_to (x, y, x, y);
}
/* Getting ready for the next contour */
first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
draw_session->close_path ();
}
void points_end () {}
bool is_consuming_contour_points () { return true; }

View file

@ -163,7 +163,7 @@ struct NameRecord
if (platformID != 1)
{
unsigned text_size = hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, nullptr, nullptr);
text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf()
unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
name_str_utf16_be = (char *) hb_calloc (byte_len, 1);
@ -174,14 +174,14 @@ struct NameRecord
}
hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, &text_size,
(hb_utf16_be_t::codepoint_t *) name_str_utf16_be);
unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
c->revert (snap);
hb_free (name_str_utf16_be);
return_trace (nullptr);
}
encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len);
}
else
@ -392,7 +392,7 @@ struct name
const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
&c->plan->name_table_overrides;
#endif
auto it =
+ nameRecordZ.as_array (count)
| hb_filter (c->plan->name_ids, &NameRecord::nameID)
@ -485,7 +485,7 @@ struct name
const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
this->table->count);
this->names.alloc (all_names.length, true);
this->names.alloc_exact (all_names.length);
for (unsigned int i = 0; i < all_names.length; i++)
{

View file

@ -30,6 +30,10 @@
#include "hb-aat-layout.hh"
#include "hb-aat-map.hh"
#include "hb-open-type.hh"
#include "hb-cache.hh"
#include "hb-bit-set.hh"
#include "hb-bit-page.hh"
namespace OT {
struct GDEF;
@ -39,10 +43,11 @@ namespace AAT {
using namespace OT;
#define HB_AAT_BUFFER_DIGEST_THRESHOLD 32
struct ankr;
using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
@ -61,10 +66,12 @@ struct hb_aat_apply_context_t :
const ankr *ankr_table;
const OT::GDEF *gdef_table;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
hb_set_digest_t buffer_digest = hb_set_digest_t::full ();
hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
hb_set_digest_t left_set = hb_set_digest_t::full ();
hb_set_digest_t right_set = hb_set_digest_t::full ();
bool using_buffer_glyph_set = false;
hb_bit_set_t buffer_glyph_set;
const hb_bit_set_t *left_set = nullptr;
const hb_bit_set_t *right_set = nullptr;
const hb_bit_set_t *machine_glyph_set = nullptr;
hb_aat_class_cache_t *machine_class_cache = nullptr;
hb_mask_t subtable_flags = 0;
/* Unused. For debug tracing only. */
@ -80,6 +87,25 @@ struct hb_aat_apply_context_t :
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
void set_lookup_index (unsigned int i) { lookup_index = i; }
void setup_buffer_glyph_set ()
{
using_buffer_glyph_set = buffer->len >= 4;
if (using_buffer_glyph_set)
buffer->collect_codepoints (buffer_glyph_set);
}
bool buffer_intersects_machine () const
{
if (using_buffer_glyph_set)
return buffer_glyph_set.intersects (*machine_glyph_set);
// Faster for shorter buffers.
for (unsigned i = 0; i < buffer->len; i++)
if (machine_glyph_set->has (buffer->info[i].codepoint))
return true;
return false;
}
};
@ -108,6 +134,13 @@ struct LookupFormat0
{
glyphs.add_range (0, num_glyphs - 1);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const
{
for (unsigned i = 0; i < num_glyphs; i++)
if (filter (arrayZ[i]))
glyphs.add (i);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -140,8 +173,13 @@ struct LookupSegmentSingle
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (first == DELETED_GLYPH)
return;
if (first == DELETED_GLYPH) return;
glyphs.add_range (first, last);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (!filter (value)) return;
glyphs.add_range (first, last);
}
@ -182,6 +220,13 @@ struct LookupFormat2
for (unsigned int i = 0; i < count; i++)
segments[i].collect_glyphs (glyphs);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
unsigned count = segments.get_length ();
for (unsigned int i = 0; i < count; i++)
segments[i].collect_glyphs_filtered (glyphs, filter);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -217,10 +262,17 @@ struct LookupSegmentArray
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (first == DELETED_GLYPH)
return;
if (first == DELETED_GLYPH) return;
glyphs.add_range (first, last);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const void *base, const filter_t &filter) const
{
const auto &values = base+valuesZ;
for (hb_codepoint_t i = first; i <= last; i++)
if (filter (values[i - first]))
glyphs.add (i);
}
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
@ -271,6 +323,13 @@ struct LookupFormat4
for (unsigned i = 0; i < count; i++)
segments[i].collect_glyphs (glyphs);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
unsigned count = segments.get_length ();
for (unsigned i = 0; i < count; i++)
segments[i].collect_glyphs_filtered (glyphs, this, filter);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -303,8 +362,13 @@ struct LookupSingle
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (glyph == DELETED_GLYPH)
return;
if (glyph == DELETED_GLYPH) return;
glyphs.add (glyph);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (!filter (value)) return;
glyphs.add (glyph);
}
@ -344,6 +408,13 @@ struct LookupFormat6
for (unsigned i = 0; i < count; i++)
entries[i].collect_glyphs (glyphs);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
unsigned count = entries.get_length ();
for (unsigned i = 0; i < count; i++)
entries[i].collect_glyphs_filtered (glyphs, filter);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -379,12 +450,20 @@ struct LookupFormat8
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (unlikely (!glyphCount))
return;
if (firstGlyph == DELETED_GLYPH)
return;
if (unlikely (!glyphCount)) return;
if (firstGlyph == DELETED_GLYPH) return;
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (unlikely (!glyphCount)) return;
if (firstGlyph == DELETED_GLYPH) return;
const T *p = valueArrayZ.arrayZ;
for (unsigned i = 0; i < glyphCount; i++)
if (filter (p[i]))
glyphs.add (firstGlyph + i);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -433,10 +512,8 @@ struct LookupFormat10
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (unlikely (!glyphCount))
return;
if (firstGlyph == DELETED_GLYPH)
return;
if (unlikely (!glyphCount)) return;
if (firstGlyph == DELETED_GLYPH) return;
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
}
@ -501,6 +578,18 @@ struct Lookup
default:return;
}
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const
{
switch (u.format) {
case 0: hb_barrier (); u.format0.collect_glyphs_filtered (glyphs, num_glyphs, filter); return;
case 2: hb_barrier (); u.format2.collect_glyphs_filtered (glyphs, filter); return;
case 4: hb_barrier (); u.format4.collect_glyphs_filtered (glyphs, filter); return;
case 6: hb_barrier (); u.format6.collect_glyphs_filtered (glyphs, filter); return;
case 8: hb_barrier (); u.format8.collect_glyphs_filtered (glyphs, filter); return;
default:return;
}
}
typename T::type get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs,
@ -563,7 +652,7 @@ DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
template <typename T>
struct Entry
{
// This does seem like it's ever called.
// This doesn't seem like it's ever called.
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -632,18 +721,47 @@ struct StateTable
{
(this+classTable).collect_glyphs (glyphs, num_glyphs);
}
template <typename set_t, typename table_t>
void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs, const table_t &table) const
{
unsigned num_classes = nClasses;
if (unlikely (num_classes > hb_bit_page_t::BITS))
{
(this+classTable).collect_glyphs (glyphs, num_glyphs);
return;
}
// Collect all classes going out from the start state.
hb_bit_page_t filter;
for (unsigned i = 0; i < num_classes; i++)
{
const auto &entry = get_entry (STATE_START_OF_TEXT, i);
if (new_state (entry.newState) == STATE_START_OF_TEXT &&
!table.is_action_initiable (entry) && !table.is_actionable (entry))
continue;
filter.add (i);
}
// And glyphs in those classes.
(this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter);
}
int new_state (unsigned int newState) const
{ return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
template <typename set_t>
unsigned int get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs,
const set_t &glyphs) const
hb_aat_class_cache_t *cache = nullptr) const
{
unsigned klass;
if (cache && cache->get (glyph_id, &klass)) return klass;
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS;
return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
klass = (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
if (cache) cache->set (glyph_id, klass);
return klass;
}
const Entry<Extra> *get_entries () const
@ -651,13 +769,14 @@ struct StateTable
const Entry<Extra> &get_entry (int state, unsigned int klass) const
{
if (unlikely (klass >= nClasses))
unsigned n_classes = nClasses;
if (unlikely (klass >= n_classes))
klass = CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
unsigned int entry = states[state * nClasses + klass];
unsigned int entry = states[state * n_classes + klass];
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
return entries[entry];
@ -803,6 +922,13 @@ struct ClassTable
if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS)
glyphs.add (firstGlyph + i);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const
{
for (unsigned i = 0; i < classArray.len; i++)
if (filter (classArray.arrayZ[i]))
glyphs.add (firstGlyph + i);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -918,7 +1044,7 @@ struct ExtendedTypes
}
};
template <typename Types, typename EntryData>
template <typename Types, typename EntryData, typename Flags>
struct StateTableDriver
{
using StateTableT = StateTable<Types, EntryData>;
@ -929,14 +1055,6 @@ struct StateTableDriver
machine (machine_),
num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t>
bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac)
{
const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS);
return !c->is_actionable (ac->buffer, this, entry) &&
machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT;
}
template <typename context_t>
void drive (context_t *c, hb_aat_apply_context_t *ac)
{
@ -977,7 +1095,7 @@ struct StateTableDriver
}
unsigned int klass = likely (buffer->idx < buffer->len) ?
machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) :
machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) :
(unsigned) CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const EntryT &entry = machine.get_entry (state, klass);
@ -1011,41 +1129,36 @@ struct StateTableDriver
*
* https://github.com/harfbuzz/harfbuzz/issues/2860
*/
const auto is_safe_to_break_extra = [&]()
{
/* 2c. */
const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
/* 2c'. */
if (c->is_actionable (buffer, this, wouldbe_entry))
return false;
/* 2c". */
return next_state == machine.new_state(wouldbe_entry.newState)
&& (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
};
const auto is_safe_to_break = [&]()
{
const EntryT *wouldbe_entry;
bool is_safe_to_break =
(
/* 1. */
if (c->is_actionable (buffer, this, entry))
return false;
!c->table->is_actionable (entry) &&
/* 2. */
// This one is meh, I know...
const auto ok =
(
state == StateTableT::STATE_START_OF_TEXT
|| ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
|| is_safe_to_break_extra();
if (!ok)
return false;
|| ((entry.flags & Flags::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
|| (
/* 2c. */
wouldbe_entry = &machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass)
,
/* 2c'. */
!c->table->is_actionable (*wouldbe_entry) &&
/* 2c". */
(
next_state == machine.new_state(wouldbe_entry->newState) &&
(entry.flags & Flags::DontAdvance) == (wouldbe_entry->flags & Flags::DontAdvance)
)
)
) &&
/* 3. */
return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT));
};
!c->table->is_actionable (machine.get_entry (state, CLASS_END_OF_TEXT))
);
if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
if (!is_safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
c->transition (buffer, this, entry);
@ -1056,7 +1169,7 @@ struct StateTableDriver
if (buffer->idx == buffer->len || unlikely (!buffer->successful))
break;
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
if (!(entry.flags & Flags::DontAdvance) || buffer->max_ops-- <= 0)
(void) buffer->next_glyph ();
}

View file

@ -112,10 +112,6 @@ struct KerxSubTableFormat0
if (header.coverage & header.Backwards)
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
@ -144,7 +140,7 @@ struct KerxSubTableFormat0
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!c->left_set[left] || !c->right_set[right]) return 0;
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -211,6 +207,9 @@ struct Format1Entry<false>
typedef void EntryData;
static bool initiateAction (const Entry<EntryData> &entry)
{ return entry.flags & Push; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
@ -227,13 +226,23 @@ struct KerxSubTableFormat1
typedef Format1Entry<Types::extended> Format1EntryT;
typedef typename Format1EntryT::EntryData EntryData;
enum Flags
{
DontAdvance = Format1EntryT::DontAdvance,
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return Format1EntryT::initiateAction (entry);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return Format1EntryT::performAction (entry);
}
struct driver_context_t
{
static constexpr bool in_place = true;
enum
{
DontAdvance = Format1EntryT::DontAdvance,
};
driver_context_t (const KerxSubTableFormat1 *table_,
hb_aat_apply_context_t *c_) :
@ -246,12 +255,8 @@ struct KerxSubTableFormat1
depth (0),
crossStream (table->header.coverage & table->header.CrossStream) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry)
{ return Format1EntryT::performAction (entry); }
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
StateTableDriver<Types, EntryData, Flags> *driver,
const Entry<EntryData> &entry)
{
unsigned int flags = entry.flags;
@ -351,9 +356,10 @@ struct KerxSubTableFormat1
}
}
private:
public:
hb_aat_apply_context_t *c;
const KerxSubTableFormat1 *table;
private:
const UnsizedArrayOf<FWORD> &kernAction;
unsigned int stack[8];
unsigned int depth;
@ -370,12 +376,7 @@ struct KerxSubTableFormat1
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->font->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
driver.drive (&dc, c);
@ -440,10 +441,6 @@ struct KerxSubTableFormat2
if (header.coverage & header.Backwards)
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
@ -469,7 +466,7 @@ struct KerxSubTableFormat2
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!c->left_set[left] || !c->right_set[right]) return 0;
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -513,17 +510,26 @@ struct KerxSubTableFormat4
DEFINE_SIZE_STATIC (2);
};
enum Flags
{
Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* Not used; set to 0. */
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return (entry.flags & Mark);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return entry.data.ankrActionIndex != 0xFFFF;
}
struct driver_context_t
{
static constexpr bool in_place = true;
enum Flags
{
Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* Not used; set to 0. */
};
enum SubTableFlags
{
ActionType = 0xC0000000, /* A two-bit field containing the action type. */
@ -533,20 +539,17 @@ struct KerxSubTableFormat4
* point table. */
};
driver_context_t (const KerxSubTableFormat4 *table,
driver_context_t (const KerxSubTableFormat4 *table_,
hb_aat_apply_context_t *c_) :
c (c_),
table (table_),
action_type ((table->flags & ActionType) >> 30),
ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
mark_set (false),
mark (0) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry)
{ return entry.data.ankrActionIndex != 0xFFFF; }
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
StateTableDriver<Types, EntryData, Flags> *driver,
const Entry<EntryData> &entry)
{
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
@ -634,8 +637,10 @@ struct KerxSubTableFormat4
}
}
private:
public:
hb_aat_apply_context_t *c;
const KerxSubTableFormat4 *table;
private:
unsigned int action_type;
const HBUINT16 *ankrData;
bool mark_set;
@ -648,12 +653,7 @@ struct KerxSubTableFormat4
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->font->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
driver.drive (&dc, c);
@ -735,10 +735,6 @@ struct KerxSubTableFormat6
if (header.coverage & header.Backwards)
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
@ -793,7 +789,7 @@ struct KerxSubTableFormat6
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!c->left_set[left] || !c->right_set[right]) return 0;
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -925,7 +921,7 @@ struct KerxSubTable
* The 'kerx' Table
*/
using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_set_digest_t, hb_set_digest_t>>;
using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_bit_set_t, hb_bit_set_t>>;
template <typename T>
struct KerxTable
@ -985,15 +981,10 @@ struct KerxTable
}
bool apply (AAT::hb_aat_apply_context_t *c,
const kern_accelerator_data_t *accel_data = nullptr) const
const kern_accelerator_data_t &accel_data) const
{
c->buffer->unsafe_to_concat ();
if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
c->buffer_digest = c->buffer->digest ();
else
c->buffer_digest = hb_set_digest_t::full ();
typedef typename T::SubTable SubTable;
bool ret = false;
@ -1037,15 +1028,8 @@ struct KerxTable
if (reverse)
c->buffer->reverse ();
if (accel_data)
{
c->left_set = (*accel_data)[i].first;
c->right_set = (*accel_data)[i].second;
}
else
{
c->left_set = c->right_set = hb_set_digest_t::full ();
}
c->left_set = &accel_data[i].first;
c->right_set = &accel_data[i].second;
{
/* See comment in sanitize() for conditional here. */
@ -1122,7 +1106,7 @@ struct KerxTable
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
hb_set_digest_t left_set, right_set;
hb_bit_set_t left_set, right_set;
st->collect_glyphs (left_set, right_set, num_glyphs);
accel_data.push (hb_pair (left_set, right_set));
st = &StructAfter<SubTable> (*st);
@ -1148,7 +1132,7 @@ struct KerxTable
bool apply (AAT::hb_aat_apply_context_t *c) const
{
return table->apply (c, &accel_data);
return table->apply (c, accel_data);
}
hb_blob_ptr_t<T> table;

View file

@ -29,6 +29,7 @@
#include "hb-open-type.hh"
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-aat-map.hh"
@ -53,35 +54,40 @@ struct RearrangementSubtable
typedef void EntryData;
struct driver_context_t
enum Flags
{
static constexpr bool in_place = true;
enum Flags
{
MarkFirst = 0x8000, /* If set, make the current glyph the first
MarkFirst = 0x8000, /* If set, make the current glyph the first
* glyph to be rearranged. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
* before going to the new state. This means
* that the glyph index doesn't change, even
* if the glyph at that index has changed. */
MarkLast = 0x2000, /* If set, make the current glyph the last
MarkLast = 0x2000, /* If set, make the current glyph the last
* glyph to be rearranged. */
Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */
Verb = 0x000F, /* The type of rearrangement specified. */
};
Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */
Verb = 0x000F, /* The type of rearrangement specified. */
};
driver_context_t (const RearrangementSubtable *table HB_UNUSED) :
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return (entry.flags & MarkFirst);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return (entry.flags & Verb);
}
struct driver_context_t
{
static constexpr bool in_place = true;
driver_context_t (const RearrangementSubtable *table_) :
ret (false),
table (table_),
start (0), end (0) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{
return (entry.flags & Verb) && start < end;
}
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
StateTableDriver<Types, EntryData, Flags> *driver,
const Entry<EntryData> &entry)
{
unsigned int flags = entry.flags;
@ -158,6 +164,7 @@ struct RearrangementSubtable
public:
bool ret;
const RearrangementSubtable *table;
private:
unsigned int start;
unsigned int end;
@ -169,11 +176,13 @@ struct RearrangementSubtable
driver_context_t dc (this);
StateTableDriver<Types, EntryData> driver (machine, c->face);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
@ -207,39 +216,40 @@ struct ContextualSubtable
DEFINE_SIZE_STATIC (4);
};
enum Flags
{
SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return (entry.flags & SetMark);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
}
struct driver_context_t
{
static constexpr bool in_place = true;
enum Flags
{
SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */
};
driver_context_t (const ContextualSubtable *table_,
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
table (table_),
gdef (*c->gdef_table),
mark_set (false),
has_glyph_classes (gdef.has_glyph_classes ()),
mark (0),
table (table_),
subs (table+table->substitutionTables) {}
bool is_actionable (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const
{
if (buffer->idx == buffer->len && !mark_set)
return false;
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
}
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
StateTableDriver<Types, EntryData, Flags> *driver,
const Entry<EntryData> &entry)
{
/* Looks like CoreText applies neither mark nor current substitution for
@ -271,8 +281,9 @@ struct ContextualSubtable
if (replacement)
{
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
buffer->info[mark].codepoint = *replacement;
c->buffer_digest.add (*replacement);
hb_codepoint_t glyph = *replacement;
buffer->info[mark].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[mark],
gdef.get_glyph_props (*replacement));
@ -301,8 +312,9 @@ struct ContextualSubtable
}
if (replacement)
{
buffer->info[idx].codepoint = *replacement;
c->buffer_digest.add (*replacement);
hb_codepoint_t glyph = *replacement;
buffer->info[idx].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[idx],
gdef.get_glyph_props (*replacement));
@ -318,13 +330,13 @@ struct ContextualSubtable
public:
bool ret;
private:
hb_aat_apply_context_t *c;
const ContextualSubtable *table;
private:
const OT::GDEF &gdef;
bool mark_set;
bool has_glyph_classes;
unsigned int mark;
const ContextualSubtable *table;
const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
};
@ -334,11 +346,13 @@ struct ContextualSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->face);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
@ -389,6 +403,16 @@ struct LigatureEntry;
template <>
struct LigatureEntry<true>
{
struct EntryData
{
HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry
* for processing this group, if indicated
* by the flags. */
public:
DEFINE_SIZE_STATIC (2);
};
enum Flags
{
SetComponent = 0x8000, /* Push this glyph onto the component stack for
@ -400,14 +424,8 @@ struct LigatureEntry<true>
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
};
struct EntryData
{
HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry
* for processing this group, if indicated
* by the flags. */
public:
DEFINE_SIZE_STATIC (2);
};
static bool initiateAction (const Entry<EntryData> &entry)
{ return entry.flags & SetComponent; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & PerformAction; }
@ -418,6 +436,8 @@ struct LigatureEntry<true>
template <>
struct LigatureEntry<false>
{
typedef void EntryData;
enum Flags
{
SetComponent = 0x8000, /* Push this glyph onto the component stack for
@ -429,7 +449,8 @@ struct LigatureEntry<false>
* multiple of 4. */
};
typedef void EntryData;
static bool initiateAction (const Entry<EntryData> &entry)
{ return entry.flags & SetComponent; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
@ -447,13 +468,23 @@ struct LigatureSubtable
typedef LigatureEntry<Types::extended> LigatureEntryT;
typedef typename LigatureEntryT::EntryData EntryData;
enum Flags
{
DontAdvance = LigatureEntryT::DontAdvance,
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return LigatureEntryT::initiateAction (entry);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return LigatureEntryT::performAction (entry);
}
struct driver_context_t
{
static constexpr bool in_place = false;
enum
{
DontAdvance = LigatureEntryT::DontAdvance,
};
enum LigActionFlags
{
LigActionLast = 0x80000000, /* This is the last action in the list. This also
@ -476,14 +507,8 @@ struct LigatureSubtable
ligature (table+table->ligature),
match_length (0) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{
return LigatureEntryT::performAction (entry);
}
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
StateTableDriver<Types, EntryData, Flags> *driver,
const Entry<EntryData> &entry)
{
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
@ -564,7 +589,7 @@ struct LigatureSubtable
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE;
_hb_glyph_info_set_default_ignorable (&buffer->cur());
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
}
@ -581,9 +606,9 @@ struct LigatureSubtable
public:
bool ret;
private:
hb_aat_apply_context_t *c;
const LigatureSubtable *table;
private:
const UnsizedArrayOf<HBUINT32> &ligAction;
const UnsizedArrayOf<HBUINT16> &component;
const UnsizedArrayOf<HBGlyphID16> &ligature;
@ -597,11 +622,13 @@ struct LigatureSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->face);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
@ -638,6 +665,12 @@ struct NoncontextualSubtable
{
TRACE_APPLY (this);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
const OT::GDEF &gdef (*c->gdef_table);
bool has_glyph_classes = gdef.has_glyph_classes ();
@ -670,8 +703,9 @@ struct NoncontextualSubtable
const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
if (replacement)
{
info[i].codepoint = *replacement;
c->buffer_digest.add (*replacement);
hb_codepoint_t glyph = *replacement;
info[i].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&info[i],
gdef.get_glyph_props (*replacement));
@ -682,6 +716,12 @@ struct NoncontextualSubtable
return_trace (ret);
}
template <typename set_t>
void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs) const
{
substitute.collect_glyphs (glyphs, num_glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -715,73 +755,78 @@ struct InsertionSubtable
DEFINE_SIZE_STATIC (4);
};
enum Flags
{
SetMark = 0x8000, /* If set, mark the current glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. This does not mean
* that the glyph pointed to is the same one as
* before. If you've made insertions immediately
* downstream of the current glyph, the next glyph
* processed would in fact be the first one
* inserted. */
CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero,
* then the specified glyph list will be inserted
* as a kashida-like insertion, either before or
* after the current glyph (depending on the state
* of the currentInsertBefore flag). If clear, and
* the currentInsertList is nonzero, then the
* specified glyph list will be inserted as a
* split-vowel-like insertion, either before or
* after the current glyph (depending on the state
* of the currentInsertBefore flag). */
MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero,
* then the specified glyph list will be inserted
* as a kashida-like insertion, either before or
* after the marked glyph (depending on the state
* of the markedInsertBefore flag). If clear, and
* the markedInsertList is nonzero, then the
* specified glyph list will be inserted as a
* split-vowel-like insertion, either before or
* after the marked glyph (depending on the state
* of the markedInsertBefore flag). */
CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made
* to the left of the current glyph. If clear,
* they're made to the right of the current glyph. */
MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be
* made to the left of the marked glyph. If clear,
* they're made to the right of the marked glyph. */
CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the
* number of glyphs to insert at the current
* position. Since zero means no insertions, the
* largest number of insertions at any given
* current location is 31 glyphs. */
MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the
* number of glyphs to insert at the marked
* position. Since zero means no insertions, the
* largest number of insertions at any given
* marked location is 31 glyphs. */
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return (entry.flags & SetMark);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
}
struct driver_context_t
{
static constexpr bool in_place = false;
enum Flags
{
SetMark = 0x8000, /* If set, mark the current glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. This does not mean
* that the glyph pointed to is the same one as
* before. If you've made insertions immediately
* downstream of the current glyph, the next glyph
* processed would in fact be the first one
* inserted. */
CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero,
* then the specified glyph list will be inserted
* as a kashida-like insertion, either before or
* after the current glyph (depending on the state
* of the currentInsertBefore flag). If clear, and
* the currentInsertList is nonzero, then the
* specified glyph list will be inserted as a
* split-vowel-like insertion, either before or
* after the current glyph (depending on the state
* of the currentInsertBefore flag). */
MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero,
* then the specified glyph list will be inserted
* as a kashida-like insertion, either before or
* after the marked glyph (depending on the state
* of the markedInsertBefore flag). If clear, and
* the markedInsertList is nonzero, then the
* specified glyph list will be inserted as a
* split-vowel-like insertion, either before or
* after the marked glyph (depending on the state
* of the markedInsertBefore flag). */
CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made
* to the left of the current glyph. If clear,
* they're made to the right of the current glyph. */
MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be
* made to the left of the marked glyph. If clear,
* they're made to the right of the marked glyph. */
CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the
* number of glyphs to insert at the current
* position. Since zero means no insertions, the
* largest number of insertions at any given
* current location is 31 glyphs. */
MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the
* number of glyphs to insert at the marked
* position. Since zero means no insertions, the
* largest number of insertions at any given
* marked location is 31 glyphs. */
};
driver_context_t (const InsertionSubtable *table,
driver_context_t (const InsertionSubtable *table_,
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
table (table_),
mark (0),
insertionAction (table+table->insertionAction) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
}
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
StateTableDriver<Types, EntryData, Flags> *driver,
const Entry<EntryData> &entry)
{
unsigned int flags = entry.flags;
@ -807,7 +852,7 @@ struct InsertionSubtable
/* TODO We ignore KashidaLike setting. */
if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
for (unsigned int i = 0; i < count; i++)
c->buffer_digest.add (glyphs[i]);
c->buffer_glyph_set.add (glyphs[i]);
ret = true;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@ -861,8 +906,9 @@ struct InsertionSubtable
public:
bool ret;
private:
hb_aat_apply_context_t *c;
const InsertionSubtable *table;
private:
unsigned int mark;
const UnsizedArrayOf<HBGlyphID16> &insertionAction;
};
@ -873,11 +919,13 @@ struct InsertionSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->face);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
@ -935,24 +983,33 @@ struct hb_accelerate_subtables_context_t :
friend struct hb_aat_layout_lookup_accelerator_t;
public:
hb_set_digest_t digest;
hb_bit_set_t glyph_set;
mutable hb_aat_class_cache_t class_cache;
template <typename T>
auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
(
obj_.machine.collect_glyphs (this->digest, num_glyphs)
obj_.machine.collect_initial_glyphs (glyph_set, num_glyphs, obj_)
)
template <typename T>
void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
{
digest = digest.full ();
obj_.collect_initial_glyphs (glyph_set, num_glyphs);
}
template <typename T>
void init (const T &obj_, unsigned num_glyphs)
{
glyph_set.init ();
init_ (obj_, num_glyphs, hb_prioritize);
class_cache.clear ();
}
void
fini ()
{
glyph_set.fini ();
}
};
@ -999,12 +1056,21 @@ struct hb_aat_layout_chain_accelerator_t
if (unlikely (!thiz))
return nullptr;
thiz->count = count;
hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
chain.dispatch (&c_accelerate_subtables);
return thiz;
}
void destroy ()
{
for (unsigned i = 0; i < count; i++)
subtables[i].fini ();
}
unsigned count;
hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
};
@ -1152,15 +1218,19 @@ struct Chain
{
bool reverse;
if (hb_none (hb_iter (c->range_flags) |
hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
goto skip;
c->subtable_flags = subtable->subFeatureFlags;
c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full ();
auto coverage = subtable->get_coverage ();
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
hb_mask_t subtable_flags = subtable->subFeatureFlags;
if (hb_none (hb_iter (c->range_flags) |
hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
goto skip;
c->subtable_flags = subtable_flags;
c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
if (!(coverage & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
bool (coverage & ChainSubtable<Types>::Vertical))
goto skip;
/* Buffer contents is always in logical direction. Determine if
@ -1190,9 +1260,9 @@ struct Chain
(the order opposite that of the characters, which
may be right-to-left or left-to-right).
*/
reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
reverse = coverage & ChainSubtable<Types>::Logical ?
bool (coverage & ChainSubtable<Types>::Backwards) :
bool (coverage & ChainSubtable<Types>::Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
@ -1298,6 +1368,12 @@ struct mortmorx
hb_sanitize_context_t sc;
this->table = sc.reference_table<T> (face);
if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
{
hb_blob_destroy (this->table.get_blob ());
this->table = hb_blob_get_empty ();
}
this->chain_count = table->get_chain_count ();
this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
@ -1311,7 +1387,11 @@ struct mortmorx
~accelerator_t ()
{
for (unsigned int i = 0; i < this->chain_count; i++)
{
if (this->accels[i])
this->accels[i]->destroy ();
hb_free (this->accels[i]);
}
hb_free (this->accels);
this->table.destroy ();
}
@ -1365,9 +1445,8 @@ struct mortmorx
unsigned get_chain_count () const
{
return chainCount;
return chainCount;
}
void apply (hb_aat_apply_context_t *c,
const hb_aat_map_t &map,
const accelerator_t &accel) const
@ -1376,10 +1455,7 @@ struct mortmorx
c->buffer->unsafe_to_concat ();
if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
c->buffer_digest = c->buffer->digest ();
else
c->buffer_digest = hb_set_digest_t::full ();
c->setup_buffer_glyph_set ();
c->set_lookup_index (0);
const Chain<Types> *chain = &firstChain;
@ -1428,8 +1504,17 @@ struct mortmorx
DEFINE_SIZE_MIN (8);
};
struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {};
struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {};
struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx>
{
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
};
struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort>
{
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
};
struct morx_accelerator_t : morx::accelerator_t {
morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}

View file

@ -48,17 +48,69 @@ struct TrackTableEntry
float get_track_value () const { return track.to_float (); }
int get_value (const void *base, unsigned int index,
unsigned int table_size) const
{ return (base+valuesZ).as_array (table_size)[index]; }
float interpolate_at (unsigned int idx,
float ptem,
const void *base,
hb_array_t<const F16DOT16> size_table) const
{
const FWORD *values = (base+valuesZ).arrayZ;
float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float ();
int v0 = values[idx];
int v1 = values[idx + 1];
// Deal with font bugs.
if (unlikely (s1 < s0))
{ hb_swap (s0, s1); hb_swap (v0, v1); }
if (unlikely (ptem < s0)) return v0;
if (unlikely (ptem > s1)) return v1;
if (unlikely (s0 == s1)) return (v0 + v1) * 0.5f;
float t = (ptem - s0) / (s1 - s0);
return v0 + t * (v1 - v0);
}
float get_value (float ptem,
const void *base,
hb_array_t<const F16DOT16> size_table) const
{
const FWORD *values = (base+valuesZ).arrayZ;
unsigned int n_sizes = size_table.length;
/*
* Choose size.
*/
if (!n_sizes) return 0.f;
if (n_sizes == 1) return values[0];
// At least two entries.
unsigned i;
for (i = 0; i < n_sizes; i++)
if (size_table[i].to_float () >= ptem)
break;
// Boundary conditions.
if (i == 0) return values[0];
if (i == n_sizes) return values[n_sizes - 1];
// Exact match.
if (size_table[i].to_float () == ptem) return values[i];
// Interpolate.
return interpolate_at (i - 1, ptem, base, size_table);
}
public:
bool sanitize (hb_sanitize_context_t *c, const void *base,
unsigned int table_size) const
bool sanitize (hb_sanitize_context_t *c,
const void *base,
unsigned int n_sizes) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(valuesZ.sanitize (c, base, table_size))));
(valuesZ.sanitize (c, base, n_sizes))));
}
protected:
@ -76,58 +128,38 @@ struct TrackTableEntry
struct TrackData
{
float interpolate_at (unsigned int idx,
float target_size,
const TrackTableEntry &trackTableEntry,
const void *base) const
float get_tracking (const void *base, float ptem, float track = 0.f) const
{
unsigned int sizes = nSizes;
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
unsigned count = nTracks;
hb_array_t<const F16DOT16> size_table = (base+sizeTable).as_array (nSizes);
float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float ();
float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
return t * trackTableEntry.get_value (base, idx + 1, sizes) +
(1.f - t) * trackTableEntry.get_value (base, idx, sizes);
}
if (!count) return 0.f;
if (count == 1) return trackTable[0].get_value (ptem, base, size_table);
int get_tracking (const void *base, float ptem) const
{
/*
* Choose track.
*/
const TrackTableEntry *trackTableEntry = nullptr;
unsigned int count = nTracks;
for (unsigned int i = 0; i < count; i++)
{
/* Note: Seems like the track entries are sorted by values. But the
* spec doesn't explicitly say that. It just mentions it in the example. */
// At least two entries.
/* For now we only seek for track entries with zero tracking value */
unsigned i = 0;
unsigned j = count - 1;
if (trackTable[i].get_track_value () == 0.f)
{
trackTableEntry = &trackTable[i];
break;
}
}
if (!trackTableEntry) return 0;
// Find the two entries that track is between.
while (i + 1 < count && trackTable[i + 1].get_track_value () < track)
i++;
while (j > 0 && trackTable[j - 1].get_track_value () > track)
j--;
/*
* Choose size.
*/
unsigned int sizes = nSizes;
if (!sizes) return 0;
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
// Exact match.
if (i == j) return trackTable[i].get_value (ptem, base, size_table);
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
unsigned int size_index;
for (size_index = 0; size_index < sizes - 1; size_index++)
if (size_table[size_index].to_float () >= ptem)
break;
// Interpolate.
return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
*trackTableEntry, base));
float t0 = trackTable[i].get_track_value ();
float t1 = trackTable[j].get_track_value ();
float t = (track - t0) / (t1 - t0);
float a = trackTable[i].get_value (ptem, base, size_table);
float b = trackTable[j].get_value (ptem, base, size_table);
return a + t * (b - a);
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
@ -158,45 +190,15 @@ struct trak
bool has_data () const { return version.to_int (); }
bool apply (hb_aat_apply_context_t *c) const
hb_position_t get_h_tracking (hb_font_t *font, float track = 0.f) const
{
TRACE_APPLY (this);
hb_mask_t trak_mask = c->plan->trak_mask;
const float ptem = c->font->ptem;
if (unlikely (ptem <= 0.f))
return_trace (false);
hb_buffer_t *buffer = c->buffer;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
const TrackData &trackData = this+horizData;
int tracking = trackData.get_tracking (this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
foreach_grapheme (buffer, start, end)
{
if (!(buffer->info[start].mask & trak_mask)) continue;
buffer->pos[start].x_advance += advance_to_add;
buffer->pos[start].x_offset += offset_to_add;
}
}
else
{
const TrackData &trackData = this+vertData;
int tracking = trackData.get_tracking (this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
foreach_grapheme (buffer, start, end)
{
if (!(buffer->info[start].mask & trak_mask)) continue;
buffer->pos[start].y_advance += advance_to_add;
buffer->pos[start].y_offset += offset_to_add;
}
}
return_trace (true);
float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE;
return font->em_scalef_x ((this+horizData).get_tracking (this, ptem, track));
}
hb_position_t get_v_tracking (hb_font_t *font, float track = 0.f) const
{
float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE;
return font->em_scalef_y ((this+vertData).get_tracking (this, ptem, track));
}
bool sanitize (hb_sanitize_context_t *c) const

View file

@ -34,9 +34,12 @@
#include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-trak-table.hh"
#include "hb-aat-layout-trak-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-ltag-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gdef-table.hh"
/*
* hb_aat_apply_context_t
@ -207,6 +210,36 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
*/
bool
AAT::morx::is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const
{
#ifdef HB_NO_AAT_LAYOUT_BLOCKLIST
return false;
#endif
switch HB_CODEPOINT_ENCODE3 (blob->length,
face->table.GSUB->table.get_length (),
face->table.GDEF->table.get_length ())
{
/* https://github.com/harfbuzz/harfbuzz/issues/4108
sha1sum:a71ca6813b7e56a772cffff7c24a5166b087197c AALMAGHRIBI.ttf */
case HB_CODEPOINT_ENCODE3 (19892, 2794, 340):
return true;
}
return false;
}
bool
AAT::mort::is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const
{
#ifdef HB_NO_AAT_LAYOUT_BLOCKLIST
return false;
#endif
return false;
}
void
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map)
@ -361,17 +394,6 @@ hb_aat_layout_has_tracking (hb_face_t *face)
return face->table.trak->has_data ();
}
void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
const AAT::trak& trak = *font->face->table.trak;
AAT::hb_aat_apply_context_t c (plan, font, buffer);
trak.apply (&c);
}
/**
* hb_aat_layout_get_feature_types:
* @face: #hb_face_t to work upon

View file

@ -32,6 +32,9 @@
#include "hb-ot-shape.hh"
#include "hb-aat-ltag-table.hh"
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
struct hb_aat_feature_mapping_t
{
hb_tag_t otFeatureTag;
@ -68,10 +71,5 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
#endif /* HB_AAT_LAYOUT_HH */

View file

@ -88,22 +88,23 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m)
/* Sort features by start/end events. */
hb_vector_t<feature_event_t> feature_events;
feature_events.alloc_exact (features.length * 2 + 1);
for (unsigned int i = 0; i < features.length; i++)
{
auto &feature = features[i];
auto &feature = features.arrayZ[i];
if (features[i].start == features[i].end)
if (feature.start == feature.end)
continue;
feature_event_t *event;
event = feature_events.push ();
event->index = features[i].start;
event->index = feature.start;
event->start = true;
event->feature = feature.info;
event = feature_events.push ();
event->index = features[i].end;
event->index = feature.end;
event->start = false;
event->feature = feature.info;
}
@ -139,12 +140,12 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m)
current_features.qsort ();
unsigned int j = 0;
for (unsigned int i = 1; i < current_features.length; i++)
if (current_features[i].type != current_features[j].type ||
if (current_features.arrayZ[i].type != current_features.arrayZ[j].type ||
/* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
* respectively, so we mask out the low-order bit when checking for "duplicates"
* (selectors referring to the same feature setting) here. */
(!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1))))
current_features[++j] = current_features[i];
(!current_features.arrayZ[i].is_exclusive && ((current_features.arrayZ[i].setting & ~1) != (current_features.arrayZ[j].setting & ~1))))
current_features.arrayZ[++j] = current_features.arrayZ[i];
current_features.shrink (j + 1);
}

View file

@ -286,7 +286,7 @@ HB_FUNCOBJ (hb_bool);
// Compression function for Merkle-Damgard construction.
// This function is generated using the framework provided.
#define mix(h) ( \
#define fasthash_mix(h) ( \
(void) ((h) ^= (h) >> 23), \
(void) ((h) *= 0x2127599bf4325c37ULL), \
(h) ^= (h) >> 47)
@ -310,7 +310,7 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
#pragma GCC diagnostic ignored "-Wcast-align"
v = * (const uint64_t *) (pos++);
#pragma GCC diagnostic pop
h ^= mix(v);
h ^= fasthash_mix(v);
h *= m;
}
}
@ -320,7 +320,7 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
while (pos != end)
{
v = pos++->v;
h ^= mix(v);
h ^= fasthash_mix(v);
h *= m;
}
}
@ -336,11 +336,11 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH;
case 2: v ^= (uint64_t)pos2[1] << 8; HB_FALLTHROUGH;
case 1: v ^= (uint64_t)pos2[0];
h ^= mix(v);
h ^= fasthash_mix(v);
h *= m;
}
return mix(h);
return fasthash_mix(h);
}
static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed)

View file

@ -251,7 +251,8 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
if (end < start + 2)
return;
for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--)
unsigned stop = start + (end - start) / 2;
for (unsigned lhs = start, rhs = end - 1; lhs < stop; lhs++, rhs--)
hb_swap (arrayZ[rhs], arrayZ[lhs]);
}

View file

@ -212,6 +212,7 @@ struct hb_atomic_ptr_t
T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
operator bool () const { return get_acquire () != nullptr; }
T * operator -> () const { return get_acquire (); }
template <typename C> operator C * () const { return get_acquire (); }

View file

@ -78,6 +78,28 @@ struct hb_vector_size_t
hb_vector_size_t operator ~ () const
{ return process (hb_bitwise_neg); }
operator bool () const
{
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
if (v[i])
return true;
return false;
}
operator unsigned int () const
{
unsigned int r = 0;
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
r += hb_popcount (v[i]);
return r;
}
bool operator == (const hb_vector_size_t &o) const
{
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
if (v[i] != o.v[i])
return false;
return true;
}
hb_array_t<const elt_t> iter () const
{ return hb_array (v); }
@ -89,6 +111,8 @@ struct hb_vector_size_t
struct hb_bit_page_t
{
hb_bit_page_t () { init0 (); }
void init0 () { v.init0 (); population = 0; }
void init1 () { v.init1 (); population = PAGE_BITS; }
@ -101,10 +125,9 @@ struct hb_bit_page_t
bool is_empty () const
{
if (has_population ()) return !population;
return
+ hb_iter (v)
| hb_none
;
bool empty = !v;
if (empty) population = 0;
return empty;
}
uint32_t hash () const
{
@ -115,6 +138,10 @@ struct hb_bit_page_t
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); }
void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
bool may_have (hb_codepoint_t g) const { return get (g); }
bool operator [] (hb_codepoint_t g) const { return get (g); }
bool operator () (hb_codepoint_t g) const { return get (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
@ -220,13 +247,17 @@ struct hb_bit_page_t
}
bool operator == (const hb_bit_page_t &other) const { return is_equal (other); }
bool is_equal (const hb_bit_page_t &other) const
bool is_equal (const hb_bit_page_t &other) const { return v == other.v; }
bool intersects (const hb_bit_page_t &other) const
{
for (unsigned i = 0; i < len (); i++)
if (v[i] != other.v[i])
return false;
return true;
if (v[i] & other.v[i])
return true;
return false;
}
bool may_intersect (const hb_bit_page_t &other) const
{ return intersects (other); }
bool operator <= (const hb_bit_page_t &larger_page) const { return is_subset (larger_page); }
bool is_subset (const hb_bit_page_t &larger_page) const
{
@ -241,14 +272,10 @@ struct hb_bit_page_t
}
bool has_population () const { return population != UINT_MAX; }
unsigned int get_population () const
unsigned get_population () const
{
if (has_population ()) return population;
population =
+ hb_iter (v)
| hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u)
;
return population;
return population = v;
}
bool next (hb_codepoint_t *codepoint) const

View file

@ -126,6 +126,7 @@ struct hb_bit_set_invertible_t
{ unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); }
bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
bool may_have (hb_codepoint_t g) const { return get (g); }
/* Has interface. */
bool operator [] (hb_codepoint_t k) const { return get (k); }
@ -139,6 +140,9 @@ struct hb_bit_set_invertible_t
hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool may_intersect (const hb_bit_set_invertible_t &other) const
{ return inverted || other.inverted || s.intersects (other.s); }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
{
hb_codepoint_t c = first - 1;

View file

@ -88,10 +88,11 @@ struct hb_bit_set_t
{
if (unlikely (!successful)) return false;
if (pages.length == 0 && count == 1)
if (pages.length < count && count <= 2)
exact_size = true; // Most sets are small and local
if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size)))
if (unlikely (!pages.resize (count, clear, exact_size) ||
!page_map.resize (count, clear)))
{
pages.resize (page_map.length, clear, exact_size);
successful = false;
@ -297,9 +298,9 @@ struct hb_bit_set_t
unsigned int write_index = 0;
for (unsigned int i = 0; i < page_map.length; i++)
{
int m = (int) page_map[i].major;
int m = (int) page_map.arrayZ[i].major;
if (m < ds || de < m)
page_map[write_index++] = page_map[i];
page_map.arrayZ[write_index++] = page_map.arrayZ[i];
}
compact (compact_workspace, write_index);
resize (write_index);
@ -345,6 +346,7 @@ struct hb_bit_set_t
return false;
return page->get (g);
}
bool may_have (hb_codepoint_t g) const { return get (g); }
/* Has interface. */
bool operator [] (hb_codepoint_t k) const { return get (k); }
@ -358,6 +360,31 @@ struct hb_bit_set_t
hb_bit_set_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (const hb_bit_set_t &other) const
{
unsigned int na = pages.length;
unsigned int nb = other.pages.length;
unsigned int a = 0, b = 0;
for (; a < na && b < nb; )
{
if (page_map.arrayZ[a].major == other.page_map.arrayZ[b].major)
{
if (page_at (a).intersects (other.page_at (b)))
return true;
a++;
b++;
}
else if (page_map.arrayZ[a].major < other.page_map.arrayZ[b].major)
a++;
else
b++;
}
return false;
}
bool may_intersect (const hb_bit_set_t &other) const
{ return intersects (other); }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
{
hb_codepoint_t c = first - 1;
@ -389,7 +416,7 @@ struct hb_bit_set_t
{
if (page_at (a).is_empty ()) { a++; continue; }
if (other.page_at (b).is_empty ()) { b++; continue; }
if (page_map[a].major != other.page_map[b].major ||
if (page_map.arrayZ[a].major != other.page_map.arrayZ[b].major ||
!page_at (a).is_equal (other.page_at (b)))
return false;
a++;
@ -412,8 +439,8 @@ struct hb_bit_set_t
uint32_t spi = 0;
for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
{
uint32_t spm = page_map[spi].major;
uint32_t lpm = larger_set.page_map[lpi].major;
uint32_t spm = page_map.arrayZ[spi].major;
uint32_t lpm = larger_set.page_map.arrayZ[lpi].major;
auto sp = page_at (spi);
if (spm < lpm && !sp.is_empty ())
@ -503,7 +530,7 @@ struct hb_bit_set_t
for (; a < na && b < nb; )
{
if (page_map[a].major == other.page_map[b].major)
if (page_map.arrayZ[a].major == other.page_map.arrayZ[b].major)
{
if (!passthru_left)
{
@ -512,7 +539,7 @@ struct hb_bit_set_t
// passthru_left is set since no left side pages will be removed
// in that case.
if (write_index < a)
page_map[write_index] = page_map[a];
page_map.arrayZ[write_index] = page_map.arrayZ[a];
write_index++;
}
@ -520,7 +547,7 @@ struct hb_bit_set_t
a++;
b++;
}
else if (page_map[a].major < other.page_map[b].major)
else if (page_map.arrayZ[a].major < other.page_map.arrayZ[b].major)
{
if (passthru_left)
count++;
@ -765,8 +792,8 @@ struct hb_bit_set_t
unsigned int initial_size = size;
for (unsigned int i = start_page; i < page_map.length && size; i++)
{
uint32_t base = major_start (page_map[i].major);
unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size);
uint32_t base = major_start (page_map.arrayZ[i].major);
unsigned int n = pages[page_map.arrayZ[i].index].write (base, start_page_value, out, size);
out += n;
size -= n;
start_page_value = 0;
@ -814,8 +841,8 @@ struct hb_bit_set_t
hb_codepoint_t next_value = codepoint + 1;
for (unsigned int i=start_page; i<page_map.length && size; i++)
{
uint32_t base = major_start (page_map[i].major);
unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value);
uint32_t base = major_start (page_map.arrayZ[i].major);
unsigned int n = pages[page_map.arrayZ[i].index].write_inverted (base, start_page_value, out, size, &next_value);
out += n;
size -= n;
start_page_value = 0;
@ -846,8 +873,8 @@ struct hb_bit_set_t
unsigned count = pages.length;
for (unsigned i = 0; i < count; i++)
{
const auto& map = page_map[i];
const auto& page = pages[map.index];
const auto& map = page_map.arrayZ[i];
const auto& page = pages.arrayZ[map.index];
if (!page.is_empty ())
return map.major * page_t::PAGE_BITS + page.get_min ();
@ -859,8 +886,8 @@ struct hb_bit_set_t
unsigned count = pages.length;
for (signed i = count - 1; i >= 0; i--)
{
const auto& map = page_map[(unsigned) i];
const auto& page = pages[map.index];
const auto& map = page_map.arrayZ[(unsigned) i];
const auto& page = pages.arrayZ[map.index];
if (!page.is_empty ())
return map.major * page_t::PAGE_BITS + page.get_max ();
@ -961,7 +988,7 @@ struct hb_bit_set_t
return nullptr;
last_page_lookup = i;
return &pages.arrayZ[page_map[i].index];
return &pages.arrayZ[page_map.arrayZ[i].index];
}
page_t &page_at (unsigned int i)
{

View file

@ -34,36 +34,36 @@
#line 36 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = {
0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
0u, 0u, 9u, 123u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u,
9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u,
9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u,
34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u,
9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u,
9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u,
9u, 123u, 0u, 0u, 0
9u, 93u, 9u, 123u, 0u, 0u, 0
};
static const char _deserialize_json_key_spans[] = {
0, 115, 26, 21, 2, 1, 50, 49,
10, 117, 117, 85, 117, 1, 50, 49,
0, 115, 115, 26, 21, 2, 1, 50,
49, 10, 117, 117, 117, 1, 50, 49,
10, 117, 117, 1, 1, 50, 49, 117,
117, 2, 1, 50, 49, 10, 117, 117,
1, 50, 49, 10, 117, 117, 1, 1,
50, 49, 117, 117, 1, 50, 49, 59,
117, 59, 117, 117, 1, 50, 49, 117,
115, 0
85, 115, 0
};
static const short _deserialize_json_index_offsets[] = {
0, 0, 116, 143, 165, 168, 170, 221,
271, 282, 400, 518, 604, 722, 724, 775,
825, 836, 954, 1072, 1074, 1076, 1127, 1177,
1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648,
1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118,
2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560,
2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137,
3255, 3371
0, 0, 116, 232, 259, 281, 284, 286,
337, 387, 398, 516, 634, 752, 754, 805,
855, 866, 984, 1102, 1104, 1106, 1157, 1207,
1325, 1443, 1446, 1448, 1499, 1549, 1560, 1678,
1796, 1798, 1849, 1899, 1910, 2028, 2146, 2148,
2150, 2201, 2251, 2369, 2487, 2489, 2540, 2590,
2650, 2768, 2828, 2946, 3064, 3066, 3117, 3167,
3285, 3371, 3487
};
static const char _deserialize_json_indicies[] = {
@ -77,51 +77,51 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 3, 1, 2, 2, 2,
2, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 3, 3, 3,
3, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 3, 1, 4, 1,
5, 1, 6, 7, 1, 8, 9, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 10, 1, 11, 12,
1, 13, 1, 13, 13, 13, 13, 13,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 13, 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, 14, 1, 14, 14,
14, 14, 14, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 14, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 15, 1, 1, 16, 17, 17,
17, 17, 17, 17, 17, 17, 17, 1,
18, 19, 19, 19, 19, 19, 19, 19,
19, 19, 1, 20, 20, 20, 20, 20,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 20, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 3,
1, 4, 4, 4, 4, 4, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
4, 1, 5, 1, 6, 1, 7, 8,
1, 9, 10, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
11, 1, 12, 13, 1, 14, 1, 14,
14, 14, 14, 14, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 14, 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,
15, 1, 15, 15, 15, 15, 15, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 15, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 16, 1,
1, 17, 18, 18, 18, 18, 18, 18,
18, 18, 18, 1, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 1, 21,
21, 21, 21, 21, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 21, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 22,
1, 23, 23, 23, 23, 23, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
23, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 3, 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, 1, 1, 1,
@ -131,24 +131,55 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 24, 1, 25,
25, 25, 25, 25, 1, 1, 1, 1,
1, 1, 1, 23, 1, 24, 24, 24,
24, 24, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 24, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
4, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 25, 1, 21, 21, 21, 21, 21,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 21, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 22, 1,
1, 1, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 23,
1, 26, 1, 26, 26, 26, 26, 26,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 25, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 26, 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, 27, 1, 27, 27,
27, 27, 27, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 27, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 28, 1, 1, 29, 30, 30,
30, 30, 30, 30, 30, 30, 30, 1,
31, 32, 32, 32, 32, 32, 32, 32,
32, 32, 1, 33, 33, 33, 33, 33,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 27, 1, 20, 20, 20,
20, 20, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 20, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
21, 1, 1, 1, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 1, 1,
1, 1, 33, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 34, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@ -157,26 +188,15 @@ static const char _deserialize_json_indicies[] = {
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, 22, 1, 28, 1, 28, 28, 28,
28, 28, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 28, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 35,
1, 33, 33, 33, 33, 33, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 29, 1,
29, 29, 29, 29, 29, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 29,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 30, 1, 1, 31,
33, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 34, 1, 1, 1,
32, 32, 32, 32, 32, 32, 32, 32,
32, 1, 33, 34, 34, 34, 34, 34,
34, 34, 34, 34, 1, 35, 35, 35,
35, 35, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 35, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
36, 1, 1, 1, 1, 1, 1, 1,
32, 32, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@ -184,41 +204,25 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 35, 1, 36,
1, 37, 1, 37, 37, 37, 37, 37,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 37, 1, 35, 35, 35, 35, 35,
1, 1, 37, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 35, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 36, 1,
1, 1, 34, 34, 34, 34, 34, 34,
34, 34, 34, 34, 1, 1, 1, 1,
1, 1, 1, 1, 38, 1, 38, 38,
38, 38, 38, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 38, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 37,
1, 38, 1, 39, 1, 39, 39, 39,
39, 39, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 39, 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, 40, 1,
40, 40, 40, 40, 40, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 40,
1, 1, 1, 1, 1, 39, 40, 40,
40, 40, 40, 40, 40, 40, 40, 1,
41, 41, 41, 41, 41, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 41,
42, 42, 42, 42, 42, 42, 42, 42,
42, 1, 43, 43, 43, 43, 43, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 43, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 44, 1, 1,
1, 1, 1, 42, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@ -228,14 +232,13 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 45, 1,
43, 43, 43, 43, 43, 1, 1, 1,
1, 1, 1, 1, 43, 1, 41, 41,
41, 41, 41, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 43,
1, 1, 1, 1, 1, 41, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 44, 1, 1, 1, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 1, 1, 1, 1, 1, 1, 1,
1, 42, 1, 1, 1, 44, 44, 44,
44, 44, 44, 44, 44, 44, 44, 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,
@ -243,86 +246,116 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 45, 1, 47, 48,
1, 49, 1, 49, 49, 49, 49, 49,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 43, 1, 45, 46, 1, 47,
1, 47, 47, 47, 47, 47, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 49, 1, 1, 1, 1, 1,
47, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 50, 1, 50, 50,
50, 50, 50, 1, 1, 1, 1, 1,
1, 1, 48, 1, 48, 48, 48, 48,
48, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 50, 1, 1,
1, 1, 1, 48, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 51, 1, 1, 52, 53, 53,
53, 53, 53, 53, 53, 53, 53, 1,
54, 55, 55, 55, 55, 55, 55, 55,
55, 55, 1, 56, 56, 56, 56, 56,
49, 1, 1, 50, 51, 51, 51, 51,
51, 51, 51, 51, 51, 1, 52, 53,
53, 53, 53, 53, 53, 53, 53, 53,
1, 54, 54, 54, 54, 54, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 56, 1, 1, 1, 1, 1,
54, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 55, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 56, 1, 54,
54, 54, 54, 54, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 54, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 55, 1, 1, 1, 53, 53,
53, 53, 53, 53, 53, 53, 53, 53,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 56, 1, 57, 1, 57,
57, 57, 57, 57, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 57, 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,
58, 1, 58, 58, 58, 58, 58, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 58, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 59, 1,
1, 60, 61, 61, 61, 61, 61, 61,
61, 61, 61, 1, 62, 63, 63, 63,
63, 63, 63, 63, 63, 63, 1, 64,
64, 64, 64, 64, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 64, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 65, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 58,
1, 56, 56, 56, 56, 56, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
56, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 57, 1, 1, 1,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 66, 1, 64, 64, 64,
64, 64, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 64, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 58, 1, 59,
1, 59, 59, 59, 59, 59, 1, 1,
65, 1, 1, 1, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
59, 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, 60, 1, 60, 60, 60, 60,
60, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 60, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
61, 1, 1, 62, 63, 63, 63, 63,
63, 63, 63, 63, 63, 1, 64, 65,
65, 65, 65, 65, 65, 65, 65, 65,
1, 66, 66, 66, 66, 66, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
66, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 67, 1, 1, 1,
1, 66, 1, 67, 1, 68, 1, 68,
68, 68, 68, 68, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 68, 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,
69, 1, 69, 69, 69, 69, 69, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 69, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 70, 71, 71, 71, 71, 71, 71,
71, 71, 71, 1, 72, 72, 72, 72,
72, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 72, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 73,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 68, 1, 66,
66, 66, 66, 66, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 66, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 67, 1, 1, 1, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@ -330,42 +363,48 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
74, 1, 72, 72, 72, 72, 72, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 68, 1, 69, 1, 70,
1, 70, 70, 70, 70, 70, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 72, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 73, 1, 1,
1, 75, 75, 75, 75, 75, 75, 75,
75, 75, 75, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
70, 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, 71, 1, 71, 71, 71, 71,
71, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 71, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 72, 73, 73, 73, 73,
73, 73, 73, 73, 73, 1, 74, 74,
74, 74, 74, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 74, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 75, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 74, 1,
76, 1, 76, 76, 76, 76, 76, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 76, 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, 77, 1, 77, 77, 77,
77, 77, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 77, 1, 78, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 79, 80, 80, 80,
80, 80, 80, 80, 80, 80, 1, 82,
81, 81, 81, 81, 81, 81, 81, 81,
81, 81, 81, 81, 81, 81, 81, 81,
81, 81, 81, 81, 81, 81, 81, 81,
81, 81, 81, 81, 81, 81, 81, 81,
81, 81, 81, 81, 81, 81, 81, 81,
81, 81, 81, 81, 81, 81, 81, 81,
81, 81, 81, 81, 81, 81, 81, 81,
81, 83, 81, 84, 84, 84, 84, 84,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 84, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 85, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 76, 1, 74, 74, 74, 74,
74, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 74, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 75,
1, 1, 1, 77, 77, 77, 77, 77,
77, 77, 77, 77, 77, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@ -373,34 +412,20 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 86,
1, 81, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
76, 1, 78, 1, 78, 78, 78, 78,
78, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 78, 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, 79, 1, 79,
79, 79, 79, 79, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 79, 1,
80, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 81, 82,
82, 82, 82, 82, 82, 82, 82, 82,
1, 84, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 85, 83, 86, 86, 86,
86, 86, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 86, 1, 1, 1,
1, 1, 1, 81, 1, 87, 87, 87,
87, 87, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
87, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 87, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
88, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@ -409,63 +434,65 @@ static const char _deserialize_json_indicies[] = {
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, 88, 1, 83, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 89, 1, 87, 87, 87, 87, 87,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 87, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 88, 1,
1, 1, 90, 90, 90, 90, 90, 90,
90, 90, 90, 90, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 83, 1, 89,
89, 89, 89, 89, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 89, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 90, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 89,
1, 91, 1, 91, 91, 91, 91, 91,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 91, 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, 92, 1, 92, 92,
92, 92, 92, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 92, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 93, 94, 94,
94, 94, 94, 94, 94, 94, 94, 1,
87, 87, 87, 87, 87, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 91, 1, 89, 89, 89,
89, 89, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 87,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 89, 1, 1, 1,
1, 1, 1, 88, 1, 1, 1, 95,
95, 95, 95, 95, 95, 95, 95, 95,
95, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
90, 1, 1, 1, 92, 92, 92, 92,
92, 92, 92, 92, 92, 92, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 89, 1, 96, 96,
96, 96, 96, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 96, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 91, 1, 93, 1, 93, 93, 93,
93, 93, 1, 1, 1, 1, 1, 1,
1, 97, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 93, 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, 94, 1,
94, 94, 94, 94, 94, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 94,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 95,
96, 96, 96, 96, 96, 96, 96, 96,
96, 1, 89, 89, 89, 89, 89, 1,
1, 1, 98, 1, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 89, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 90, 1, 1,
1, 97, 97, 97, 97, 97, 97, 97,
97, 97, 97, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@ -473,54 +500,42 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 91, 1,
0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 1, 1, 0
1, 1, 1, 1, 1, 1, 3, 1,
1, 0
};
static const char _deserialize_json_trans_targs[] = {
1, 0, 2, 2, 3, 4, 19, 25,
38, 44, 52, 5, 13, 6, 7, 8,
9, 12, 9, 12, 10, 2, 11, 10,
11, 11, 56, 57, 14, 15, 16, 17,
18, 17, 18, 10, 2, 11, 20, 21,
22, 23, 24, 10, 2, 11, 24, 26,
32, 27, 28, 29, 30, 31, 30, 31,
10, 2, 11, 33, 34, 35, 36, 37,
36, 37, 10, 2, 11, 39, 40, 41,
42, 43, 10, 2, 11, 43, 45, 46,
47, 50, 51, 47, 48, 49, 10, 2,
11, 10, 2, 11, 51, 53, 54, 50,
55, 55
1, 0, 2, 3, 3, 4, 5, 19,
25, 38, 44, 52, 6, 13, 7, 8,
9, 10, 12, 10, 12, 11, 3, 56,
11, 56, 14, 15, 16, 17, 18, 17,
18, 11, 3, 56, 20, 21, 22, 23,
24, 11, 3, 56, 24, 26, 32, 27,
28, 29, 30, 31, 30, 31, 11, 3,
56, 33, 34, 35, 36, 37, 36, 37,
11, 3, 56, 39, 40, 41, 42, 43,
11, 3, 56, 43, 45, 46, 47, 50,
51, 47, 48, 49, 11, 3, 56, 11,
3, 56, 51, 53, 54, 50, 55, 55,
56, 57, 58
};
static const char _deserialize_json_trans_actions[] = {
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2,
2, 2, 0, 0, 3, 3, 4, 0,
5, 0, 0, 0, 0, 0, 2, 2,
2, 0, 0, 6, 6, 7, 0, 0,
0, 2, 2, 8, 8, 9, 0, 0,
0, 0, 0, 2, 2, 2, 0, 0,
10, 10, 11, 0, 0, 2, 2, 2,
0, 0, 12, 12, 13, 0, 0, 0,
2, 2, 14, 14, 15, 0, 0, 0,
2, 16, 16, 0, 17, 0, 18, 18,
19, 20, 20, 21, 17, 0, 0, 22,
22, 23
0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 0, 0, 3, 3, 4,
0, 5, 0, 0, 2, 2, 2, 0,
0, 6, 6, 7, 0, 0, 0, 2,
2, 8, 8, 9, 0, 0, 0, 0,
0, 2, 2, 2, 0, 0, 10, 10,
11, 0, 0, 2, 2, 2, 0, 0,
12, 12, 13, 0, 0, 0, 2, 2,
14, 14, 15, 0, 0, 0, 2, 16,
16, 0, 17, 0, 18, 18, 19, 20,
20, 21, 17, 0, 0, 22, 22, 23,
0, 0, 0
};
static const int deserialize_json_start = 1;
@ -545,22 +560,17 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? ',' : '['))
*end_ptr = ++p;
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
#line 559 "hb-buffer-deserialize-json.hh"
#line 569 "hb-buffer-deserialize-json.hh"
{
cs = deserialize_json_start;
}
#line 564 "hb-buffer-deserialize-json.hh"
#line 574 "hb-buffer-deserialize-json.hh"
{
int _slen;
int _trans;
@ -772,7 +782,7 @@ _resume:
*end_ptr = p;
}
break;
#line 776 "hb-buffer-deserialize-json.hh"
#line 786 "hb-buffer-deserialize-json.hh"
}
_again:
@ -784,7 +794,7 @@ _again:
_out: {}
}
#line 137 "hb-buffer-deserialize-json.rl"
#line 132 "hb-buffer-deserialize-json.rl"
*end_ptr = p;

View file

@ -860,7 +860,7 @@ hb_buffer_destroy (hb_buffer_t *buffer)
* @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified buffer.
* Attaches a user-data key/data pair to the specified buffer.
*
* Return value: `true` if success, `false` otherwise
*
@ -1209,7 +1209,7 @@ hb_buffer_get_flags (const hb_buffer_t *buffer)
* @cluster_level: The cluster level to set on the buffer
*
* Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t
* dictates one aspect of how HarfBuzz will treat non-base characters
* dictates one aspect of how HarfBuzz will treat non-base characters
* during shaping.
*
* Since: 0.9.42
@ -1229,7 +1229,7 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer,
* @buffer: An #hb_buffer_t
*
* Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t
* dictates one aspect of how HarfBuzz will treat non-base characters
* dictates one aspect of how HarfBuzz will treat non-base characters
* during shaping.
*
* Return value: The cluster level of @buffer
@ -1983,7 +1983,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
* @buffer: An #hb_buffer_t
* @source: source #hb_buffer_t
* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.
* @end: end index into source buffer to copy. Use @HB_FEATURE_GLOBAL_END to copy to end of buffer.
* @end: end index into source buffer to copy. Use @UINT_MAX (or ((unsigned int) -1)) to copy to end of buffer.
*
* Append (part of) contents of another buffer to this buffer.
*

View file

@ -32,7 +32,6 @@
#include "hb.hh"
#include "hb-unicode.hh"
#include "hb-set-digest.hh"
static_assert ((sizeof (hb_glyph_info_t) == 20), "");
@ -182,22 +181,24 @@ struct hb_buffer_t
allocated_var_bits = 0;
}
HB_ALWAYS_INLINE
hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
HB_ALWAYS_INLINE
hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
HB_ALWAYS_INLINE
hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
HB_ALWAYS_INLINE
hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
HB_ALWAYS_INLINE
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
HB_ALWAYS_INLINE
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
hb_set_digest_t digest () const
{
hb_set_digest_t d;
d.init ();
d.add_array (&info[0].codepoint, len, sizeof (info[0]));
return d;
}
template <typename set_t>
void collect_codepoints (set_t &d) const
{ d.clear (); d.add_array (&info[0].codepoint, len, sizeof (info[0])); }
HB_INTERNAL void similar (const hb_buffer_t &src);
HB_INTERNAL void reset ();

View file

@ -180,7 +180,7 @@ hb_cairo_paint_color_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
hb_position_t x_scale, y_scale;
hb_font_get_scale (font, &x_scale, &y_scale);
cairo_scale (cr, x_scale, y_scale);
cairo_scale (cr, x_scale, -y_scale);
cairo_glyph_t cairo_glyph = { glyph, 0, 0 };
cairo_set_scaled_font (cr, c->scaled_font);
@ -597,7 +597,9 @@ hb_cairo_render_glyph (cairo_scaled_font_t *scaled_font,
hb_position_t x_scale, y_scale;
hb_font_get_scale (font, &x_scale, &y_scale);
cairo_scale (cr, +1./x_scale, -1./y_scale);
cairo_scale (cr,
+1. / (x_scale ? x_scale : 1),
-1. / (y_scale ? y_scale : 1));
hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
@ -628,7 +630,9 @@ hb_cairo_render_color_glyph (cairo_scaled_font_t *scaled_font,
hb_color_t color = HB_COLOR (0, 0, 0, 255);
hb_position_t x_scale, y_scale;
hb_font_get_scale (font, &x_scale, &y_scale);
cairo_scale (cr, +1./x_scale, -1./y_scale);
cairo_scale (cr,
+1. / (x_scale ? x_scale : 1),
-1. / (y_scale ? y_scale : 1));
hb_cairo_context_t c;
c.scaled_font = scaled_font;
@ -1000,6 +1004,7 @@ hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
else
end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
(const uint8_t *) utf8, utf8_len,
(signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster));
(*clusters)[cluster].num_bytes = end - start;
start = end;
@ -1020,6 +1025,7 @@ hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
else
end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
(const uint8_t *) utf8, utf8_len,
(signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster));
(*clusters)[cluster].num_bytes = end - start;
start = end;

View file

@ -522,7 +522,7 @@ struct parsed_values_t
void alloc (unsigned n)
{
values.alloc (n, true);
values.alloc_exact (n);
}
void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t (), const VAL &v = VAL ())

View file

@ -625,6 +625,9 @@ hb_script_get_horizontal_direction (hb_script_t script)
/* Unicode-14.0 additions */
case HB_SCRIPT_OLD_UYGHUR:
/* Unicode-16.0 additions */
case HB_SCRIPT_GARAY:
return HB_DIRECTION_RTL;

View file

@ -68,8 +68,6 @@
#define HB_NO_FACE_COLLECT_UNICODES
#define HB_NO_GETENV
#define HB_NO_HINTING
#define HB_NO_LANGUAGE_LONG
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
#define HB_NO_LAYOUT_FEATURE_PARAMS
#define HB_NO_LAYOUT_COLLECT_GLYPHS
#define HB_NO_LAYOUT_RARELY_USED
@ -159,6 +157,7 @@
#define HB_NO_FALLBACK_SHAPE
#define HB_NO_OT_KERN
#define HB_NO_OT_LAYOUT_BLOCKLIST
#define HB_NO_AAT_LAYOUT_BLOCKLIST
#define HB_NO_OT_SHAPE_FALLBACK
#endif

View file

@ -34,8 +34,12 @@
#include "hb-font.hh"
#include "hb-machinery.hh"
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
#if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1080) \
|| (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 60000) \
|| (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 90000)
# define kCTFontOrientationDefault kCTFontDefaultOrientation
# define kCTFontOrientationHorizontal kCTFontHorizontalOrientation
# define kCTFontOrientationVertical kCTFontVerticalOrientation
#endif
#define MAX_GLYPHS 64u
@ -56,11 +60,25 @@ hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch = unicode;
CGGlyph cg_glyph;
if (CTFontGetGlyphsForCharacters (ct_font, &ch, &cg_glyph, 1))
UniChar ch[2];
CGGlyph cg_glyph[2];
unsigned count = 0;
if (unicode <= 0xFFFF)
{
*glyph = cg_glyph;
ch[count++] = unicode;
}
else if (unicode <= 0x10FFFF)
{
ch[count++] = (unicode >> 10) + 0xD7C0;
ch[count++] = (unicode & 0x3FF) + 0xDC00;
}
else
ch[count++] = 0xFFFD;
if (CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count))
{
*glyph = cg_glyph[0];
return true;
}
return false;
@ -76,6 +94,31 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
// If any non-BMP codepoint is requested, use the slow path.
bool slow_path = false;
auto *unicode = first_unicode;
for (unsigned i = 0; i < count; i++)
{
if (*unicode > 0xFFFF)
{
slow_path = true;
break;
}
unicode = &StructAtOffset<const hb_codepoint_t> (unicode, unicode_stride);
}
if (unlikely (slow_path))
{
for (unsigned i = 0; i < count; i++)
{
if (!hb_coretext_get_nominal_glyph (font, font_data, *first_unicode, first_glyph, nullptr))
return i;
first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
}
return count;
}
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch[MAX_GLYPHS];
@ -88,7 +131,16 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
ch[j] = *first_unicode;
first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
}
CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c);
if (unlikely (!CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c)))
{
// Use slow path partially and return at first failure.
for (unsigned j = 0; j < c; j++)
{
if (!hb_coretext_get_nominal_glyph (font, font_data, ch[j], first_glyph, nullptr))
return i + j;
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
}
}
for (unsigned j = 0; j < c; j++)
{
*first_glyph = cg_glyph[j];
@ -109,13 +161,38 @@ hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
{
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch[2] = { unicode, variation_selector };
CGGlyph cg_glyph[2];
UniChar ch[4];
CGGlyph cg_glyph[4];
unsigned count = 0;
CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, 2);
// Add Unicode, then variation selector. Ugly, but works.
//
if (unicode <= 0xFFFF)
ch[count++] = unicode;
else if (unicode <= 0x10FFFF)
{
ch[count++] = (unicode >> 10) + 0xD7C0;
ch[count++] = (unicode & 0x3FF) + 0xDC00;
}
else
ch[count++] = 0xFFFD;
if (cg_glyph[1])
return false;
if (variation_selector <= 0xFFFF)
ch[count++] = variation_selector;
else if (variation_selector <= 0x10FFFF)
{
ch[count++] = (variation_selector >> 10) + 0xD7C0;
ch[count++] = (variation_selector & 0x3FF) + 0xDC00;
}
else
ch[count++] = 0xFFFD;
CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count);
// All except for first should be zero if we succeeded
for (unsigned i = 1; i < count; i++)
if (cg_glyph[i])
return false;
*glyph = cg_glyph[0];
return true;
@ -434,10 +511,6 @@ _hb_coretext_get_font_funcs ()
* created with hb_face_create(), and therefore was not
* initially configured to use CoreText font functions.
*
* An #hb_font_t object created with hb_coretext_font_create()
* is preconfigured for CoreText font functions and does not
* require this function to be used.
*
* <note>Note: Internally, this function creates a CTFont.
* </note>
*
@ -448,7 +521,12 @@ hb_coretext_font_set_funcs (hb_font_t *font)
{
CTFontRef ct_font = hb_coretext_font_get_ct_font (font);
if (unlikely (!ct_font))
{
hb_font_set_funcs (font,
hb_font_funcs_get_empty (),
nullptr, nullptr);
return;
}
hb_font_set_funcs (font,
_hb_coretext_get_font_funcs (),

View file

@ -45,9 +45,6 @@
* Functions for using HarfBuzz with the CoreText fonts.
**/
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size);
static void
@ -384,9 +381,9 @@ hb_coretext_face_create_from_file_or_fail (const char *file_name,
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, index) : nullptr;
if (unlikely (!ct_font_desc))
{
CFRelease (ct_font_desc_array);
CFRelease (url);
return nullptr;
CFRelease (ct_font_desc_array);
CFRelease (url);
return nullptr;
}
CFRelease (url);
auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
@ -400,6 +397,7 @@ hb_coretext_face_create_from_file_or_fail (const char *file_name,
return nullptr;
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
if (unlikely (hb_face_is_immutable (face)))
return nullptr;
@ -432,7 +430,7 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
if (unlikely (!face_data)) return nullptr;
CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
CGFloat font_size = (CGFloat) (font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem);
CGFloat font_size = (CGFloat) (font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE);
CTFontRef ct_font = create_ct_font (cg_font, font_size);
if (unlikely (!ct_font))
@ -451,11 +449,11 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
for (unsigned i = 0; i < font->num_coords; i++)
{
if (font->coords[i] == 0.) continue;
hb_ot_var_axis_info_t info;
unsigned int c = 1;
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
if (font->design_coords[i] == info.default_value)
continue;
float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
@ -499,7 +497,7 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
* CTFontRef.
*
* The created font uses the default font functions implemented
* navitely by HarfBuzz. If you want to use the CoreText font functions
* natively by HarfBuzz. If you want to use the CoreText font functions
* instead (rarely needed), you can do so by calling
* by hb_coretext_font_set_funcs().
*
@ -521,6 +519,36 @@ hb_coretext_font_create (CTFontRef ct_font)
hb_font_set_ptem (font, CTFontGetSize (ct_font));
/* Copy font variations */
CFDictionaryRef variations = CTFontCopyVariation (ct_font);
if (variations)
{
hb_vector_t<hb_variation_t> vars;
hb_vector_t<CFTypeRef> keys;
hb_vector_t<CFTypeRef> values;
CFIndex count = CFDictionaryGetCount (variations);
if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
goto done;
// Fetch them one by one and collect in a vector of our own.
CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
for (CFIndex i = 0; i < count; i++)
{
int tag;
float value;
CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
hb_variation_t var = {tag, value};
vars.push (var);
}
hb_font_set_variations (font, vars.arrayZ, vars.length);
done:
CFRelease (variations);
}
/* Let there be dragons here... */
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));

164
thirdparty/harfbuzz/src/hb-decycler.hh vendored Normal file
View file

@ -0,0 +1,164 @@
/*
* Copyright © 2025 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_DECYCLER_HH
#define HB_DECYCLER_HH
#include "hb.hh"
/*
* hb_decycler_t is an efficient cycle detector for graph traversal.
* It's a simple tortoise-and-hare algorithm with a twist: it's
* designed to detect cycles while traversing a graph in a DFS manner,
* instead of just a linked list.
*
* For Floyd's tortoise and hare algorithm, see:
* https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare
*
* hb_decycler_t is O(n) in the number of nodes in the DFS traversal
* if there are no cycles. Unlike Floyd's algorithm, hb_decycler_t
* can be used in a DFS traversal, where the graph is not a simple
* linked list, but a tree with possible cycles. Like Floyd's algorithm,
* it is constant-memory (~three pointers).
*
* The decycler works by creating an implicit linked-list on the stack,
* of the path from the root to the current node, and apply Floyd's
* algorithm on that list as it goes.
*
* The decycler is malloc-free, and as such, much faster to use than a
* hb_set_t or hb_map_t equivalent.
*
* The decycler detects cycles in the graph *eventually*, not *immediately*.
* That is, it may not detect a cycle until the cycle is fully traversed,
* even multiple times. See Floyd's algorithm analysis for details.
*
* The implementation saves a pointer storage on the stack by combining
* this->u.decycler and this->u.next into a union. This is possible because
* at any point we only need one of those values. The invariant is that
* after construction, and before destruction, of a node, the u.decycler
* field is always valid. The u.next field is only valid when the node is
* in the traversal path, parent to another node.
*
* There are three method's:
*
* - hb_decycler_node_t() constructor: Creates a new node in the traversal.
* The constructor takes a reference to the decycler object and inserts
* itself as the latest node in the traversal path, by advancing the hare
* pointer, and for every other descent, advancing the tortoise pointer.
*
* - ~hb_decycler_node_t() destructor: Restores the decycler object to its
* previous state by removing the node from the traversal path.
*
* - bool visit(uintptr_t value): Called on every node in the graph. Returns
* true if the node is not part of a cycle, and false if it is. The value
* parameter is used to detect cycles. It's the caller's responsibility
* to ensure that the value is unique for each node in the graph.
* The cycle detection is as simple as comparing the value to the value
* held by the tortoise pointer, which is the Floyd's algorithm.
*
* For usage examples see test-decycler.cc.
*/
struct hb_decycler_node_t;
struct hb_decycler_t
{
friend struct hb_decycler_node_t;
private:
bool tortoise_awake = false;
hb_decycler_node_t *tortoise = nullptr;
hb_decycler_node_t *hare = nullptr;
};
struct hb_decycler_node_t
{
hb_decycler_node_t (hb_decycler_t &decycler)
{
u.decycler = &decycler;
decycler.tortoise_awake = !decycler.tortoise_awake;
if (!decycler.tortoise)
{
// First node.
assert (decycler.tortoise_awake);
assert (!decycler.hare);
decycler.tortoise = decycler.hare = this;
return;
}
if (decycler.tortoise_awake)
decycler.tortoise = decycler.tortoise->u.next; // Time to move.
this->prev = decycler.hare;
decycler.hare->u.next = this;
decycler.hare = this;
}
~hb_decycler_node_t ()
{
hb_decycler_t &decycler = *u.decycler;
// Inverse of the constructor.
assert (decycler.hare == this);
decycler.hare = prev;
if (prev)
prev->u.decycler = &decycler;
assert (decycler.tortoise);
if (decycler.tortoise_awake)
decycler.tortoise = decycler.tortoise->prev;
decycler.tortoise_awake = !decycler.tortoise_awake;
}
bool visit (uintptr_t value_)
{
value = value_;
hb_decycler_t &decycler = *u.decycler;
if (decycler.tortoise == this)
return true; // First node; not a cycle.
if (decycler.tortoise->value == value)
return false; // Cycle detected.
return true;
}
private:
union {
hb_decycler_t *decycler;
hb_decycler_node_t *next;
} u = {nullptr};
hb_decycler_node_t *prev = nullptr;
uintptr_t value = 0;
};
#endif /* HB_DECYCLER_HH */

View file

@ -29,6 +29,7 @@
#include "hb-shaper-impl.hh"
#include <dwrite_1.h>
#include <dwrite_3.h>
#include "hb-directwrite.h"
@ -275,6 +276,8 @@ _hb_directwrite_shaper_font_data_create (hb_font_t *font)
void
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
{
if (data != HB_SHAPER_DATA_SUCCEEDED)
((IDWriteFont *) (const void *) data)->Release();
}
@ -839,7 +842,7 @@ _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *
}
static void
_hb_directwrite_font_release (void *data)
_hb_directwrite_face_release (void *data)
{
if (data)
((IDWriteFontFace *) data)->Release ();
@ -847,7 +850,7 @@ _hb_directwrite_font_release (void *data)
/**
* hb_directwrite_face_create:
* @font_face: a DirectWrite IDWriteFontFace object.
* @dw_face: a DirectWrite IDWriteFontFace object.
*
* Constructs a new face object from the specified DirectWrite IDWriteFontFace.
*
@ -856,14 +859,32 @@ _hb_directwrite_font_release (void *data)
* Since: 2.4.0
**/
hb_face_t *
hb_directwrite_face_create (IDWriteFontFace *font_face)
hb_directwrite_face_create (IDWriteFontFace *dw_face)
{
if (font_face)
font_face->AddRef ();
return hb_face_create_for_tables (_hb_directwrite_reference_table, font_face,
_hb_directwrite_font_release);
if (dw_face)
dw_face->AddRef ();
return hb_face_create_for_tables (_hb_directwrite_reference_table, dw_face,
_hb_directwrite_face_release);
}
/**
* hb_directwrite_face_get_dw_font_face:
* @face: a #hb_face_t object
*
* Gets the DirectWrite IDWriteFontFace associated with @face.
*
* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
*
* Since: 10.4.0
**/
IDWriteFontFace *
hb_directwrite_face_get_dw_font_face (hb_face_t *face)
{
return face->data.directwrite->fontFace;
}
#ifndef HB_DISABLE_DEPRECATED
/**
* hb_directwrite_face_get_font_face:
* @face: a #hb_face_t object
@ -873,12 +894,90 @@ hb_directwrite_face_create (IDWriteFontFace *font_face)
* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
*
* Since: 2.5.0
* Deprecated: 10.4.0: Use hb_directwrite_face_get_dw_font_face() instead
**/
IDWriteFontFace *
hb_directwrite_face_get_font_face (hb_face_t *face)
{
return face->data.directwrite->fontFace;
return hb_directwrite_face_get_dw_font_face (face);
}
#endif
/**
* hb_directwrite_font_create:
* @dw_font: a DirectWrite IDWriteFont object.
*
* Constructs a new font object from the specified DirectWrite IDWriteFont.
*
* Return value: #hb_font_t object corresponding to the given input
*
* Since: 10.3.0
**/
hb_font_t *
hb_directwrite_font_create (IDWriteFont *dw_font)
{
IDWriteFontFace *dw_face = nullptr;
IDWriteFontFace5 *dw_face5 = nullptr;
if (FAILED (dw_font->CreateFontFace (&dw_face)))
return hb_font_get_empty ();
hb_face_t *face = hb_directwrite_face_create (dw_face);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
if (unlikely (hb_object_is_immutable (font)))
goto done;
/* Copy font variations */
if (SUCCEEDED (dw_face->QueryInterface (__uuidof (IDWriteFontFace5), (void**) &dw_face5)))
{
if (dw_face5->HasVariations ())
{
hb_vector_t<DWRITE_FONT_AXIS_VALUE> values;
uint32_t count = dw_face5->GetFontAxisValueCount ();
if (likely (values.resize_exact (count)) &&
SUCCEEDED (dw_face5->GetFontAxisValues (values.arrayZ, count)))
{
hb_vector_t<hb_variation_t> vars;
if (likely (vars.resize_exact (count)))
{
for (uint32_t i = 0; i < count; ++i)
{
hb_tag_t tag = values[i].axisTag;
float value = values[i].value;
vars[i] = {tag, value};
}
hb_font_set_variations (font, vars.arrayZ, vars.length);
}
}
}
dw_face5->Release ();
}
dw_font->AddRef ();
font->data.directwrite.cmpexch (nullptr, (hb_directwrite_font_data_t *) dw_font);
done:
dw_face->Release ();
return font;
}
/**
* hb_directwrite_font_get_dw_font:
* @font: a #hb_font_t object
*
* Gets the DirectWrite IDWriteFont associated with @font.
*
* Return value: DirectWrite IDWriteFont object corresponding to the given input
*
* Since: 10.3.0
**/
IDWriteFont *
hb_directwrite_font_get_dw_font (hb_font_t *font)
{
return (IDWriteFont *) (const void *) font->data.directwrite;
}
#endif

View file

@ -30,11 +30,25 @@
HB_BEGIN_DECLS
HB_EXTERN hb_face_t *
hb_directwrite_face_create (IDWriteFontFace *font_face);
hb_directwrite_face_create (IDWriteFontFace *dw_face);
HB_EXTERN IDWriteFontFace *
hb_directwrite_face_get_dw_font_face (hb_face_t *face);
HB_EXTERN hb_font_t *
hb_directwrite_font_create (IDWriteFont *dw_font);
HB_EXTERN IDWriteFont *
hb_directwrite_font_get_dw_font (hb_font_t *font);
#ifndef HB_DISABLE_DEPRECATED
HB_DEPRECATED_FOR (hb_directwrite_face_get_dw_font_face)
HB_EXTERN IDWriteFontFace *
hb_directwrite_face_get_font_face (hb_face_t *face);
#endif
HB_END_DECLS
#endif /* HB_DIRECTWRITE_H */

View file

@ -291,6 +291,7 @@ hb_face_create_or_fail (hb_blob_t *blob,
return face;
}
#ifndef HB_NO_OPEN
/**
* hb_face_create_from_file_or_fail:
* @file_name: A font filename
@ -317,6 +318,7 @@ hb_face_create_from_file_or_fail (const char *file_name,
return face;
}
#endif
/**
* hb_face_get_empty:
@ -470,7 +472,8 @@ hb_face_is_immutable (const hb_face_t *face)
* @tag: The #hb_tag_t of the table to query
*
* Fetches a reference to the specified table within
* the specified face.
* the specified face. Returns an empty blob if referencing table data is not
* possible.
*
* Return value: (transfer full): A pointer to the @tag table within @face
*
@ -490,9 +493,10 @@ hb_face_reference_table (const hb_face_t *face,
* hb_face_reference_blob:
* @face: A face object
*
* Fetches a pointer to the binary blob that contains the
* specified face. Returns an empty blob if referencing face data is not
* possible.
* Fetches a pointer to the binary blob that contains the specified face.
* If referencing the face data is not possible, this function creates a blob
* out of individual table blobs if hb_face_get_table_tags() works with this
* face, otherwise it returns an empty blob.
*
* Return value: (transfer full): A pointer to the blob for @face
*
@ -501,7 +505,41 @@ hb_face_reference_table (const hb_face_t *face,
hb_blob_t *
hb_face_reference_blob (hb_face_t *face)
{
return face->reference_table (HB_TAG_NONE);
hb_blob_t *blob = face->reference_table (HB_TAG_NONE);
if (blob == hb_blob_get_empty ())
{
// If referencing the face blob is not possible (e.g. not implemented by the
// font functions), use face builder to create a blob out of individual
// table blobs.
unsigned total_count = hb_face_get_table_tags (face, 0, nullptr, nullptr);
if (total_count)
{
hb_tag_t tags[64];
unsigned count = ARRAY_LENGTH (tags);
hb_face_t* builder = hb_face_builder_create ();
for (unsigned offset = 0; offset < total_count; offset += count)
{
hb_face_get_table_tags (face, offset, &count, tags);
if (unlikely (!count))
break; // Allocation error
for (unsigned i = 0; i < count; i++)
{
if (unlikely (!tags[i]))
continue;
hb_blob_t *table = hb_face_reference_table (face, tags[i]);
hb_face_builder_add_table (builder, tags[i], table);
hb_blob_destroy (table);
}
}
blob = hb_face_reference_blob (builder);
hb_face_destroy (builder);
}
}
return blob;
}
/**
@ -643,6 +681,7 @@ hb_face_set_get_table_tags_func (hb_face_t *face,
{
if (destroy)
destroy (user_data);
return;
}
if (face->get_table_tags_destroy)

View file

@ -73,9 +73,14 @@ hb_face_create_from_file_or_fail (const char *file_name,
* @tag: the tag of the table to reference
* @user_data: User data pointer passed by the caller
*
* Callback function for hb_face_create_for_tables().
* Callback function for hb_face_create_for_tables(). The @tag is the tag of the
* table to reference, and the special tag #HB_TAG_NONE is used to reference the
* blob of the face itself. If referencing the face blob is not possible, it is
* recommended to set hb_get_table_tags_func_t on the @face to allow
* hb_face_reference_blob() to create a face blob out of individual table blobs.
*
* Return value: (transfer full): A pointer to the @tag table within @face
* Return value: (transfer full): A pointer to the @tag table within @face or
* `NULL` if the table is not found or cannot be referenced.
*
* Since: 0.9.2
*/

View file

@ -27,6 +27,7 @@
#include "hb.hh"
#include "hb-decycler.hh"
#include "hb-paint-extents.hh"
#include FT_COLOR_H
@ -105,8 +106,8 @@ struct hb_ft_paint_context_t
FT_Color *palette;
unsigned palette_index;
hb_color_t foreground;
hb_map_t current_glyphs;
hb_map_t current_layers;
hb_decycler_t glyphs_decycler;
hb_decycler_t layers_decycler;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_MAX_GRAPH_EDGE_COUNT;
};
@ -218,22 +219,19 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
case FT_COLR_PAINTFORMAT_COLR_LAYERS:
{
FT_OpaquePaint other_paint = {0};
hb_decycler_node_t node (c->layers_decycler);
while (FT_Get_Paint_Layers (ft_face,
&paint.u.colr_layers.layer_iterator,
&other_paint))
{
unsigned i = paint.u.colr_layers.layer_iterator.layer;
if (unlikely (c->current_layers.has (i)))
// FreeType doesn't provide a way to get the layer index, so we use the pointer
// for cycle detection.
if (unlikely (!node.visit ((uintptr_t) other_paint.p)))
continue;
c->current_layers.add (i);
c->funcs->push_group (c->data);
c->recurse (other_paint);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
c->current_layers.del (i);
}
}
break;
@ -333,18 +331,16 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
{
hb_codepoint_t gid = paint.u.colr_glyph.glyphID;
if (unlikely (c->current_glyphs.has (gid)))
hb_decycler_node_t node (c->glyphs_decycler);
if (unlikely (!node.visit (gid)))
return;
c->current_glyphs.add (gid);
c->funcs->push_inverse_root_transform (c->data, c->font);
c->ft_font->lock.unlock ();
if (c->funcs->color_glyph (c->data, gid, c->font))
{
c->ft_font->lock.lock ();
c->funcs->pop_transform (c->data);
c->current_glyphs.del (gid);
return;
}
c->ft_font->lock.lock ();
@ -380,8 +376,6 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
if (has_clip_box)
c->funcs->pop_clip (c->data);
c->current_glyphs.del (gid);
}
}
break;
@ -506,7 +500,8 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
hb_ft_paint_context_t c (ft_font, font,
paint_funcs, paint_data,
palette, palette_index, foreground);
c.current_glyphs.add (gid);
hb_decycler_node_t node (c.glyphs_decycler);
node.visit (gid);
bool is_bounded = true;
FT_ClipBox clip_box;
@ -530,7 +525,8 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
hb_ft_paint_context_t ce (ft_font, font,
extents_funcs, &extents_data,
palette, palette_index, foreground);
ce.current_glyphs.add (gid);
hb_decycler_node_t node2 (ce.glyphs_decycler);
node2.visit (gid);
ce.funcs->push_root_transform (ce.data, font);
ce.recurse (paint);
ce.funcs->pop_transform (ce.data);
@ -547,7 +543,9 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
c.funcs->push_root_transform (c.data, font);
if (is_bounded)
{
c.recurse (paint);
}
c.funcs->pop_transform (c.data);
c.funcs->pop_clip (c.data);

View file

@ -37,7 +37,11 @@
#include "hb-draw.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
#ifndef HB_NO_AAT
#include "hb-aat-layout-trak-table.hh"
#endif
#include "hb-ot-os2-table.hh"
#include "hb-ot-stat-table.hh"
#include "hb-ot-shaper-arabic-pua.hh"
#include "hb-paint.hh"
@ -274,6 +278,33 @@ hb_ft_font_get_load_flags (hb_font_t *font)
return ft_font->load_flags;
}
/**
* hb_ft_font_get_ft_face: (skip)
* @font: #hb_font_t to work upon
*
* Fetches the FT_Face associated with the specified #hb_font_t
* font object.
*
* This function works with #hb_font_t objects created by
* hb_ft_font_create() or hb_ft_font_create_referenced().
*
* Return value: (nullable): the FT_Face found or `NULL`
*
* Since: 10.4.0
**/
FT_Face
hb_ft_font_get_ft_face (hb_font_t *font)
{
if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
return nullptr;
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
return ft_font->ft_face;
}
#ifndef HB_DISABLE_DEPRECATED
/**
* hb_ft_font_get_face: (skip)
* @font: #hb_font_t to work upon
@ -287,18 +318,16 @@ hb_ft_font_get_load_flags (hb_font_t *font)
* Return value: (nullable): the FT_Face found or `NULL`
*
* Since: 0.9.2
* Deprecated: 10.4.0: Use hb_ft_font_get_ft_face() instead.
**/
FT_Face
hb_ft_font_get_face (hb_font_t *font)
{
if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
return nullptr;
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
return ft_font->ft_face;
return hb_ft_font_get_ft_face (font);
}
#endif
/**
* hb_ft_font_lock_face: (skip)
* @font: #hb_font_t to work upon
@ -502,6 +531,26 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
#ifndef HB_NO_AAT
/* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */
#ifndef HB_NO_STYLE
bool apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data ();
#else
bool apply_trak = false;
#endif
if (apply_trak)
{
hb_position_t tracking = font->face->table.trak->get_h_tracking (font);
first_advance = orig_first_advance;
for (unsigned int i = 0; i < count; i++)
{
*first_advance += tracking;
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
#endif
}
#ifndef HB_NO_VERTICAL
@ -538,7 +587,20 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
* have a Y growing upward. Hence the extra negation. */
hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength;
return ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength);
v = ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength);
#ifndef HB_NO_AAT
/* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */
#ifndef HB_NO_STYLE
bool apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data ();
#else
bool apply_trak = false;
#endif
if (apply_trak)
v += font->face->table.trak->get_v_tracking (font);
#endif
return v;
}
#endif
@ -931,11 +993,15 @@ hb_ft_paint_glyph (hb_font_t *font,
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
FT_Long load_flags = ft_font->load_flags | FT_LOAD_NO_BITMAP | FT_LOAD_COLOR;
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21301
load_flags |= FT_LOAD_NO_SVG;
#endif
/* We release the lock before calling into glyph callbacks, such that
* eg. draw API can call back into the face.*/
if (unlikely (FT_Load_Glyph (ft_face, gid,
ft_font->load_flags | FT_LOAD_COLOR)))
if (unlikely (FT_Load_Glyph (ft_face, gid, load_flags)))
return;
if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
@ -1286,7 +1352,7 @@ hb_ft_face_create_cached (FT_Face ft_face)
*
* If you know you have valid reasons not to use hb_ft_font_create_referenced(),
* then it is the client program's responsibility to destroy @ft_face
* after the #hb_font_t font object has been destroyed.
* only after the #hb_font_t font object has been destroyed.
*
* HarfBuzz will use the @destroy callback on the #hb_font_t font object
* if it is supplied when you use this function. However, even if @destroy
@ -1594,6 +1660,11 @@ _release_blob (void *arg)
void
hb_ft_font_set_funcs (hb_font_t *font)
{
// In case of failure...
hb_font_set_funcs (font,
hb_font_funcs_get_empty (),
nullptr, nullptr);
hb_blob_t *blob = hb_face_reference_blob (font->face);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);

View file

@ -111,7 +111,7 @@ HB_EXTERN hb_font_t *
hb_ft_font_create_referenced (FT_Face ft_face);
HB_EXTERN FT_Face
hb_ft_font_get_face (hb_font_t *font);
hb_ft_font_get_ft_face (hb_font_t *font);
HB_EXTERN FT_Face
hb_ft_font_lock_face (hb_font_t *font);
@ -142,6 +142,13 @@ hb_ft_hb_font_changed (hb_font_t *font);
HB_EXTERN void
hb_ft_font_set_funcs (hb_font_t *font);
#ifndef HB_DISABLE_DEPRECATED
HB_DEPRECATED_FOR (hb_ft_font_get_ft_face)
HB_EXTERN FT_Face
hb_ft_font_get_face (hb_font_t *font);
#endif
HB_END_DECLS

View file

@ -83,6 +83,13 @@ struct hb_transform_t
float x0, float y0) :
xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
bool is_identity () const
{
return xx == 1.f && yx == 0.f &&
xy == 0.f && yy == 1.f &&
x0 == 0.f && y0 == 0.f;
}
void multiply (const hb_transform_t &o)
{
/* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
@ -201,6 +208,8 @@ struct hb_transform_t
float y0 = 0.f;
};
#define HB_TRANSFORM_IDENTITY hb_transform_t{1.f, 0.f, 0.f, 1.f, 0.f, 0.f}
struct hb_bounds_t
{
enum status_t {

View file

@ -176,7 +176,7 @@ template <typename Type>
static inline Type& Crap () {
static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
memcpy (obj, std::addressof (Null (Type)), sizeof (*obj));
memcpy (reinterpret_cast<void*>(obj), std::addressof (Null (Type)), sizeof (*obj));
return *obj;
}
template <typename QType>

View file

@ -86,21 +86,12 @@ struct IntType
return pb->cmp (*pa);
}
template <typename Type2,
hb_enable_if (std::is_integral<Type2>::value &&
sizeof (Type2) < sizeof (int) &&
sizeof (Type) < sizeof (int))>
int cmp (Type2 a) const
{
Type b = v;
return (int) a - (int) b;
}
template <typename Type2,
hb_enable_if (hb_is_convertible (Type2, Type))>
int cmp (Type2 a) const
{
Type b = v;
return a < b ? -1 : a == b ? 0 : +1;
return (a > b) - (a < b);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -299,11 +290,6 @@ typedef Index NameID;
struct VarIdx : HBUINT32 {
static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, "");
static uint32_t add (uint32_t i, unsigned short v)
{
if (i == NO_VARIATION) return i;
return i + v;
}
VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
};
DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
@ -1747,6 +1733,19 @@ struct TupleValues
else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_WORDS)
{
if (unlikely (p + run_count * HBINT16::static_size > end)) return false;
#ifndef HB_OPTIMIZE_SIZE
for (; i + 3 < stop; i += 4)
{
values.arrayZ[i] = * (const HBINT16 *) p;
p += HBINT16::static_size;
values.arrayZ[i + 1] = * (const HBINT16 *) p;
p += HBINT16::static_size;
values.arrayZ[i + 2] = * (const HBINT16 *) p;
p += HBINT16::static_size;
values.arrayZ[i + 3] = * (const HBINT16 *) p;
p += HBINT16::static_size;
}
#endif
for (; i < stop; i++)
{
values.arrayZ[i] = * (const HBINT16 *) p;
@ -1765,10 +1764,17 @@ struct TupleValues
else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_BYTES)
{
if (unlikely (p + run_count > end)) return false;
#ifndef HB_OPTIMIZE_SIZE
for (; i + 3 < stop; i += 4)
{
values.arrayZ[i] = * (const HBINT8 *) p++;
values.arrayZ[i + 1] = * (const HBINT8 *) p++;
values.arrayZ[i + 2] = * (const HBINT8 *) p++;
values.arrayZ[i + 3] = * (const HBINT8 *) p++;
}
#endif
for (; i < stop; i++)
{
values.arrayZ[i] = * (const HBINT8 *) p++;
}
}
}
return true;
@ -1777,12 +1783,12 @@ struct TupleValues
struct iter_t : hb_iter_with_fallback_t<iter_t, int>
{
iter_t (const unsigned char *p_, unsigned len_)
: p (p_), end (p_ + len_)
: p (p_), endp (p_ + len_)
{ if (ensure_run ()) read_value (); }
private:
const unsigned char *p;
const unsigned char * const end;
const unsigned char * const endp;
int current_value = 0;
signed run_count = 0;
unsigned width = 0;
@ -1791,7 +1797,7 @@ struct TupleValues
{
if (likely (run_count > 0)) return true;
if (unlikely (p >= end))
if (unlikely (p >= endp))
{
run_count = 0;
current_value = 0;
@ -1810,7 +1816,7 @@ struct TupleValues
default: assert (false);
}
if (unlikely (p + run_count * width > end))
if (unlikely (p + run_count * width > endp))
{
run_count = 0;
current_value = 0;
@ -1837,7 +1843,7 @@ struct TupleValues
__item_t__ __item__ () const
{ return current_value; }
bool __more__ () const { return run_count || p < end; }
bool __more__ () const { return run_count || p < endp; }
void __next__ ()
{
run_count--;
@ -1864,10 +1870,146 @@ struct TupleValues
{ return p != o.p || run_count != o.run_count; }
iter_t __end__ () const
{
iter_t it (end, 0);
iter_t it (endp, 0);
return it;
}
};
struct fetcher_t
{
fetcher_t (const unsigned char *p_, unsigned len_)
: p (p_), end (p_ + len_) {}
private:
const unsigned char *p;
const unsigned char * const end;
signed run_count = 0;
unsigned width = 0;
bool ensure_run ()
{
if (likely (run_count > 0)) return true;
if (unlikely (p >= end))
{
run_count = 0;
return false;
}
unsigned control = *p++;
run_count = (control & VALUE_RUN_COUNT_MASK) + 1;
width = control & VALUES_SIZE_MASK;
switch (width)
{
case VALUES_ARE_ZEROS: width = 0; break;
case VALUES_ARE_BYTES: width = HBINT8::static_size; break;
case VALUES_ARE_WORDS: width = HBINT16::static_size; break;
case VALUES_ARE_LONGS: width = HBINT32::static_size; break;
default: assert (false);
}
if (unlikely (p + run_count * width > end))
{
run_count = 0;
return false;
}
return true;
}
void skip (unsigned n)
{
while (n)
{
if (unlikely (!ensure_run ()))
return;
unsigned i = hb_min (n, (unsigned) run_count);
run_count -= i;
n -= i;
p += i * width;
}
}
template <bool scaled>
void _add_to (hb_array_t<float> out, float scale = 1.0f)
{
unsigned n = out.length;
float *arrayZ = out.arrayZ;
for (unsigned i = 0; i < n;)
{
if (unlikely (!ensure_run ()))
break;
unsigned count = hb_min (n - i, (unsigned) run_count);
switch (width)
{
case 1:
{
const auto *pp = (const HBINT8 *) p;
unsigned j = 0;
#ifndef HB_OPTIMIZE_SIZE
for (; j + 3 < count; j += 4)
{
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
}
#endif
for (; j < count; j++)
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
}
break;
case 2:
{
const auto *pp = (const HBINT16 *) p;
unsigned j = 0;
#ifndef HB_OPTIMIZE_SIZE
for (; j + 3 < count; j += 4)
{
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
}
#endif
for (; j < count; j++)
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
}
break;
case 4:
{
const auto *pp = (const HBINT32 *) p;
for (unsigned j = 0; j < count; j++)
*arrayZ++ += scaled ? *pp++ * scale : *pp++;
}
break;
}
p += count * width;
run_count -= count;
i += count;
}
}
public:
void add_to (hb_array_t<float> out, float scale = 1.0f)
{
unsigned n = out.length;
if (scale == 0.0f)
{
skip (n);
return;
}
#ifndef HB_OPTIMIZE_SIZE
if (scale == 1.0f)
_add_to<false> (out);
else
#endif
_add_to<true> (out, scale);
}
};
};
struct TupleList : CFF2Index
@ -1877,6 +2019,12 @@ struct TupleList : CFF2Index
auto bytes = CFF2Index::operator [] (i);
return TupleValues::iter_t (bytes.arrayZ, bytes.length);
}
TupleValues::fetcher_t fetcher (unsigned i) const
{
auto bytes = CFF2Index::operator [] (i);
return TupleValues::fetcher_t (bytes.arrayZ, bytes.length);
}
};

View file

@ -553,15 +553,6 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
return true;
}
bool OT::cff1::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
{
funcs->push_clip_glyph (data, glyph, font);
funcs->color (data, true, foreground);
funcs->pop_clip (data);
return true;
}
bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
{
#ifdef HB_NO_OT_FONT_CFF

View file

@ -1462,7 +1462,6 @@ struct cff1
}
HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
private:

View file

@ -143,15 +143,6 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
return true;
}
bool OT::cff2::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
{
funcs->push_clip_glyph (data, glyph, font);
funcs->color (data, true, foreground);
funcs->pop_clip (data);
return true;
}
struct cff2_path_param_t
{
cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_)

View file

@ -518,7 +518,6 @@ struct cff2
HB_INTERNAL bool get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const;
HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const;
};

View file

@ -1397,6 +1397,9 @@ struct CmapSubtableFormat14
hb_vector_t<hb_pair_t<unsigned, unsigned>> obj_indices;
for (int i = src_tbl->record.len - 1; i >= 0; i--)
{
if (!unicodes->has(src_tbl->record[i].varSelector))
continue;
hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
if (result.first || result.second)
obj_indices.push (result);
@ -1453,6 +1456,7 @@ struct CmapSubtableFormat14
{
+ hb_iter (record)
| hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS)
| hb_filter (unicodes, &VariationSelectorRecord::varSelector)
| hb_map (&VariationSelectorRecord::nonDefaultUVS)
| hb_map (hb_add (this))
| hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })

View file

@ -95,9 +95,12 @@ HB_OT_CORE_TABLE (OT, fvar)
HB_OT_CORE_TABLE (OT, avar)
HB_OT_CORE_TABLE (OT, cvar)
HB_OT_ACCELERATOR (OT, gvar)
#ifndef HB_NO_BEYOND_64K
HB_OT_ACCELERATOR (OT, GVAR)
#endif
HB_OT_CORE_TABLE (OT, MVAR)
#ifndef HB_NO_VAR_COMPOSITES
HB_OT_CORE_TABLE (OT, VARC)
HB_OT_ACCELERATOR (OT, VARC)
#endif
#endif

View file

@ -41,6 +41,7 @@
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-var-varc-table.hh"
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"

View file

@ -36,13 +36,16 @@
#include "hb-ot-face.hh"
#include "hb-outline.hh"
#ifndef HB_NO_AAT
#include "hb-aat-layout-trak-table.hh"
#endif
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
#include "hb-ot-stat-table.hh"
#include "hb-ot-var-varc-table.hh"
#include "hb-ot-vorg-table.hh"
#include "OT/Color/CBDT/CBDT.hh"
@ -73,6 +76,10 @@ struct hb_ot_font_t
{
const hb_ot_face_t *ot_face;
#ifndef HB_NO_AAT
bool apply_trak;
#endif
#ifndef HB_NO_OT_FONT_CMAP_CACHE
hb_ot_font_cmap_cache_t *cmap_cache;
#endif
@ -91,6 +98,15 @@ _hb_ot_font_create (hb_font_t *font)
ot_font->ot_face = &font->face->table;
#ifndef HB_NO_AAT
/* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */
#ifndef HB_NO_STYLE
ot_font->apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data ();
#else
ot_font->apply_trak = false;
#endif
#endif
#ifndef HB_NO_OT_FONT_CMAP_CACHE
// retry:
auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face,
@ -200,7 +216,6 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_t *ot_face = ot_font->ot_face;
const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
@ -292,6 +307,20 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
#ifndef HB_NO_AAT
if (ot_font->apply_trak)
{
hb_position_t tracking = font->face->table.trak->get_h_tracking (font);
first_advance = orig_first_advance;
for (unsigned int i = 0; i < count; i++)
{
*first_advance += tracking;
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
#endif
}
#ifndef HB_NO_VERTICAL
@ -356,6 +385,20 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
#ifndef HB_NO_AAT
if (ot_font->apply_trak)
{
hb_position_t tracking = font->face->table.trak->get_v_tracking (font);
first_advance = orig_first_advance;
for (unsigned int i = 0; i < count; i++)
{
*first_advance += tracking;
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
#endif
}
#endif
@ -568,14 +611,11 @@ hb_ot_paint_glyph (hb_font_t *font,
if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
#endif
#endif
#ifndef HB_NO_VAR_COMPOSITES
if (font->face->table.VARC->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#endif
if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#ifndef HB_NO_CFF
if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#endif
// Outline glyph
paint_funcs->push_clip_glyph (paint_data, glyph, font);
paint_funcs->color (paint_data, true, foreground);
paint_funcs->pop_clip (paint_data);
}
#endif

View file

@ -95,7 +95,7 @@ struct hdmx
bool serialize (hb_serialize_context_t *c,
unsigned version,
Iterator it,
const hb_vector_t<hb_codepoint_pair_t> &new_to_old_gid_list,
hb_array_t<const hb_codepoint_pair_t> new_to_old_gid_list,
unsigned num_glyphs)
{
TRACE_SERIALIZE (this);

View file

@ -182,7 +182,7 @@ struct hmtxvmtx
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
hb_array_t<const hb_codepoint_pair_t> new_to_old_gid_list,
unsigned num_long_metrics,
unsigned total_num_metrics)
{

View file

@ -342,7 +342,7 @@ struct kern
}
bool apply (AAT::hb_aat_apply_context_t *c,
const AAT::kern_accelerator_data_t *accel_data = nullptr) const
const AAT::kern_accelerator_data_t &accel_data) const
{ return dispatch (c, accel_data); }
template <typename context_t, typename ...Ts>
@ -395,7 +395,7 @@ struct kern
bool apply (AAT::hb_aat_apply_context_t *c) const
{
return table->apply (c, &accel_data);
return table->apply (c, accel_data);
}
hb_blob_ptr_t<kern> table;

View file

@ -460,7 +460,7 @@ struct BaseScript
{ return (this+baseValues).get_base_coord (baseline_tag_index); }
bool has_values () const { return baseValues; }
bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
bool has_min_max () const { return defaultMinMax || baseLangSysRecords; }
void collect_variation_indices (const hb_subset_plan_t* plan,
hb_set_t& varidx_set /* OUT */) const

View file

@ -34,6 +34,7 @@
#include "hb-open-type.hh"
#include "hb-set.hh"
#include "hb-bimap.hh"
#include "hb-cache.hh"
#include "OT/Layout/Common/Coverage.hh"
#include "OT/Layout/types.hh"
@ -2076,6 +2077,15 @@ struct ClassDef
default:return 0;
}
}
unsigned int get_class (hb_codepoint_t glyph_id,
hb_ot_lookup_cache_t *cache) const
{
unsigned klass;
if (cache && cache->get (glyph_id, &klass)) return klass;
klass = get_class (glyph_id);
if (cache) cache->set (glyph_id, klass);
return klass;
}
unsigned get_population () const
{
@ -3137,23 +3147,14 @@ struct MultiVarData
{
auto &deltaSets = StructAfter<decltype (deltaSetsX)> (regionIndices);
auto values_iter = deltaSets[inner];
auto values_iter = deltaSets.fetcher (inner);
unsigned regionCount = regionIndices.len;
unsigned count = out.length;
for (unsigned regionIndex = 0; regionIndex < regionCount; regionIndex++)
{
float scalar = regions.evaluate (regionIndices.arrayZ[regionIndex],
coords, coord_count,
cache);
if (scalar == 1.f)
for (unsigned i = 0; i < count; i++)
out.arrayZ[i] += *values_iter++;
else if (scalar)
for (unsigned i = 0; i < count; i++)
out.arrayZ[i] += *values_iter++ * scalar;
else
values_iter += count;
values_iter.add_to (out, scalar);
}
}
@ -3439,7 +3440,7 @@ struct MultiItemVariationStore
{
using cache_t = SparseVarRegionList::cache_t;
cache_t *create_cache () const
cache_t *create_cache (hb_array_t<float> static_cache = hb_array_t<float> ()) const
{
#ifdef HB_NO_VAR
return nullptr;
@ -3447,8 +3448,14 @@ struct MultiItemVariationStore
auto &r = this+regions;
unsigned count = r.regions.len;
float *cache = (float *) hb_malloc (sizeof (float) * count);
if (unlikely (!cache)) return nullptr;
float *cache;
if (count <= static_cache.length)
cache = static_cache.arrayZ;
else
{
cache = (float *) hb_malloc (sizeof (float) * count);
if (unlikely (!cache)) return nullptr;
}
for (unsigned i = 0; i < count; i++)
cache[i] = REGION_CACHE_ITEM_CACHE_INVALID;
@ -3456,7 +3463,12 @@ struct MultiItemVariationStore
return cache;
}
static void destroy_cache (cache_t *cache) { hb_free (cache); }
static void destroy_cache (cache_t *cache,
hb_array_t<float> static_cache = hb_array_t<float> ())
{
if (cache != static_cache.arrayZ)
hb_free (cache);
}
private:
void get_delta (unsigned int outer, unsigned int inner,
@ -3731,11 +3743,13 @@ struct ItemVarStoreInstancer
float operator() (uint32_t varIdx, unsigned short offset = 0) const
{
if (!coords || varIdx == VarIdx::NO_VARIATION)
return 0.f;
varIdx += offset;
if (varIdxMap)
varIdx = varIdxMap->map (VarIdx::add (varIdx, offset));
else
varIdx += offset;
return coords ? varStore->get_delta (varIdx, coords, cache) : 0.f;
varIdx = varIdxMap->map (varIdx);
return varStore->get_delta (varIdx, coords, cache);
}
const ItemVariationStore *varStore;
@ -3767,12 +3781,11 @@ struct MultiItemVarStoreInstancer
void operator() (hb_array_t<float> out, uint32_t varIdx, unsigned short offset = 0) const
{
if (coords)
if (coords && varIdx != VarIdx::NO_VARIATION)
{
varIdx += offset;
if (varIdxMap)
varIdx = varIdxMap->map (VarIdx::add (varIdx, offset));
else
varIdx += offset;
varIdx = varIdxMap->map (varIdx);
varStore->get_delta (varIdx, coords, out, cache);
}
else
@ -3890,8 +3903,8 @@ struct ConditionAxisRange
{
// add axisIndex->value into the hashmap so we can check if the record is
// unique with variations
int16_t int_filter_max_val = filterRangeMaxValue.to_int ();
int16_t int_filter_min_val = filterRangeMinValue.to_int ();
uint16_t int_filter_max_val = (uint16_t) filterRangeMaxValue.to_int ();
uint16_t int_filter_min_val = (uint16_t) filterRangeMinValue.to_int ();
hb_codepoint_t val = (int_filter_max_val << 16) + int_filter_min_val;
condition_map->set (axisIndex, val);

View file

@ -713,6 +713,7 @@ struct hb_ot_apply_context_t :
recurse_func_t recurse_func = nullptr;
const GDEF &gdef;
const GDEF::accelerator_t &gdef_accel;
const hb_ot_layout_lookup_accelerator_t *lookup_accel = nullptr;
const ItemVariationStore &var_store;
ItemVariationStore::cache_t *var_store_cache;
hb_set_digest_t digest;
@ -762,10 +763,12 @@ struct hb_ot_apply_context_t :
nullptr
#endif
),
digest (buffer_->digest ()),
direction (buffer_->props.direction),
has_glyph_classes (gdef.has_glyph_classes ())
{ init_iters (); }
{
init_iters ();
buffer->collect_codepoints (digest);
}
~hb_ot_apply_context_t ()
{
@ -899,6 +902,13 @@ struct hb_ot_apply_context_t :
}
};
enum class hb_ot_lookup_cache_op_t
{
CREATE,
ENTER,
LEAVE,
DESTROY,
};
struct hb_accelerate_subtables_context_t :
hb_dispatch_context_t<hb_accelerate_subtables_context_t>
@ -923,19 +933,23 @@ struct hb_accelerate_subtables_context_t :
}
template <typename T>
static inline auto cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<1>) HB_RETURN (bool, obj->cache_func (c, enter) )
template <typename T>
static inline bool cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; }
static inline auto cache_func_ (void *p,
hb_ot_lookup_cache_op_t op,
hb_priority<1>) HB_RETURN (void *, T::cache_func (p, op) )
template <typename T=void>
static inline void * cache_func_ (void *p,
hb_ot_lookup_cache_op_t op HB_UNUSED,
hb_priority<0>) { return (void *) false; }
template <typename Type>
static inline bool cache_func_to (const void *obj, hb_ot_apply_context_t *c, bool enter)
static inline void * cache_func_to (void *p,
hb_ot_lookup_cache_op_t op)
{
const Type *typed_obj = (const Type *) obj;
return cache_func_ (typed_obj, c, enter, hb_prioritize);
return cache_func_<Type> (p, op, hb_prioritize);
}
#endif
typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c);
typedef bool (*hb_cache_func_t) (const void *obj, hb_ot_apply_context_t *c, bool enter);
typedef void * (*hb_cache_func_t) (void *p, hb_ot_lookup_cache_op_t op);
struct hb_applicable_t
{
@ -972,11 +986,11 @@ struct hb_accelerate_subtables_context_t :
}
bool cache_enter (hb_ot_apply_context_t *c) const
{
return cache_func (obj, c, true);
return (bool) cache_func (c, hb_ot_lookup_cache_op_t::ENTER);
}
void cache_leave (hb_ot_apply_context_t *c) const
{
cache_func (obj, c, false);
cache_func (c, hb_ot_lookup_cache_op_t::LEAVE);
}
#endif
@ -1462,6 +1476,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
if (this_comp == 0)
this_comp = last_num_components;
assert (components_so_far >= last_num_components);
unsigned int new_lig_comp = components_so_far - last_num_components +
hb_min (this_comp, last_num_components);
_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
@ -1487,6 +1502,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
if (!this_comp) break;
assert (components_so_far >= last_num_components);
unsigned new_lig_comp = components_so_far - last_num_components +
hb_min (this_comp, last_num_components);
_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
@ -1542,6 +1558,7 @@ static bool match_lookahead (hb_ot_apply_context_t *c,
TRACE_APPLY (nullptr);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
assert (start_index >= 1);
skippy_iter.reset (start_index - 1);
skippy_iter.set_match_func (match_func, match_data);
skippy_iter.set_glyph_data (lookahead);
@ -1852,6 +1869,7 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
if (match_positions != match_positions_input)
hb_free (match_positions);
assert (end >= 0);
(void) buffer->move_to (end);
}
@ -2619,25 +2637,35 @@ struct ContextFormat2_5
unsigned c = (this+classDef).cost () * ruleSet.len;
return c >= 4 ? c : 0;
}
bool cache_func (hb_ot_apply_context_t *c, bool enter) const
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
if (enter)
switch (op)
{
if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
return false;
auto &info = c->buffer->info;
unsigned count = c->buffer->len;
for (unsigned i = 0; i < count; i++)
info[i].syllable() = 255;
c->new_syllables = 255;
return true;
}
else
{
c->new_syllables = (unsigned) -1;
HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
return true;
case hb_ot_lookup_cache_op_t::CREATE:
return (void *) true;
case hb_ot_lookup_cache_op_t::ENTER:
{
hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
return (void *) false;
auto &info = c->buffer->info;
unsigned count = c->buffer->len;
for (unsigned i = 0; i < count; i++)
info[i].syllable() = 255;
c->new_syllables = 255;
return (void *) true;
}
case hb_ot_lookup_cache_op_t::LEAVE:
{
hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
c->new_syllables = (unsigned) -1;
HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
return nullptr;
}
case hb_ot_lookup_cache_op_t::DESTROY:
return nullptr;
}
return nullptr;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
@ -2646,7 +2674,7 @@ struct ContextFormat2_5
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
const ClassDef &class_def = this+classDef;
@ -2832,7 +2860,7 @@ struct ContextFormat3
{
TRACE_APPLY (this);
unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
struct ContextApplyLookupContext lookup_context = {
@ -3646,7 +3674,7 @@ struct ChainContextFormat1_4
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
const ChainRuleSet &rule_set = this+ruleSet[index];
struct ChainContextApplyLookupContext lookup_context = {
@ -3857,28 +3885,37 @@ struct ChainContextFormat2_5
unsigned cache_cost () const
{
unsigned c = (this+lookaheadClassDef).cost () * ruleSet.len;
return c >= 4 ? c : 0;
return (this+lookaheadClassDef).cost () * ruleSet.len;
}
bool cache_func (hb_ot_apply_context_t *c, bool enter) const
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
if (enter)
switch (op)
{
if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
return false;
auto &info = c->buffer->info;
unsigned count = c->buffer->len;
for (unsigned i = 0; i < count; i++)
info[i].syllable() = 255;
c->new_syllables = 255;
return true;
}
else
{
c->new_syllables = (unsigned) -1;
HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
return true;
case hb_ot_lookup_cache_op_t::CREATE:
return (void *) true;
case hb_ot_lookup_cache_op_t::ENTER:
{
hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
return (void *) false;
auto &info = c->buffer->info;
unsigned count = c->buffer->len;
for (unsigned i = 0; i < count; i++)
info[i].syllable() = 255;
c->new_syllables = 255;
return (void *) true;
}
case hb_ot_lookup_cache_op_t::LEAVE:
{
hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
c->new_syllables = (unsigned) -1;
HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
return nullptr;
}
case hb_ot_lookup_cache_op_t::DESTROY:
return nullptr;
}
return nullptr;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
@ -3887,7 +3924,7 @@ struct ChainContextFormat2_5
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
const ClassDef &backtrack_class_def = this+backtrackClassDef;
const ClassDef &input_class_def = this+inputClassDef;
@ -4133,7 +4170,7 @@ struct ChainContextFormat3
const auto &input = StructAfter<decltype (inputX)> (backtrack);
unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (index == NOT_COVERED) return_trace (false);
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
@ -4404,7 +4441,18 @@ struct hb_ot_layout_lookup_accelerator_t
thiz->digest.union_ (subtable.digest);
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
if (c_accelerate_subtables.cache_user_cost < 4)
c_accelerate_subtables.cache_user_idx = (unsigned) -1;
thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx;
if (thiz->cache_user_idx != (unsigned) -1)
{
thiz->cache = thiz->subtables[thiz->cache_user_idx].cache_func (nullptr, hb_ot_lookup_cache_op_t::CREATE);
if (!thiz->cache)
thiz->cache_user_idx = (unsigned) -1;
}
for (unsigned i = 0; i < count; i++)
if (i != thiz->cache_user_idx)
thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
@ -4413,6 +4461,17 @@ struct hb_ot_layout_lookup_accelerator_t
return thiz;
}
void fini ()
{
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
if (cache)
{
assert (cache_user_idx != (unsigned) -1);
subtables[cache_user_idx].cache_func (cache, hb_ot_lookup_cache_op_t::DESTROY);
}
#endif
}
bool may_have (hb_codepoint_t g) const
{ return digest.may_have (g); }
@ -4421,6 +4480,7 @@ struct hb_ot_layout_lookup_accelerator_t
#endif
bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const
{
c->lookup_accel = this;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
if (use_cache)
{
@ -4460,10 +4520,13 @@ struct hb_ot_layout_lookup_accelerator_t
hb_set_digest_t digest;
private:
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
public:
void *cache = nullptr;
private:
unsigned cache_user_idx = (unsigned) -1;
#endif
private:
hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
};
@ -4848,7 +4911,12 @@ struct GSUBGPOS
~accelerator_t ()
{
for (unsigned int i = 0; i < this->lookup_count; i++)
hb_free (this->accels[i]);
{
auto *accel = this->accels[i].get_relaxed ();
if (accel)
accel->fini ();
hb_free (accel);
}
hb_free (this->accels);
this->table.destroy ();
}
@ -4869,6 +4937,7 @@ struct GSUBGPOS
if (unlikely (!accels[lookup_index].cmpexch (nullptr, accel)))
{
accel->fini ();
hb_free (accel);
goto retry;
}

View file

@ -246,6 +246,18 @@ OT::GDEF::is_blocklisted (hb_blob_t *blob,
/* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf
* "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
case HB_CODEPOINT_ENCODE3 (1004, 59092, 14836):
/* 88d2006ca084f04af2df1954ed714a8c71e8400f Courier New.ttf from macOS 15 */
case HB_CODEPOINT_ENCODE3 (588, 5078, 14418):
/* 608e3ebb6dd1aee521cff08eb07d500a2c59df68 Courier New Bold.ttf from macOS 15 */
case HB_CODEPOINT_ENCODE3 (588, 5078, 14238):
/* d13221044ff054efd78f1cd8631b853c3ce85676 cour.ttf from Windows 10 */
case HB_CODEPOINT_ENCODE3 (894, 17162, 33960):
/* 68ed4a22d8067fcf1622ac6f6e2f4d3a2e3ec394 courbd.ttf from Windows 10 */
case HB_CODEPOINT_ENCODE3 (894, 17154, 34472):
/* 4cdb0259c96b7fd7c103821bb8f08f7cc6b211d7 cour.ttf from Windows 8.1 */
case HB_CODEPOINT_ENCODE3 (816, 7868, 17052):
/* 920483d8a8ed37f7f0afdabbe7f679aece7c75d8 courbd.ttf from Windows 8.1 */
case HB_CODEPOINT_ENCODE3 (816, 7868, 17138):
return true;
}
return false;
@ -1911,9 +1923,10 @@ apply_forward (OT::hb_ot_apply_context_t *c,
while (buffer->idx < buffer->len && buffer->successful)
{
bool applied = false;
if (accel.digest.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
auto &cur = buffer->cur();
if (accel.digest.may_have (cur.codepoint) &&
(cur.mask & c->lookup_mask) &&
c->check_glyph_property (&cur, c->lookup_props))
{
applied = accel.apply (c, subtable_count, use_cache);
}
@ -1939,9 +1952,10 @@ apply_backward (OT::hb_ot_apply_context_t *c,
hb_buffer_t *buffer = c->buffer;
do
{
if (accel.digest.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
auto &cur = buffer->cur();
if (accel.digest.may_have (cur.codepoint) &&
(cur.mask & c->lookup_mask) &&
c->check_glyph_property (&cur, c->lookup_props))
ret |= accel.apply (c, subtable_count, false);
/* The reverse lookup doesn't "advance" cursor (for good reason). */
@ -2021,7 +2035,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
* (plus some past glyphs).
*
* Only try applying the lookup if there is any overlap. */
if (accel->digest.may_have (c.digest))
if (accel->digest.may_intersect (c.digest))
{
c.set_lookup_index (lookup_index);
c.set_lookup_mask (lookup.mask, false);
@ -2047,7 +2061,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
if (stage->pause_func (plan, font, buffer))
{
/* Refresh working buffer digest since buffer changed. */
c.digest = buffer->digest ();
buffer->collect_codepoints (c.digest);
}
}
}

View file

@ -339,6 +339,11 @@ _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
!_hb_glyph_info_substituted (info);
}
static inline void
_hb_glyph_info_set_default_ignorable (hb_glyph_info_t *info)
{
info->unicode_props() |= UPROPS_MASK_IGNORABLE;
}
static inline void
_hb_glyph_info_clear_default_ignorable (hb_glyph_info_t *info)
{
info->unicode_props() &= ~ UPROPS_MASK_IGNORABLE;
@ -360,7 +365,7 @@ _hb_glyph_info_set_continuation (hb_glyph_info_t *info)
info->unicode_props() |= UPROPS_MASK_CONTINUATION;
}
static inline void
_hb_glyph_info_reset_continuation (hb_glyph_info_t *info)
_hb_glyph_info_clear_continuation (hb_glyph_info_t *info)
{
info->unicode_props() &= ~ UPROPS_MASK_CONTINUATION;
}
@ -633,8 +638,7 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
}
/* Make sure no one directly touches our props... */
#undef unicode_props0
#undef unicode_props1
#undef unicode_props
#undef lig_props
#undef glyph_props

View file

@ -390,5 +390,19 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
}
}
unsigned int hb_ot_map_t::get_feature_tags (unsigned int start_offset, unsigned int *tag_count, hb_tag_t *tags) const
{
if (tag_count)
{
auto sub_features = features.as_array ().sub_array (start_offset, tag_count);
if (tags)
{
for (unsigned int i = 0; i < sub_features.length; i++)
tags[i] = sub_features[i].tag;
}
}
return features.length;
}
#endif

View file

@ -166,6 +166,9 @@ struct hb_ot_map_t
const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
HB_INTERNAL unsigned int get_feature_tags (unsigned int start_offset,
unsigned int *tag_count, /* IN/OUT */
hb_tag_t *tags /* OUT */) const;
public:
hb_tag_t chosen_script[2];

View file

@ -284,8 +284,8 @@ struct OS2
os2_prime->usWidthClass = width_class;
}
os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
os2_prime->usLastCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->os2_info.min_cmap_codepoint);
os2_prime->usLastCharIndex = hb_min (0xFFFFu, c->plan->os2_info.max_cmap_codepoint);
if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
return_trace (true);

View file

@ -46,6 +46,8 @@
#include "hb-set.hh"
#include "hb-aat-layout.hh"
#include "hb-ot-stat-table.hh"
static inline bool
_hb_codepoint_is_regional_indicator (hb_codepoint_t u)
@ -121,10 +123,6 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
plan.kern_mask = plan.map.get_mask (kern_tag);
plan.requested_kerning = !!plan.kern_mask;
#endif
#ifndef HB_NO_AAT_SHAPE
plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k'));
plan.requested_tracking = !!plan.trak_mask;
#endif
bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX;
bool disable_gpos = plan.shaper->gpos_tag &&
@ -207,9 +205,6 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
https://github.com/harfbuzz/harfbuzz/issues/2967. */
if (plan.apply_morx)
plan.adjust_mark_positioning_when_zeroing = false;
/* Currently we always apply trak. */
plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
#endif
}
@ -274,11 +269,6 @@ hb_ot_shape_plan_t::position (hb_font_t *font,
#endif
else if (this->apply_fallback_kern)
_hb_ot_shape_fallback_kern (this, font, buffer);
#ifndef HB_NO_AAT_SHAPE
if (this->apply_trak)
hb_aat_layout_track (this, font, buffer);
#endif
}
@ -346,13 +336,6 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
/* Random! */
map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE);
#ifndef HB_NO_AAT_SHAPE
/* Tracking. We enable dummy feature here just to allow disabling
* AAT 'trak' table using features.
* https://github.com/harfbuzz/harfbuzz/issues/1303 */
map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK);
#endif
map->enable_feature (HB_TAG ('H','a','r','f')); /* Considered required. */
map->enable_feature (HB_TAG ('H','A','R','F')); /* Considered discretionary. */
@ -1277,6 +1260,36 @@ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
}
/**
* hb_ot_shape_plan_get_feature_tags:
* @shape_plan: A shaping plan
* @start_offset: The index of first feature to retrieve
* @tag_count: (inout): Input = the maximum number of features to return;
* Output = the actual number of features returned (may be zero)
* @tags: (out) (array length=tag_count): The array of enabled feature
*
* Fetches the list of OpenType feature tags enabled for a shaping plan, if possible.
*
* Return value: Total number of feature tagss.
*
* Since: 10.3.0
*/
unsigned int
hb_ot_shape_plan_get_feature_tags (hb_shape_plan_t *shape_plan,
unsigned int start_offset,
unsigned int *tag_count, /* IN/OUT */
hb_tag_t *tags /* OUT */)
{
#ifndef HB_NO_OT_SHAPE
return shape_plan->ot.map.get_feature_tags (start_offset, tag_count, tags);
#else
if (tag_count)
*tag_count = 0;
return 0;
#endif
}
/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
static void
add_char (hb_font_t *font,

View file

@ -48,6 +48,12 @@ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */);
HB_EXTERN unsigned int
hb_ot_shape_plan_get_feature_tags (hb_shape_plan_t *shape_plan,
unsigned int start_offset,
unsigned int *tag_count, /* IN/OUT */
hb_tag_t *tags /* OUT */);
HB_END_DECLS
#endif /* HB_OT_SHAPE_H */

View file

@ -51,7 +51,8 @@ struct hb_ot_shape_plan_key_t
bool equal (const hb_ot_shape_plan_key_t *other)
{
return 0 == hb_memcmp (this, other, sizeof (*this));
return variations_index[0] == other->variations_index[0] &&
variations_index[1] == other->variations_index[1];
}
};
@ -79,22 +80,12 @@ struct hb_ot_shape_plan_t
#else
static constexpr hb_mask_t kern_mask = 0;
#endif
#ifndef HB_NO_AAT_SHAPE
hb_mask_t trak_mask;
#else
static constexpr hb_mask_t trak_mask = 0;
#endif
#ifndef HB_NO_OT_KERN
bool requested_kerning : 1;
#else
static constexpr bool requested_kerning = false;
#endif
#ifndef HB_NO_AAT_SHAPE
bool requested_tracking : 1;
#else
static constexpr bool requested_tracking = false;
#endif
#ifndef HB_NO_OT_SHAPE_FRACTIONS
bool has_frac : 1;
#else
@ -117,11 +108,9 @@ struct hb_ot_shape_plan_t
#ifndef HB_NO_AAT_SHAPE
bool apply_kerx : 1;
bool apply_morx : 1;
bool apply_trak : 1;
#else
static constexpr bool apply_kerx = false;
static constexpr bool apply_morx = false;
static constexpr bool apply_trak = false;
#endif
void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const

View file

@ -355,6 +355,8 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
if (fallback_plan->lookup_array[i])
{
if (fallback_plan->accel_array[i])
fallback_plan->accel_array[i]->fini ();
hb_free (fallback_plan->accel_array[i]);
if (fallback_plan->free_lookups)
hb_free (fallback_plan->lookup_array[i]);

File diff suppressed because it is too large Load diff

View file

@ -48,6 +48,7 @@
#define OT_CM I_Cat(CM)
#define OT_Symbol I_Cat(Symbol)
#define OT_CS I_Cat(CS)
#define OT_SMPst I_Cat(SMPst)
/* khmer */
#define OT_VAbv K_Cat(VAbv)
#define OT_VBlw K_Cat(VBlw)
@ -94,7 +95,8 @@ static_assert (OT_VPst == M_Cat(VPst), "");
#define _OT_R OT_Ra /* 14 chars; Ra */
#define _OT_Rf OT_Repha /* 1 chars; Repha */
#define _OT_Rt OT_Robatic /* 3 chars; Robatic */
#define _OT_SM OT_SM /* 56 chars; SM */
#define _OT_SM OT_SM /* 50 chars; SM */
#define _OT_SP OT_SMPst /* 6 chars; SMPst */
#define _OT_S OT_Symbol /* 22 chars; Symbol */
#define _OT_V OT_V /* 172 chars; V */
#define _OT_VA OT_VAbv /* 18 chars; VAbv */
@ -145,7 +147,7 @@ static const uint16_t indic_table[] = {
/* Latin-1 Supplement */
/* 00B0 */ _(X,X), _(X,X),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X),
/* 00B0 */ _(X,X), _(X,X),_(SP,SM),_(SP,SM), _(X,X), _(X,X), _(X,X), _(X,X),
/* 00B8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
/* 00C0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
/* 00C8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
@ -398,9 +400,9 @@ static const uint16_t indic_table[] = {
/* Superscripts and Subscripts */
/* 2070 */ _(X,X), _(X,X), _(X,X), _(X,X),_(SM,SM), _(X,X), _(X,X), _(X,X),
/* 2070 */ _(X,X), _(X,X), _(X,X), _(X,X),_(SP,SM), _(X,X), _(X,X), _(X,X),
/* 2078 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X),
/* 2080 */ _(X,X), _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X),
/* 2080 */ _(X,X), _(X,X),_(SP,SM),_(SP,SM),_(SP,SM), _(X,X), _(X,X), _(X,X),
#define indic_offset_0x25f8u 1592
@ -540,6 +542,7 @@ hb_indic_get_categories (hb_codepoint_t u)
#undef _OT_Rf
#undef _OT_Rt
#undef _OT_SM
#undef _OT_SP
#undef _OT_S
#undef _OT_V
#undef _OT_VA

View file

@ -68,6 +68,7 @@ enum myanmar_syllable_type_t {
#define myanmar_syllable_machine_ex_PT 39u
#define myanmar_syllable_machine_ex_Ra 15u
#define myanmar_syllable_machine_ex_SM 8u
#define myanmar_syllable_machine_ex_SMPst 57u
#define myanmar_syllable_machine_ex_VAbv 20u
#define myanmar_syllable_machine_ex_VBlw 21u
#define myanmar_syllable_machine_ex_VPre 22u
@ -77,35 +78,35 @@ enum myanmar_syllable_type_t {
#define myanmar_syllable_machine_ex_ZWNJ 5u
#line 81 "hb-ot-shaper-myanmar-machine.hh"
#line 82 "hb-ot-shaper-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u,
5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u,
3u, 40u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 41u,
3u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u,
5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 41u, 3u, 39u,
3u, 39u, 3u, 40u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 39u, 3u, 41u, 3u, 41u,
3u, 41u, 3u, 41u, 3u, 41u, 3u, 41u, 3u, 41u, 1u, 41u, 1u, 15u, 0
1u, 57u, 3u, 57u, 5u, 57u, 5u, 57u, 3u, 57u, 5u, 57u, 3u, 57u, 3u, 57u,
3u, 57u, 3u, 57u, 3u, 57u, 5u, 57u, 1u, 15u, 3u, 57u, 3u, 57u, 3u, 57u,
3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u,
3u, 57u, 5u, 57u, 5u, 57u, 3u, 57u, 5u, 57u, 3u, 57u, 3u, 57u, 3u, 57u,
3u, 57u, 3u, 57u, 5u, 57u, 1u, 15u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u,
3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u,
3u, 57u, 3u, 57u, 3u, 57u, 1u, 57u, 1u, 15u, 0
};
static const char _myanmar_syllable_machine_key_spans[] = {
41, 39, 35, 4, 39, 37, 37, 35,
35, 37, 37, 39, 35, 15, 37, 37,
38, 37, 39, 39, 37, 39, 39, 39,
39, 39, 35, 4, 39, 37, 37, 35,
35, 37, 37, 39, 35, 15, 39, 37,
37, 38, 37, 39, 39, 37, 39, 39,
39, 39, 39, 39, 39, 41, 15
57, 55, 53, 53, 55, 53, 55, 55,
55, 55, 55, 53, 15, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 53, 53, 55, 53, 55, 55, 55,
55, 55, 53, 15, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 57, 15
};
static const short _myanmar_syllable_machine_index_offsets[] = {
0, 42, 82, 118, 123, 163, 201, 239,
275, 311, 349, 387, 427, 463, 479, 517,
555, 594, 632, 672, 712, 750, 790, 830,
870, 910, 950, 986, 991, 1031, 1069, 1107,
1143, 1179, 1217, 1255, 1295, 1331, 1347, 1387,
1425, 1463, 1502, 1540, 1580, 1620, 1658, 1698,
1738, 1778, 1818, 1858, 1898, 1938, 1980
0, 58, 114, 168, 222, 278, 332, 388,
444, 500, 556, 612, 666, 682, 738, 794,
850, 906, 962, 1018, 1074, 1130, 1186, 1242,
1298, 1354, 1408, 1462, 1518, 1572, 1628, 1684,
1740, 1796, 1852, 1906, 1922, 1978, 2034, 2090,
2146, 2202, 2258, 2314, 2370, 2426, 2482, 2538,
2594, 2650, 2706, 2762, 2820
};
static const char _myanmar_syllable_machine_indicies[] = {
@ -114,273 +115,378 @@ static const char _myanmar_syllable_machine_indicies[] = {
0, 8, 0, 9, 10, 11, 12, 0,
0, 0, 0, 0, 0, 0, 0, 13,
0, 0, 14, 15, 16, 17, 18, 19,
20, 0, 22, 23, 24, 24, 21, 25,
26, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 27, 28, 29, 30, 21,
21, 21, 21, 21, 21, 21, 21, 31,
21, 21, 32, 33, 34, 35, 36, 37,
38, 21, 24, 24, 21, 25, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 30, 21, 21, 21,
21, 21, 21, 21, 21, 39, 21, 21,
21, 21, 21, 21, 36, 21, 24, 24,
21, 25, 21, 22, 21, 24, 24, 21,
25, 26, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 40, 21, 21, 30,
21, 21, 21, 21, 21, 21, 21, 21,
41, 21, 21, 42, 21, 21, 21, 36,
21, 41, 21, 22, 21, 24, 24, 21,
25, 26, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 30,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 36,
21, 43, 21, 24, 24, 21, 25, 36,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 44, 21,
21, 21, 21, 21, 21, 36, 21, 24,
24, 21, 25, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 44, 21, 21, 21, 21, 21,
21, 36, 21, 24, 24, 21, 25, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 36, 21, 22,
21, 24, 24, 21, 25, 26, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
40, 21, 21, 30, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 36, 21, 22, 21, 24,
24, 21, 25, 26, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 40, 21,
21, 30, 21, 21, 21, 21, 21, 21,
21, 21, 41, 21, 21, 21, 21, 21,
21, 36, 21, 22, 21, 24, 24, 21,
25, 26, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 40, 21, 21, 30,
21, 21, 21, 21, 21, 21, 21, 21,
41, 21, 21, 21, 21, 21, 21, 36,
21, 41, 21, 24, 24, 21, 25, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 30, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 36, 21, 1,
1, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 1, 21, 22,
21, 24, 24, 21, 25, 26, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
27, 28, 21, 30, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 36, 21, 22, 21, 24,
24, 21, 25, 26, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 28,
21, 30, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 36, 21, 22, 21, 24, 24, 21,
25, 26, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 27, 28, 29, 30,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 36,
45, 21, 22, 21, 24, 24, 21, 25,
26, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 27, 28, 29, 30, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 36, 21,
22, 21, 24, 24, 21, 25, 26, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 27, 28, 29, 30, 21, 21, 21,
21, 21, 21, 21, 21, 31, 21, 21,
32, 33, 34, 35, 36, 21, 38, 21,
22, 21, 24, 24, 21, 25, 26, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 27, 28, 29, 30, 21, 21, 21,
21, 21, 21, 21, 21, 45, 21, 21,
21, 21, 21, 21, 36, 21, 38, 21,
22, 21, 24, 24, 21, 25, 26, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 27, 28, 29, 30, 21, 21, 21,
21, 21, 21, 21, 21, 45, 21, 21,
21, 21, 21, 21, 36, 21, 22, 21,
24, 24, 21, 25, 26, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 27,
28, 29, 30, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 32, 21,
34, 21, 36, 21, 38, 21, 22, 21,
24, 24, 21, 25, 26, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 27,
28, 29, 30, 21, 21, 21, 21, 21,
21, 21, 21, 45, 21, 21, 32, 21,
21, 21, 36, 21, 38, 21, 22, 21,
24, 24, 21, 25, 26, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 27,
28, 29, 30, 21, 21, 21, 21, 21,
21, 21, 21, 46, 21, 21, 32, 33,
34, 21, 36, 21, 38, 21, 22, 21,
24, 24, 21, 25, 26, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 27,
28, 29, 30, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 32, 33,
34, 21, 36, 21, 38, 21, 22, 23,
24, 24, 21, 25, 26, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 27,
28, 29, 30, 21, 21, 21, 21, 21,
21, 21, 21, 31, 21, 21, 32, 33,
34, 35, 36, 21, 38, 21, 48, 48,
20, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 0, 23, 24, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 32,
22, 22, 33, 34, 35, 36, 37, 38,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 25, 25, 22, 26, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 31, 22, 22, 22,
22, 22, 22, 22, 22, 40, 22, 22,
22, 22, 22, 22, 37, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 26, 22,
25, 25, 22, 26, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 37, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 26, 22, 41, 22,
25, 25, 22, 26, 37, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 26, 22, 22, 22, 22,
22, 22, 37, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 26, 22, 25, 25,
22, 26, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 26, 22, 22, 22, 22, 22, 22,
37, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 26, 22, 23, 22, 25, 25,
22, 26, 27, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 42, 22, 22,
31, 22, 22, 22, 22, 22, 22, 22,
22, 43, 22, 22, 44, 22, 22, 22,
37, 22, 43, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 26, 22, 23, 22, 25, 25,
22, 26, 27, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
31, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
37, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 26, 22, 23, 22, 25, 25,
22, 26, 27, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 42, 22, 22,
31, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
37, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 26, 22, 23, 22, 25, 25,
22, 26, 27, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 42, 22, 22,
31, 22, 22, 22, 22, 22, 22, 22,
22, 43, 22, 22, 22, 22, 22, 22,
37, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 26, 22, 23, 22, 25, 25,
22, 26, 27, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 42, 22, 22,
31, 22, 22, 22, 22, 22, 22, 22,
22, 43, 22, 22, 22, 22, 22, 22,
37, 22, 43, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 26, 22, 25, 25, 22, 26,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 31, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 37, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 1, 1, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
1, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 22, 31, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 37, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 29, 22, 31, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 37, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 37, 45,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 37, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 32,
22, 22, 33, 34, 35, 36, 37, 22,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 45,
22, 22, 22, 22, 22, 22, 37, 22,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 45,
22, 22, 22, 22, 22, 22, 37, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 33, 22, 35, 22, 37, 22,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 45,
22, 22, 33, 22, 22, 22, 37, 22,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 46,
22, 22, 33, 34, 35, 22, 37, 22,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 22, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 33, 34, 35, 22, 37, 22,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 24, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 32,
22, 22, 33, 34, 35, 36, 37, 22,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 48, 48, 47, 5, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 12, 47, 47, 47,
47, 47, 47, 47, 47, 49, 47, 47,
47, 47, 47, 47, 18, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 5, 47,
48, 48, 50, 5, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 18, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 5, 50, 51, 47,
48, 48, 47, 5, 18, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 5, 47, 47, 47, 47,
47, 47, 18, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 5, 47, 48, 48,
47, 5, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
12, 47, 47, 47, 47, 47, 47, 47,
47, 49, 47, 47, 47, 47, 47, 47,
18, 47, 48, 48, 47, 5, 47, 2,
47, 48, 48, 47, 5, 6, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
50, 47, 47, 12, 47, 47, 47, 47,
47, 47, 47, 47, 51, 47, 47, 52,
47, 47, 47, 18, 47, 51, 47, 2,
47, 48, 48, 47, 5, 6, 47, 47,
47, 5, 47, 47, 47, 47, 47, 47,
18, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 12, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 18, 47, 53, 47, 48,
48, 47, 5, 18, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 54, 47, 47, 47, 47, 47,
47, 18, 47, 48, 48, 47, 5, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 54, 47,
47, 47, 47, 47, 47, 18, 47, 48,
48, 47, 5, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 18, 47, 2, 47, 48, 48, 47,
5, 6, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 50, 47, 47, 12,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 18,
47, 2, 47, 48, 48, 47, 5, 6,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 50, 47, 47, 12, 47, 47,
47, 47, 47, 47, 47, 47, 51, 47,
47, 47, 47, 47, 47, 18, 47, 2,
47, 48, 48, 47, 5, 6, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
50, 47, 47, 12, 47, 47, 47, 47,
47, 47, 47, 47, 51, 47, 47, 47,
47, 47, 47, 18, 47, 51, 47, 48,
48, 47, 5, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 12, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 18, 47, 55, 55, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 55, 47, 2, 3, 48, 48, 47,
5, 6, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 9, 10, 11, 12,
47, 47, 47, 47, 47, 47, 47, 47,
13, 47, 47, 14, 15, 16, 17, 18,
19, 20, 47, 2, 47, 48, 48, 47,
5, 6, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 9, 10, 47, 12,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 18,
47, 2, 47, 48, 48, 47, 5, 6,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 10, 47, 12, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 18, 47, 2,
47, 48, 48, 47, 5, 6, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
9, 10, 11, 12, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 18, 56, 47, 2, 47,
48, 48, 47, 5, 6, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 9,
10, 11, 12, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 18, 47, 2, 47, 48, 48,
47, 47, 5, 47, 2, 47, 48, 48,
47, 5, 6, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 9, 10, 11,
47, 47, 47, 47, 47, 52, 47, 47,
12, 47, 47, 47, 47, 47, 47, 47,
47, 13, 47, 47, 14, 15, 16, 17,
18, 47, 20, 47, 2, 47, 48, 48,
47, 53, 47, 47, 54, 47, 47, 47,
18, 47, 53, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 5, 47, 2, 47, 48, 48,
47, 5, 6, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 9, 10, 11,
47, 47, 47, 47, 47, 47, 47, 47,
12, 47, 47, 47, 47, 47, 47, 47,
47, 56, 47, 47, 47, 47, 47, 47,
18, 47, 20, 47, 2, 47, 48, 48,
47, 47, 47, 47, 47, 47, 47, 47,
18, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 5, 47, 2, 47, 48, 48,
47, 5, 6, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 9, 10, 11,
47, 47, 47, 47, 47, 52, 47, 47,
12, 47, 47, 47, 47, 47, 47, 47,
47, 56, 47, 47, 47, 47, 47, 47,
18, 47, 2, 47, 48, 48, 47, 5,
47, 47, 47, 47, 47, 47, 47, 47,
18, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 5, 47, 2, 47, 48, 48,
47, 5, 6, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 52, 47, 47,
12, 47, 47, 47, 47, 47, 47, 47,
47, 53, 47, 47, 47, 47, 47, 47,
18, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 5, 47, 2, 47, 48, 48,
47, 5, 6, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 52, 47, 47,
12, 47, 47, 47, 47, 47, 47, 47,
47, 53, 47, 47, 47, 47, 47, 47,
18, 47, 53, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 5, 47, 48, 48, 47, 5,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 12, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 18, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 55, 55, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
55, 47, 2, 3, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 13,
47, 47, 14, 15, 16, 17, 18, 19,
20, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 47, 12, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 18, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 10, 47, 12, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 18, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 14, 47, 16, 47, 18, 47,
20, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 56,
47, 47, 14, 47, 47, 47, 18, 47,
20, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 57,
47, 47, 14, 15, 16, 47, 18, 47,
20, 47, 2, 47, 48, 48, 47, 5,
47, 47, 47, 47, 47, 47, 18, 56,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 14, 15, 16, 47, 18, 47,
20, 47, 2, 3, 48, 48, 47, 5,
47, 47, 47, 47, 47, 47, 18, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 13,
47, 47, 14, 15, 16, 17, 18, 47,
20, 47, 22, 23, 24, 24, 21, 25,
26, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 27, 28, 29, 30, 21,
21, 21, 21, 21, 21, 21, 21, 58,
21, 21, 32, 33, 34, 35, 36, 37,
38, 21, 22, 59, 24, 24, 21, 25,
26, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 27, 28, 29, 30, 21,
21, 21, 21, 21, 21, 21, 21, 31,
21, 21, 32, 33, 34, 35, 36, 21,
38, 21, 1, 1, 2, 3, 48, 48,
20, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 56,
47, 47, 47, 47, 47, 47, 18, 47,
20, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 56,
47, 47, 47, 47, 47, 47, 18, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 14, 47, 16, 47, 18, 47,
20, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 56,
47, 47, 14, 47, 47, 47, 18, 47,
20, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 57,
47, 47, 14, 15, 16, 47, 18, 47,
20, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 47, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 14, 15, 16, 47, 18, 47,
20, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 2, 3, 48, 48, 47, 5,
6, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 9, 10, 11, 12, 47,
47, 47, 47, 47, 47, 47, 47, 13,
47, 47, 14, 15, 16, 17, 18, 47,
20, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
5, 47, 23, 24, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 58,
22, 22, 33, 34, 35, 36, 37, 38,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 23, 59, 25, 25, 22, 26,
27, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 28, 29, 30, 31, 22,
22, 22, 22, 22, 22, 22, 22, 32,
22, 22, 33, 34, 35, 36, 37, 22,
39, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
26, 22, 1, 1, 2, 3, 48, 48,
47, 5, 6, 1, 1, 47, 47, 47,
1, 47, 47, 47, 47, 9, 10, 11,
12, 47, 47, 47, 47, 47, 47, 47,
47, 13, 47, 47, 14, 15, 16, 17,
18, 19, 20, 47, 1, 1, 60, 60,
18, 19, 20, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 5, 47, 1, 1, 60, 60,
60, 60, 60, 60, 60, 1, 1, 60,
60, 60, 1, 60, 0
};
static const char _myanmar_syllable_machine_trans_targs[] = {
0, 1, 26, 37, 0, 27, 29, 51,
54, 39, 40, 41, 28, 43, 44, 46,
47, 48, 30, 50, 45, 0, 2, 13,
0, 3, 5, 14, 15, 16, 4, 18,
19, 21, 22, 23, 6, 25, 20, 12,
9, 10, 11, 7, 8, 17, 24, 0,
0, 36, 33, 34, 35, 31, 32, 38,
42, 49, 52, 53, 0
0, 1, 25, 35, 0, 26, 30, 49,
52, 37, 38, 39, 29, 41, 42, 44,
45, 46, 27, 48, 43, 26, 0, 2,
12, 0, 3, 7, 13, 14, 15, 6,
17, 18, 20, 21, 22, 4, 24, 19,
11, 5, 8, 9, 10, 16, 23, 0,
0, 34, 0, 28, 31, 32, 33, 36,
40, 47, 50, 51, 0
};
static const char _myanmar_syllable_machine_trans_actions[] = {
3, 0, 0, 0, 4, 0, 0, 0,
3, 0, 0, 0, 4, 5, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 5, 0, 0,
6, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 6, 7, 0,
0, 8, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 7,
8, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 9
0, 0, 0, 0, 0, 0, 0, 9,
10, 0, 11, 0, 0, 0, 0, 0,
0, 0, 0, 0, 12
};
static const char _myanmar_syllable_machine_to_state_actions[] = {
@ -390,7 +496,7 @@ static const char _myanmar_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0
};
static const char _myanmar_syllable_machine_from_state_actions[] = {
@ -400,17 +506,17 @@ static const char _myanmar_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0
};
static const short _myanmar_syllable_machine_eof_trans[] = {
0, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 48, 48, 48, 48, 48, 48,
0, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23,
23, 48, 51, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 22, 22, 48, 61
48, 23, 23, 48, 61
};
static const int myanmar_syllable_machine_start = 0;
@ -424,7 +530,7 @@ static const int myanmar_syllable_machine_en_main = 0;
#line 117 "hb-ot-shaper-myanmar-machine.rl"
#line 118 "hb-ot-shaper-myanmar-machine.rl"
#define found_syllable(syllable_type) \
@ -443,7 +549,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
#line 447 "hb-ot-shaper-myanmar-machine.hh"
#line 553 "hb-ot-shaper-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
@ -451,7 +557,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
act = 0;
}
#line 137 "hb-ot-shaper-myanmar-machine.rl"
#line 138 "hb-ot-shaper-myanmar-machine.rl"
p = 0;
@ -459,7 +565,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
#line 463 "hb-ot-shaper-myanmar-machine.hh"
#line 569 "hb-ot-shaper-myanmar-machine.hh"
{
int _slen;
int _trans;
@ -473,7 +579,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
#line 477 "hb-ot-shaper-myanmar-machine.hh"
#line 583 "hb-ot-shaper-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@ -491,35 +597,59 @@ _eof_trans:
goto _again;
switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
case 6:
#line 110 "hb-ot-shaper-myanmar-machine.rl"
case 8:
#line 111 "hb-ot-shaper-myanmar-machine.rl"
{te = p+1;{ found_syllable (myanmar_consonant_syllable); }}
break;
case 4:
#line 111 "hb-ot-shaper-myanmar-machine.rl"
#line 112 "hb-ot-shaper-myanmar-machine.rl"
{te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
case 8:
#line 112 "hb-ot-shaper-myanmar-machine.rl"
case 10:
#line 113 "hb-ot-shaper-myanmar-machine.rl"
{te = p+1;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
break;
case 3:
#line 113 "hb-ot-shaper-myanmar-machine.rl"
#line 114 "hb-ot-shaper-myanmar-machine.rl"
{te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
case 5:
#line 110 "hb-ot-shaper-myanmar-machine.rl"
{te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
break;
case 7:
#line 112 "hb-ot-shaper-myanmar-machine.rl"
{te = p;p--;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
#line 111 "hb-ot-shaper-myanmar-machine.rl"
{te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
break;
case 9:
#line 113 "hb-ot-shaper-myanmar-machine.rl"
{te = p;p--;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
break;
case 12:
#line 114 "hb-ot-shaper-myanmar-machine.rl"
{te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
#line 523 "hb-ot-shaper-myanmar-machine.hh"
case 11:
#line 1 "NONE"
{ switch( act ) {
case 2:
{{p = ((te))-1;} found_syllable (myanmar_non_myanmar_cluster); }
break;
case 3:
{{p = ((te))-1;} found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }
break;
}
}
break;
case 6:
#line 1 "NONE"
{te = p+1;}
#line 112 "hb-ot-shaper-myanmar-machine.rl"
{act = 2;}
break;
case 5:
#line 1 "NONE"
{te = p+1;}
#line 113 "hb-ot-shaper-myanmar-machine.rl"
{act = 3;}
break;
#line 653 "hb-ot-shaper-myanmar-machine.hh"
}
_again:
@ -528,7 +658,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
#line 532 "hb-ot-shaper-myanmar-machine.hh"
#line 662 "hb-ot-shaper-myanmar-machine.hh"
}
if ( ++p != pe )
@ -544,7 +674,7 @@ _again:
}
#line 145 "hb-ot-shaper-myanmar-machine.rl"
#line 146 "hb-ot-shaper-myanmar-machine.rl"
}

File diff suppressed because it is too large Load diff

View file

@ -24,7 +24,7 @@ static void
_output_dotted_circle (hb_buffer_t *buffer)
{
(void) buffer->output_glyph (0x25CCu);
_hb_glyph_info_reset_continuation (&buffer->prev());
_hb_glyph_info_clear_continuation (&buffer->prev());
}
static void

View file

@ -6,8 +6,8 @@
*
* on files with these headers:
*
* <meta name="updated_at" content="2024-07-07 12:57 AM" />
* File-Date: 2024-06-14
* <meta name="updated_at" content="2024-12-06 06:35 AM" />
* File-Date: 2025-01-21
*/
#ifndef HB_OT_TAG_TABLE_HH
@ -745,6 +745,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('h','n','d',' '), HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */
{HB_TAG('h','n','e',' '), HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */
{HB_TAG('h','n','j',' '), HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */
{HB_TAG('h','n','m',' '), HB_TAG('Z','H','S',' ')}, /* Hainanese -> Chinese, Simplified */
{HB_TAG('h','n','o',' '), HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */
{HB_TAG('h','o','c',' '), HB_TAG('H','O',' ',' ')}, /* Ho */
{HB_TAG('h','o','i',' '), HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */
@ -830,6 +831,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('k','f','x',' '), HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */
{HB_TAG('k','f','y',' '), HB_TAG('K','M','N',' ')}, /* Kumaoni */
{HB_TAG('k','g','e',' '), HB_TAG_NONE }, /* Komering != Khutsuri Georgian */
/*{HB_TAG('k','g','f',' '), HB_TAG('K','G','F',' ')},*/ /* Kube */
{HB_TAG('k','h','a',' '), HB_TAG('K','S','I',' ')}, /* Khasi */
{HB_TAG('k','h','b',' '), HB_TAG('X','B','D',' ')}, /* Lü */
{HB_TAG('k','h','k',' '), HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */
@ -855,6 +857,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('k','l','m',' '), HB_TAG_NONE }, /* Migum != Kalmyk */
{HB_TAG('k','l','n',' '), HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */
{HB_TAG('k','m','b',' '), HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */
/*{HB_TAG('k','m','g',' '), HB_TAG('K','M','G',' ')},*/ /* Kâte */
{HB_TAG('k','m','n',' '), HB_TAG_NONE }, /* Awtuw != Kumaoni */
{HB_TAG('k','m','o',' '), HB_TAG_NONE }, /* Kwoma != Komo */
{HB_TAG('k','m','r',' '), HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */
@ -898,6 +901,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('k','s','i',' '), HB_TAG_NONE }, /* Krisa != Khasi */
{HB_TAG('k','s','m',' '), HB_TAG_NONE }, /* Kumba != Kildin Sami */
{HB_TAG('k','s','s',' '), HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */
/*{HB_TAG('k','s','u',' '), HB_TAG('K','S','U',' ')},*/ /* Khamyang */
{HB_TAG('k','s','w',' '), HB_TAG('K','S','W',' ')}, /* Sgaw Karen */
{HB_TAG('k','s','w',' '), HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */
{HB_TAG('k','t','b',' '), HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */
@ -911,6 +915,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('k','u','y',' '), HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */
{HB_TAG('k','v','b',' '), HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */
{HB_TAG('k','v','l',' '), HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */
{HB_TAG('k','v','q',' '), HB_TAG('K','V','Q',' ')}, /* Geba Karen */
{HB_TAG('k','v','q',' '), HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */
{HB_TAG('k','v','r',' '), HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */
{HB_TAG('k','v','t',' '), HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */
@ -977,9 +982,11 @@ static const LangTag ot_languages3[] = {
{HB_TAG('l','t','o',' '), HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */
{HB_TAG('l','t','s',' '), HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */
/*{HB_TAG('l','u','a',' '), HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */
{HB_TAG('l','u','h',' '), HB_TAG('Z','H','S',' ')}, /* Leizhou Chinese -> Chinese, Simplified */
/*{HB_TAG('l','u','o',' '), HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */
{HB_TAG('l','u','s',' '), HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */
{HB_TAG('l','u','s',' '), HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */
/*{HB_TAG('l','u','t',' '), HB_TAG('L','U','T',' ')},*/ /* Lushootseed */
{HB_TAG('l','u','y',' '), HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */
{HB_TAG('l','u','z',' '), HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */
{HB_TAG('l','v','i',' '), HB_TAG_NONE }, /* Lavi != Latvian */
@ -1146,6 +1153,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('n','o','d',' '), HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */
/*{HB_TAG('n','o','e',' '), HB_TAG('N','O','E',' ')},*/ /* Nimadi */
/*{HB_TAG('n','o','g',' '), HB_TAG('N','O','G',' ')},*/ /* Nogai */
/*{HB_TAG('n','o','p',' '), HB_TAG('N','O','P',' ')},*/ /* Numanggang */
/*{HB_TAG('n','o','v',' '), HB_TAG('N','O','V',' ')},*/ /* Novial */
{HB_TAG('n','p','i',' '), HB_TAG('N','E','P',' ')}, /* Nepali */
{HB_TAG('n','p','l',' '), HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */
@ -1156,6 +1164,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('n','s','u',' '), HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */
{HB_TAG('n','t','o',' '), HB_TAG_NONE }, /* Ntomba != Esperanto */
{HB_TAG('n','u','e',' '), HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */
/*{HB_TAG('n','u','k',' '), HB_TAG('N','U','K',' ')},*/ /* Nuu-chah-nulth */
{HB_TAG('n','u','u',' '), HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */
{HB_TAG('n','u','z',' '), HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */
{HB_TAG('n','w','e',' '), HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */
@ -1398,9 +1407,12 @@ static const LangTag ot_languages3[] = {
{HB_TAG('s','i','g',' '), HB_TAG_NONE }, /* Paasaal != Silte Gurage */
{HB_TAG('s','i','z',' '), HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */
/*{HB_TAG('s','j','a',' '), HB_TAG('S','J','A',' ')},*/ /* Epena */
{HB_TAG('s','j','c',' '), HB_TAG('Z','H','S',' ')}, /* Shaojiang Chinese -> Chinese, Simplified */
{HB_TAG('s','j','d',' '), HB_TAG('K','S','M',' ')}, /* Kildin Sami */
/*{HB_TAG('s','j','e',' '), HB_TAG('S','J','E',' ')},*/ /* Pite Sami */
{HB_TAG('s','j','o',' '), HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */
{HB_TAG('s','j','s',' '), HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */
/*{HB_TAG('s','j','u',' '), HB_TAG('S','J','U',' ')},*/ /* Ume Sami */
{HB_TAG('s','k','g',' '), HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */
{HB_TAG('s','k','r',' '), HB_TAG('S','R','K',' ')}, /* Saraiki */
{HB_TAG('s','k','s',' '), HB_TAG_NONE }, /* Maia != Skolt Sami */
@ -1461,6 +1473,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('t','a','q',' '), HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */
{HB_TAG('t','a','s',' '), HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */
{HB_TAG('t','a','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */
/*{HB_TAG('t','b','v',' '), HB_TAG('T','B','V',' ')},*/ /* Tobo */
{HB_TAG('t','c','b',' '), HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */
{HB_TAG('t','c','e',' '), HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */
{HB_TAG('t','c','h',' '), HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */
@ -1623,7 +1636,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('y','b','a',' '), HB_TAG_NONE }, /* Yala != Yoruba */
{HB_TAG('y','b','b',' '), HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */
{HB_TAG('y','b','d',' '), HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */
{HB_TAG('y','c','r',' '), HB_TAG_NONE }, /* Yilan Creole != Y-Cree */
{HB_TAG('y','c','r',' '), HB_TAG('C','P','P',' ')}, /* Yilan Creole -> Creoles */
{HB_TAG('y','d','d',' '), HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */
/*{HB_TAG('y','g','p',' '), HB_TAG('Y','G','P',' ')},*/ /* Gepo */
{HB_TAG('y','i','h',' '), HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */
@ -2377,6 +2390,26 @@ out:
*count = i;
return true;
}
if (lang_matches (&lang_str[1], limit, "nm-hant-hk", 10))
{
/* Hainanese; Han (Traditional variant); Hong Kong */
tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "nm-hant-mo", 10))
{
/* Hainanese; Han (Traditional variant); Macao */
unsigned int i;
hb_tag_t possible_tags[] = {
HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */
HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */
};
for (i = 0; i < 2 && i < *count; i++)
tags[i] = possible_tags[i];
*count = i;
return true;
}
if (lang_matches (&lang_str[1], limit, "sn-hant-hk", 10))
{
/* Xiang Chinese; Han (Traditional variant); Hong Kong */
@ -2411,6 +2444,20 @@ out:
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "nm-hans", 7))
{
/* Hainanese; Han (Simplified variant) */
tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "nm-hant", 7))
{
/* Hainanese; Han (Traditional variant) */
tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "sn-hans", 7))
{
/* Xiang Chinese; Han (Simplified variant) */
@ -2455,6 +2502,36 @@ out:
*count = 1;
return true;
}
if (0 == strncmp (&lang_str[1], "nm-", 3)
&& subtag_matches (lang_str, limit, "-hk", 3))
{
/* Hainanese; Hong Kong */
tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */
*count = 1;
return true;
}
if (0 == strncmp (&lang_str[1], "nm-", 3)
&& subtag_matches (lang_str, limit, "-mo", 3))
{
/* Hainanese; Macao */
unsigned int i;
hb_tag_t possible_tags[] = {
HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */
HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */
};
for (i = 0; i < 2 && i < *count; i++)
tags[i] = possible_tags[i];
*count = i;
return true;
}
if (0 == strncmp (&lang_str[1], "nm-", 3)
&& subtag_matches (lang_str, limit, "-tw", 3))
{
/* Hainanese; Taiwan, Province of China */
tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */
*count = 1;
return true;
}
if (0 == strncmp (&lang_str[1], "sn-", 3)
&& subtag_matches (lang_str, limit, "-hk", 3))
{
@ -2516,6 +2593,40 @@ out:
}
break;
case 'l':
if (lang_matches (&lang_str[1], limit, "uh-hant-hk", 10))
{
/* Leizhou Chinese; Han (Traditional variant); Hong Kong */
tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "uh-hant-mo", 10))
{
/* Leizhou Chinese; Han (Traditional variant); Macao */
unsigned int i;
hb_tag_t possible_tags[] = {
HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */
HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */
};
for (i = 0; i < 2 && i < *count; i++)
tags[i] = possible_tags[i];
*count = i;
return true;
}
if (lang_matches (&lang_str[1], limit, "uh-hans", 7))
{
/* Leizhou Chinese; Han (Simplified variant) */
tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "uh-hant", 7))
{
/* Leizhou Chinese; Han (Traditional variant) */
tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "zh-hans", 7))
{
/* Literary Chinese; Han (Simplified variant) */
@ -2523,6 +2634,36 @@ out:
*count = 1;
return true;
}
if (0 == strncmp (&lang_str[1], "uh-", 3)
&& subtag_matches (lang_str, limit, "-hk", 3))
{
/* Leizhou Chinese; Hong Kong */
tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */
*count = 1;
return true;
}
if (0 == strncmp (&lang_str[1], "uh-", 3)
&& subtag_matches (lang_str, limit, "-mo", 3))
{
/* Leizhou Chinese; Macao */
unsigned int i;
hb_tag_t possible_tags[] = {
HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */
HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */
};
for (i = 0; i < 2 && i < *count; i++)
tags[i] = possible_tags[i];
*count = i;
return true;
}
if (0 == strncmp (&lang_str[1], "uh-", 3)
&& subtag_matches (lang_str, limit, "-tw", 3))
{
/* Leizhou Chinese; Taiwan, Province of China */
tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */
*count = 1;
return true;
}
break;
case 'm':
if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10))
@ -2694,6 +2835,72 @@ out:
return true;
}
break;
case 's':
if (lang_matches (&lang_str[1], limit, "jc-hant-hk", 10))
{
/* Shaojiang Chinese; Han (Traditional variant); Hong Kong */
tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "jc-hant-mo", 10))
{
/* Shaojiang Chinese; Han (Traditional variant); Macao */
unsigned int i;
hb_tag_t possible_tags[] = {
HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */
HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */
};
for (i = 0; i < 2 && i < *count; i++)
tags[i] = possible_tags[i];
*count = i;
return true;
}
if (lang_matches (&lang_str[1], limit, "jc-hans", 7))
{
/* Shaojiang Chinese; Han (Simplified variant) */
tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */
*count = 1;
return true;
}
if (lang_matches (&lang_str[1], limit, "jc-hant", 7))
{
/* Shaojiang Chinese; Han (Traditional variant) */
tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */
*count = 1;
return true;
}
if (0 == strncmp (&lang_str[1], "jc-", 3)
&& subtag_matches (lang_str, limit, "-hk", 3))
{
/* Shaojiang Chinese; Hong Kong */
tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */
*count = 1;
return true;
}
if (0 == strncmp (&lang_str[1], "jc-", 3)
&& subtag_matches (lang_str, limit, "-mo", 3))
{
/* Shaojiang Chinese; Macao */
unsigned int i;
hb_tag_t possible_tags[] = {
HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */
HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */
};
for (i = 0; i < 2 && i < *count; i++)
tags[i] = possible_tags[i];
*count = i;
return true;
}
if (0 == strncmp (&lang_str[1], "jc-", 3)
&& subtag_matches (lang_str, limit, "-tw", 3))
{
/* Shaojiang Chinese; Taiwan, Province of China */
tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */
*count = 1;
return true;
}
break;
case 'w':
if (lang_matches (&lang_str[1], limit, "uu-hant-hk", 10))
{

View file

@ -231,9 +231,9 @@ struct tuple_delta_t
/* indices_length = point_count, indice[i] = 1 means point i is referenced */
hb_vector_t<bool> indices;
hb_vector_t<double> deltas_x;
hb_vector_t<float> deltas_x;
/* empty for cvar tuples */
hb_vector_t<double> deltas_y;
hb_vector_t<float> deltas_y;
/* compiled data: header and deltas
* compiled point data is saved in a hashmap within tuple_variations_t cause
@ -299,9 +299,9 @@ struct tuple_delta_t
return *this;
}
tuple_delta_t& operator *= (double scalar)
tuple_delta_t& operator *= (float scalar)
{
if (scalar == 1.0)
if (scalar == 1.0f)
return *this;
unsigned num = indices.length;
@ -514,9 +514,9 @@ struct tuple_delta_t
bool compile_deltas ()
{ return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
static bool compile_deltas (const hb_vector_t<bool> &point_indices,
const hb_vector_t<double> &x_deltas,
const hb_vector_t<double> &y_deltas,
static bool compile_deltas (hb_array_t<const bool> point_indices,
hb_array_t<const float> x_deltas,
hb_array_t<const float> y_deltas,
hb_vector_t<unsigned char> &compiled_deltas /* OUT */)
{
hb_vector_t<int> rounded_deltas;
@ -629,11 +629,11 @@ struct tuple_delta_t
deltas_x.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].x,
(double) orig_points.arrayZ[prev].x,
(double) orig_points.arrayZ[next].x,
deltas_x.arrayZ[prev], deltas_x.arrayZ[next]);
(double) deltas_x.arrayZ[prev], (double) deltas_x.arrayZ[next]);
deltas_y.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].y,
(double) orig_points.arrayZ[prev].y,
(double) orig_points.arrayZ[next].y,
deltas_y.arrayZ[prev], deltas_y.arrayZ[next]);
(double) deltas_y.arrayZ[prev], (double) deltas_y.arrayZ[next]);
inferred_idxes.add (i);
if (--unref_count == 0) goto no_more_gaps;
}
@ -692,7 +692,7 @@ struct tuple_delta_t
if (ref_count == count) return true;
hb_vector_t<double> opt_deltas_x, opt_deltas_y;
hb_vector_t<float> opt_deltas_x, opt_deltas_y;
bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0);
if (is_comp_glyph_wo_deltas)
{
@ -841,6 +841,7 @@ struct tuple_delta_t
{ return (i >= end) ? start : (i + 1); }
};
template <typename OffType = HBUINT16>
struct TupleVariationData
{
bool sanitize (hb_sanitize_context_t *c) const
@ -875,7 +876,7 @@ struct TupleVariationData
private:
/* referenced point set->compiled point data map */
hb_hashmap_t<const hb_vector_t<bool>*, hb_vector_t<char>> point_data_map;
hb_hashmap_t<const hb_vector_t<bool>*, hb_vector_t<unsigned char>> point_data_map;
/* referenced point set-> count map, used in finding shared points */
hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
@ -883,11 +884,11 @@ struct TupleVariationData
* shared_points_bytes is a pointer to some value in the point_data_map,
* which will be freed during map destruction. Save it for serialization, so
* no need to do find_shared_points () again */
hb_vector_t<char> *shared_points_bytes = nullptr;
hb_vector_t<unsigned char> *shared_points_bytes = nullptr;
/* total compiled byte size as TupleVariationData format, initialized to its
* min_size: 4 */
unsigned compiled_byte_size = 4;
/* total compiled byte size as TupleVariationData format, initialized to 0 */
unsigned compiled_byte_size = 0;
bool needs_padding = false;
/* for gvar iup delta optimization: whether this is a composite glyph */
bool is_composite = false;
@ -1219,12 +1220,21 @@ struct TupleVariationData
bool compile_bytes (const hb_map_t& axes_index_map,
const hb_map_t& axes_old_index_tag_map,
bool use_shared_points,
bool is_gvar = false,
const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map = nullptr)
{
// return true for empty glyph
if (!tuple_vars)
return true;
// compile points set and store data in hashmap
if (!compile_all_point_sets ())
return false;
/* total compiled byte size as TupleVariationData format, initialized to its
* min_size: 4 */
compiled_byte_size += 4;
if (use_shared_points)
{
find_shared_points ();
@ -1235,7 +1245,7 @@ struct TupleVariationData
for (auto& tuple: tuple_vars)
{
const hb_vector_t<bool>* points_set = &(tuple.indices);
hb_vector_t<char> *points_data;
hb_vector_t<unsigned char> *points_data;
if (unlikely (!point_data_map.has (points_set, &points_data)))
return false;
@ -1253,6 +1263,13 @@ struct TupleVariationData
return false;
compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length;
}
if (is_gvar && (compiled_byte_size % 2))
{
needs_padding = true;
compiled_byte_size += 1;
}
return true;
}
@ -1273,20 +1290,20 @@ struct TupleVariationData
TRACE_SERIALIZE (this);
if (is_gvar && shared_points_bytes)
{
hb_bytes_t s (shared_points_bytes->arrayZ, shared_points_bytes->length);
hb_ubytes_t s (shared_points_bytes->arrayZ, shared_points_bytes->length);
s.copy (c);
}
for (const auto& tuple: tuple_vars)
{
const hb_vector_t<bool>* points_set = &(tuple.indices);
hb_vector_t<char> *point_data;
hb_vector_t<unsigned char> *point_data;
if (!point_data_map.has (points_set, &point_data))
return_trace (false);
if (!is_gvar || point_data != shared_points_bytes)
{
hb_bytes_t s (point_data->arrayZ, point_data->length);
hb_ubytes_t s (point_data->arrayZ, point_data->length);
s.copy (c);
}
@ -1295,7 +1312,7 @@ struct TupleVariationData
}
/* padding for gvar */
if (is_gvar && (compiled_byte_size % 2))
if (is_gvar && needs_padding)
{
HBUINT8 pad;
pad = 0;
@ -1505,15 +1522,16 @@ struct TupleVariationData
* low 12 bits are the number of tuple variation tables
* for this glyph. The number of tuple variation tables
* can be any number between 1 and 4095. */
Offset16To<HBUINT8>
OffsetTo<HBUINT8, OffType>
data; /* Offset from the start of the base table
* to the serialized data. */
/* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
public:
DEFINE_SIZE_MIN (4);
DEFINE_SIZE_MIN (2 + OffType::static_size);
};
using tuple_variations_t = TupleVariationData::tuple_variations_t;
// TODO: Move tuple_variations_t to outside of TupleVariationData
using tuple_variations_t = TupleVariationData<HBUINT16>::tuple_variations_t;
struct item_variations_t
{
using region_t = const hb_hashmap_t<hb_tag_t, Triple>*;

View file

@ -50,7 +50,7 @@ struct cvar
tupleVariationData.sanitize (c));
}
const TupleVariationData* get_tuple_var_data (void) const
const TupleVariationData<>* get_tuple_var_data (void) const
{ return &tupleVariationData; }
bool decompile_tuple_variations (unsigned axis_count,
@ -58,12 +58,12 @@ struct cvar
hb_blob_t *blob,
bool is_gvar,
const hb_map_t *axes_old_index_tag_map,
TupleVariationData::tuple_variations_t& tuple_variations /* OUT */) const
TupleVariationData<>::tuple_variations_t& tuple_variations /* OUT */) const
{
hb_vector_t<unsigned> shared_indices;
TupleVariationData::tuple_iterator_t iterator;
TupleVariationData<>::tuple_iterator_t iterator;
hb_bytes_t var_data_bytes = blob->as_bytes ().sub_array (4);
if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, this,
if (!TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, this,
shared_indices, &iterator))
return false;
@ -77,16 +77,16 @@ struct cvar
static bool calculate_cvt_deltas (unsigned axis_count,
hb_array_t<int> coords,
unsigned num_cvt_item,
const TupleVariationData *tuple_var_data,
const TupleVariationData<> *tuple_var_data,
const void *base,
hb_vector_t<float>& cvt_deltas /* OUT */)
{
if (!coords) return true;
hb_vector_t<unsigned> shared_indices;
TupleVariationData::tuple_iterator_t iterator;
TupleVariationData<>::tuple_iterator_t iterator;
unsigned var_data_length = tuple_var_data->get_size (axis_count);
hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast<const char*> (tuple_var_data), var_data_length);
if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, base,
if (!TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, base,
shared_indices, &iterator))
return true; /* isn't applied at all */
@ -107,14 +107,14 @@ struct cvar
bool has_private_points = iterator.current_tuple->has_private_points ();
if (has_private_points &&
!TupleVariationData::decompile_points (p, private_indices, end))
!TupleVariationData<>::decompile_points (p, private_indices, end))
return false;
const hb_vector_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
bool apply_to_all = (indices.length == 0);
unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length;
if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false;
if (unlikely (!TupleVariationData::decompile_deltas (p, unpacked_deltas, end))) return false;
if (unlikely (!TupleVariationData<>::decompile_deltas (p, unpacked_deltas, end))) return false;
for (unsigned int i = 0; i < num_deltas; i++)
{
@ -129,7 +129,7 @@ struct cvar
}
bool serialize (hb_serialize_context_t *c,
TupleVariationData::tuple_variations_t& tuple_variations) const
TupleVariationData<>::tuple_variations_t& tuple_variations) const
{
TRACE_SERIALIZE (this);
if (!tuple_variations) return_trace (false);
@ -144,7 +144,7 @@ struct cvar
if (c->plan->all_axes_pinned)
return_trace (false);
OT::TupleVariationData::tuple_variations_t tuple_variations;
OT::TupleVariationData<>::tuple_variations_t tuple_variations;
unsigned axis_count = c->plan->axes_old_index_tag_map.get_population ();
const hb_tag_t cvt = HB_TAG('c','v','t',' ');
@ -169,7 +169,7 @@ struct cvar
}
static bool add_cvt_and_apply_deltas (hb_subset_plan_t *plan,
const TupleVariationData *tuple_var_data,
const TupleVariationData<> *tuple_var_data,
const void *base)
{
const hb_tag_t cvt = HB_TAG('c','v','t',' ');
@ -209,7 +209,7 @@ struct cvar
protected:
FixedVersion<>version; /* Version of the CVT variation table
* initially set to 0x00010000u */
TupleVariationData tupleVariationData; /* TupleVariationDate for cvar table */
TupleVariationData<> tupleVariationData; /* TupleVariationDate for cvar table */
public:
DEFINE_SIZE_MIN (8);
};

View file

@ -28,6 +28,7 @@
#ifndef HB_OT_VAR_GVAR_TABLE_HH
#define HB_OT_VAR_GVAR_TABLE_HH
#include "hb-decycler.hh"
#include "hb-open-type.hh"
#include "hb-ot-var-common.hh"
@ -36,15 +37,37 @@
* https://docs.microsoft.com/en-us/typography/opentype/spec/gvar
*/
#define HB_OT_TAG_gvar HB_TAG('g','v','a','r')
#define HB_OT_TAG_GVAR HB_TAG('G','V','A','R')
struct hb_glyf_scratch_t
{
// glyf
contour_point_vector_t all_points;
contour_point_vector_t comp_points;
hb_decycler_t decycler;
// gvar
contour_point_vector_t orig_points;
hb_vector_t<int> x_deltas;
hb_vector_t<int> y_deltas;
contour_point_vector_t deltas;
hb_vector_t<unsigned int> shared_indices;
hb_vector_t<unsigned int> private_indices;
// VARC
hb_vector_t<unsigned> axisIndices;
hb_vector_t<float> axisValues;
};
namespace OT {
struct GlyphVariationData : TupleVariationData
{};
template <typename OffsetType>
struct glyph_variations_t
{
using tuple_variations_t = TupleVariationData::tuple_variations_t;
// TODO: Move tuple_variations_t to outside of TupleVariationData
using tuple_variations_t = typename TupleVariationData<OffsetType>::tuple_variations_t;
using GlyphVariationData = TupleVariationData<OffsetType>;
hb_vector_t<tuple_variations_t> glyph_variations;
hb_vector_t<char> compiled_shared_tuples;
@ -72,7 +95,7 @@ struct glyph_variations_t
const hb_subset_plan_t *plan,
const hb_hashmap_t<hb_codepoint_t, hb_bytes_t>& new_gid_var_data_map)
{
if (unlikely (!glyph_variations.alloc (plan->new_to_old_gid_list.length, true)))
if (unlikely (!glyph_variations.alloc_exact (plan->new_to_old_gid_list.length)))
return false;
auto it = hb_iter (plan->new_to_old_gid_list);
@ -86,10 +109,11 @@ struct glyph_variations_t
hb_bytes_t var_data = new_gid_var_data_map.get (new_gid);
const GlyphVariationData* p = reinterpret_cast<const GlyphVariationData*> (var_data.arrayZ);
hb_vector_t<unsigned> shared_indices;
GlyphVariationData::tuple_iterator_t iterator;
typename GlyphVariationData::tuple_iterator_t iterator;
tuple_variations_t tuple_vars;
hb_vector_t<unsigned> shared_indices;
/* in case variation data is empty, push an empty struct into the vector,
* keep the vector in sync with the new_to_old_gid_list */
if (!var_data || ! p->has_data () || !all_contour_points->length ||
@ -140,6 +164,7 @@ struct glyph_variations_t
for (tuple_variations_t& vars: glyph_variations)
if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map,
true, /* use shared points*/
true,
&shared_tuples_idx_map))
return false;
@ -258,7 +283,7 @@ struct glyph_variations_t
hb_codepoint_t last_gid = 0;
unsigned idx = 0;
TupleVariationData* cur_glyph = c->start_embed<TupleVariationData> ();
GlyphVariationData* cur_glyph = c->start_embed<GlyphVariationData> ();
if (!cur_glyph) return_trace (false);
for (auto &_ : it)
{
@ -272,7 +297,7 @@ struct glyph_variations_t
if (idx >= glyph_variations.length) return_trace (false);
if (!cur_glyph->serialize (c, true, glyph_variations[idx])) return_trace (false);
TupleVariationData* next_glyph = c->start_embed<TupleVariationData> ();
GlyphVariationData* next_glyph = c->start_embed<GlyphVariationData> ();
glyph_offset += (char *) next_glyph - (char *) cur_glyph;
if (long_offset)
@ -295,9 +320,14 @@ struct glyph_variations_t
}
};
struct gvar
template <typename GidOffsetType, unsigned TableTag>
struct gvar_GVAR
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar;
static constexpr hb_tag_t tableTag = TableTag;
using GlyphVariationData = TupleVariationData<GidOffsetType>;
bool has_data () const { return version.to_int () != 0; }
bool sanitize_shallow (hb_sanitize_context_t *c) const
{
@ -316,7 +346,7 @@ struct gvar
{ return sanitize_shallow (c); }
bool decompile_glyph_variations (hb_subset_context_t *c,
glyph_variations_t& glyph_vars /* OUT */) const
glyph_variations_t<GidOffsetType>& glyph_vars /* OUT */) const
{
hb_hashmap_t<hb_codepoint_t, hb_bytes_t> new_gid_var_data_map;
auto it = hb_iter (c->plan->new_to_old_gid_list);
@ -343,14 +373,14 @@ struct gvar
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
const glyph_variations_t& glyph_vars,
const glyph_variations_t<GidOffsetType>& glyph_vars,
Iterator it,
unsigned axis_count,
unsigned num_glyphs,
bool force_long_offsets) const
{
TRACE_SERIALIZE (this);
gvar *out = c->allocate_min<gvar> ();
gvar_GVAR *out = c->allocate_min<gvar_GVAR> ();
if (unlikely (!out)) return_trace (false);
out->version.major = 1;
@ -392,7 +422,7 @@ struct gvar
bool instantiate (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
glyph_variations_t glyph_vars;
glyph_variations_t<GidOffsetType> glyph_vars;
if (!decompile_glyph_variations (c, glyph_vars))
return_trace (false);
@ -422,7 +452,7 @@ struct gvar
unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0;
gvar *out = c->serializer->allocate_min<gvar> ();
gvar_GVAR *out = c->serializer->allocate_min<gvar_GVAR> ();
if (unlikely (!out)) return_trace (false);
out->version.major = 1;
@ -556,9 +586,11 @@ struct gvar
public:
struct accelerator_t
{
bool has_data () const { return table->has_data (); }
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<gvar> (face);
table = hb_sanitize_context_t ().reference_table<gvar_GVAR> (face);
/* If sanitize failed, set glyphCount to 0. */
glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0;
@ -626,35 +658,40 @@ struct gvar
bool apply_deltas_to_points (hb_codepoint_t glyph,
hb_array_t<const int> coords,
const hb_array_t<contour_point_t> points,
hb_glyf_scratch_t &scratch,
bool phantom_only = false) const
{
if (unlikely (glyph >= glyphCount)) return true;
hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph);
if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) return true;
hb_vector_t<unsigned int> shared_indices;
GlyphVariationData::tuple_iterator_t iterator;
auto &shared_indices = scratch.shared_indices;
shared_indices.clear ();
typename GlyphVariationData::tuple_iterator_t iterator;
if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
var_data_bytes.arrayZ,
shared_indices, &iterator))
return true; /* so isn't applied at all */
/* Save original points for inferred delta calculation */
contour_point_vector_t orig_points_vec; // Populated lazily
auto &orig_points_vec = scratch.orig_points;
orig_points_vec.clear (); // Populated lazily
auto orig_points = orig_points_vec.as_array ();
/* flag is used to indicate referenced point */
contour_point_vector_t deltas_vec; // Populated lazily
auto &deltas_vec = scratch.deltas;
deltas_vec.clear (); // Populated lazily
auto deltas = deltas_vec.as_array ();
hb_vector_t<unsigned> end_points; // Populated lazily
unsigned num_coords = table->axisCount;
hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * num_coords);
hb_vector_t<unsigned int> private_indices;
hb_vector_t<int> x_deltas;
hb_vector_t<int> y_deltas;
auto &private_indices = scratch.private_indices;
auto &x_deltas = scratch.x_deltas;
auto &y_deltas = scratch.y_deltas;
unsigned count = points.length;
bool flush = false;
do
@ -725,8 +762,8 @@ struct gvar
if (phantom_only && pt_index < count - 4) continue;
auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
delta.add_delta (x_deltas.arrayZ[i] * scalar,
y_deltas.arrayZ[i] * scalar);
}
}
else
@ -737,10 +774,9 @@ struct gvar
if (apply_to_all)
for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
{
unsigned int pt_index = i;
auto &delta = deltas.arrayZ[pt_index];
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
auto &delta = deltas.arrayZ[i];
delta.add_delta (x_deltas.arrayZ[i] * scalar,
y_deltas.arrayZ[i] * scalar);
}
else
for (unsigned int i = 0; i < num_deltas; i++)
@ -750,8 +786,8 @@ struct gvar
if (phantom_only && pt_index < count - 4) continue;
auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
delta.add_delta (x_deltas.arrayZ[i] * scalar,
y_deltas.arrayZ[i] * scalar);
}
}
else
@ -759,10 +795,9 @@ struct gvar
if (apply_to_all)
for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
{
unsigned int pt_index = i;
auto &delta = deltas.arrayZ[pt_index];
delta.x += x_deltas.arrayZ[i];
delta.y += y_deltas.arrayZ[i];
auto &delta = deltas.arrayZ[i];
delta.add_delta (x_deltas.arrayZ[i],
y_deltas.arrayZ[i]);
}
else
for (unsigned int i = 0; i < num_deltas; i++)
@ -772,8 +807,8 @@ struct gvar
if (phantom_only && pt_index < count - 4) continue;
auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i];
delta.y += y_deltas.arrayZ[i];
delta.add_delta (x_deltas.arrayZ[i],
y_deltas.arrayZ[i]);
}
}
}
@ -781,17 +816,14 @@ struct gvar
/* infer deltas for unreferenced points */
if (!apply_to_all && !phantom_only)
{
if (!end_points)
{
for (unsigned i = 0; i < count; ++i)
if (points.arrayZ[i].is_end_point)
end_points.push (i);
if (unlikely (end_points.in_error ())) return false;
}
unsigned start_point = 0;
for (unsigned end_point : end_points)
unsigned end_point = 0;
while (true)
{
while (end_point < count && !points.arrayZ[end_point].is_end_point)
end_point++;
if (unlikely (end_point == count)) break;
/* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
unsigned unref_count = 0;
for (unsigned i = start_point; i < end_point + 1; i++)
@ -834,7 +866,7 @@ struct gvar
}
}
no_more_gaps:
start_point = end_point + 1;
start_point = end_point = end_point + 1;
}
}
@ -854,7 +886,7 @@ struct gvar
unsigned int get_axis_count () const { return table->axisCount; }
private:
hb_blob_ptr_t<gvar> table;
hb_blob_ptr_t<gvar_GVAR> table;
unsigned glyphCount;
hb_vector_t<hb_pair_t<int, int>> shared_tuple_active_idx;
};
@ -872,7 +904,7 @@ struct gvar
NNOffset32To<UnsizedArrayOf<F2DOT14>>
sharedTuples; /* Offset from the start of this table to the shared tuple records.
* Array of tuple records shared across all glyph variation data tables. */
HBUINT16 glyphCountX; /* The number of glyphs in this font. This must match the number of
GidOffsetType glyphCountX; /* The number of glyphs in this font. This must match the number of
* glyphs stored elsewhere in the font. */
HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows.
* If bit 0 is clear, the offsets are uint16; if bit 0 is set, the
@ -887,9 +919,15 @@ struct gvar
DEFINE_SIZE_ARRAY (20, offsetZ);
};
using gvar = gvar_GVAR<HBUINT16, HB_OT_TAG_gvar>;
using GVAR = gvar_GVAR<HBUINT24, HB_OT_TAG_GVAR>;
struct gvar_accelerator_t : gvar::accelerator_t {
gvar_accelerator_t (hb_face_t *face) : gvar::accelerator_t (face) {}
};
struct GVAR_accelerator_t : GVAR::accelerator_t {
GVAR_accelerator_t (hb_face_t *face) : GVAR::accelerator_t (face) {}
};
} /* namespace OT */

View file

@ -146,7 +146,7 @@ typedef void (*hb_paint_pop_transform_func_t) (hb_paint_funcs_t *funcs,
*
* A virtual method for the #hb_paint_funcs_t to render a color glyph by glyph index.
*
* Return value: %true if the glyph was painted, %false otherwise.
* Return value: `true` if the glyph was painted, `false` otherwise.
*
* Since: 8.2.0
*/

View file

@ -72,8 +72,8 @@
*
* === The sanitize() contract ===
*
* The sanitize() method of each object type shall return true if it's safe to
* call other methods of the object, and %false otherwise.
* The sanitize() method of each object type shall return `true` if it's safe to
* call other methods of the object, and `false` otherwise.
*
* Note that what sanitize() checks for might align with what the specification
* describes as valid table data, but does not have to be. In particular, we

View file

@ -36,9 +36,7 @@
#include "hb-map.hh"
#include "hb-pool.hh"
#ifdef HB_EXPERIMENTAL_API
#include "hb-subset-repacker.h"
#endif
#include "hb-subset-serialize.h"
/*
* Serialize
@ -75,21 +73,19 @@ struct hb_serialize_context_t
object_t () = default;
#ifdef HB_EXPERIMENTAL_API
object_t (const hb_object_t &o)
object_t (const hb_subset_serialize_object_t &o)
{
head = o.head;
tail = o.tail;
next = nullptr;
real_links.alloc (o.num_real_links, true);
real_links.alloc_exact (o.num_real_links);
for (unsigned i = 0 ; i < o.num_real_links; i++)
real_links.push (o.real_links[i]);
virtual_links.alloc (o.num_virtual_links, true);
virtual_links.alloc_exact (o.num_virtual_links);
for (unsigned i = 0; i < o.num_virtual_links; i++)
virtual_links.push (o.virtual_links[i]);
}
#endif
bool add_virtual_link (objidx_t objidx)
{
@ -148,8 +144,7 @@ struct hb_serialize_context_t
link_t () = default;
#ifdef HB_EXPERIMENTAL_API
link_t (const hb_link_t &o)
link_t (const hb_subset_serialize_link_t &o)
{
width = o.width;
is_signed = 0;
@ -158,7 +153,6 @@ struct hb_serialize_context_t
bias = 0;
objidx = o.objidx;
}
#endif
HB_INTERNAL static int cmp (const void* a, const void* b)
{
@ -178,7 +172,7 @@ struct hb_serialize_context_t
auto all_links () const HB_AUTO_RETURN
(( hb_concat (real_links, virtual_links) ));
auto all_links_writer () HB_AUTO_RETURN
(( hb_concat (real_links.writer (), virtual_links.writer ()) ));
(( hb_concat (real_links.writer (), virtual_links.writer ()) ));
};
struct snapshot_t
@ -400,6 +394,7 @@ struct hb_serialize_context_t
{
merge_virtual_links (obj, objidx);
obj->fini ();
object_pool.release (obj);
return objidx;
}
}
@ -463,9 +458,11 @@ struct hb_serialize_context_t
while (packed.length > 1 &&
packed.tail ()->head < tail)
{
packed_map.del (packed.tail ());
assert (!packed.tail ()->next);
packed.tail ()->fini ();
object_t *obj = packed.tail ();
packed_map.del (obj);
assert (!obj->next);
obj->fini ();
object_pool.release (obj);
packed.pop ();
}
if (packed.length > 1)

View file

@ -56,7 +56,7 @@
* - For each glyph, if it doesn't match the subtable digest,
* skip it.
*
* The main filter we use is a combination of three bits-pattern
* The main filter we use is a combination of four bits-pattern
* filters. A bits-pattern filter checks a number of bits (5 or 6)
* of the input number (glyph-id in this case) and checks whether
* its pattern is amongst the patterns of any of the accepted values.
@ -64,45 +64,60 @@
* check is done using four bitwise operations only.
*/
template <typename mask_t, unsigned int shift>
struct hb_set_digest_bits_pattern_t
static constexpr unsigned hb_set_digest_shifts[] = {4, 0, 6};
struct hb_set_digest_t
{
// No science in these. Intuition and testing only.
using mask_t = uint64_t;
static constexpr unsigned n = ARRAY_LENGTH_CONST (hb_set_digest_shifts);
static constexpr unsigned mask_bytes = sizeof (mask_t);
static constexpr unsigned mask_bits = sizeof (mask_t) * 8;
static constexpr unsigned num_bits = 0
+ (mask_bytes >= 1 ? 3 : 0)
+ (mask_bytes >= 2 ? 1 : 0)
+ (mask_bytes >= 4 ? 1 : 0)
+ (mask_bytes >= 8 ? 1 : 0)
+ (mask_bytes >= 16? 1 : 0)
+ 0;
static constexpr hb_codepoint_t mb1 = mask_bits - 1;
static constexpr mask_t one = 1;
static constexpr mask_t all = (mask_t) -1;
static_assert ((shift < sizeof (hb_codepoint_t) * 8), "");
static_assert ((shift + num_bits <= sizeof (hb_codepoint_t) * 8), "");
void init ()
{ for (unsigned i = 0; i < n; i++) masks[i] = 0; }
void init () { mask = 0; }
void clear () { init (); }
static hb_set_digest_bits_pattern_t full () { hb_set_digest_bits_pattern_t d; d.mask = (mask_t) -1; return d; }
static hb_set_digest_t full ()
{
hb_set_digest_t d;
for (unsigned i = 0; i < n; i++) d.masks[i] = all;
return d;
}
void union_ (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
void add (hb_codepoint_t g) { mask |= mask_for (g); }
void union_ (const hb_set_digest_t &o)
{ for (unsigned i = 0; i < n; i++) masks[i] |= o.masks[i]; }
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
if (mask == (mask_t) -1) return false;
if ((b >> shift) - (a >> shift) >= mask_bits - 1)
bool ret;
ret = false;
for (unsigned i = 0; i < n; i++)
if (masks[i] != all)
ret = true;
if (!ret) return false;
ret = false;
for (unsigned i = 0; i < n; i++)
{
mask = (mask_t) -1;
return false;
}
else
{
mask_t ma = mask_for (a);
mask_t mb = mask_for (b);
mask |= mb + (mb - ma) - (mb < ma);
return true;
mask_t shift = hb_set_digest_shifts[i];
if ((b >> shift) - (a >> shift) >= mb1)
masks[i] = all;
else
{
mask_t ma = one << ((a >> shift) & mb1);
mask_t mb = one << ((b >> shift) & mb1);
masks[i] |= mb + (mb - ma) - (mb < ma);
ret = true;
}
}
return ret;
}
template <typename T>
@ -125,103 +140,37 @@ struct hb_set_digest_bits_pattern_t
template <typename T>
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
bool may_have (const hb_set_digest_bits_pattern_t &o) const
{ return mask & o.mask; }
bool may_have (hb_codepoint_t g) const
{ return mask & mask_for (g); }
bool operator [] (hb_codepoint_t g) const
{ return may_have (g); }
private:
static mask_t mask_for (hb_codepoint_t g)
{ return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); }
mask_t mask = 0;
};
template <typename head_t, typename tail_t>
struct hb_set_digest_combiner_t
{
void init ()
{
head.init ();
tail.init ();
}
static hb_set_digest_combiner_t full () { hb_set_digest_combiner_t d; d.head = head_t::full(); d.tail = tail_t::full (); return d; }
void union_ (const hb_set_digest_combiner_t &o)
{
head.union_ (o.head);
tail.union_(o.tail);
}
void add (hb_codepoint_t g)
{
head.add (g);
tail.add (g);
}
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
return (int) head.add_range (a, b) | (int) tail.add_range (a, b);
}
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
head.add_array (array, count, stride);
tail.add_array (array, count, stride);
}
template <typename T>
void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
return head.add_sorted_array (array, count, stride) &&
tail.add_sorted_array (array, count, stride);
}
template <typename T>
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
bool may_have (const hb_set_digest_combiner_t &o) const
{
return head.may_have (o.head) && tail.may_have (o.tail);
for (unsigned i = 0; i < n; i++)
masks[i] |= one << ((g >> hb_set_digest_shifts[i]) & mb1);
}
HB_ALWAYS_INLINE
bool may_have (hb_codepoint_t g) const
{
return head.may_have (g) && tail.may_have (g);
for (unsigned i = 0; i < n; i++)
if (!(masks[i] & (one << ((g >> hb_set_digest_shifts[i]) & mb1))))
return false;
return true;
}
bool operator [] (hb_codepoint_t g) const
{ return may_have (g); }
bool may_intersect (const hb_set_digest_t &o) const
{
for (unsigned i = 0; i < n; i++)
if (!(masks[i] & o.masks[i]))
return false;
return true;
}
private:
head_t head;
tail_t tail;
mask_t masks[n] = {};
};
/*
* hb_set_digest_t
*
* This is a combination of digests that performs "best".
* There is not much science to this: it's a result of intuition
* and testing.
*/
using hb_set_digest_t =
hb_set_digest_combiner_t
<
hb_set_digest_bits_pattern_t<unsigned long, 4>,
hb_set_digest_combiner_t
<
hb_set_digest_bits_pattern_t<unsigned long, 0>,
hb_set_digest_bits_pattern_t<unsigned long, 9>
>
>
;
#endif /* HB_SET_DIGEST_HH */

View file

@ -106,6 +106,7 @@ struct hb_sparseset_t
void del_range (hb_codepoint_t a, hb_codepoint_t b) { s.del_range (a, b); }
bool get (hb_codepoint_t g) const { return s.get (g); }
bool may_have (hb_codepoint_t g) const { return get (g); }
/* Has interface. */
bool operator [] (hb_codepoint_t k) const { return get (k); }
@ -120,6 +121,9 @@ struct hb_sparseset_t
hb_sparseset_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool may_intersect (const hb_sparseset_t &other) const
{ return s.may_intersect (other.s); }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
{ return s.intersects (first, last); }

View file

@ -209,7 +209,7 @@ hb_shape_plan_create (hb_face_t *face,
* @num_coords: The number of variation-space coordinates
* @shaper_list: (array zero-terminated=1): List of shapers to try
*
* The variable-font version of #hb_shape_plan_create.
* The variable-font version of #hb_shape_plan_create.
* Constructs a shaping plan for a combination of @face, @user_features, @props,
* and @shaper_list, plus the variation-space coordinates @coords.
*
@ -233,7 +233,7 @@ hb_shape_plan_create2 (hb_face_t *face,
num_coords,
shaper_list);
if (unlikely (props->direction == HB_DIRECTION_INVALID))
if (unlikely (!HB_DIRECTION_IS_VALID (props->direction)))
return hb_shape_plan_get_empty ();
hb_shape_plan_t *shape_plan;
@ -331,7 +331,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
* @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the given shaping plan.
* Attaches a user-data key/data pair to the given shaping plan.
*
* Return value: `true` if success, `false` otherwise.
*
@ -352,7 +352,7 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
* @shape_plan: A shaping plan
* @key: The user-data key to query
*
* Fetches the user data associated with the specified key,
* Fetches the user data associated with the specified key,
* attached to the specified shaping plan.
*
* Return value: (transfer none): A pointer to the user data
@ -501,7 +501,7 @@ hb_shape_plan_create_cached (hb_face_t *face,
* @num_coords: The number of variation-space coordinates
* @shaper_list: (array zero-terminated=1): List of shapers to try
*
* The variable-font version of #hb_shape_plan_create_cached.
* The variable-font version of #hb_shape_plan_create_cached.
* Creates a cached shaping plan suitable for reuse, for a combination
* of @face, @user_features, @props, and @shaper_list, plus the
* variation-space coordinates @coords.

Some files were not shown because too many files have changed in this diff Show more