mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8348597: Update HarfBuzz to 10.4.0
Reviewed-by: erikj, prr
This commit is contained in:
parent
7999091e3e
commit
dbdbbd4730
@ -331,7 +331,7 @@ else
|
||||
|
||||
HARFBUZZ_DISABLED_WARNINGS_gcc := missing-field-initializers \
|
||||
strict-aliasing unused-result array-bounds parentheses \
|
||||
unused-variable
|
||||
unused-variable dangling-pointer
|
||||
# noexcept-type required for GCC 7 builds. Not required for GCC 8+.
|
||||
# expansion-to-defined required for GCC 9 builds. Not required for GCC 10+.
|
||||
# maybe-uninitialized required for GCC 8 builds. Not required for GCC 9+.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
## Harfbuzz v8.2.2
|
||||
## Harfbuzz v10.4.0
|
||||
|
||||
### Harfbuzz License
|
||||
|
||||
@ -8,14 +8,14 @@ HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
|
||||
For parts of HarfBuzz that are licensed under different licenses see individual
|
||||
files names COPYING in subdirectories where applicable.
|
||||
|
||||
Copyright © 2010-2023 Google, Inc.
|
||||
Copyright © 2010-2024 Google, Inc.
|
||||
Copyright © 2018-2020 Ebrahim Byagowi
|
||||
Copyright © 2004-2013 Red Hat, Inc.
|
||||
Copyright © 2019 Facebook, Inc.
|
||||
Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
|
||||
Copyright © 2007 Chris Wilson
|
||||
Copyright © 2018-2019 Adobe Inc.
|
||||
Copyright © 2006-2023 Behdad Esfahbod
|
||||
Copyright © 2006-2025 Behdad Esfahbod
|
||||
Copyright © 1998-2004 David Turner and Werner Lemberg
|
||||
Copyright © 2009 Keith Stribley
|
||||
Copyright © 2018 Khaled Hosny
|
||||
@ -54,7 +54,7 @@ exception is licensed with a slightly different MIT variant:
|
||||
The contents of this directory are licensed under the following terms:
|
||||
|
||||
---------------------------------
|
||||
The below license applies to the following files:
|
||||
The below applies to the following file(s):
|
||||
libharfbuzz/hb-ucd.cc
|
||||
|
||||
Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
|
||||
@ -72,13 +72,14 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
---------------------------------
|
||||
The below license applies to the following files:
|
||||
The below applies to the following file(s):
|
||||
libharfbuzz/hb-unicode-emoji-table.hh
|
||||
|
||||
© 2023 Unicode®, Inc.
|
||||
© 2024 Unicode®, Inc.
|
||||
|
||||
Unicode and the Unicode Logo are registered trademarks of Unicode, Inc.
|
||||
in the U.S. and other countries.
|
||||
For terms of use, see https://www.unicode.org/terms_of_use.html
|
||||
For terms of use and license, see https://www.unicode.org/terms_of_use.html
|
||||
|
||||
</pre>
|
||||
|
||||
|
||||
@ -204,6 +204,7 @@ struct IndexSubtable
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.header.sanitize (c)) return_trace (false);
|
||||
hb_barrier ();
|
||||
switch (u.header.indexFormat)
|
||||
{
|
||||
case 1: return_trace (u.format1.sanitize (c, glyph_count));
|
||||
@ -378,6 +379,7 @@ struct IndexSubtableRecord
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
firstGlyphIndex <= lastGlyphIndex &&
|
||||
offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
|
||||
}
|
||||
@ -635,6 +637,7 @@ struct BitmapSizeTable
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
|
||||
horizontal.sanitize (c) &&
|
||||
vertical.sanitize (c));
|
||||
@ -738,7 +741,9 @@ struct CBLC
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
likely (version.major == 2 || version.major == 3) &&
|
||||
hb_barrier () &&
|
||||
sizeTables.sanitize (c, this));
|
||||
}
|
||||
|
||||
@ -936,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);
|
||||
@ -975,6 +982,7 @@ struct CBDT
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
likely (version.major == 2 || version.major == 3));
|
||||
}
|
||||
|
||||
|
||||
@ -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,13 +69,13 @@ 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;
|
||||
VarStoreInstancer &instancer;
|
||||
hb_map_t current_glyphs;
|
||||
hb_map_t current_layers;
|
||||
ItemVarStoreInstancer &instancer;
|
||||
hb_decycler_t glyphs_decycler;
|
||||
hb_decycler_t layers_decycler;
|
||||
int depth_left = HB_MAX_NESTING_LEVEL;
|
||||
int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
|
||||
int edge_count = HB_MAX_GRAPH_EDGE_COUNT;
|
||||
|
||||
hb_paint_context_t (const void *base_,
|
||||
hb_paint_funcs_t *funcs_,
|
||||
@ -80,12 +83,16 @@ public:
|
||||
hb_font_t *font_,
|
||||
unsigned int palette_,
|
||||
hb_color_t foreground_,
|
||||
VarStoreInstancer &instancer_) :
|
||||
ItemVarStoreInstancer &instancer_) :
|
||||
base (base_),
|
||||
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;
|
||||
}
|
||||
@ -159,23 +161,35 @@ struct hb_colrv1_closure_context_t :
|
||||
void add_palette_index (unsigned palette_index)
|
||||
{ palette_indices->add (palette_index); }
|
||||
|
||||
void add_var_idxes (unsigned first_var_idx, unsigned num_idxes)
|
||||
{
|
||||
if (!num_idxes || first_var_idx == VarIdx::NO_VARIATION) return;
|
||||
variation_indices->add_range (first_var_idx, first_var_idx + num_idxes - 1);
|
||||
}
|
||||
|
||||
public:
|
||||
const void *base;
|
||||
hb_set_t visited_paint;
|
||||
hb_set_t *glyphs;
|
||||
hb_set_t *layer_indices;
|
||||
hb_set_t *palette_indices;
|
||||
hb_set_t *variation_indices;
|
||||
unsigned num_var_idxes;
|
||||
unsigned nesting_level_left;
|
||||
|
||||
hb_colrv1_closure_context_t (const void *base_,
|
||||
hb_set_t *glyphs_,
|
||||
hb_set_t *layer_indices_,
|
||||
hb_set_t *palette_indices_,
|
||||
hb_set_t *variation_indices_,
|
||||
unsigned num_var_idxes_ = 1,
|
||||
unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
|
||||
base (base_),
|
||||
glyphs (glyphs_),
|
||||
layer_indices (layer_indices_),
|
||||
palette_indices (palette_indices_),
|
||||
variation_indices (variation_indices_),
|
||||
num_var_idxes (num_var_idxes_),
|
||||
nesting_level_left (nesting_level_left_)
|
||||
{}
|
||||
};
|
||||
@ -242,18 +256,33 @@ struct Variable
|
||||
}
|
||||
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ value.closurev1 (c); }
|
||||
{
|
||||
c->num_var_idxes = 0;
|
||||
// update c->num_var_idxes during value closure
|
||||
value.closurev1 (c);
|
||||
c->add_var_idxes (varIdxBase, c->num_var_idxes);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
|
||||
if (c->plan->all_axes_pinned)
|
||||
return_trace (true);
|
||||
|
||||
//TODO: update varIdxBase for partial-instancing
|
||||
return_trace (c->serializer->embed (varIdxBase));
|
||||
VarIdx new_varidx;
|
||||
new_varidx = varIdxBase;
|
||||
if (varIdxBase != VarIdx::NO_VARIATION)
|
||||
{
|
||||
hb_pair_t<unsigned, int> *new_varidx_delta;
|
||||
if (!c->plan->colrv1_variation_idx_delta_map.has (varIdxBase, &new_varidx_delta))
|
||||
return_trace (false);
|
||||
|
||||
new_varidx = hb_first (*new_varidx_delta);
|
||||
}
|
||||
|
||||
return_trace (c->serializer->embed (new_varidx));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -270,7 +299,7 @@ struct Variable
|
||||
|
||||
void get_color_stop (hb_paint_context_t *c,
|
||||
hb_color_stop_t *stop,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
value.get_color_stop (c, stop, varIdxBase, instancer);
|
||||
}
|
||||
@ -305,7 +334,7 @@ struct NoVariable
|
||||
{ value.closurev1 (c); }
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
return_trace (value.subset (c, instancer, varIdxBase));
|
||||
@ -325,7 +354,7 @@ struct NoVariable
|
||||
|
||||
void get_color_stop (hb_paint_context_t *c,
|
||||
hb_color_stop_t *stop,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
|
||||
}
|
||||
@ -345,10 +374,13 @@ struct NoVariable
|
||||
struct ColorStop
|
||||
{
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ c->add_palette_index (paletteIndex); }
|
||||
{
|
||||
c->add_palette_index (paletteIndex);
|
||||
c->num_var_idxes = 2;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -374,7 +406,7 @@ struct ColorStop
|
||||
void get_color_stop (hb_paint_context_t *c,
|
||||
hb_color_stop_t *out,
|
||||
uint32_t varIdx,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
out->offset = stopOffset.to_float(instancer (varIdx, 0));
|
||||
out->color = c->get_color (paletteIndex,
|
||||
@ -410,7 +442,7 @@ struct ColorLine
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (this);
|
||||
@ -439,7 +471,7 @@ struct ColorLine
|
||||
unsigned int start,
|
||||
unsigned int *count,
|
||||
hb_color_stop_t *color_stops,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
unsigned int len = stops.len;
|
||||
|
||||
@ -542,8 +574,11 @@ struct Affine2x3
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ c->num_var_idxes = 6; }
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -588,7 +623,7 @@ struct PaintColrLayers
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer HB_UNUSED) const
|
||||
const ItemVarStoreInstancer &instancer HB_UNUSED) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
@ -617,10 +652,13 @@ struct PaintColrLayers
|
||||
struct PaintSolid
|
||||
{
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ c->add_palette_index (paletteIndex); }
|
||||
{
|
||||
c->add_palette_index (paletteIndex);
|
||||
c->num_var_idxes = 1;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -666,10 +704,13 @@ template <template<typename> class Var>
|
||||
struct PaintLinearGradient
|
||||
{
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+colorLine).closurev1 (c); }
|
||||
{
|
||||
(this+colorLine).closurev1 (c);
|
||||
c->num_var_idxes = 6;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -733,10 +774,13 @@ template <template<typename> class Var>
|
||||
struct PaintRadialGradient
|
||||
{
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+colorLine).closurev1 (c); }
|
||||
{
|
||||
(this+colorLine).closurev1 (c);
|
||||
c->num_var_idxes = 6;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -800,10 +844,13 @@ template <template<typename> class Var>
|
||||
struct PaintSweepGradient
|
||||
{
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+colorLine).closurev1 (c); }
|
||||
{
|
||||
(this+colorLine).closurev1 (c);
|
||||
c->num_var_idxes = 4;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -863,7 +910,7 @@ struct PaintGlyph
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
@ -906,7 +953,7 @@ struct PaintColrGlyph
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer HB_UNUSED) const
|
||||
const ItemVarStoreInstancer &instancer HB_UNUSED) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
@ -936,7 +983,7 @@ struct PaintTransform
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
@ -958,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);
|
||||
}
|
||||
@ -975,7 +1022,7 @@ struct PaintTranslate
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1024,7 +1071,7 @@ struct PaintScale
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1073,7 +1120,7 @@ struct PaintScaleAroundCenter
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1132,7 +1179,7 @@ struct PaintScaleUniform
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1176,7 +1223,7 @@ struct PaintScaleUniformAroundCenter
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1232,7 +1279,7 @@ struct PaintRotate
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1276,7 +1323,7 @@ struct PaintRotateAroundCenter
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1332,7 +1379,7 @@ struct PaintSkew
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1381,7 +1428,7 @@ struct PaintSkewAroundCenter
|
||||
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1440,7 +1487,7 @@ struct PaintComposite
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const;
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
@ -1491,7 +1538,7 @@ struct ClipBoxFormat1
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
|
||||
void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
|
||||
{
|
||||
clip_box.xMin = xMin;
|
||||
clip_box.yMin = yMin;
|
||||
@ -1500,7 +1547,7 @@ struct ClipBoxFormat1
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -1533,7 +1580,7 @@ struct ClipBoxFormat1
|
||||
|
||||
struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
|
||||
{
|
||||
void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
|
||||
void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
value.get_clip_box(clip_box, instancer);
|
||||
if (instancer)
|
||||
@ -1544,12 +1591,15 @@ struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
|
||||
clip_box.yMax += roundf (instancer (varIdxBase, 3));
|
||||
}
|
||||
}
|
||||
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ c->variation_indices->add_range (varIdxBase, varIdxBase + 3); }
|
||||
};
|
||||
|
||||
struct ClipBox
|
||||
{
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
switch (u.format) {
|
||||
@ -1559,6 +1609,14 @@ struct ClipBox
|
||||
}
|
||||
}
|
||||
|
||||
void closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 2: u.format2.closurev1 (c);
|
||||
default:return;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
@ -1572,7 +1630,7 @@ struct ClipBox
|
||||
}
|
||||
|
||||
bool get_extents (hb_glyph_extents_t *extents,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
ClipBoxData clip_box;
|
||||
switch (u.format) {
|
||||
@ -1606,9 +1664,15 @@ struct ClipRecord
|
||||
int cmp (hb_codepoint_t g) const
|
||||
{ return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
|
||||
|
||||
void closurev1 (hb_colrv1_closure_context_t* c, const void *base) const
|
||||
{
|
||||
if (!c->glyphs->intersects (startGlyphID, endGlyphID)) return;
|
||||
(base+clipBox).closurev1 (c);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const void *base,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
@ -1625,7 +1689,7 @@ struct ClipRecord
|
||||
|
||||
bool get_extents (hb_glyph_extents_t *extents,
|
||||
const void *base,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
return (base+clipBox).get_extents (extents, instancer);
|
||||
}
|
||||
@ -1642,7 +1706,7 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
|
||||
struct ClipList
|
||||
{
|
||||
unsigned serialize_clip_records (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer,
|
||||
const ItemVarStoreInstancer &instancer,
|
||||
const hb_set_t& gids,
|
||||
const hb_map_t& gid_offset_map) const
|
||||
{
|
||||
@ -1695,7 +1759,7 @@ struct ClipList
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
@ -1735,7 +1799,7 @@ struct ClipList
|
||||
bool
|
||||
get_extents (hb_codepoint_t gid,
|
||||
hb_glyph_extents_t *extents,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
auto *rec = clips.as_array ().bsearch (gid);
|
||||
if (rec)
|
||||
@ -1855,7 +1919,7 @@ struct BaseGlyphPaintRecord
|
||||
|
||||
bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
|
||||
const void* src_base, hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto *out = s->embed (this);
|
||||
@ -1884,7 +1948,7 @@ struct BaseGlyphPaintRecord
|
||||
struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
|
||||
{
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (this);
|
||||
@ -1916,7 +1980,7 @@ struct LayerList : Array32OfOffset32To<Paint>
|
||||
{ return this+(*this)[i]; }
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const VarStoreInstancer &instancer) const
|
||||
const ItemVarStoreInstancer &instancer) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (this);
|
||||
@ -1941,6 +2005,76 @@ struct LayerList : Array32OfOffset32To<Paint>
|
||||
}
|
||||
};
|
||||
|
||||
struct delta_set_index_map_subset_plan_t
|
||||
{
|
||||
unsigned get_inner_bit_count () const { return inner_bit_count; }
|
||||
unsigned get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
|
||||
hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
|
||||
|
||||
delta_set_index_map_subset_plan_t (const hb_map_t &new_deltaset_idx_varidx_map)
|
||||
{
|
||||
map_count = 0;
|
||||
outer_bit_count = 0;
|
||||
inner_bit_count = 1;
|
||||
output_map.init ();
|
||||
|
||||
/* search backwards */
|
||||
unsigned count = new_deltaset_idx_varidx_map.get_population ();
|
||||
if (!count) return;
|
||||
|
||||
unsigned last_idx = (unsigned)-1;
|
||||
unsigned last_varidx = (unsigned)-1;
|
||||
|
||||
for (unsigned i = count; i; i--)
|
||||
{
|
||||
unsigned delta_set_idx = i - 1;
|
||||
unsigned var_idx = new_deltaset_idx_varidx_map.get (delta_set_idx);
|
||||
if (i == count)
|
||||
{
|
||||
last_idx = delta_set_idx;
|
||||
last_varidx = var_idx;
|
||||
continue;
|
||||
}
|
||||
if (var_idx != last_varidx)
|
||||
break;
|
||||
last_idx = delta_set_idx;
|
||||
}
|
||||
|
||||
map_count = last_idx + 1;
|
||||
}
|
||||
|
||||
bool remap (const hb_map_t &new_deltaset_idx_varidx_map)
|
||||
{
|
||||
/* recalculate bit_count */
|
||||
outer_bit_count = 1;
|
||||
inner_bit_count = 1;
|
||||
|
||||
if (unlikely (!output_map.resize (map_count, false))) return false;
|
||||
|
||||
for (unsigned idx = 0; idx < map_count; idx++)
|
||||
{
|
||||
uint32_t *var_idx;
|
||||
if (!new_deltaset_idx_varidx_map.has (idx, &var_idx)) return false;
|
||||
output_map.arrayZ[idx] = *var_idx;
|
||||
|
||||
unsigned outer = (*var_idx) >> 16;
|
||||
unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
|
||||
outer_bit_count = hb_max (bit_count, outer_bit_count);
|
||||
|
||||
unsigned inner = (*var_idx) & 0xFFFF;
|
||||
bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
|
||||
inner_bit_count = hb_max (bit_count, inner_bit_count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned map_count;
|
||||
unsigned outer_bit_count;
|
||||
unsigned inner_bit_count;
|
||||
hb_vector_t<uint32_t> output_map;
|
||||
};
|
||||
|
||||
struct COLR
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
|
||||
@ -1948,10 +2082,11 @@ struct COLR
|
||||
bool has_v0_data () const { return numBaseGlyphs; }
|
||||
bool has_v1_data () const
|
||||
{
|
||||
if (version == 1)
|
||||
return (this+baseGlyphList).len > 0;
|
||||
if (version < 1)
|
||||
return false;
|
||||
hb_barrier ();
|
||||
|
||||
return false;
|
||||
return (this+baseGlyphList).len > 0;
|
||||
}
|
||||
|
||||
unsigned int get_glyph_layers (hb_codepoint_t glyph,
|
||||
@ -1991,8 +2126,26 @@ struct COLR
|
||||
|
||||
void closure_forV1 (hb_set_t *glyphset,
|
||||
hb_set_t *layer_indices,
|
||||
hb_set_t *palette_indices) const
|
||||
{ colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
|
||||
hb_set_t *palette_indices,
|
||||
hb_set_t *variation_indices,
|
||||
hb_set_t *delta_set_indices) const
|
||||
{ colr->closure_forV1 (glyphset, layer_indices, palette_indices, variation_indices, delta_set_indices); }
|
||||
|
||||
bool has_var_store () const
|
||||
{ return colr->has_var_store (); }
|
||||
|
||||
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;
|
||||
@ -2029,12 +2182,16 @@ struct COLR
|
||||
|
||||
void closure_forV1 (hb_set_t *glyphset,
|
||||
hb_set_t *layer_indices,
|
||||
hb_set_t *palette_indices) const
|
||||
hb_set_t *palette_indices,
|
||||
hb_set_t *variation_indices,
|
||||
hb_set_t *delta_set_indices) const
|
||||
{
|
||||
if (version != 1) return;
|
||||
if (version < 1) return;
|
||||
hb_barrier ();
|
||||
|
||||
hb_set_t visited_glyphs;
|
||||
|
||||
hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
|
||||
hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices, variation_indices);
|
||||
const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
|
||||
|
||||
for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
|
||||
@ -2046,6 +2203,22 @@ struct COLR
|
||||
paint.dispatch (&c);
|
||||
}
|
||||
hb_set_union (glyphset, &visited_glyphs);
|
||||
|
||||
const ClipList &cliplist = this+clipList;
|
||||
c.glyphs = glyphset;
|
||||
for (const ClipRecord &clip_record : cliplist.clips.iter())
|
||||
clip_record.closurev1 (&c, &cliplist);
|
||||
|
||||
// if a DeltaSetIndexMap is included, collected variation indices are
|
||||
// actually delta set indices, we need to map them into variation indices
|
||||
if (has_delta_set_index_map ())
|
||||
{
|
||||
const DeltaSetIndexMap &var_idx_map = this+varIdxMap;
|
||||
delta_set_indices->set (*variation_indices);
|
||||
variation_indices->clear ();
|
||||
for (unsigned delta_set_idx : *delta_set_indices)
|
||||
variation_indices->add (var_idx_map.map (delta_set_idx));
|
||||
}
|
||||
}
|
||||
|
||||
const LayerList& get_layerList () const
|
||||
@ -2054,14 +2227,37 @@ struct COLR
|
||||
const BaseGlyphList& get_baseglyphList () const
|
||||
{ return (this+baseGlyphList); }
|
||||
|
||||
bool has_var_store () const
|
||||
{ return version >= 1 && hb_barrier () && varStore != 0; }
|
||||
|
||||
bool has_delta_set_index_map () const
|
||||
{ return version >= 1 && hb_barrier () && varIdxMap != 0; }
|
||||
|
||||
bool has_clip_list () const
|
||||
{ return version >= 1 && hb_barrier () && clipList != 0; }
|
||||
|
||||
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); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
|
||||
(this+layersZ).sanitize (c, numLayers) &&
|
||||
(version == 0 ||
|
||||
(version == 1 &&
|
||||
(hb_barrier () &&
|
||||
baseGlyphList.sanitize (c, this) &&
|
||||
layerList.sanitize (c, this) &&
|
||||
clipList.sanitize (c, this) &&
|
||||
@ -2127,6 +2323,94 @@ struct COLR
|
||||
return record;
|
||||
}
|
||||
|
||||
bool downgrade_to_V0 (const hb_set_t &glyphset) const
|
||||
{
|
||||
//no more COLRv1 glyphs, downgrade to version 0
|
||||
for (const BaseGlyphPaintRecord& _ : get_baseglyphList ())
|
||||
if (glyphset.has (_.glyphId))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subset_varstore (hb_subset_context_t *c,
|
||||
COLR* out /* OUT */) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
if (!varStore || c->plan->all_axes_pinned ||
|
||||
!c->plan->colrv1_variation_idx_delta_map)
|
||||
return_trace (true);
|
||||
|
||||
const ItemVariationStore& var_store = this+varStore;
|
||||
if (c->plan->normalized_coords)
|
||||
{
|
||||
item_variations_t item_vars;
|
||||
/* turn off varstore optimization when varIdxMap is null, so we maintain
|
||||
* original var_idx sequence */
|
||||
bool optimize = (varIdxMap != 0) ? true : false;
|
||||
if (!item_vars.instantiate (var_store, c->plan,
|
||||
optimize, /* optimization */
|
||||
optimize, /* use_no_variation_idx = false */
|
||||
c->plan->colrv1_varstore_inner_maps.as_array ()))
|
||||
return_trace (false);
|
||||
|
||||
/* do not serialize varStore if there's no variation data after
|
||||
* instancing: region_list or var_data is empty */
|
||||
if (item_vars.get_region_list () &&
|
||||
item_vars.get_vardata_encodings () &&
|
||||
!out->varStore.serialize_serialize (c->serializer,
|
||||
item_vars.has_long_word (),
|
||||
c->plan->axis_tags,
|
||||
item_vars.get_region_list (),
|
||||
item_vars.get_vardata_encodings ()))
|
||||
return_trace (false);
|
||||
|
||||
/* if varstore is optimized, update colrv1_new_deltaset_idx_varidx_map in
|
||||
* subset plan.
|
||||
* If varstore is empty after instancing, varidx_map would be empty and
|
||||
* all var_idxes will be updated to VarIdx::NO_VARIATION */
|
||||
if (optimize)
|
||||
{
|
||||
const hb_map_t &varidx_map = item_vars.get_varidx_map ();
|
||||
for (auto _ : c->plan->colrv1_new_deltaset_idx_varidx_map.iter_ref ())
|
||||
{
|
||||
uint32_t varidx = _.second;
|
||||
uint32_t *new_varidx;
|
||||
if (varidx_map.has (varidx, &new_varidx))
|
||||
_.second = *new_varidx;
|
||||
else
|
||||
_.second = VarIdx::NO_VARIATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unlikely (!out->varStore.serialize_serialize (c->serializer,
|
||||
&var_store,
|
||||
c->plan->colrv1_varstore_inner_maps.as_array ())))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool subset_delta_set_index_map (hb_subset_context_t *c,
|
||||
COLR* out /* OUT */) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
if (!varIdxMap || c->plan->all_axes_pinned ||
|
||||
!c->plan->colrv1_new_deltaset_idx_varidx_map)
|
||||
return_trace (true);
|
||||
|
||||
const hb_map_t &deltaset_idx_varidx_map = c->plan->colrv1_new_deltaset_idx_varidx_map;
|
||||
delta_set_index_map_subset_plan_t index_map_plan (deltaset_idx_varidx_map);
|
||||
|
||||
if (unlikely (!index_map_plan.remap (deltaset_idx_varidx_map)))
|
||||
return_trace (false);
|
||||
|
||||
return_trace (out->varIdxMap.serialize_serialize (c->serializer, index_map_plan));
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -2195,34 +2479,30 @@ struct COLR
|
||||
auto *colr_prime = c->serializer->start_embed<COLR> ();
|
||||
if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false);
|
||||
|
||||
if (version == 0)
|
||||
return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it));
|
||||
if (version == 0 || downgrade_to_V0 (glyphset))
|
||||
return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
|
||||
|
||||
auto snap = c->serializer->snapshot ();
|
||||
hb_barrier ();
|
||||
|
||||
//start version 1
|
||||
if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
|
||||
if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
|
||||
|
||||
VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
|
||||
varIdxMap ? &(this+varIdxMap) : nullptr,
|
||||
c->plan->normalized_coords.as_array ());
|
||||
/* subset ItemVariationStore first, cause varidx_map needs to be updated
|
||||
* after instancing */
|
||||
if (!subset_varstore (c, colr_prime)) return_trace (false);
|
||||
|
||||
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))
|
||||
{
|
||||
if (c->serializer->in_error ()) return_trace (false);
|
||||
//no more COLRv1 glyphs: downgrade to version 0
|
||||
c->serializer->revert (snap);
|
||||
return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
|
||||
}
|
||||
|
||||
if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
|
||||
return_trace (false);
|
||||
|
||||
colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
|
||||
colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
|
||||
if (!varStore || c->plan->all_axes_pinned)
|
||||
return_trace (true);
|
||||
|
||||
colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
|
||||
colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
|
||||
return_trace (true);
|
||||
return_trace (subset_delta_set_index_map (c, colr_prime));
|
||||
}
|
||||
|
||||
const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
|
||||
@ -2242,12 +2522,10 @@ struct COLR
|
||||
bool
|
||||
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
if (version != 1)
|
||||
return false;
|
||||
|
||||
VarStoreInstancer instancer (&(this+varStore),
|
||||
&(this+varIdxMap),
|
||||
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));
|
||||
|
||||
if (get_clip (glyph, extents, instancer))
|
||||
{
|
||||
@ -2282,8 +2560,10 @@ struct COLR
|
||||
bool
|
||||
has_paint_for_glyph (hb_codepoint_t glyph) const
|
||||
{
|
||||
if (version == 1)
|
||||
if (version >= 1)
|
||||
{
|
||||
hb_barrier ();
|
||||
|
||||
const Paint *paint = get_base_glyph_paint (glyph);
|
||||
|
||||
return paint != nullptr;
|
||||
@ -2294,9 +2574,9 @@ struct COLR
|
||||
|
||||
bool get_clip (hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents,
|
||||
const VarStoreInstancer instancer) const
|
||||
const ItemVarStoreInstancer instancer) const
|
||||
{
|
||||
return (this+clipList).get_extents (glyph,
|
||||
return get_clip_list ().get_extents (glyph,
|
||||
extents,
|
||||
instancer);
|
||||
}
|
||||
@ -2305,23 +2585,23 @@ 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
|
||||
{
|
||||
VarStoreInstancer instancer (&(this+varStore),
|
||||
&(this+varIdxMap),
|
||||
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);
|
||||
|
||||
if (version == 1)
|
||||
hb_decycler_node_t node (c.glyphs_decycler);
|
||||
node.visit (glyph);
|
||||
|
||||
if (version >= 1)
|
||||
{
|
||||
hb_barrier ();
|
||||
|
||||
const Paint *paint = get_base_glyph_paint (glyph);
|
||||
if (paint)
|
||||
{
|
||||
// COLRv1 glyph
|
||||
|
||||
VarStoreInstancer instancer (&(this+varStore),
|
||||
&(this+varIdxMap),
|
||||
hb_array (font->coords, font->num_coords));
|
||||
|
||||
bool is_bounded = true;
|
||||
if (clip)
|
||||
{
|
||||
@ -2404,7 +2684,7 @@ struct COLR
|
||||
Offset32To<LayerList> layerList;
|
||||
Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL)
|
||||
Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL)
|
||||
Offset32To<VariationStore> varStore;
|
||||
Offset32To<ItemVariationStore> varStore;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (14);
|
||||
};
|
||||
@ -2427,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2447,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);
|
||||
@ -2479,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 */
|
||||
|
||||
@ -66,34 +66,64 @@ HB_INTERNAL void PaintColrGlyph::closurev1 (hb_colrv1_closure_context_t* c) cons
|
||||
|
||||
template <template<typename> class Var>
|
||||
HB_INTERNAL void PaintTransform<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
(this+transform).closurev1 (c);
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintTranslate::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 2;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintScale::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 2;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintScaleAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 4;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintScaleUniform::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 1;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintScaleUniformAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 3;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintRotate::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 1;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintRotateAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 3;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintSkew::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 2;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintSkewAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{ (this+src).dispatch (c); }
|
||||
{
|
||||
(this+src).dispatch (c);
|
||||
c->num_var_idxes = 4;
|
||||
}
|
||||
|
||||
HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const
|
||||
{
|
||||
|
||||
@ -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. */
|
||||
@ -214,13 +222,17 @@ struct CPAL
|
||||
hb_set_t *nameids_to_retain /* OUT */) const
|
||||
{
|
||||
if (version == 1)
|
||||
{
|
||||
hb_barrier ();
|
||||
v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const CPALV1Tail& v1 () const
|
||||
{
|
||||
if (version == 0) return Null (CPALV1Tail);
|
||||
hb_barrier ();
|
||||
return StructAfter<CPALV1Tail> (*this);
|
||||
}
|
||||
|
||||
@ -312,7 +324,10 @@ struct CPAL
|
||||
return_trace (false);
|
||||
|
||||
if (version == 1)
|
||||
{
|
||||
hb_barrier ();
|
||||
return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
@ -321,6 +336,7 @@ struct CPAL
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
(this+colorRecordsZ).sanitize (c, numColorRecords) &&
|
||||
colorRecordIndicesZ.sanitize (c, numPalettes) &&
|
||||
(version == 0 || v1 ().sanitize (c, this, numPalettes, numColors)));
|
||||
|
||||
@ -368,6 +368,7 @@ struct sbix
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
version >= 1 &&
|
||||
strikes.sanitize (c, this)));
|
||||
}
|
||||
|
||||
@ -56,6 +56,7 @@ struct SVGDocumentIndexEntry
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
svgDoc.sanitize (c, base, svgDocLength));
|
||||
}
|
||||
|
||||
|
||||
@ -64,6 +64,7 @@ struct Coverage
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.format.sanitize (c)) return_trace (false);
|
||||
hb_barrier ();
|
||||
switch (u.format)
|
||||
{
|
||||
case 1: return_trace (u.format1.sanitize (c));
|
||||
@ -95,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
|
||||
{
|
||||
@ -200,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>
|
||||
|
||||
@ -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 ()); }
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -189,7 +189,7 @@ struct CaretValueFormat3
|
||||
friend struct CaretValue;
|
||||
|
||||
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
|
||||
const VariationStore &var_store) const
|
||||
const ItemVariationStore &var_store) const
|
||||
{
|
||||
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
|
||||
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
|
||||
@ -251,7 +251,7 @@ struct CaretValue
|
||||
hb_position_t get_caret_value (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph_id,
|
||||
const VariationStore &var_store) const
|
||||
const ItemVariationStore &var_store) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.get_caret_value (font, direction);
|
||||
@ -291,6 +291,7 @@ struct CaretValue
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.format.sanitize (c)) return_trace (false);
|
||||
hb_barrier ();
|
||||
switch (u.format) {
|
||||
case 1: return_trace (u.format1.sanitize (c));
|
||||
case 2: return_trace (u.format2.sanitize (c));
|
||||
@ -315,7 +316,7 @@ struct LigGlyph
|
||||
unsigned get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph_id,
|
||||
const VariationStore &var_store,
|
||||
const ItemVariationStore &var_store,
|
||||
unsigned start_offset,
|
||||
unsigned *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */) const
|
||||
@ -371,7 +372,7 @@ struct LigCaretList
|
||||
unsigned int get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph_id,
|
||||
const VariationStore &var_store,
|
||||
const ItemVariationStore &var_store,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */) const
|
||||
@ -441,6 +442,20 @@ struct MarkGlyphSetsFormat1
|
||||
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
|
||||
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
|
||||
|
||||
void collect_used_mark_sets (const hb_set_t& glyph_set,
|
||||
hb_set_t& used_mark_sets /* OUT */) const
|
||||
{
|
||||
unsigned i = 0;
|
||||
for (const auto &offset : coverage)
|
||||
{
|
||||
const auto &cov = this+offset;
|
||||
if (cov.intersects (&glyph_set))
|
||||
used_mark_sets.add (i);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_coverage (hb_vector_t<set_t> &sets) const
|
||||
{
|
||||
@ -461,6 +476,7 @@ struct MarkGlyphSetsFormat1
|
||||
bool ret = true;
|
||||
for (const Offset32To<Coverage>& offset : coverage.iter ())
|
||||
{
|
||||
auto snap = c->serializer->snapshot ();
|
||||
auto *o = out->coverage.serialize_append (c->serializer);
|
||||
if (unlikely (!o))
|
||||
{
|
||||
@ -468,11 +484,17 @@ struct MarkGlyphSetsFormat1
|
||||
break;
|
||||
}
|
||||
|
||||
//not using o->serialize_subset (c, offset, this, out) here because
|
||||
//OTS doesn't allow null offset.
|
||||
//See issue: https://github.com/khaledhosny/ots/issues/172
|
||||
//skip empty coverage
|
||||
c->serializer->push ();
|
||||
c->dispatch (this+offset);
|
||||
bool res = false;
|
||||
if (offset) res = c->dispatch (this+offset);
|
||||
if (!res)
|
||||
{
|
||||
c->serializer->pop_discard ();
|
||||
c->serializer->revert (snap);
|
||||
(out->coverage.len)--;
|
||||
continue;
|
||||
}
|
||||
c->serializer->add_link (*o, c->serializer->pop_pack ());
|
||||
}
|
||||
|
||||
@ -513,6 +535,15 @@ struct MarkGlyphSets
|
||||
}
|
||||
}
|
||||
|
||||
void collect_used_mark_sets (const hb_set_t& glyph_set,
|
||||
hb_set_t& used_mark_sets /* OUT */) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
|
||||
default:return;
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -526,6 +557,7 @@ struct MarkGlyphSets
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.format.sanitize (c)) return_trace (false);
|
||||
hb_barrier ();
|
||||
switch (u.format) {
|
||||
case 1: return_trace (u.format1.sanitize (c));
|
||||
default:return_trace (true);
|
||||
@ -577,7 +609,7 @@ struct GDEFVersion1_2
|
||||
* definitions--from beginning of GDEF
|
||||
* header (may be NULL). Introduced
|
||||
* in version 0x00010002. */
|
||||
Offset32To<VariationStore>
|
||||
Offset32To<ItemVariationStore>
|
||||
varStore; /* Offset to the table of Item Variation
|
||||
* Store--from beginning of GDEF
|
||||
* header (may be NULL). Introduced
|
||||
@ -600,8 +632,9 @@ struct GDEFVersion1_2
|
||||
attachList.sanitize (c, this) &&
|
||||
ligCaretList.sanitize (c, this) &&
|
||||
markAttachClassDef.sanitize (c, this) &&
|
||||
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
|
||||
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
|
||||
hb_barrier () &&
|
||||
((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) &&
|
||||
((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this)));
|
||||
}
|
||||
|
||||
static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
|
||||
@ -627,23 +660,23 @@ struct GDEFVersion1_2
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
|
||||
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
|
||||
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
|
||||
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
|
||||
|
||||
bool subset_markglyphsetsdef = false;
|
||||
if (version.to_int () >= 0x00010002u)
|
||||
{
|
||||
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
|
||||
}
|
||||
// Push var store first (if it's needed) so that it's last in the
|
||||
// serialization order. Some font consumers assume that varstore runs to
|
||||
// the end of the GDEF table.
|
||||
// See: https://github.com/harfbuzz/harfbuzz/issues/4636
|
||||
auto snapshot_version0 = c->serializer->snapshot ();
|
||||
if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef)))
|
||||
return_trace (false);
|
||||
|
||||
bool subset_varstore = false;
|
||||
if (version.to_int () >= 0x00010003u)
|
||||
unsigned varstore_index = (unsigned) -1;
|
||||
auto snapshot_version2 = c->serializer->snapshot ();
|
||||
if (version.to_int () >= 0x00010003u && hb_barrier ())
|
||||
{
|
||||
if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
|
||||
if (c->plan->all_axes_pinned)
|
||||
out->varStore = 0;
|
||||
else if (c->plan->normalized_coords)
|
||||
@ -652,27 +685,56 @@ struct GDEFVersion1_2
|
||||
{
|
||||
item_variations_t item_vars;
|
||||
if (item_vars.instantiate (this+varStore, c->plan, true, true,
|
||||
c->plan->gdef_varstore_inner_maps.as_array ()))
|
||||
c->plan->gdef_varstore_inner_maps.as_array ())) {
|
||||
subset_varstore = out->varStore.serialize_serialize (c->serializer,
|
||||
item_vars.has_long_word (),
|
||||
c->plan->axis_tags,
|
||||
item_vars.get_region_list (),
|
||||
item_vars.get_vardata_encodings ());
|
||||
varstore_index = c->serializer->last_added_child_index();
|
||||
}
|
||||
remap_varidx_after_instantiation (item_vars.get_varidx_map (),
|
||||
c->plan->layout_variation_idx_delta_map);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
|
||||
varstore_index = c->serializer->last_added_child_index();
|
||||
}
|
||||
}
|
||||
|
||||
out->version.major = version.major;
|
||||
out->version.minor = version.minor;
|
||||
|
||||
if (!subset_varstore && version.to_int () >= 0x00010002u) {
|
||||
c->serializer->revert (snapshot_version2);
|
||||
}
|
||||
|
||||
bool subset_markglyphsetsdef = false;
|
||||
if (version.to_int () >= 0x00010002u && hb_barrier ())
|
||||
{
|
||||
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
|
||||
}
|
||||
|
||||
if (subset_varstore)
|
||||
{
|
||||
out->version.minor = 3;
|
||||
c->plan->has_gdef_varstore = true;
|
||||
} else if (subset_markglyphsetsdef) {
|
||||
out->version.minor = 2;
|
||||
} else {
|
||||
out->version.minor = 0;
|
||||
c->serializer->revert (snapshot_version0);
|
||||
}
|
||||
|
||||
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
|
||||
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
|
||||
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
|
||||
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
|
||||
|
||||
if (subset_varstore && varstore_index != (unsigned) -1) {
|
||||
c->serializer->repack_last(varstore_index);
|
||||
}
|
||||
|
||||
return_trace (subset_glyphclassdef || subset_attachlist ||
|
||||
@ -709,6 +771,7 @@ struct GDEF
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!u.version.sanitize (c))) return_trace (false);
|
||||
hb_barrier ();
|
||||
switch (u.version.major) {
|
||||
case 1: return_trace (u.version1.sanitize (c));
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
@ -812,7 +875,7 @@ struct GDEF
|
||||
bool has_mark_glyph_sets () const
|
||||
{
|
||||
switch (u.version.major) {
|
||||
case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
|
||||
case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0;
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
case 2: return u.version2.markGlyphSetsDef != 0;
|
||||
#endif
|
||||
@ -822,7 +885,7 @@ struct GDEF
|
||||
const MarkGlyphSets &get_mark_glyph_sets () const
|
||||
{
|
||||
switch (u.version.major) {
|
||||
case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
|
||||
case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
case 2: return this+u.version2.markGlyphSetsDef;
|
||||
#endif
|
||||
@ -832,21 +895,21 @@ struct GDEF
|
||||
bool has_var_store () const
|
||||
{
|
||||
switch (u.version.major) {
|
||||
case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
|
||||
case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0;
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
case 2: return u.version2.varStore != 0;
|
||||
#endif
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
const VariationStore &get_var_store () const
|
||||
const ItemVariationStore &get_var_store () const
|
||||
{
|
||||
switch (u.version.major) {
|
||||
case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
|
||||
case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore);
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
case 2: return this+u.version2.varStore;
|
||||
#endif
|
||||
default: return Null(VariationStore);
|
||||
default: return Null(ItemVariationStore);
|
||||
}
|
||||
}
|
||||
|
||||
@ -959,47 +1022,6 @@ struct GDEF
|
||||
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
|
||||
{ get_lig_caret_list ().collect_variation_indices (c); }
|
||||
|
||||
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
|
||||
const hb_vector_t<int>& normalized_coords,
|
||||
bool calculate_delta, /* not pinned at default */
|
||||
bool no_variations, /* all axes pinned */
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
|
||||
{
|
||||
if (!has_var_store ()) return;
|
||||
const VariationStore &var_store = get_var_store ();
|
||||
float *store_cache = var_store.create_cache ();
|
||||
|
||||
unsigned new_major = 0, new_minor = 0;
|
||||
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
|
||||
for (unsigned idx : layout_variation_indices->iter ())
|
||||
{
|
||||
int delta = 0;
|
||||
if (calculate_delta)
|
||||
delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
|
||||
normalized_coords.length, store_cache));
|
||||
|
||||
if (no_variations)
|
||||
{
|
||||
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t major = idx >> 16;
|
||||
if (major >= var_store.get_sub_table_count ()) break;
|
||||
if (major != last_major)
|
||||
{
|
||||
new_minor = 0;
|
||||
++new_major;
|
||||
}
|
||||
|
||||
unsigned new_idx = (new_major << 16) + new_minor;
|
||||
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
|
||||
++new_minor;
|
||||
last_major = major;
|
||||
}
|
||||
var_store.destroy_cache (store_cache);
|
||||
}
|
||||
|
||||
protected:
|
||||
union {
|
||||
FixedVersion<> version; /* Version identifier */
|
||||
|
||||
@ -25,6 +25,7 @@ struct Anchor
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.format.sanitize (c)) return_trace (false);
|
||||
hb_barrier ();
|
||||
switch (u.format) {
|
||||
case 1: return_trace (u.format1.sanitize (c));
|
||||
case 2: return_trace (u.format2.sanitize (c));
|
||||
|
||||
@ -38,9 +38,15 @@ struct AnchorFormat3
|
||||
*y = font->em_fscale_y (yCoordinate);
|
||||
|
||||
if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
|
||||
{
|
||||
hb_barrier ();
|
||||
*x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
|
||||
}
|
||||
if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
|
||||
{
|
||||
hb_barrier ();
|
||||
*y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
|
||||
@ -8,7 +8,7 @@ namespace GPOS_impl {
|
||||
struct AnchorMatrix
|
||||
{
|
||||
HBUINT16 rows; /* Number of rows */
|
||||
UnsizedArrayOf<Offset16To<Anchor>>
|
||||
UnsizedArrayOf<Offset16To<Anchor, AnchorMatrix>>
|
||||
matrixZ; /* Matrix of offsets to Anchor tables--
|
||||
* from beginning of AnchorMatrix table */
|
||||
public:
|
||||
@ -18,6 +18,7 @@ struct AnchorMatrix
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!c->check_struct (this)) return_trace (false);
|
||||
hb_barrier ();
|
||||
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
|
||||
unsigned int count = rows * cols;
|
||||
if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
|
||||
@ -25,6 +26,7 @@ struct AnchorMatrix
|
||||
if (c->lazy_some_gpos)
|
||||
return_trace (true);
|
||||
|
||||
hb_barrier ();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!matrixZ[i].sanitize (c, this)) return_trace (false);
|
||||
return_trace (true);
|
||||
@ -38,6 +40,7 @@ struct AnchorMatrix
|
||||
if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
|
||||
auto &offset = matrixZ[row * cols + col];
|
||||
if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor);
|
||||
hb_barrier ();
|
||||
*found = !offset.is_null ();
|
||||
return this+offset;
|
||||
}
|
||||
@ -65,15 +68,14 @@ struct AnchorMatrix
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
out->rows = num_rows;
|
||||
bool ret = false;
|
||||
for (const unsigned i : index_iter)
|
||||
{
|
||||
auto *offset = c->serializer->embed (matrixZ[i]);
|
||||
if (!offset) return_trace (false);
|
||||
ret |= offset->serialize_subset (c, matrixZ[i], this);
|
||||
offset->serialize_subset (c, matrixZ[i], this);
|
||||
}
|
||||
|
||||
return_trace (ret);
|
||||
return_trace (true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ static void SinglePos_serialize (hb_serialize_context_t *c,
|
||||
const SrcLookup *src,
|
||||
Iterator it,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
|
||||
bool all_axes_pinned);
|
||||
unsigned new_format);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -11,21 +11,21 @@ struct EntryExitRecord
|
||||
{
|
||||
friend struct CursivePosFormat1;
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1 *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
|
||||
}
|
||||
|
||||
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
|
||||
const void *src_base) const
|
||||
const struct CursivePosFormat1 *src_base) const
|
||||
{
|
||||
(src_base+entryAnchor).collect_variation_indices (c);
|
||||
(src_base+exitAnchor).collect_variation_indices (c);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const void *src_base) const
|
||||
const struct CursivePosFormat1 *src_base) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
@ -38,11 +38,11 @@ struct EntryExitRecord
|
||||
}
|
||||
|
||||
protected:
|
||||
Offset16To<Anchor>
|
||||
Offset16To<Anchor, struct CursivePosFormat1>
|
||||
entryAnchor; /* Offset to EntryAnchor table--from
|
||||
* beginning of CursivePos
|
||||
* subtable--may be NULL */
|
||||
Offset16To<Anchor>
|
||||
Offset16To<Anchor, struct CursivePosFormat1>
|
||||
exitAnchor; /* Offset to ExitAnchor table--from
|
||||
* beginning of CursivePos
|
||||
* subtable--may be NULL */
|
||||
@ -128,6 +128,7 @@ struct CursivePosFormat1
|
||||
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
|
||||
if (!this_record.entryAnchor ||
|
||||
unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
|
||||
hb_barrier ();
|
||||
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
|
||||
skippy_iter.reset_fast (buffer->idx);
|
||||
@ -145,6 +146,7 @@ struct CursivePosFormat1
|
||||
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
|
||||
return_trace (false);
|
||||
}
|
||||
hb_barrier ();
|
||||
|
||||
unsigned int i = skippy_iter.idx;
|
||||
unsigned int j = buffer->idx;
|
||||
@ -262,7 +264,7 @@ struct CursivePosFormat1
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
void serialize (hb_subset_context_t *c,
|
||||
Iterator it,
|
||||
const void *src_base)
|
||||
const struct CursivePosFormat1 *src_base)
|
||||
{
|
||||
if (unlikely (!c->serializer->extend_min ((*this)))) return;
|
||||
this->format = 1;
|
||||
|
||||
@ -42,6 +42,7 @@ struct MarkMarkPosFormat1_2
|
||||
mark1Coverage.sanitize (c, this) &&
|
||||
mark2Coverage.sanitize (c, this) &&
|
||||
mark1Array.sanitize (c, this) &&
|
||||
hb_barrier () &&
|
||||
mark2Array.sanitize (c, this, (unsigned int) classCount));
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ struct PairPosFormat1_3
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
if (!c->check_struct (this)) return_trace (false);
|
||||
hb_barrier ();
|
||||
|
||||
unsigned int len1 = valueFormat[0].get_len ();
|
||||
unsigned int len2 = valueFormat[1].get_len ();
|
||||
@ -102,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);
|
||||
@ -131,20 +170,33 @@ struct PairPosFormat1_3
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
out->format = format;
|
||||
out->valueFormat[0] = valueFormat[0];
|
||||
out->valueFormat[1] = valueFormat[1];
|
||||
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||
|
||||
hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]);
|
||||
|
||||
if (c->plan->normalized_coords)
|
||||
{
|
||||
hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
|
||||
out->valueFormat[0] = newFormats.first;
|
||||
out->valueFormat[1] = newFormats.second;
|
||||
/* all device flags will be dropped when full instancing, no need to strip
|
||||
* hints, also do not strip emtpy cause we don't compute the new default
|
||||
* value during stripping */
|
||||
newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map);
|
||||
}
|
||||
/* do not strip hints for VF */
|
||||
else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||
{
|
||||
hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
|
||||
bool has_fvar = (blob != hb_blob_get_empty ());
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
bool strip = !has_fvar;
|
||||
/* special case: strip hints when a VF has no GDEF varstore after
|
||||
* subsetting*/
|
||||
if (has_fvar && !c->plan->has_gdef_varstore)
|
||||
strip = true;
|
||||
newFormats = compute_effective_value_formats (glyphset, strip, true);
|
||||
}
|
||||
|
||||
if (c->plan->all_axes_pinned)
|
||||
{
|
||||
out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
|
||||
out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
|
||||
}
|
||||
out->valueFormat[0] = newFormats.first;
|
||||
out->valueFormat[1] = newFormats.second;
|
||||
|
||||
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
|
||||
|
||||
@ -175,7 +227,9 @@ struct PairPosFormat1_3
|
||||
}
|
||||
|
||||
|
||||
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
|
||||
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset,
|
||||
bool strip_hints, bool strip_empty,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
|
||||
{
|
||||
unsigned record_size = PairSet::get_size (valueFormat);
|
||||
|
||||
@ -195,8 +249,8 @@ struct PairPosFormat1_3
|
||||
{
|
||||
if (record->intersects (glyphset))
|
||||
{
|
||||
format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
|
||||
format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
|
||||
format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map);
|
||||
format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map);
|
||||
}
|
||||
record = &StructAtOffset<const PairValueRecord> (record, record_size);
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ namespace Layout {
|
||||
namespace GPOS_impl {
|
||||
|
||||
template <typename Types>
|
||||
struct PairPosFormat2_4
|
||||
struct PairPosFormat2_4 : ValueBase
|
||||
{
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
@ -123,12 +123,61 @@ struct PairPosFormat2_4
|
||||
|
||||
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,14 +188,13 @@ struct PairPosFormat2_4
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
|
||||
if (!klass2)
|
||||
{
|
||||
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
|
||||
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);
|
||||
@ -287,18 +335,31 @@ struct PairPosFormat2_4
|
||||
unsigned len2 = valueFormat2.get_len ();
|
||||
|
||||
hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
|
||||
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||
newFormats = compute_effective_value_formats (klass1_map, klass2_map);
|
||||
|
||||
if (c->plan->normalized_coords)
|
||||
{
|
||||
/* in case of full instancing, all var device flags will be dropped so no
|
||||
* need to strip hints here */
|
||||
newFormats = compute_effective_value_formats (klass1_map, klass2_map, false, false, &c->plan->layout_variation_idx_delta_map);
|
||||
}
|
||||
/* do not strip hints for VF */
|
||||
else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||
{
|
||||
hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
|
||||
bool has_fvar = (blob != hb_blob_get_empty ());
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
bool strip = !has_fvar;
|
||||
/* special case: strip hints when a VF has no GDEF varstore after
|
||||
* subsetting*/
|
||||
if (has_fvar && !c->plan->has_gdef_varstore)
|
||||
strip = true;
|
||||
newFormats = compute_effective_value_formats (klass1_map, klass2_map, strip, true);
|
||||
}
|
||||
|
||||
out->valueFormat1 = newFormats.first;
|
||||
out->valueFormat2 = newFormats.second;
|
||||
|
||||
if (c->plan->all_axes_pinned)
|
||||
{
|
||||
out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
|
||||
out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
|
||||
}
|
||||
|
||||
unsigned total_len = len1 + len2;
|
||||
hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map));
|
||||
for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
|
||||
@ -311,22 +372,15 @@ struct PairPosFormat2_4
|
||||
}
|
||||
}
|
||||
|
||||
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
|
||||
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||
|
||||
auto it =
|
||||
+ hb_iter (this+coverage)
|
||||
| hb_filter (glyphset)
|
||||
| hb_map_retains_sorting (glyph_map)
|
||||
;
|
||||
|
||||
out->coverage.serialize_serialize (c->serializer, it);
|
||||
return_trace (out->class1Count && out->class2Count && bool (it));
|
||||
bool ret = out->coverage.serialize_subset(c, coverage, this);
|
||||
return_trace (out->class1Count && out->class2Count && ret);
|
||||
}
|
||||
|
||||
|
||||
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
|
||||
const hb_map_t& klass2_map) const
|
||||
const hb_map_t& klass2_map,
|
||||
bool strip_hints, bool strip_empty,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
|
||||
{
|
||||
unsigned len1 = valueFormat1.get_len ();
|
||||
unsigned len2 = valueFormat2.get_len ();
|
||||
@ -340,8 +394,8 @@ struct PairPosFormat2_4
|
||||
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
|
||||
{
|
||||
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
|
||||
format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
|
||||
format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
|
||||
format1 = format1 | valueFormat1.get_effective_format (&values[idx], strip_hints, strip_empty, this, varidx_delta_map);
|
||||
format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1], strip_hints, strip_empty, this, varidx_delta_map);
|
||||
}
|
||||
|
||||
if (format1 == valueFormat1 && format2 == valueFormat2)
|
||||
|
||||
@ -9,7 +9,7 @@ namespace GPOS_impl {
|
||||
|
||||
|
||||
template <typename Types>
|
||||
struct PairSet
|
||||
struct PairSet : ValueBase
|
||||
{
|
||||
template <typename Types2>
|
||||
friend struct PairPosFormat1_3;
|
||||
@ -45,10 +45,12 @@ struct PairSet
|
||||
bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!(c->check_struct (this)
|
||||
&& c->check_range (&firstPairValueRecord,
|
||||
if (!(c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
c->check_range (&firstPairValueRecord,
|
||||
len,
|
||||
closure->stride))) return_trace (false);
|
||||
hb_barrier ();
|
||||
|
||||
unsigned int count = len;
|
||||
const PairValueRecord *record = &firstPairValueRecord;
|
||||
|
||||
@ -29,7 +29,7 @@ struct PairValueRecord
|
||||
|
||||
struct context_t
|
||||
{
|
||||
const void *base;
|
||||
const ValueBase *base;
|
||||
const ValueFormat *valueFormats;
|
||||
const ValueFormat *newFormats;
|
||||
unsigned len1; /* valueFormats[0].get_len() */
|
||||
@ -62,7 +62,7 @@ struct PairValueRecord
|
||||
|
||||
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
|
||||
const ValueFormat *valueFormats,
|
||||
const void *base) const
|
||||
const ValueBase *base) const
|
||||
{
|
||||
unsigned record1_len = valueFormats[0].get_len ();
|
||||
unsigned record2_len = valueFormats[1].get_len ();
|
||||
|
||||
@ -39,14 +39,12 @@ struct SinglePos
|
||||
const SrcLookup* src,
|
||||
Iterator glyph_val_iter_pairs,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
|
||||
bool all_axes_pinned)
|
||||
unsigned newFormat)
|
||||
{
|
||||
if (unlikely (!c->extend_min (u.format))) return;
|
||||
unsigned format = 2;
|
||||
ValueFormat new_format = src->get_value_format ();
|
||||
|
||||
if (all_axes_pinned)
|
||||
new_format = new_format.drop_device_table_flags ();
|
||||
ValueFormat new_format;
|
||||
new_format = newFormat;
|
||||
|
||||
if (glyph_val_iter_pairs)
|
||||
format = get_format (glyph_val_iter_pairs);
|
||||
@ -89,8 +87,8 @@ SinglePos_serialize (hb_serialize_context_t *c,
|
||||
const SrcLookup *src,
|
||||
Iterator it,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
|
||||
bool all_axes_pinned)
|
||||
{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); }
|
||||
unsigned new_format)
|
||||
{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, new_format); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ namespace OT {
|
||||
namespace Layout {
|
||||
namespace GPOS_impl {
|
||||
|
||||
struct SinglePosFormat1
|
||||
struct SinglePosFormat1 : ValueBase
|
||||
{
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 1 */
|
||||
@ -28,6 +28,7 @@ struct SinglePosFormat1
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
coverage.sanitize (c, this) &&
|
||||
hb_barrier () &&
|
||||
/* The coverage table may use a range to represent a set
|
||||
* of glyphs, which means a small number of bytes can
|
||||
* generate a large glyph set. Manually modify the
|
||||
@ -66,7 +67,7 @@ struct SinglePosFormat1
|
||||
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 ())
|
||||
{
|
||||
@ -146,6 +147,30 @@ struct SinglePosFormat1
|
||||
hb_set_t intersection;
|
||||
(this+coverage).intersect_set (glyphset, intersection);
|
||||
|
||||
unsigned new_format = valueFormat;
|
||||
|
||||
if (c->plan->normalized_coords)
|
||||
{
|
||||
new_format = valueFormat.get_effective_format (values.arrayZ, false, false, this, &c->plan->layout_variation_idx_delta_map);
|
||||
}
|
||||
/* do not strip hints for VF */
|
||||
else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||
{
|
||||
hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
|
||||
bool has_fvar = (blob != hb_blob_get_empty ());
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
bool strip = !has_fvar;
|
||||
/* special case: strip hints when a VF has no GDEF varstore after
|
||||
* subsetting*/
|
||||
if (has_fvar && !c->plan->has_gdef_varstore)
|
||||
strip = true;
|
||||
new_format = valueFormat.get_effective_format (values.arrayZ,
|
||||
strip, /* strip hints */
|
||||
true, /* strip empty */
|
||||
this, nullptr);
|
||||
}
|
||||
|
||||
auto it =
|
||||
+ hb_iter (intersection)
|
||||
| hb_map_retains_sorting (glyph_map)
|
||||
@ -153,7 +178,7 @@ struct SinglePosFormat1
|
||||
;
|
||||
|
||||
bool ret = bool (it);
|
||||
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
|
||||
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
|
||||
return_trace (ret);
|
||||
}
|
||||
};
|
||||
|
||||
@ -7,7 +7,7 @@ namespace OT {
|
||||
namespace Layout {
|
||||
namespace GPOS_impl {
|
||||
|
||||
struct SinglePosFormat2
|
||||
struct SinglePosFormat2 : ValueBase
|
||||
{
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
@ -66,7 +66,7 @@ struct SinglePosFormat2
|
||||
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);
|
||||
|
||||
@ -143,6 +143,37 @@ struct SinglePosFormat2
|
||||
coverage.serialize_serialize (c, glyphs);
|
||||
}
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
unsigned compute_effective_format (const hb_face_t *face,
|
||||
Iterator it,
|
||||
bool is_instancing, bool strip_hints,
|
||||
bool has_gdef_varstore,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
|
||||
{
|
||||
hb_blob_t* blob = hb_face_reference_table (face, HB_TAG ('f','v','a','r'));
|
||||
bool has_fvar = (blob != hb_blob_get_empty ());
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
unsigned new_format = 0;
|
||||
if (is_instancing)
|
||||
{
|
||||
new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), false, false, this, varidx_delta_map);
|
||||
}
|
||||
/* do not strip hints for VF */
|
||||
else if (strip_hints)
|
||||
{
|
||||
bool strip = !has_fvar;
|
||||
if (has_fvar && !has_gdef_varstore)
|
||||
strip = true;
|
||||
new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), strip, true, this, nullptr);
|
||||
}
|
||||
else
|
||||
new_format = valueFormat;
|
||||
|
||||
return new_format;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -163,8 +194,13 @@ struct SinglePosFormat2
|
||||
})
|
||||
;
|
||||
|
||||
unsigned new_format = compute_effective_format (c->plan->source, it,
|
||||
bool (c->plan->normalized_coords),
|
||||
bool (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING),
|
||||
c->plan->has_gdef_varstore,
|
||||
&c->plan->layout_variation_idx_delta_map);
|
||||
bool ret = bool (it);
|
||||
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
|
||||
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
|
||||
return_trace (ret);
|
||||
}
|
||||
};
|
||||
|
||||
@ -9,6 +9,8 @@ namespace GPOS_impl {
|
||||
|
||||
typedef HBUINT16 Value;
|
||||
|
||||
struct ValueBase {}; // Dummy base class tag for OffsetTo<Value> bases.
|
||||
|
||||
typedef UnsizedArrayOf<Value> ValueRecord;
|
||||
|
||||
struct ValueFormat : HBUINT16
|
||||
@ -78,7 +80,7 @@ struct ValueFormat : HBUINT16
|
||||
}
|
||||
|
||||
bool apply_value (hb_ot_apply_context_t *c,
|
||||
const void *base,
|
||||
const ValueBase *base,
|
||||
const Value *values,
|
||||
hb_glyph_position_t &glyph_pos) const
|
||||
{
|
||||
@ -114,7 +116,7 @@ struct ValueFormat : HBUINT16
|
||||
|
||||
if (!use_x_device && !use_y_device) return ret;
|
||||
|
||||
const VariationStore &store = c->var_store;
|
||||
const ItemVariationStore &store = c->var_store;
|
||||
auto *cache = c->var_store_cache;
|
||||
|
||||
/* pixel -> fractional pixel */
|
||||
@ -142,11 +144,29 @@ struct ValueFormat : HBUINT16
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned int get_effective_format (const Value *values) const
|
||||
unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
|
||||
{
|
||||
unsigned int format = *this;
|
||||
for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
|
||||
if (format & flag) should_drop (*values++, (Flags) flag, &format);
|
||||
if (format & flag)
|
||||
{
|
||||
if (strip_hints && flag >= xPlaDevice)
|
||||
{
|
||||
format = format & ~flag;
|
||||
values++;
|
||||
continue;
|
||||
}
|
||||
if (varidx_delta_map && flag >= xPlaDevice)
|
||||
{
|
||||
update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map);
|
||||
continue;
|
||||
}
|
||||
/* do not strip empty when instancing, cause we don't know whether the new
|
||||
* default value is 0 or not */
|
||||
if (strip_empty) should_drop (*values, (Flags) flag, &format);
|
||||
values++;
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
@ -154,18 +174,19 @@ struct ValueFormat : HBUINT16
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
unsigned int get_effective_format (Iterator it) const {
|
||||
unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const {
|
||||
unsigned int new_format = 0;
|
||||
|
||||
for (const hb_array_t<const Value>& values : it)
|
||||
new_format = new_format | get_effective_format (&values);
|
||||
new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map);
|
||||
|
||||
return new_format;
|
||||
}
|
||||
|
||||
void copy_values (hb_serialize_context_t *c,
|
||||
unsigned int new_format,
|
||||
const void *base,
|
||||
const ValueBase *base,
|
||||
const Value *values,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
|
||||
{
|
||||
@ -217,7 +238,7 @@ struct ValueFormat : HBUINT16
|
||||
}
|
||||
|
||||
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
|
||||
const void *base,
|
||||
const ValueBase *base,
|
||||
const hb_array_t<const Value>& values) const
|
||||
{
|
||||
unsigned format = *this;
|
||||
@ -251,17 +272,8 @@ struct ValueFormat : HBUINT16
|
||||
}
|
||||
}
|
||||
|
||||
unsigned drop_device_table_flags () const
|
||||
{
|
||||
unsigned format = *this;
|
||||
for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
|
||||
format = format & ~flag;
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
private:
|
||||
bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
|
||||
bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
|
||||
{
|
||||
unsigned int format = *this;
|
||||
|
||||
@ -278,17 +290,17 @@ struct ValueFormat : HBUINT16
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline Offset16To<Device>& get_device (Value* value)
|
||||
static inline Offset16To<Device, ValueBase>& get_device (Value* value)
|
||||
{
|
||||
return *static_cast<Offset16To<Device> *> (value);
|
||||
return *static_cast<Offset16To<Device, ValueBase> *> (value);
|
||||
}
|
||||
static inline const Offset16To<Device>& get_device (const Value* value)
|
||||
static inline const Offset16To<Device, ValueBase>& get_device (const Value* value)
|
||||
{
|
||||
return *static_cast<const Offset16To<Device> *> (value);
|
||||
return *static_cast<const Offset16To<Device, ValueBase> *> (value);
|
||||
}
|
||||
static inline const Device& get_device (const Value* value,
|
||||
bool *worked,
|
||||
const void *base,
|
||||
const ValueBase *base,
|
||||
hb_sanitize_context_t &c)
|
||||
{
|
||||
if (worked) *worked |= bool (*value);
|
||||
@ -296,12 +308,13 @@ struct ValueFormat : HBUINT16
|
||||
|
||||
if (unlikely (!offset.sanitize (&c, base)))
|
||||
return Null(Device);
|
||||
hb_barrier ();
|
||||
|
||||
return base + offset;
|
||||
}
|
||||
|
||||
void add_delta_to_value (HBINT16 *value,
|
||||
const void *base,
|
||||
const ValueBase *base,
|
||||
const Value *src_value,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
|
||||
{
|
||||
@ -313,7 +326,8 @@ struct ValueFormat : HBUINT16
|
||||
*value += hb_second (*varidx_delta);
|
||||
}
|
||||
|
||||
bool copy_device (hb_serialize_context_t *c, const void *base,
|
||||
bool copy_device (hb_serialize_context_t *c,
|
||||
const ValueBase *base,
|
||||
const Value *src_value,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
|
||||
unsigned int new_format, Flags flag) const
|
||||
@ -354,7 +368,7 @@ struct ValueFormat : HBUINT16
|
||||
return (format & devices) != 0;
|
||||
}
|
||||
|
||||
bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
|
||||
bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
@ -366,7 +380,7 @@ struct ValueFormat : HBUINT16
|
||||
return_trace (!has_device () || sanitize_value_devices (c, base, values));
|
||||
}
|
||||
|
||||
bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
|
||||
bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
unsigned size = get_size ();
|
||||
@ -376,11 +390,12 @@ struct ValueFormat : HBUINT16
|
||||
if (c->lazy_some_gpos)
|
||||
return_trace (true);
|
||||
|
||||
hb_barrier ();
|
||||
return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
|
||||
}
|
||||
|
||||
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */
|
||||
bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
|
||||
bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
@ -403,6 +418,20 @@ struct ValueFormat : HBUINT16
|
||||
*format = *format & ~flag;
|
||||
}
|
||||
|
||||
void update_var_flag (const Value* value, Flags flag,
|
||||
unsigned int* format, const ValueBase *base,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
|
||||
{
|
||||
if (*value)
|
||||
{
|
||||
unsigned varidx = (base + get_device (value)).get_variation_index ();
|
||||
hb_pair_t<unsigned, int> *varidx_delta;
|
||||
if (varidx_delta_map->has (varidx, &varidx_delta) &&
|
||||
varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
|
||||
return;
|
||||
}
|
||||
*format = *format & ~flag;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -90,8 +90,17 @@ struct Ligature
|
||||
|
||||
unsigned int total_component_count = 0;
|
||||
|
||||
if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false;
|
||||
unsigned match_positions_stack[4];
|
||||
unsigned *match_positions = match_positions_stack;
|
||||
if (unlikely (count > ARRAY_LENGTH (match_positions_stack)))
|
||||
{
|
||||
match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned));
|
||||
if (unlikely (!match_positions))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
unsigned int match_end = 0;
|
||||
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
|
||||
|
||||
if (likely (!match_input (c, count,
|
||||
&component[1],
|
||||
@ -102,6 +111,8 @@ struct Ligature
|
||||
&total_component_count)))
|
||||
{
|
||||
c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
|
||||
if (match_positions != match_positions_stack)
|
||||
hb_free (match_positions);
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
@ -145,6 +156,8 @@ struct Ligature
|
||||
pos);
|
||||
}
|
||||
|
||||
if (match_positions != match_positions_stack)
|
||||
hb_free (match_positions);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -33,9 +33,11 @@ struct ReverseChainSingleSubstFormat1
|
||||
TRACE_SANITIZE (this);
|
||||
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
|
||||
return_trace (false);
|
||||
hb_barrier ();
|
||||
const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
|
||||
if (!lookahead.sanitize (c, this))
|
||||
return_trace (false);
|
||||
hb_barrier ();
|
||||
const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
|
||||
return_trace (substitute.sanitize (c));
|
||||
}
|
||||
@ -109,12 +111,12 @@ struct ReverseChainSingleSubstFormat1
|
||||
bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
|
||||
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 */
|
||||
|
||||
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
|
||||
if (likely (index == NOT_COVERED)) return_trace (false);
|
||||
|
||||
const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
|
||||
const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
|
||||
|
||||
|
||||
@ -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 ();
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -38,8 +41,8 @@ struct SmallTypes {
|
||||
using HBUINT = HBUINT16;
|
||||
using HBGlyphID = HBGlyphID16;
|
||||
using Offset = Offset16;
|
||||
template <typename Type, bool has_null=true>
|
||||
using OffsetTo = OT::Offset16To<Type, has_null>;
|
||||
template <typename Type, typename BaseType=void, bool has_null=true>
|
||||
using OffsetTo = OT::Offset16To<Type, BaseType, has_null>;
|
||||
template <typename Type>
|
||||
using ArrayOf = OT::Array16Of<Type>;
|
||||
template <typename Type>
|
||||
@ -52,8 +55,8 @@ struct MediumTypes {
|
||||
using HBUINT = HBUINT24;
|
||||
using HBGlyphID = HBGlyphID24;
|
||||
using Offset = Offset24;
|
||||
template <typename Type, bool has_null=true>
|
||||
using OffsetTo = OT::Offset24To<Type, has_null>;
|
||||
template <typename Type, typename BaseType=void, bool has_null=true>
|
||||
using OffsetTo = OT::Offset24To<Type, BaseType, has_null>;
|
||||
template <typename Type>
|
||||
using ArrayOf = OT::Array24Of<Type>;
|
||||
template <typename Type>
|
||||
|
||||
218
src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh
Normal file
218
src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh
Normal file
@ -0,0 +1,218 @@
|
||||
#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"
|
||||
#include "../../../hb-ot-cff1-table.hh"
|
||||
|
||||
#include "coord-setter.hh"
|
||||
|
||||
namespace OT {
|
||||
|
||||
//namespace Var {
|
||||
|
||||
/*
|
||||
* VARC -- Variable Composites
|
||||
* https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md
|
||||
*/
|
||||
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
|
||||
struct VarComponent
|
||||
{
|
||||
enum class flags_t : uint32_t
|
||||
{
|
||||
RESET_UNSPECIFIED_AXES = 1u << 0,
|
||||
HAVE_AXES = 1u << 1,
|
||||
AXIS_VALUES_HAVE_VARIATION = 1u << 2,
|
||||
TRANSFORM_HAS_VARIATION = 1u << 3,
|
||||
HAVE_TRANSLATE_X = 1u << 4,
|
||||
HAVE_TRANSLATE_Y = 1u << 5,
|
||||
HAVE_ROTATION = 1u << 6,
|
||||
HAVE_CONDITION = 1u << 7,
|
||||
HAVE_SCALE_X = 1u << 8,
|
||||
HAVE_SCALE_Y = 1u << 9,
|
||||
HAVE_TCENTER_X = 1u << 10,
|
||||
HAVE_TCENTER_Y = 1u << 11,
|
||||
GID_IS_24BIT = 1u << 12,
|
||||
HAVE_SKEW_X = 1u << 13,
|
||||
HAVE_SKEW_Y = 1u << 14,
|
||||
RESERVED_MASK = ~((1u << 15) - 1),
|
||||
};
|
||||
|
||||
HB_INTERNAL hb_ubytes_t
|
||||
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 transform,
|
||||
hb_ubytes_t record,
|
||||
hb_decycler_t *decycler,
|
||||
signed *edges_left,
|
||||
signed depth_left,
|
||||
hb_glyf_scratch_t &scratch,
|
||||
VarRegionList::cache_t *cache = nullptr) const;
|
||||
};
|
||||
|
||||
struct VarCompositeGlyph
|
||||
{
|
||||
static void
|
||||
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_ubytes_t record,
|
||||
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, transform,
|
||||
record,
|
||||
decycler, edges_left, depth_left, scratch, cache);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
HB_MARK_AS_FLAG_T (VarComponent::flags_t);
|
||||
|
||||
struct VARC
|
||||
{
|
||||
friend struct VarComponent;
|
||||
|
||||
static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
|
||||
|
||||
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_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,
|
||||
hb_glyf_scratch_t &scratch) const
|
||||
{
|
||||
hb_decycler_t decycler;
|
||||
signed edges = HB_MAX_GRAPH_EDGE_COUNT;
|
||||
|
||||
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
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (version.sanitize (c) &&
|
||||
hb_barrier () &&
|
||||
version.major == 1 &&
|
||||
coverage.sanitize (c, this) &&
|
||||
varStore.sanitize (c, this) &&
|
||||
conditionList.sanitize (c, this) &&
|
||||
axisIndicesList.sanitize (c, this) &&
|
||||
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;
|
||||
Offset32To<MultiItemVariationStore> varStore;
|
||||
Offset32To<ConditionList> conditionList;
|
||||
Offset32To<TupleList> axisIndicesList;
|
||||
Offset32To<CFF2Index/*Of<VarCompositeGlyph>*/> glyphRecords;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (24);
|
||||
};
|
||||
|
||||
struct VARC_accelerator_t : VARC::accelerator_t {
|
||||
VARC_accelerator_t (hb_face_t *face) : VARC::accelerator_t (face) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
#endif /* OT_VAR_VARC_VARC_HH */
|
||||
@ -0,0 +1,63 @@
|
||||
#ifndef OT_VAR_VARC_COORD_SETTER_HH
|
||||
#define OT_VAR_VARC_COORD_SETTER_HH
|
||||
|
||||
|
||||
#include "../../../hb.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
//namespace Var {
|
||||
|
||||
|
||||
struct coord_setter_t
|
||||
{
|
||||
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 (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 length <= ARRAY_LENGTH (static_coords) ? hb_array (static_coords, length) : dynamic_coords.as_array (); }
|
||||
|
||||
private:
|
||||
hb_vector_t<int> dynamic_coords;
|
||||
unsigned length;
|
||||
int static_coords[sizeof (void *) * 8];
|
||||
};
|
||||
|
||||
|
||||
//} // namespace Var
|
||||
|
||||
} // namespace OT
|
||||
|
||||
#endif /* OT_VAR_VARC_COORD_SETTER_HH */
|
||||
@ -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;
|
||||
}
|
||||
@ -240,7 +240,8 @@ struct CompositeGlyphRecord
|
||||
}
|
||||
if (is_anchored ()) tx = ty = 0;
|
||||
|
||||
trans.init ((float) tx, (float) ty);
|
||||
/* set is_end_point flag to true, used by IUP delta optimization */
|
||||
trans.init ((float) tx, (float) ty, true);
|
||||
|
||||
{
|
||||
const F2DOT14 *points = (const F2DOT14 *) p;
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
#include "GlyphHeader.hh"
|
||||
#include "SimpleGlyph.hh"
|
||||
#include "CompositeGlyph.hh"
|
||||
#include "VarCompositeGlyph.hh"
|
||||
#include "coord-setter.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
@ -33,9 +31,6 @@ struct Glyph
|
||||
EMPTY,
|
||||
SIMPLE,
|
||||
COMPOSITE,
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
VAR_COMPOSITE,
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
@ -44,22 +39,10 @@ struct Glyph
|
||||
if (type != COMPOSITE) return composite_iter_t ();
|
||||
return CompositeGlyph (*header, bytes).iter ();
|
||||
}
|
||||
var_composite_iter_t get_var_composite_iterator () const
|
||||
{
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
if (type != VAR_COMPOSITE) return var_composite_iter_t ();
|
||||
return VarCompositeGlyph (*header, bytes).iter ();
|
||||
#else
|
||||
return var_composite_iter_t ();
|
||||
#endif
|
||||
}
|
||||
|
||||
const hb_bytes_t trim_padding () const
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
|
||||
#endif
|
||||
case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
|
||||
case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
|
||||
case EMPTY: return bytes;
|
||||
@ -70,9 +53,6 @@ struct Glyph
|
||||
void drop_hints ()
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No hinting
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
|
||||
case EMPTY: return;
|
||||
@ -82,9 +62,6 @@ struct Glyph
|
||||
void set_overlaps_flag ()
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No overlaps flag
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
|
||||
case EMPTY: return;
|
||||
@ -94,15 +71,15 @@ struct Glyph
|
||||
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No hinting
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
|
||||
case EMPTY: return;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_composite () const
|
||||
{ return type == COMPOSITE; }
|
||||
|
||||
bool get_all_points_without_var (const hb_face_t *face,
|
||||
contour_point_vector_t &points /* OUT */) const
|
||||
{
|
||||
@ -117,14 +94,6 @@ struct Glyph
|
||||
if (unlikely (!item.get_points (points))) return false;
|
||||
break;
|
||||
}
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE:
|
||||
{
|
||||
for (auto &item : get_var_composite_iterator ())
|
||||
if (unlikely (!item.get_points (points))) return false;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case EMPTY:
|
||||
break;
|
||||
}
|
||||
@ -282,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
|
||||
@ -300,13 +270,6 @@ struct Glyph
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE:
|
||||
// TODO
|
||||
dest_end = hb_bytes_t ();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case COMPOSITE:
|
||||
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
|
||||
points_with_deltas,
|
||||
@ -343,27 +306,23 @@ 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 */
|
||||
bool shift_points_hori = true,
|
||||
bool use_my_metrics = true,
|
||||
bool phantom_only = false,
|
||||
hb_array_t<int> coords = hb_array_t<int> (),
|
||||
hb_map_t *current_glyphs = nullptr,
|
||||
hb_array_t<const int> coords = hb_array_t<const int> (),
|
||||
unsigned int depth = 0,
|
||||
unsigned *edge_count = nullptr) const
|
||||
{
|
||||
if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
|
||||
unsigned stack_edge_count = 0;
|
||||
if (!edge_count) edge_count = &stack_edge_count;
|
||||
if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
|
||||
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 = ¤t_glyphs_stack;
|
||||
|
||||
if (head_maxp_info)
|
||||
{
|
||||
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
|
||||
@ -372,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) {
|
||||
@ -391,14 +349,6 @@ struct Glyph
|
||||
if (unlikely (!item.get_points (points))) return false;
|
||||
break;
|
||||
}
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE:
|
||||
{
|
||||
for (auto &item : get_var_composite_iterator ())
|
||||
if (unlikely (!item.get_points (points))) return false;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case EMPTY:
|
||||
break;
|
||||
}
|
||||
@ -434,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;
|
||||
|
||||
@ -472,6 +439,7 @@ struct Glyph
|
||||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
all_points,
|
||||
scratch,
|
||||
points_with_deltas,
|
||||
head_maxp_info,
|
||||
composite_contours,
|
||||
@ -479,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 */
|
||||
@ -501,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)
|
||||
@ -522,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)
|
||||
@ -538,84 +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;
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE:
|
||||
{
|
||||
hb_array_t<contour_point_t> points_left = points.as_array ();
|
||||
for (auto &item : get_var_composite_iterator ())
|
||||
{
|
||||
hb_codepoint_t item_gid = item.get_gid ();
|
||||
|
||||
if (unlikely (current_glyphs->has (item_gid)))
|
||||
continue;
|
||||
|
||||
current_glyphs->add (item_gid);
|
||||
|
||||
unsigned item_num_points = item.get_num_points ();
|
||||
hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
|
||||
assert (record_points.length == item_num_points);
|
||||
|
||||
auto component_coords = coords;
|
||||
/* Copying coords is expensive; so we have put an arbitrary
|
||||
* limit on the max number of coords for now. */
|
||||
if (item.is_reset_unspecified_axes () ||
|
||||
coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
|
||||
component_coords = hb_array<int> ();
|
||||
|
||||
coord_setter_t coord_setter (component_coords);
|
||||
item.set_variations (coord_setter, record_points);
|
||||
|
||||
unsigned old_count = all_points.length;
|
||||
|
||||
if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
|
||||
!glyf_accelerator.glyph_for_gid (item_gid)
|
||||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
all_points,
|
||||
points_with_deltas,
|
||||
head_maxp_info,
|
||||
nullptr,
|
||||
shift_points_hori,
|
||||
use_my_metrics,
|
||||
phantom_only,
|
||||
coord_setter.get_coords (),
|
||||
current_glyphs,
|
||||
depth + 1,
|
||||
edge_count)))
|
||||
{
|
||||
current_glyphs->del (item_gid);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto comp_points = all_points.as_array ().sub_array (old_count);
|
||||
|
||||
/* Apply component transformation */
|
||||
if (comp_points) // Empty in case of phantom_only
|
||||
item.transform_points (record_points, comp_points);
|
||||
|
||||
/* Copy phantom points from component if USE_MY_METRICS flag set */
|
||||
if (use_my_metrics && item.is_use_my_metrics ())
|
||||
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
|
||||
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
|
||||
|
||||
all_points.resize (all_points.length - PHANTOM_COUNT);
|
||||
|
||||
if (all_points.length > HB_GLYF_MAX_POINTS)
|
||||
{
|
||||
current_glyphs->del (item_gid);
|
||||
return false;
|
||||
}
|
||||
|
||||
points_left += item_num_points;
|
||||
|
||||
current_glyphs->del (item_gid);
|
||||
}
|
||||
all_points.extend (phantoms);
|
||||
} break;
|
||||
#endif
|
||||
case EMPTY:
|
||||
all_points.extend (phantoms);
|
||||
shift = phantoms[PHANTOM_LEFT].x;
|
||||
points.resize (old_length);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -624,10 +522,9 @@ struct Glyph
|
||||
/* Undocumented rasterizer behavior:
|
||||
* Shift points horizontally by the updated left side bearing
|
||||
*/
|
||||
int 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 ();
|
||||
@ -658,10 +555,7 @@ struct Glyph
|
||||
int num_contours = header->numberOfContours;
|
||||
if (unlikely (num_contours == 0)) type = EMPTY;
|
||||
else if (num_contours > 0) type = SIMPLE;
|
||||
else if (num_contours == -1) type = COMPOSITE;
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
else if (num_contours == -2) type = VAR_COMPOSITE;
|
||||
#endif
|
||||
else if (num_contours <= -1) type = COMPOSITE;
|
||||
else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -53,23 +53,12 @@ struct SubsetGlyph
|
||||
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
|
||||
const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
|
||||
}
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
|
||||
{
|
||||
hb_codepoint_t new_gid;
|
||||
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
|
||||
const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
auto it = Glyph (dest_glyph).get_composite_iterator ();
|
||||
if (it)
|
||||
{
|
||||
/* lower GID24 to GID16 in components if possible.
|
||||
*
|
||||
* TODO: VarComposite. Not as critical, since VarComposite supports
|
||||
* gid24 from the first version. */
|
||||
/* lower GID24 to GID16 in components if possible. */
|
||||
char *p = it ? (char *) &*it : nullptr;
|
||||
char *q = p;
|
||||
const char *end = dest_glyph.arrayZ + dest_glyph.length;
|
||||
|
||||
@ -1,401 +0,0 @@
|
||||
#ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH
|
||||
#define OT_GLYF_VARCOMPOSITEGLYPH_HH
|
||||
|
||||
|
||||
#include "../../hb-open-type.hh"
|
||||
#include "coord-setter.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
namespace glyf_impl {
|
||||
|
||||
|
||||
struct VarCompositeGlyphRecord
|
||||
{
|
||||
protected:
|
||||
enum var_composite_glyph_flag_t
|
||||
{
|
||||
USE_MY_METRICS = 0x0001,
|
||||
AXIS_INDICES_ARE_SHORT = 0x0002,
|
||||
UNIFORM_SCALE = 0x0004,
|
||||
HAVE_TRANSLATE_X = 0x0008,
|
||||
HAVE_TRANSLATE_Y = 0x0010,
|
||||
HAVE_ROTATION = 0x0020,
|
||||
HAVE_SCALE_X = 0x0040,
|
||||
HAVE_SCALE_Y = 0x0080,
|
||||
HAVE_SKEW_X = 0x0100,
|
||||
HAVE_SKEW_Y = 0x0200,
|
||||
HAVE_TCENTER_X = 0x0400,
|
||||
HAVE_TCENTER_Y = 0x0800,
|
||||
GID_IS_24BIT = 0x1000,
|
||||
AXES_HAVE_VARIATION = 0x2000,
|
||||
RESET_UNSPECIFIED_AXES = 0x4000,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
unsigned int get_size () const
|
||||
{
|
||||
unsigned fl = flags;
|
||||
unsigned int size = min_size;
|
||||
|
||||
unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
|
||||
size += numAxes * axis_width;
|
||||
|
||||
if (fl & GID_IS_24BIT) size += 1;
|
||||
|
||||
// 2 bytes each for the following flags
|
||||
fl = fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y |
|
||||
HAVE_ROTATION |
|
||||
HAVE_SCALE_X | HAVE_SCALE_Y |
|
||||
HAVE_SKEW_X | HAVE_SKEW_Y |
|
||||
HAVE_TCENTER_X | HAVE_TCENTER_Y);
|
||||
size += hb_popcount (fl) * 2;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool has_more () const { return true; }
|
||||
|
||||
bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
|
||||
bool is_reset_unspecified_axes () const { return flags & RESET_UNSPECIFIED_AXES; }
|
||||
|
||||
hb_codepoint_t get_gid () const
|
||||
{
|
||||
if (flags & GID_IS_24BIT)
|
||||
return * (const HBGlyphID24 *) &pad;
|
||||
else
|
||||
return * (const HBGlyphID16 *) &pad;
|
||||
}
|
||||
|
||||
void set_gid (hb_codepoint_t gid)
|
||||
{
|
||||
if (flags & GID_IS_24BIT)
|
||||
* (HBGlyphID24 *) &pad = gid;
|
||||
else
|
||||
* (HBGlyphID16 *) &pad = gid;
|
||||
}
|
||||
|
||||
unsigned get_numAxes () const
|
||||
{
|
||||
return numAxes;
|
||||
}
|
||||
|
||||
unsigned get_num_points () const
|
||||
{
|
||||
unsigned fl = flags;
|
||||
unsigned num = 0;
|
||||
if (fl & AXES_HAVE_VARIATION) num += numAxes;
|
||||
|
||||
/* Hopefully faster code, relying on the value of the flags. */
|
||||
fl = (((fl & (HAVE_TRANSLATE_Y | HAVE_SCALE_Y | HAVE_SKEW_Y | HAVE_TCENTER_Y)) >> 1) | fl) &
|
||||
(HAVE_TRANSLATE_X | HAVE_ROTATION | HAVE_SCALE_X | HAVE_SKEW_X | HAVE_TCENTER_X);
|
||||
num += hb_popcount (fl);
|
||||
return num;
|
||||
|
||||
/* Slower but more readable code. */
|
||||
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
|
||||
if (fl & HAVE_ROTATION) num++;
|
||||
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
|
||||
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
|
||||
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
|
||||
return num;
|
||||
}
|
||||
|
||||
void transform_points (hb_array_t<const contour_point_t> record_points,
|
||||
hb_array_t<contour_point_t> points) const
|
||||
{
|
||||
float matrix[4];
|
||||
contour_point_t trans;
|
||||
|
||||
get_transformation_from_points (record_points.arrayZ, matrix, trans);
|
||||
|
||||
auto arrayZ = points.arrayZ;
|
||||
unsigned count = points.length;
|
||||
|
||||
if (matrix[0] != 1.f || matrix[1] != 0.f ||
|
||||
matrix[2] != 0.f || matrix[3] != 1.f)
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
arrayZ[i].transform (matrix);
|
||||
|
||||
if (trans.x != 0.f || trans.y != 0.f)
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
arrayZ[i].translate (trans);
|
||||
}
|
||||
|
||||
static inline void transform (float (&matrix)[4], contour_point_t &trans,
|
||||
float (other)[6])
|
||||
{
|
||||
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268
|
||||
float xx1 = other[0];
|
||||
float xy1 = other[1];
|
||||
float yx1 = other[2];
|
||||
float yy1 = other[3];
|
||||
float dx1 = other[4];
|
||||
float dy1 = other[5];
|
||||
float xx2 = matrix[0];
|
||||
float xy2 = matrix[1];
|
||||
float yx2 = matrix[2];
|
||||
float yy2 = matrix[3];
|
||||
float dx2 = trans.x;
|
||||
float dy2 = trans.y;
|
||||
|
||||
matrix[0] = xx1*xx2 + xy1*yx2;
|
||||
matrix[1] = xx1*xy2 + xy1*yy2;
|
||||
matrix[2] = yx1*xx2 + yy1*yx2;
|
||||
matrix[3] = yx1*xy2 + yy1*yy2;
|
||||
trans.x = xx2*dx1 + yx2*dy1 + dx2;
|
||||
trans.y = xy2*dx1 + yy2*dy1 + dy2;
|
||||
}
|
||||
|
||||
static void translate (float (&matrix)[4], contour_point_t &trans,
|
||||
float translateX, float translateY)
|
||||
{
|
||||
if (!translateX && !translateY)
|
||||
return;
|
||||
|
||||
trans.x += matrix[0] * translateX + matrix[2] * translateY;
|
||||
trans.y += matrix[1] * translateX + matrix[3] * translateY;
|
||||
}
|
||||
|
||||
static void scale (float (&matrix)[4], contour_point_t &trans,
|
||||
float scaleX, float scaleY)
|
||||
{
|
||||
if (scaleX == 1.f && scaleY == 1.f)
|
||||
return;
|
||||
|
||||
matrix[0] *= scaleX;
|
||||
matrix[1] *= scaleX;
|
||||
matrix[2] *= scaleY;
|
||||
matrix[3] *= scaleY;
|
||||
}
|
||||
|
||||
static void rotate (float (&matrix)[4], contour_point_t &trans,
|
||||
float rotation)
|
||||
{
|
||||
if (!rotation)
|
||||
return;
|
||||
|
||||
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
|
||||
rotation = rotation * HB_PI;
|
||||
float c;
|
||||
float s;
|
||||
#ifdef HAVE_SINCOSF
|
||||
sincosf (rotation, &s, &c);
|
||||
#else
|
||||
c = cosf (rotation);
|
||||
s = sinf (rotation);
|
||||
#endif
|
||||
float other[6] = {c, s, -s, c, 0.f, 0.f};
|
||||
transform (matrix, trans, other);
|
||||
}
|
||||
|
||||
static void skew (float (&matrix)[4], contour_point_t &trans,
|
||||
float skewX, float skewY)
|
||||
{
|
||||
if (!skewX && !skewY)
|
||||
return;
|
||||
|
||||
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
|
||||
skewX = skewX * HB_PI;
|
||||
skewY = skewY * HB_PI;
|
||||
float other[6] = {1.f,
|
||||
skewY ? tanf (skewY) : 0.f,
|
||||
skewX ? tanf (skewX) : 0.f,
|
||||
1.f,
|
||||
0.f, 0.f};
|
||||
transform (matrix, trans, other);
|
||||
}
|
||||
|
||||
bool get_points (contour_point_vector_t &points) const
|
||||
{
|
||||
unsigned num_points = get_num_points ();
|
||||
|
||||
points.alloc (points.length + num_points + 4); // For phantom points
|
||||
if (unlikely (!points.resize (points.length + num_points, false))) return false;
|
||||
contour_point_t *rec_points = points.arrayZ + (points.length - num_points);
|
||||
hb_memset (rec_points, 0, num_points * sizeof (rec_points[0]));
|
||||
|
||||
unsigned fl = flags;
|
||||
|
||||
unsigned num_axes = numAxes;
|
||||
unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
|
||||
unsigned axes_size = num_axes * axis_width;
|
||||
|
||||
const F2DOT14 *q = (const F2DOT14 *) (axes_size +
|
||||
(fl & GID_IS_24BIT ? 3 : 2) +
|
||||
(const HBUINT8 *) &pad);
|
||||
|
||||
unsigned count = num_axes;
|
||||
if (fl & AXES_HAVE_VARIATION)
|
||||
{
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
rec_points++->x = q++->to_int ();
|
||||
}
|
||||
else
|
||||
q += count;
|
||||
|
||||
const HBUINT16 *p = (const HBUINT16 *) q;
|
||||
|
||||
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
|
||||
{
|
||||
int translateX = (fl & HAVE_TRANSLATE_X) ? * (const FWORD *) p++ : 0;
|
||||
int translateY = (fl & HAVE_TRANSLATE_Y) ? * (const FWORD *) p++ : 0;
|
||||
rec_points->x = translateX;
|
||||
rec_points->y = translateY;
|
||||
rec_points++;
|
||||
}
|
||||
if (fl & HAVE_ROTATION)
|
||||
{
|
||||
int rotation = (fl & HAVE_ROTATION) ? ((const F4DOT12 *) p++)->to_int () : 0;
|
||||
rec_points->x = rotation;
|
||||
rec_points++;
|
||||
}
|
||||
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
|
||||
{
|
||||
int scaleX = (fl & HAVE_SCALE_X) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
|
||||
int scaleY = (fl & HAVE_SCALE_Y) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
|
||||
if ((fl & UNIFORM_SCALE) && !(fl & HAVE_SCALE_Y))
|
||||
scaleY = scaleX;
|
||||
rec_points->x = scaleX;
|
||||
rec_points->y = scaleY;
|
||||
rec_points++;
|
||||
}
|
||||
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
|
||||
{
|
||||
int skewX = (fl & HAVE_SKEW_X) ? ((const F4DOT12 *) p++)->to_int () : 0;
|
||||
int skewY = (fl & HAVE_SKEW_Y) ? ((const F4DOT12 *) p++)->to_int () : 0;
|
||||
rec_points->x = skewX;
|
||||
rec_points->y = skewY;
|
||||
rec_points++;
|
||||
}
|
||||
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
|
||||
{
|
||||
int tCenterX = (fl & HAVE_TCENTER_X) ? * (const FWORD *) p++ : 0;
|
||||
int tCenterY = (fl & HAVE_TCENTER_Y) ? * (const FWORD *) p++ : 0;
|
||||
rec_points->x = tCenterX;
|
||||
rec_points->y = tCenterY;
|
||||
rec_points++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void get_transformation_from_points (const contour_point_t *rec_points,
|
||||
float (&matrix)[4], contour_point_t &trans) const
|
||||
{
|
||||
unsigned fl = flags;
|
||||
|
||||
if (fl & AXES_HAVE_VARIATION)
|
||||
rec_points += numAxes;
|
||||
|
||||
matrix[0] = matrix[3] = 1.f;
|
||||
matrix[1] = matrix[2] = 0.f;
|
||||
trans.init (0.f, 0.f);
|
||||
|
||||
float translateX = 0.f;
|
||||
float translateY = 0.f;
|
||||
float rotation = 0.f;
|
||||
float scaleX = 1.f;
|
||||
float scaleY = 1.f;
|
||||
float skewX = 0.f;
|
||||
float skewY = 0.f;
|
||||
float tCenterX = 0.f;
|
||||
float tCenterY = 0.f;
|
||||
|
||||
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
|
||||
{
|
||||
translateX = rec_points->x;
|
||||
translateY = rec_points->y;
|
||||
rec_points++;
|
||||
}
|
||||
if (fl & HAVE_ROTATION)
|
||||
{
|
||||
rotation = rec_points->x / (1 << 12);
|
||||
rec_points++;
|
||||
}
|
||||
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
|
||||
{
|
||||
scaleX = rec_points->x / (1 << 10);
|
||||
scaleY = rec_points->y / (1 << 10);
|
||||
rec_points++;
|
||||
}
|
||||
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
|
||||
{
|
||||
skewX = rec_points->x / (1 << 12);
|
||||
skewY = rec_points->y / (1 << 12);
|
||||
rec_points++;
|
||||
}
|
||||
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
|
||||
{
|
||||
tCenterX = rec_points->x;
|
||||
tCenterY = rec_points->y;
|
||||
rec_points++;
|
||||
}
|
||||
|
||||
translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
|
||||
rotate (matrix, trans, rotation);
|
||||
scale (matrix, trans, scaleX, scaleY);
|
||||
skew (matrix, trans, -skewX, skewY);
|
||||
translate (matrix, trans, -tCenterX, -tCenterY);
|
||||
}
|
||||
|
||||
void set_variations (coord_setter_t &setter,
|
||||
hb_array_t<contour_point_t> rec_points) const
|
||||
{
|
||||
bool have_variations = flags & AXES_HAVE_VARIATION;
|
||||
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
|
||||
unsigned num_axes = numAxes;
|
||||
|
||||
const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
|
||||
const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
|
||||
|
||||
const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + num_axes) : (HBUINT8 *) (q + num_axes)));
|
||||
|
||||
unsigned count = num_axes;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
|
||||
|
||||
signed v = have_variations ? rec_points.arrayZ[i].x : a++->to_int ();
|
||||
|
||||
v = hb_clamp (v, -(1<<14), (1<<14));
|
||||
setter[axis_index] = v;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 flags;
|
||||
HBUINT8 numAxes;
|
||||
HBUINT16 pad;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (5);
|
||||
};
|
||||
|
||||
using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>;
|
||||
|
||||
struct VarCompositeGlyph
|
||||
{
|
||||
const GlyphHeader &header;
|
||||
hb_bytes_t bytes;
|
||||
VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
|
||||
header (header_), bytes (bytes_) {}
|
||||
|
||||
var_composite_iter_t iter () const
|
||||
{ return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
|
||||
|
||||
const hb_bytes_t trim_padding () const
|
||||
{
|
||||
unsigned length = GlyphHeader::static_size;
|
||||
for (auto &comp : iter ())
|
||||
length += comp.get_size ();
|
||||
return bytes.sub_array (0, length);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} /* namespace glyf_impl */
|
||||
} /* namespace OT */
|
||||
|
||||
|
||||
#endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */
|
||||
@ -1,36 +0,0 @@
|
||||
#ifndef OT_GLYF_COORD_SETTER_HH
|
||||
#define OT_GLYF_COORD_SETTER_HH
|
||||
|
||||
|
||||
#include "../../hb.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
namespace glyf_impl {
|
||||
|
||||
|
||||
struct coord_setter_t
|
||||
{
|
||||
coord_setter_t (hb_array_t<int> coords) :
|
||||
coords (coords) {}
|
||||
|
||||
int& operator [] (unsigned idx)
|
||||
{
|
||||
if (unlikely (idx >= HB_GLYF_VAR_COMPOSITE_MAX_AXES))
|
||||
return Crap(int);
|
||||
if (coords.length < idx + 1)
|
||||
coords.resize (idx + 1);
|
||||
return coords[idx];
|
||||
}
|
||||
|
||||
hb_array_t<int> get_coords ()
|
||||
{ return coords.as_array (); }
|
||||
|
||||
hb_vector_t<int> coords;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace glyf_impl */
|
||||
} /* namespace OT */
|
||||
|
||||
#endif /* OT_GLYF_COORD_SETTER_HH */
|
||||
@ -38,7 +38,7 @@ _write_loca (IteratorIn&& it,
|
||||
|
||||
unsigned padded_size = *it++;
|
||||
offset += padded_size;
|
||||
DEBUG_MSG (SUBSET, nullptr, "loca entry gid %u offset %u padded-size %u", gid, offset, padded_size);
|
||||
DEBUG_MSG (SUBSET, nullptr, "loca entry gid %" PRIu32 " offset %u padded-size %u", gid, offset, padded_size);
|
||||
value = offset >> right_shift;
|
||||
*dest++ = value;
|
||||
|
||||
|
||||
@ -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 ();
|
||||
}
|
||||
|
||||
@ -205,18 +218,17 @@ struct glyf_accelerator_t
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
|
||||
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
|
||||
hb_array_t<const int> coords,
|
||||
hb_glyf_scratch_t &scratch) const
|
||||
{
|
||||
if (gid >= num_glyphs) return false;
|
||||
|
||||
/* Making this allocfree is not that easy
|
||||
https://github.com/harfbuzz/harfbuzz/issues/2095
|
||||
mostly because of gvar handling in VF fonts,
|
||||
perhaps a separate path for non-VF fonts can be considered */
|
||||
contour_point_vector_t all_points;
|
||||
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)))
|
||||
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;
|
||||
@ -225,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 ();
|
||||
}
|
||||
|
||||
@ -299,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; }
|
||||
@ -314,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
|
||||
@ -334,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
|
||||
@ -362,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
|
||||
{
|
||||
@ -406,10 +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,
|
||||
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
|
||||
@ -421,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;
|
||||
};
|
||||
|
||||
|
||||
@ -430,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)
|
||||
{
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -242,7 +242,9 @@ struct NameRecord
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
offset.sanitize (c, base, length));
|
||||
}
|
||||
|
||||
HBUINT16 platformID; /* Platform ID. */
|
||||
@ -465,6 +467,7 @@ struct name
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
likely (format == 0 || format == 1) &&
|
||||
c->check_array (nameRecordZ.arrayZ, count) &&
|
||||
c->check_range (this, stringOffset) &&
|
||||
@ -482,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++)
|
||||
{
|
||||
|
||||
@ -53,9 +53,9 @@ STEP 2: BUILD CHANGES INCREMENTALLY
|
||||
|
||||
STEP 3: COMPILER WARNINGS AND SETTING FLAGS
|
||||
-------------------------------------------
|
||||
- Update make parameters in Awt2DLibraries.gmk
|
||||
- Update make parameters in make/modules/java.desktop/lib/ClientLibraries.gmk
|
||||
Since we don't use configure we need to manually specify the options
|
||||
we need in the Harfbuzz section of Awt2DLibraries.gmk.
|
||||
we need in the Harfbuzz section of ClientLibraries.gmk.
|
||||
As well as adding new options, we may need to clean up obsolete options.
|
||||
Note there may be platform variations in the flags.
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ struct ClassDefFormat1 : public OT::ClassDefFormat1_3<SmallTypes>
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::min_size;
|
||||
if (vertex_len < min_size) return false;
|
||||
hb_barrier ();
|
||||
return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size ();
|
||||
}
|
||||
};
|
||||
@ -50,6 +51,7 @@ struct ClassDefFormat2 : public OT::ClassDefFormat2_4<SmallTypes>
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size;
|
||||
if (vertex_len < min_size) return false;
|
||||
hb_barrier ();
|
||||
return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
|
||||
}
|
||||
};
|
||||
@ -114,6 +116,7 @@ struct ClassDef : public OT::ClassDef
|
||||
{
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
if (vertex_len < OT::ClassDef::min_size) return false;
|
||||
hb_barrier ();
|
||||
switch (u.format)
|
||||
{
|
||||
case 1: return ((ClassDefFormat1*)this)->sanitize (vertex);
|
||||
@ -131,20 +134,23 @@ struct ClassDef : public OT::ClassDef
|
||||
|
||||
struct class_def_size_estimator_t
|
||||
{
|
||||
// TODO(garretrieger): update to support beyond64k coverage/classdef tables.
|
||||
constexpr static unsigned class_def_format1_base_size = 6;
|
||||
constexpr static unsigned class_def_format2_base_size = 4;
|
||||
constexpr static unsigned coverage_base_size = 4;
|
||||
constexpr static unsigned bytes_per_range = 6;
|
||||
constexpr static unsigned bytes_per_glyph = 2;
|
||||
|
||||
template<typename It>
|
||||
class_def_size_estimator_t (It glyph_and_class)
|
||||
: gids_consecutive (true), num_ranges_per_class (), glyphs_per_class ()
|
||||
: num_ranges_per_class (), glyphs_per_class ()
|
||||
{
|
||||
unsigned last_gid = (unsigned) -1;
|
||||
reset();
|
||||
for (auto p : + glyph_and_class)
|
||||
{
|
||||
unsigned gid = p.first;
|
||||
unsigned klass = p.second;
|
||||
|
||||
if (last_gid != (unsigned) -1 && gid != last_gid + 1)
|
||||
gids_consecutive = false;
|
||||
last_gid = gid;
|
||||
|
||||
hb_set_t* glyphs;
|
||||
if (glyphs_per_class.has (klass, &glyphs) && glyphs) {
|
||||
glyphs->add (gid);
|
||||
@ -174,28 +180,54 @@ struct class_def_size_estimator_t
|
||||
}
|
||||
}
|
||||
|
||||
// Incremental increase in the Coverage and ClassDef table size
|
||||
// (worst case) if all glyphs associated with 'klass' were added.
|
||||
unsigned incremental_coverage_size (unsigned klass) const
|
||||
{
|
||||
// Coverage takes 2 bytes per glyph worst case,
|
||||
return 2 * glyphs_per_class.get (klass).get_population ();
|
||||
void reset() {
|
||||
class_def_1_size = class_def_format1_base_size;
|
||||
class_def_2_size = class_def_format2_base_size;
|
||||
included_glyphs.clear();
|
||||
included_classes.clear();
|
||||
}
|
||||
|
||||
// Incremental increase in the Coverage and ClassDef table size
|
||||
// (worst case) if all glyphs associated with 'klass' were added.
|
||||
unsigned incremental_class_def_size (unsigned klass) const
|
||||
// Compute the size of coverage for all glyphs added via 'add_class_def_size'.
|
||||
unsigned coverage_size () const
|
||||
{
|
||||
// ClassDef takes 6 bytes per range
|
||||
unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass);
|
||||
if (gids_consecutive)
|
||||
{
|
||||
// ClassDef1 takes 2 bytes per glyph, but only can be used
|
||||
// when gids are consecutive.
|
||||
return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size);
|
||||
unsigned format1_size = coverage_base_size + bytes_per_glyph * included_glyphs.get_population();
|
||||
unsigned format2_size = coverage_base_size + bytes_per_range * num_glyph_ranges();
|
||||
return hb_min(format1_size, format2_size);
|
||||
}
|
||||
|
||||
// Compute the new size of the ClassDef table if all glyphs associated with 'klass' were added.
|
||||
unsigned add_class_def_size (unsigned klass)
|
||||
{
|
||||
if (!included_classes.has(klass)) {
|
||||
hb_set_t* glyphs = nullptr;
|
||||
if (glyphs_per_class.has(klass, &glyphs)) {
|
||||
included_glyphs.union_(*glyphs);
|
||||
}
|
||||
|
||||
class_def_1_size = class_def_format1_base_size;
|
||||
if (!included_glyphs.is_empty()) {
|
||||
unsigned min_glyph = included_glyphs.get_min();
|
||||
unsigned max_glyph = included_glyphs.get_max();
|
||||
class_def_1_size += bytes_per_glyph * (max_glyph - min_glyph + 1);
|
||||
}
|
||||
|
||||
class_def_2_size += bytes_per_range * num_ranges_per_class.get (klass);
|
||||
|
||||
included_classes.add(klass);
|
||||
}
|
||||
|
||||
return class_def_2_size;
|
||||
return hb_min (class_def_1_size, class_def_2_size);
|
||||
}
|
||||
|
||||
unsigned num_glyph_ranges() const {
|
||||
hb_codepoint_t start = HB_SET_VALUE_INVALID;
|
||||
hb_codepoint_t end = HB_SET_VALUE_INVALID;
|
||||
|
||||
unsigned count = 0;
|
||||
while (included_glyphs.next_range (&start, &end)) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool in_error ()
|
||||
@ -211,9 +243,12 @@ struct class_def_size_estimator_t
|
||||
}
|
||||
|
||||
private:
|
||||
bool gids_consecutive;
|
||||
hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
|
||||
hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class;
|
||||
hb_set_t included_classes;
|
||||
hb_set_t included_glyphs;
|
||||
unsigned class_def_1_size;
|
||||
unsigned class_def_2_size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3<SmallTypes
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size;
|
||||
if (vertex_len < min_size) return false;
|
||||
hb_barrier ();
|
||||
return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
|
||||
}
|
||||
};
|
||||
@ -50,6 +51,7 @@ struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
|
||||
if (vertex_len < min_size) return false;
|
||||
hb_barrier ();
|
||||
return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
|
||||
}
|
||||
};
|
||||
@ -138,6 +140,7 @@ struct Coverage : public OT::Layout::Common::Coverage
|
||||
{
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
|
||||
hb_barrier ();
|
||||
switch (u.format)
|
||||
{
|
||||
case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
|
||||
|
||||
@ -195,6 +195,15 @@ struct graph_t
|
||||
return incoming_edges_;
|
||||
}
|
||||
|
||||
unsigned incoming_edges_from_parent (unsigned parent_index) const {
|
||||
if (single_parent != (unsigned) -1) {
|
||||
return single_parent == parent_index ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned* count;
|
||||
return parents.has(parent_index, &count) ? *count : 0;
|
||||
}
|
||||
|
||||
void reset_parents ()
|
||||
{
|
||||
incoming_edges_ = 0;
|
||||
@ -334,6 +343,16 @@ struct graph_t
|
||||
return true;
|
||||
}
|
||||
|
||||
bool give_max_priority ()
|
||||
{
|
||||
bool result = false;
|
||||
while (!has_max_priority()) {
|
||||
result = true;
|
||||
priority++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool has_max_priority () const {
|
||||
return priority >= 3;
|
||||
}
|
||||
@ -349,7 +368,7 @@ struct graph_t
|
||||
// it's parent where possible.
|
||||
|
||||
int64_t modified_distance =
|
||||
hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF);
|
||||
hb_clamp (distance + distance_modifier (), (int64_t) 0, 0x7FFFFFFFFFF);
|
||||
if (has_max_priority ()) {
|
||||
modified_distance = 0;
|
||||
}
|
||||
@ -567,6 +586,7 @@ struct graph_t
|
||||
update_distances ();
|
||||
|
||||
hb_priority_queue_t<int64_t> queue;
|
||||
queue.alloc (vertices_.length);
|
||||
hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
|
||||
if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
|
||||
hb_vector_t<unsigned> id_map;
|
||||
@ -1022,6 +1042,11 @@ struct graph_t
|
||||
* Creates a copy of child and re-assigns the link from
|
||||
* parent to the clone. The copy is a shallow copy, objects
|
||||
* linked from child are not duplicated.
|
||||
*
|
||||
* Returns the index of the newly created duplicate.
|
||||
*
|
||||
* If the child_idx only has incoming edges from parent_idx, this
|
||||
* will do nothing and return the original child_idx.
|
||||
*/
|
||||
unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
|
||||
{
|
||||
@ -1035,18 +1060,20 @@ struct graph_t
|
||||
* Creates a copy of child and re-assigns the link from
|
||||
* parent to the clone. The copy is a shallow copy, objects
|
||||
* linked from child are not duplicated.
|
||||
*
|
||||
* Returns the index of the newly created duplicate.
|
||||
*
|
||||
* If the child_idx only has incoming edges from parent_idx,
|
||||
* duplication isn't possible and this will return -1.
|
||||
*/
|
||||
unsigned duplicate (unsigned parent_idx, unsigned child_idx)
|
||||
{
|
||||
update_parents ();
|
||||
|
||||
unsigned links_to_child = 0;
|
||||
for (const auto& l : vertices_[parent_idx].obj.all_links ())
|
||||
{
|
||||
if (l.objidx == child_idx) links_to_child++;
|
||||
}
|
||||
const auto& child = vertices_[child_idx];
|
||||
unsigned links_to_child = child.incoming_edges_from_parent(parent_idx);
|
||||
|
||||
if (vertices_[child_idx].incoming_edges () <= links_to_child)
|
||||
if (child.incoming_edges () <= links_to_child)
|
||||
{
|
||||
// Can't duplicate this node, doing so would orphan the original one as all remaining links
|
||||
// to child are from parent.
|
||||
@ -1059,7 +1086,7 @@ struct graph_t
|
||||
parent_idx, child_idx);
|
||||
|
||||
unsigned clone_idx = duplicate (child_idx);
|
||||
if (clone_idx == (unsigned) -1) return false;
|
||||
if (clone_idx == (unsigned) -1) return -1;
|
||||
// duplicate shifts the root node idx, so if parent_idx was root update it.
|
||||
if (parent_idx == clone_idx) parent_idx++;
|
||||
|
||||
@ -1075,6 +1102,62 @@ struct graph_t
|
||||
return clone_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a copy of child and re-assigns the links from
|
||||
* parents to the clone. The copy is a shallow copy, objects
|
||||
* linked from child are not duplicated.
|
||||
*
|
||||
* Returns the index of the newly created duplicate.
|
||||
*
|
||||
* If the child_idx only has incoming edges from parents,
|
||||
* duplication isn't possible or duplication fails and this will
|
||||
* return -1.
|
||||
*/
|
||||
unsigned duplicate (const hb_set_t* parents, unsigned child_idx)
|
||||
{
|
||||
if (parents->is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
update_parents ();
|
||||
|
||||
const auto& child = vertices_[child_idx];
|
||||
unsigned links_to_child = 0;
|
||||
unsigned last_parent = parents->get_max();
|
||||
unsigned first_parent = parents->get_min();
|
||||
for (unsigned parent_idx : *parents) {
|
||||
links_to_child += child.incoming_edges_from_parent(parent_idx);
|
||||
}
|
||||
|
||||
if (child.incoming_edges () <= links_to_child)
|
||||
{
|
||||
// Can't duplicate this node, doing so would orphan the original one as all remaining links
|
||||
// to child are from parent.
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
|
||||
|
||||
unsigned clone_idx = duplicate (child_idx);
|
||||
if (clone_idx == (unsigned) -1) return false;
|
||||
|
||||
for (unsigned parent_idx : *parents) {
|
||||
// duplicate shifts the root node idx, so if parent_idx was root update it.
|
||||
if (parent_idx == clone_idx) parent_idx++;
|
||||
auto& parent = vertices_[parent_idx];
|
||||
for (auto& l : parent.obj.all_links_writer ())
|
||||
{
|
||||
if (l.objidx != child_idx)
|
||||
continue;
|
||||
|
||||
reassign_link (l, parent_idx, clone_idx);
|
||||
}
|
||||
}
|
||||
|
||||
return clone_idx;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adds a new node to the graph, not connected to anything.
|
||||
@ -1370,6 +1453,7 @@ struct graph_t
|
||||
vertices_.tail ().distance = 0;
|
||||
|
||||
hb_priority_queue_t<int64_t> queue;
|
||||
queue.alloc (count);
|
||||
queue.insert (0, vertices_.length - 1);
|
||||
|
||||
hb_vector_t<bool> visited;
|
||||
|
||||
@ -76,6 +76,7 @@ struct Lookup : public OT::Lookup
|
||||
{
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
if (vertex_len < OT::Lookup::min_size) return false;
|
||||
hb_barrier ();
|
||||
return vertex_len >= this->get_size ();
|
||||
}
|
||||
|
||||
@ -351,6 +352,7 @@ struct LookupList : public OT::LookupList<T>
|
||||
{
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
if (vertex_len < OT::LookupList<T>::min_size) return false;
|
||||
hb_barrier ();
|
||||
return vertex_len >= OT::LookupList<T>::item_size * this->len;
|
||||
}
|
||||
};
|
||||
@ -364,6 +366,7 @@ struct GSTAR : public OT::GSUBGPOS
|
||||
GSTAR* gstar = (GSTAR*) r.obj.head;
|
||||
if (!gstar || !gstar->sanitize (r))
|
||||
return nullptr;
|
||||
hb_barrier ();
|
||||
|
||||
return gstar;
|
||||
}
|
||||
@ -383,6 +386,7 @@ struct GSTAR : public OT::GSUBGPOS
|
||||
{
|
||||
int64_t len = vertex.obj.tail - vertex.obj.head;
|
||||
if (len < OT::GSUBGPOS::min_size) return false;
|
||||
hb_barrier ();
|
||||
return len >= get_size ();
|
||||
}
|
||||
|
||||
|
||||
@ -40,6 +40,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix
|
||||
{
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
if (vertex_len < AnchorMatrix::min_size) return false;
|
||||
hb_barrier ();
|
||||
|
||||
return vertex_len >= AnchorMatrix::min_size +
|
||||
OT::Offset16::static_size * class_count * this->rows;
|
||||
@ -128,6 +129,7 @@ struct MarkArray : public OT::Layout::GPOS_impl::MarkArray
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
unsigned min_size = MarkArray::min_size;
|
||||
if (vertex_len < min_size) return false;
|
||||
hb_barrier ();
|
||||
|
||||
return vertex_len >= get_size ();
|
||||
}
|
||||
@ -495,6 +497,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
|
||||
{
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
if (vertex_len < u.format.get_size ()) return false;
|
||||
hb_barrier ();
|
||||
|
||||
switch (u.format) {
|
||||
case 1:
|
||||
|
||||
@ -42,6 +42,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
|
||||
if (vertex_len < min_size) return false;
|
||||
hb_barrier ();
|
||||
|
||||
return vertex_len >=
|
||||
min_size + pairSet.get_size () - pairSet.len.get_size();
|
||||
@ -198,6 +199,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
|
||||
size_t vertex_len = vertex.table_size ();
|
||||
unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
|
||||
if (vertex_len < min_size) return false;
|
||||
hb_barrier ();
|
||||
|
||||
const unsigned class1_count = class1Count;
|
||||
return vertex_len >=
|
||||
@ -245,8 +247,8 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
|
||||
for (unsigned i = 0; i < class1_count; i++)
|
||||
{
|
||||
unsigned accumulated_delta = class1_record_size;
|
||||
coverage_size += estimator.incremental_coverage_size (i);
|
||||
class_def_1_size += estimator.incremental_class_def_size (i);
|
||||
class_def_1_size = estimator.add_class_def_size (i);
|
||||
coverage_size = estimator.coverage_size ();
|
||||
max_coverage_size = hb_max (max_coverage_size, coverage_size);
|
||||
max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
|
||||
|
||||
@ -278,8 +280,10 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
|
||||
split_points.push (i);
|
||||
// split does not include i, so add the size for i when we reset the size counters.
|
||||
accumulated = base_size + accumulated_delta;
|
||||
coverage_size = 4 + estimator.incremental_coverage_size (i);
|
||||
class_def_1_size = 4 + estimator.incremental_class_def_size (i);
|
||||
|
||||
estimator.reset();
|
||||
class_def_1_size = estimator.add_class_def_size(i);
|
||||
coverage_size = estimator.coverage_size();
|
||||
visited.clear (); // node sharing isn't allowed between splits.
|
||||
}
|
||||
}
|
||||
@ -625,6 +629,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos
|
||||
{
|
||||
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
||||
if (vertex_len < u.format.get_size ()) return false;
|
||||
hb_barrier ();
|
||||
|
||||
switch (u.format) {
|
||||
case 1:
|
||||
|
||||
@ -75,6 +75,7 @@ struct ankr
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
version == 0 &&
|
||||
c->check_range (this, anchorData) &&
|
||||
lookupTable.sanitize (c, this, &(this+anchorData))));
|
||||
|
||||
@ -123,6 +123,7 @@ struct bsln
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!(c->check_struct (this) && defaultBaseline < 32)))
|
||||
return_trace (false);
|
||||
hb_barrier ();
|
||||
|
||||
switch (format)
|
||||
{
|
||||
|
||||
@ -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,15 +43,18 @@ namespace AAT {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
|
||||
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>
|
||||
{
|
||||
const char *get_name () { return "APPLY"; }
|
||||
template <typename T>
|
||||
return_t dispatch (const T &obj) { return obj.apply (this); }
|
||||
template <typename T, typename ...Ts>
|
||||
return_t dispatch (const T &obj, Ts&&... ds)
|
||||
{ return obj.apply (this, std::forward<Ts> (ds)...); }
|
||||
static return_t default_return_value () { return false; }
|
||||
bool stop_sublookup_iteration (return_t r) const { return r; }
|
||||
|
||||
@ -59,6 +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;
|
||||
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. */
|
||||
@ -74,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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -81,6 +113,8 @@ struct hb_aat_apply_context_t :
|
||||
* Lookup Table
|
||||
*/
|
||||
|
||||
enum { DELETED_GLYPH = 0xFFFF };
|
||||
|
||||
template <typename T> struct Lookup;
|
||||
|
||||
template <typename T>
|
||||
@ -95,6 +129,19 @@ struct LookupFormat0
|
||||
return &arrayZ[glyph_id];
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
|
||||
{
|
||||
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
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -123,6 +170,19 @@ struct LookupSegmentSingle
|
||||
int cmp (hb_codepoint_t g) const
|
||||
{ return g < first ? -1 : g <= last ? 0 : +1 ; }
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -153,6 +213,21 @@ struct LookupFormat2
|
||||
return v ? &v->value : nullptr;
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs) const
|
||||
{
|
||||
unsigned count = segments.get_length ();
|
||||
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
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -184,6 +259,21 @@ struct LookupSegmentArray
|
||||
return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs) const
|
||||
{
|
||||
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; }
|
||||
|
||||
@ -191,6 +281,7 @@ struct LookupSegmentArray
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
first <= last &&
|
||||
valuesZ.sanitize (c, base, last - first + 1));
|
||||
}
|
||||
@ -199,6 +290,7 @@ struct LookupSegmentArray
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
first <= last &&
|
||||
valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...));
|
||||
}
|
||||
@ -224,6 +316,21 @@ struct LookupFormat4
|
||||
return v ? v->get_value (glyph_id, this) : nullptr;
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs) const
|
||||
{
|
||||
unsigned count = segments.get_length ();
|
||||
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
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -252,6 +359,19 @@ struct LookupSingle
|
||||
|
||||
int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -281,6 +401,21 @@ struct LookupFormat6
|
||||
return v ? &v->value : nullptr;
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs) const
|
||||
{
|
||||
unsigned count = entries.get_length ();
|
||||
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
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -312,6 +447,24 @@ struct LookupFormat8
|
||||
&valueArrayZ[glyph_id - firstGlyph] : nullptr;
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs) const
|
||||
{
|
||||
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
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -356,10 +509,19 @@ struct LookupFormat10
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs) const
|
||||
{
|
||||
if (unlikely (!glyphCount)) return;
|
||||
if (firstGlyph == DELETED_GLYPH) return;
|
||||
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
valueSize <= 4 &&
|
||||
valueArrayZ.sanitize (c, glyphCount * valueSize));
|
||||
}
|
||||
@ -383,11 +545,11 @@ struct Lookup
|
||||
const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 0: return u.format0.get_value (glyph_id, num_glyphs);
|
||||
case 2: return u.format2.get_value (glyph_id);
|
||||
case 4: return u.format4.get_value (glyph_id);
|
||||
case 6: return u.format6.get_value (glyph_id);
|
||||
case 8: return u.format8.get_value (glyph_id);
|
||||
case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs);
|
||||
case 2: hb_barrier (); return u.format2.get_value (glyph_id);
|
||||
case 4: hb_barrier (); return u.format4.get_value (glyph_id);
|
||||
case 6: hb_barrier (); return u.format6.get_value (glyph_id);
|
||||
case 8: hb_barrier (); return u.format8.get_value (glyph_id);
|
||||
default:return nullptr;
|
||||
}
|
||||
}
|
||||
@ -396,13 +558,39 @@ struct Lookup
|
||||
{
|
||||
switch (u.format) {
|
||||
/* Format 10 cannot return a pointer. */
|
||||
case 10: return u.format10.get_value_or_null (glyph_id);
|
||||
case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id);
|
||||
default:
|
||||
const T *v = get_value (glyph_id, num_glyphs);
|
||||
return v ? *v : Null (T);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return;
|
||||
case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return;
|
||||
case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return;
|
||||
case 6: hb_barrier (); u.format6.collect_glyphs (glyphs); return;
|
||||
case 8: hb_barrier (); u.format8.collect_glyphs (glyphs); return;
|
||||
case 10: hb_barrier (); u.format10.collect_glyphs (glyphs); return;
|
||||
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,
|
||||
unsigned int outOfRange) const
|
||||
@ -415,13 +603,14 @@ struct Lookup
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.format.sanitize (c)) return_trace (false);
|
||||
hb_barrier ();
|
||||
switch (u.format) {
|
||||
case 0: return_trace (u.format0.sanitize (c));
|
||||
case 2: return_trace (u.format2.sanitize (c));
|
||||
case 4: return_trace (u.format4.sanitize (c));
|
||||
case 6: return_trace (u.format6.sanitize (c));
|
||||
case 8: return_trace (u.format8.sanitize (c));
|
||||
case 10: return_trace (u.format10.sanitize (c));
|
||||
case 0: hb_barrier (); return_trace (u.format0.sanitize (c));
|
||||
case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
|
||||
case 4: hb_barrier (); return_trace (u.format4.sanitize (c));
|
||||
case 6: hb_barrier (); return_trace (u.format6.sanitize (c));
|
||||
case 8: hb_barrier (); return_trace (u.format8.sanitize (c));
|
||||
case 10: hb_barrier (); return_trace (u.format10.sanitize (c));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
@ -429,12 +618,13 @@ struct Lookup
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.format.sanitize (c)) return_trace (false);
|
||||
hb_barrier ();
|
||||
switch (u.format) {
|
||||
case 0: return_trace (u.format0.sanitize (c, base));
|
||||
case 2: return_trace (u.format2.sanitize (c, base));
|
||||
case 4: return_trace (u.format4.sanitize (c, base));
|
||||
case 6: return_trace (u.format6.sanitize (c, base));
|
||||
case 8: return_trace (u.format8.sanitize (c, base));
|
||||
case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base));
|
||||
case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base));
|
||||
case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base));
|
||||
case 6: hb_barrier (); return_trace (u.format6.sanitize (c, base));
|
||||
case 8: hb_barrier (); return_trace (u.format8.sanitize (c, base));
|
||||
case 10: return_trace (false); /* We don't support format10 here currently. */
|
||||
default:return_trace (true);
|
||||
}
|
||||
@ -455,8 +645,6 @@ struct Lookup
|
||||
};
|
||||
DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
|
||||
|
||||
enum { DELETED_GLYPH = 0xFFFF };
|
||||
|
||||
/*
|
||||
* (Extended) State Table
|
||||
*/
|
||||
@ -464,7 +652,7 @@ enum { DELETED_GLYPH = 0xFFFF };
|
||||
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);
|
||||
@ -507,6 +695,14 @@ struct Entry<void>
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
enum Class
|
||||
{
|
||||
CLASS_END_OF_TEXT = 0,
|
||||
CLASS_OUT_OF_BOUNDS = 1,
|
||||
CLASS_DELETED_GLYPH = 2,
|
||||
CLASS_END_OF_LINE = 3,
|
||||
};
|
||||
|
||||
template <typename Types, typename Extra>
|
||||
struct StateTable
|
||||
{
|
||||
@ -519,21 +715,53 @@ struct StateTable
|
||||
STATE_START_OF_TEXT = 0,
|
||||
STATE_START_OF_LINE = 1,
|
||||
};
|
||||
enum Class
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
|
||||
{
|
||||
CLASS_END_OF_TEXT = 0,
|
||||
CLASS_OUT_OF_BOUNDS = 1,
|
||||
CLASS_DELETED_GLYPH = 2,
|
||||
CLASS_END_OF_LINE = 3,
|
||||
};
|
||||
(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; }
|
||||
|
||||
unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
|
||||
unsigned int get_class (hb_codepoint_t glyph_id,
|
||||
unsigned int num_glyphs,
|
||||
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;
|
||||
return (this+classTable).get_class (glyph_id, num_glyphs, 1);
|
||||
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
|
||||
@ -541,13 +769,14 @@ struct StateTable
|
||||
|
||||
const Entry<Extra> &get_entry (int state, unsigned int klass) const
|
||||
{
|
||||
if (unlikely (klass >= nClasses))
|
||||
klass = StateTable::CLASS_OUT_OF_BOUNDS;
|
||||
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];
|
||||
@ -558,6 +787,7 @@ struct StateTable
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!(c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
|
||||
classTable.sanitize (c, this)))) return_trace (false);
|
||||
|
||||
@ -684,6 +914,22 @@ struct ClassTable
|
||||
{
|
||||
return get_class (glyph_id, outOfRange);
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
|
||||
{
|
||||
for (unsigned i = 0; i < classArray.len; i++)
|
||||
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
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -697,6 +943,38 @@ struct ClassTable
|
||||
DEFINE_SIZE_ARRAY (4, classArray);
|
||||
};
|
||||
|
||||
struct SubtableGlyphCoverage
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned subtable_count) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
if (unlikely (!c->check_array (&subtableOffsets, subtable_count)))
|
||||
return_trace (false);
|
||||
|
||||
unsigned bytes = (c->get_num_glyphs () + CHAR_BIT - 1) / CHAR_BIT;
|
||||
for (unsigned i = 0; i < subtable_count; i++)
|
||||
{
|
||||
uint32_t offset = (uint32_t) subtableOffsets[i];
|
||||
if (offset == 0 || offset == 0xFFFFFFFF)
|
||||
continue;
|
||||
if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes)))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
protected:
|
||||
UnsizedArrayOf<NNOffset32To<UnsizedArrayOf<HBUINT8>>> subtableOffsets;
|
||||
/* Array of offsets from the beginning of the
|
||||
* subtable glyph coverage table to the glyph
|
||||
* coverage bitfield for a given subtable; there
|
||||
* is one offset for each subtable in the chain */
|
||||
/* UnsizedArrayOf<HBUINT8> coverageBitfields; *//* The individual coverage bitfields. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (0, subtableOffsets);
|
||||
};
|
||||
|
||||
struct ObsoleteTypes
|
||||
{
|
||||
static constexpr bool extended = false;
|
||||
@ -766,22 +1044,22 @@ struct ExtendedTypes
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Types, typename EntryData>
|
||||
template <typename Types, typename EntryData, typename Flags>
|
||||
struct StateTableDriver
|
||||
{
|
||||
using StateTableT = StateTable<Types, EntryData>;
|
||||
using EntryT = Entry<EntryData>;
|
||||
|
||||
StateTableDriver (const StateTableT &machine_,
|
||||
hb_buffer_t *buffer_,
|
||||
hb_face_t *face_) :
|
||||
machine (machine_),
|
||||
buffer (buffer_),
|
||||
num_glyphs (face_->get_num_glyphs ()) {}
|
||||
|
||||
template <typename context_t>
|
||||
void drive (context_t *c, hb_aat_apply_context_t *ac)
|
||||
{
|
||||
hb_buffer_t *buffer = ac->buffer;
|
||||
|
||||
if (!c->in_place)
|
||||
buffer->clear_output ();
|
||||
|
||||
@ -816,9 +1094,9 @@ struct StateTableDriver
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int klass = buffer->idx < buffer->len ?
|
||||
machine.get_class (buffer->cur().codepoint, num_glyphs) :
|
||||
(unsigned) StateTableT::CLASS_END_OF_TEXT;
|
||||
unsigned int klass = likely (buffer->idx < buffer->len) ?
|
||||
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);
|
||||
const int next_state = machine.new_state (entry.newState);
|
||||
@ -851,44 +1129,39 @@ 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 (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 (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 (this, machine.get_entry (state, StateTableT::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 (this, entry);
|
||||
c->transition (buffer, this, entry);
|
||||
|
||||
state = next_state;
|
||||
DEBUG_MSG (APPLY, nullptr, "s%d", state);
|
||||
@ -896,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 ();
|
||||
}
|
||||
|
||||
@ -906,7 +1179,6 @@ struct StateTableDriver
|
||||
|
||||
public:
|
||||
const StateTableT &machine;
|
||||
hb_buffer_t *buffer;
|
||||
unsigned int num_glyphs;
|
||||
};
|
||||
|
||||
|
||||
@ -138,6 +138,7 @@ struct FeatureName
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
(base+settingTableZ).sanitize (c, nSettings)));
|
||||
}
|
||||
|
||||
@ -200,6 +201,7 @@ struct feat
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
version.major == 1 &&
|
||||
namesZ.sanitize (c, featureNameCount, this)));
|
||||
}
|
||||
|
||||
@ -185,15 +185,16 @@ struct ActionSubrecord
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
hb_barrier ();
|
||||
|
||||
switch (u.header.actionType)
|
||||
{
|
||||
case 0: return_trace (u.decompositionAction.sanitize (c));
|
||||
case 1: return_trace (u.unconditionalAddGlyphAction.sanitize (c));
|
||||
case 2: return_trace (u.conditionalAddGlyphAction.sanitize (c));
|
||||
// case 3: return_trace (u.stretchGlyphAction.sanitize (c));
|
||||
case 4: return_trace (u.decompositionAction.sanitize (c));
|
||||
case 5: return_trace (u.decompositionAction.sanitize (c));
|
||||
case 0: hb_barrier (); return_trace (u.decompositionAction.sanitize (c));
|
||||
case 1: hb_barrier (); return_trace (u.unconditionalAddGlyphAction.sanitize (c));
|
||||
case 2: hb_barrier (); return_trace (u.conditionalAddGlyphAction.sanitize (c));
|
||||
// case 3: hb_barrier (); return_trace (u.stretchGlyphAction.sanitize (c));
|
||||
case 4: hb_barrier (); return_trace (u.decompositionAction.sanitize (c));
|
||||
case 5: hb_barrier (); return_trace (u.decompositionAction.sanitize (c));
|
||||
default: return_trace (true);
|
||||
}
|
||||
}
|
||||
@ -220,6 +221,7 @@ struct PostcompensationActionChain
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
hb_barrier ();
|
||||
|
||||
unsigned int offset = min_size;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
@ -389,6 +391,7 @@ struct just
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
version.major == 1 &&
|
||||
horizData.sanitize (c, this, this) &&
|
||||
vertData.sanitize (c, this, this)));
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
|
||||
#include "hb-kern.hh"
|
||||
#include "hb-aat-layout-ankr-table.hh"
|
||||
#include "hb-set-digest.hh"
|
||||
|
||||
/*
|
||||
* kerx -- Extended Kerning
|
||||
@ -54,6 +55,7 @@ kerxTupleKern (int value,
|
||||
unsigned int offset = value;
|
||||
const FWORD *pv = &StructAtOffset<FWORD> (base, offset);
|
||||
if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0;
|
||||
hb_barrier ();
|
||||
return *pv;
|
||||
}
|
||||
|
||||
@ -81,7 +83,7 @@ struct KernPair
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
protected:
|
||||
public:
|
||||
HBGlyphID16 left;
|
||||
HBGlyphID16 right;
|
||||
FWORD value;
|
||||
@ -105,10 +107,10 @@ struct KerxSubTableFormat0
|
||||
TRACE_APPLY (this);
|
||||
|
||||
if (!c->plan->requested_kerning)
|
||||
return false;
|
||||
return_trace (false);
|
||||
|
||||
if (header.coverage & header.Backwards)
|
||||
return false;
|
||||
return_trace (false);
|
||||
|
||||
accelerator_t accel (*this, c);
|
||||
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
|
||||
@ -117,6 +119,16 @@ struct KerxSubTableFormat0
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
|
||||
{
|
||||
for (const KernPair& pair : pairs)
|
||||
{
|
||||
left_set.add (pair.left);
|
||||
right_set.add (pair.right);
|
||||
}
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
const KerxSubTableFormat0 &table;
|
||||
@ -127,7 +139,10 @@ struct KerxSubTableFormat0
|
||||
table (table_), c (c_) {}
|
||||
|
||||
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
|
||||
{ return table.get_kerning (left, right, c); }
|
||||
{
|
||||
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
|
||||
return table.get_kerning (left, right, c);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -192,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; }
|
||||
|
||||
@ -208,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_) :
|
||||
@ -227,13 +255,10 @@ struct KerxSubTableFormat1
|
||||
depth (0),
|
||||
crossStream (table->header.coverage & table->header.CrossStream) {}
|
||||
|
||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> &entry)
|
||||
{ return Format1EntryT::performAction (entry); }
|
||||
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||
void transition (hb_buffer_t *buffer,
|
||||
StateTableDriver<Types, EntryData, Flags> *driver,
|
||||
const Entry<EntryData> &entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
unsigned int flags = entry.flags;
|
||||
|
||||
if (flags & Format1EntryT::Reset)
|
||||
@ -259,6 +284,7 @@ struct KerxSubTableFormat1
|
||||
depth = 0;
|
||||
return;
|
||||
}
|
||||
hb_barrier ();
|
||||
|
||||
hb_mask_t kern_mask = c->plan->kern_mask;
|
||||
|
||||
@ -330,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;
|
||||
@ -349,7 +376,8 @@ struct KerxSubTableFormat1
|
||||
|
||||
driver_context_t dc (this, c);
|
||||
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
|
||||
StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (true);
|
||||
@ -363,12 +391,21 @@ struct KerxSubTableFormat1
|
||||
machine.sanitize (c)));
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
|
||||
{
|
||||
set_t set;
|
||||
machine.collect_glyphs (set, num_glyphs);
|
||||
left_set.union_ (set);
|
||||
right_set.union_ (set);
|
||||
}
|
||||
|
||||
protected:
|
||||
KernSubTableHeader header;
|
||||
StateTable<Types, EntryData> machine;
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT));
|
||||
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT::static_size));
|
||||
};
|
||||
|
||||
template <typename KernSubTableHeader>
|
||||
@ -389,6 +426,7 @@ struct KerxSubTableFormat2
|
||||
kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
|
||||
const FWORD *v = &arrayZ[kern_idx];
|
||||
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
|
||||
hb_barrier ();
|
||||
|
||||
return kerxTupleKern (*v, header.tuple_count (), this, c);
|
||||
}
|
||||
@ -398,10 +436,10 @@ struct KerxSubTableFormat2
|
||||
TRACE_APPLY (this);
|
||||
|
||||
if (!c->plan->requested_kerning)
|
||||
return false;
|
||||
return_trace (false);
|
||||
|
||||
if (header.coverage & header.Backwards)
|
||||
return false;
|
||||
return_trace (false);
|
||||
|
||||
accelerator_t accel (*this, c);
|
||||
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
|
||||
@ -410,6 +448,13 @@ struct KerxSubTableFormat2
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
|
||||
{
|
||||
(this+leftClassTable).collect_glyphs (left_set, num_glyphs);
|
||||
(this+rightClassTable).collect_glyphs (right_set, num_glyphs);
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
const KerxSubTableFormat2 &table;
|
||||
@ -420,7 +465,10 @@ struct KerxSubTableFormat2
|
||||
table (table_), c (c_) {}
|
||||
|
||||
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
|
||||
{ return table.get_kerning (left, right, c); }
|
||||
{
|
||||
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
|
||||
return table.get_kerning (left, right, c);
|
||||
}
|
||||
};
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -429,6 +477,7 @@ struct KerxSubTableFormat2
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
leftClassTable.sanitize (c, this) &&
|
||||
rightClassTable.sanitize (c, this) &&
|
||||
hb_barrier () &&
|
||||
c->check_range (this, array)));
|
||||
}
|
||||
|
||||
@ -461,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. */
|
||||
@ -481,22 +539,19 @@ 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 (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> &entry)
|
||||
{ return entry.data.ankrActionIndex != 0xFFFF; }
|
||||
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||
void transition (hb_buffer_t *buffer,
|
||||
StateTableDriver<Types, EntryData, Flags> *driver,
|
||||
const Entry<EntryData> &entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
|
||||
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
|
||||
{
|
||||
hb_glyph_position_t &o = buffer->cur_pos();
|
||||
@ -509,6 +564,7 @@ struct KerxSubTableFormat4
|
||||
double the ankrActionIndex to get the correct offset here. */
|
||||
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
|
||||
if (!c->sanitizer.check_array (data, 2)) return;
|
||||
hb_barrier ();
|
||||
unsigned int markControlPoint = *data++;
|
||||
unsigned int currControlPoint = *data++;
|
||||
hb_position_t markX = 0;
|
||||
@ -537,6 +593,7 @@ struct KerxSubTableFormat4
|
||||
double the ankrActionIndex to get the correct offset here. */
|
||||
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
|
||||
if (!c->sanitizer.check_array (data, 2)) return;
|
||||
hb_barrier ();
|
||||
unsigned int markAnchorPoint = *data++;
|
||||
unsigned int currAnchorPoint = *data++;
|
||||
const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
|
||||
@ -557,6 +614,7 @@ struct KerxSubTableFormat4
|
||||
by 4 to get the correct offset for the given action. */
|
||||
const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
|
||||
if (!c->sanitizer.check_array (data, 4)) return;
|
||||
hb_barrier ();
|
||||
int markX = *data++;
|
||||
int markY = *data++;
|
||||
int currX = *data++;
|
||||
@ -579,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;
|
||||
@ -593,7 +653,8 @@ struct KerxSubTableFormat4
|
||||
|
||||
driver_context_t dc (this, c);
|
||||
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
|
||||
StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (true);
|
||||
@ -607,12 +668,21 @@ struct KerxSubTableFormat4
|
||||
machine.sanitize (c)));
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
|
||||
{
|
||||
set_t set;
|
||||
machine.collect_glyphs (set, num_glyphs);
|
||||
left_set.union_ (set);
|
||||
right_set.union_ (set);
|
||||
}
|
||||
|
||||
protected:
|
||||
KernSubTableHeader header;
|
||||
StateTable<Types, EntryData> machine;
|
||||
HBUINT32 flags;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 20);
|
||||
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT32::static_size));
|
||||
};
|
||||
|
||||
template <typename KernSubTableHeader>
|
||||
@ -631,7 +701,7 @@ struct KerxSubTableFormat6
|
||||
unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
|
||||
if (is_long ())
|
||||
{
|
||||
const typename U::Long &t = u.l;
|
||||
const auto &t = u.l;
|
||||
unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
|
||||
unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
|
||||
unsigned int offset = l + r;
|
||||
@ -639,16 +709,18 @@ struct KerxSubTableFormat6
|
||||
if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
|
||||
const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
|
||||
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
|
||||
hb_barrier ();
|
||||
return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
|
||||
}
|
||||
else
|
||||
{
|
||||
const typename U::Short &t = u.s;
|
||||
const auto &t = u.s;
|
||||
unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
|
||||
unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
|
||||
unsigned int offset = l + r;
|
||||
const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD));
|
||||
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
|
||||
hb_barrier ();
|
||||
return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
|
||||
}
|
||||
}
|
||||
@ -658,10 +730,10 @@ struct KerxSubTableFormat6
|
||||
TRACE_APPLY (this);
|
||||
|
||||
if (!c->plan->requested_kerning)
|
||||
return false;
|
||||
return_trace (false);
|
||||
|
||||
if (header.coverage & header.Backwards)
|
||||
return false;
|
||||
return_trace (false);
|
||||
|
||||
accelerator_t accel (*this, c);
|
||||
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
|
||||
@ -674,6 +746,7 @@ struct KerxSubTableFormat6
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
(is_long () ?
|
||||
(
|
||||
u.l.rowIndexTable.sanitize (c, this) &&
|
||||
@ -688,6 +761,23 @@ struct KerxSubTableFormat6
|
||||
c->check_range (this, vector))));
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
|
||||
{
|
||||
if (is_long ())
|
||||
{
|
||||
const auto &t = u.l;
|
||||
(this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
|
||||
(this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &t = u.s;
|
||||
(this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
|
||||
(this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
|
||||
}
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
const KerxSubTableFormat6 &table;
|
||||
@ -698,7 +788,10 @@ struct KerxSubTableFormat6
|
||||
table (table_), c (c_) {}
|
||||
|
||||
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
|
||||
{ return table.get_kerning (left, right, c); }
|
||||
{
|
||||
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
|
||||
return table.get_kerning (left, right, c);
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -784,12 +877,27 @@ struct KerxSubTable
|
||||
}
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
switch (subtable_type) {
|
||||
case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
|
||||
case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
|
||||
case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
|
||||
case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return;
|
||||
case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.header.sanitize (c) ||
|
||||
u.header.length <= u.header.static_size ||
|
||||
!c->check_range (this, u.header.length))
|
||||
if (!(u.header.sanitize (c) &&
|
||||
hb_barrier () &&
|
||||
u.header.length >= u.header.static_size &&
|
||||
c->check_range (this, u.header.length)))
|
||||
return_trace (false);
|
||||
|
||||
return_trace (dispatch (c));
|
||||
@ -813,6 +921,8 @@ struct KerxSubTable
|
||||
* The 'kerx' Table
|
||||
*/
|
||||
|
||||
using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_bit_set_t, hb_bit_set_t>>;
|
||||
|
||||
template <typename T>
|
||||
struct KerxTable
|
||||
{
|
||||
@ -829,6 +939,9 @@ struct KerxTable
|
||||
{
|
||||
if (st->get_type () == 1)
|
||||
return true;
|
||||
|
||||
// TODO: What about format 4? What's this API used for anyway?
|
||||
|
||||
st = &StructAfter<SubTable> (*st);
|
||||
}
|
||||
return false;
|
||||
@ -867,7 +980,8 @@ struct KerxTable
|
||||
return v;
|
||||
}
|
||||
|
||||
bool apply (AAT::hb_aat_apply_context_t *c) const
|
||||
bool apply (AAT::hb_aat_apply_context_t *c,
|
||||
const kern_accelerator_data_t &accel_data) const
|
||||
{
|
||||
c->buffer->unsafe_to_concat ();
|
||||
|
||||
@ -914,6 +1028,9 @@ struct KerxTable
|
||||
if (reverse)
|
||||
c->buffer->reverse ();
|
||||
|
||||
c->left_set = &accel_data[i].first;
|
||||
c->right_set = &accel_data[i].second;
|
||||
|
||||
{
|
||||
/* See comment in sanitize() for conditional here. */
|
||||
hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
|
||||
@ -936,9 +1053,10 @@ struct KerxTable
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!thiz()->version.sanitize (c) ||
|
||||
(unsigned) thiz()->version < (unsigned) T::minVersion ||
|
||||
!thiz()->tableCount.sanitize (c)))
|
||||
if (unlikely (!(thiz()->version.sanitize (c) &&
|
||||
hb_barrier () &&
|
||||
(unsigned) thiz()->version >= (unsigned) T::minVersion &&
|
||||
thiz()->tableCount.sanitize (c))))
|
||||
return_trace (false);
|
||||
|
||||
typedef typename T::SubTable SubTable;
|
||||
@ -949,6 +1067,7 @@ struct KerxTable
|
||||
{
|
||||
if (unlikely (!st->u.header.sanitize (c)))
|
||||
return_trace (false);
|
||||
hb_barrier ();
|
||||
/* OpenType kern table has 2-byte subtable lengths. That's limiting.
|
||||
* MS implementation also only supports one subtable, of format 0,
|
||||
* anyway. Certain versions of some fonts, like Calibry, contain
|
||||
@ -964,8 +1083,61 @@ struct KerxTable
|
||||
st = &StructAfter<SubTable> (*st);
|
||||
}
|
||||
|
||||
unsigned majorVersion = thiz()->version;
|
||||
if (sizeof (thiz()->version) == 4)
|
||||
majorVersion = majorVersion >> 16;
|
||||
if (majorVersion >= 3)
|
||||
{
|
||||
const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st;
|
||||
if (!coverage->sanitize (c, count))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
|
||||
{
|
||||
kern_accelerator_data_t accel_data;
|
||||
|
||||
typedef typename T::SubTable SubTable;
|
||||
|
||||
const SubTable *st = &thiz()->firstSubTable;
|
||||
unsigned int count = thiz()->tableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
return accel_data;
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
accelerator_t (hb_face_t *face)
|
||||
{
|
||||
hb_sanitize_context_t sc;
|
||||
this->table = sc.reference_table<T> (face);
|
||||
this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
|
||||
}
|
||||
~accelerator_t ()
|
||||
{
|
||||
this->table.destroy ();
|
||||
}
|
||||
|
||||
hb_blob_t *get_blob () const { return table.get_blob (); }
|
||||
|
||||
bool apply (AAT::hb_aat_apply_context_t *c) const
|
||||
{
|
||||
return table->apply (c, accel_data);
|
||||
}
|
||||
|
||||
hb_blob_ptr_t<T> table;
|
||||
kern_accelerator_data_t accel_data;
|
||||
};
|
||||
};
|
||||
|
||||
struct kerx : KerxTable<kerx>
|
||||
@ -994,8 +1166,10 @@ struct kerx : KerxTable<kerx>
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
struct kerx_accelerator_t : kerx::accelerator_t {
|
||||
kerx_accelerator_t (hb_face_t *face) : kerx::accelerator_t (face) {}
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -133,8 +133,8 @@ struct opbd
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
|
||||
case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
|
||||
case 0: hb_barrier (); return u.format0.get_bounds (font, glyph_id, extents, this);
|
||||
case 1: hb_barrier (); return u.format1.get_bounds (font, glyph_id, extents, this);
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
@ -144,11 +144,12 @@ struct opbd
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this) || version.major != 1))
|
||||
return_trace (false);
|
||||
hb_barrier ();
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return_trace (u.format0.sanitize (c, this));
|
||||
case 1: return_trace (u.format1.sanitize (c, this));
|
||||
case 0: hb_barrier (); return_trace (u.format0.sanitize (c, this));
|
||||
case 1: hb_barrier (); return_trace (u.format1.sanitize (c, this));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,64 +128,45 @@ 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
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
sizeTable.sanitize (c, base, nSizes) &&
|
||||
trackTable.sanitize (c, nTracks, base, nSizes)));
|
||||
}
|
||||
@ -157,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
|
||||
@ -203,6 +206,7 @@ struct trak
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
version.major == 1 &&
|
||||
horizData.sanitize (c, this, this) &&
|
||||
vertData.sanitize (c, this, this)));
|
||||
|
||||
@ -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,18 +210,48 @@ 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)
|
||||
{
|
||||
const AAT::morx& morx = *mapper->face->table.morx;
|
||||
const AAT::morx& morx = *mapper->face->table.morx->table;
|
||||
if (morx.has_data ())
|
||||
{
|
||||
morx.compile_flags (mapper, map);
|
||||
return;
|
||||
}
|
||||
|
||||
const AAT::mort& mort = *mapper->face->table.mort;
|
||||
const AAT::mort& mort = *mapper->face->table.mort->table;
|
||||
if (mort.has_data ())
|
||||
{
|
||||
mort.compile_flags (mapper, map);
|
||||
@ -243,8 +276,8 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_substitution (hb_face_t *face)
|
||||
{
|
||||
return face->table.morx->has_data () ||
|
||||
face->table.mort->has_data ();
|
||||
return face->table.morx->table->has_data () ||
|
||||
face->table.mort->table->has_data ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -260,26 +293,30 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
||||
hb_aat_map_t map;
|
||||
builder.compile (map);
|
||||
|
||||
hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
|
||||
const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
|
||||
if (morx.has_data ())
|
||||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
|
||||
if (!buffer->message (font, "start table morx")) return;
|
||||
morx.apply (&c, map);
|
||||
(void) buffer->message (font, "end table morx");
|
||||
return;
|
||||
auto &accel = *font->face->table.morx;
|
||||
const AAT::morx& morx = *accel.table;
|
||||
if (morx.has_data ())
|
||||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
|
||||
if (!buffer->message (font, "start table morx")) return;
|
||||
morx.apply (&c, map, accel);
|
||||
(void) buffer->message (font, "end table morx");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hb_blob_t *mort_blob = font->face->table.mort.get_blob ();
|
||||
const AAT::mort& mort = *mort_blob->as<AAT::mort> ();
|
||||
if (mort.has_data ())
|
||||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
|
||||
if (!buffer->message (font, "start table mort")) return;
|
||||
mort.apply (&c, map);
|
||||
(void) buffer->message (font, "end table mort");
|
||||
return;
|
||||
auto &accel = *font->face->table.mort;
|
||||
const AAT::mort& mort = *accel.table;
|
||||
if (mort.has_data ())
|
||||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
|
||||
if (!buffer->message (font, "start table mort")) return;
|
||||
mort.apply (&c, map, accel);
|
||||
(void) buffer->message (font, "end table mort");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,7 +359,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_positioning (hb_face_t *face)
|
||||
{
|
||||
return face->table.kerx->has_data ();
|
||||
return face->table.kerx->table->has_data ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -330,13 +367,12 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
|
||||
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
|
||||
auto &accel = *font->face->table.kerx;
|
||||
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
|
||||
if (!buffer->message (font, "start table kerx")) return;
|
||||
c.set_ankr_table (font->face->table.ankr.get ());
|
||||
kerx.apply (&c);
|
||||
accel.apply (&c);
|
||||
(void) buffer->message (font, "end table kerx");
|
||||
}
|
||||
|
||||
@ -358,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
|
||||
|
||||
@ -40,7 +40,7 @@ HB_BEGIN_DECLS
|
||||
* @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type
|
||||
* @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0)
|
||||
* @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1)
|
||||
* @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2)
|
||||
* @HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2)
|
||||
* @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3)
|
||||
* @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4)
|
||||
* @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5)
|
||||
@ -88,7 +88,7 @@ typedef enum
|
||||
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5,
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -46,7 +46,9 @@ struct FTStringRange
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && (base+tag).sanitize (c, length));
|
||||
return_trace (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
(base+tag).sanitize (c, length));
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -73,6 +75,7 @@ struct ltag
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
hb_barrier () &&
|
||||
version >= 1 &&
|
||||
tagRanges.sanitize (c, this)));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -202,8 +202,12 @@ struct BEInt<Type, 4>
|
||||
/* Floats. */
|
||||
|
||||
/* We want our rounding towards +infinity. */
|
||||
static inline double
|
||||
_hb_roundf (double x) { return floor (x + .5); }
|
||||
|
||||
static inline float
|
||||
_hb_roundf (float x) { return floorf (x + .5f); }
|
||||
|
||||
#define roundf(x) _hb_roundf(x)
|
||||
|
||||
|
||||
@ -282,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)
|
||||
@ -306,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;
|
||||
}
|
||||
}
|
||||
@ -316,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;
|
||||
}
|
||||
}
|
||||
@ -332,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)
|
||||
@ -671,7 +675,7 @@ struct hb_pair_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
friend void swap (hb_pair_t& a, hb_pair_t& b)
|
||||
friend void swap (hb_pair_t& a, hb_pair_t& b) noexcept
|
||||
{
|
||||
hb_swap (a.first, b.first);
|
||||
hb_swap (a.second, b.second);
|
||||
@ -1053,6 +1057,18 @@ _hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
|
||||
return val.cmp (key, ds...);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
static int
|
||||
_hb_cmp_operator (const void *pkey, const void *pval)
|
||||
{
|
||||
const K& key = * (const K*) pkey;
|
||||
const V& val = * (const V*) pval;
|
||||
|
||||
if (key < val) return -1;
|
||||
if (key > val) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename V, typename K, typename ...Ts>
|
||||
static inline bool
|
||||
hb_bsearch_impl (unsigned *pos, /* Out */
|
||||
|
||||
@ -47,6 +47,8 @@ enum hb_not_found_t
|
||||
template <typename Type>
|
||||
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
{
|
||||
static constexpr bool realloc_move = true;
|
||||
|
||||
/*
|
||||
* Constructors.
|
||||
*/
|
||||
@ -249,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]);
|
||||
}
|
||||
|
||||
|
||||
@ -118,12 +118,12 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
*/
|
||||
#ifndef _hb_compiler_memory_r_barrier
|
||||
#if defined(__ATOMIC_ACQUIRE) // gcc-like
|
||||
#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory")
|
||||
static inline void _hb_compiler_memory_r_barrier () { asm volatile("": : :"memory"); }
|
||||
#elif !defined(_MSC_VER)
|
||||
#include <atomic>
|
||||
#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
|
||||
#else
|
||||
#define _hb_compiler_memory_r_barrier() do {} while (0)
|
||||
static inline void _hb_compiler_memory_r_barrier () {}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -212,11 +212,18 @@ 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 (); }
|
||||
|
||||
T *v = nullptr;
|
||||
};
|
||||
|
||||
static inline bool hb_barrier ()
|
||||
{
|
||||
_hb_compiler_memory_r_barrier ();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif /* HB_ATOMIC_HH */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -39,10 +39,10 @@ struct hb_bit_set_invertible_t
|
||||
|
||||
hb_bit_set_invertible_t () = default;
|
||||
hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default;
|
||||
hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); }
|
||||
hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) noexcept : hb_bit_set_invertible_t () { hb_swap (*this, other); }
|
||||
hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default;
|
||||
hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; }
|
||||
friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b)
|
||||
hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) noexcept { hb_swap (*this, other); return *this; }
|
||||
friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) noexcept
|
||||
{
|
||||
if (likely (!a.s.successful || !b.s.successful))
|
||||
return;
|
||||
@ -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;
|
||||
@ -359,8 +363,8 @@ struct hb_bit_set_invertible_t
|
||||
typedef hb_codepoint_t __item_t__;
|
||||
hb_codepoint_t __item__ () const { return v; }
|
||||
bool __more__ () const { return v != INVALID; }
|
||||
void __next__ () { s->next (&v); if (l) l--; }
|
||||
void __prev__ () { s->previous (&v); }
|
||||
void __next__ () { s->next (&v); if (likely (l)) l--; }
|
||||
void __prev__ () { s->previous (&v); l++; }
|
||||
unsigned __len__ () const { return l; }
|
||||
iter_t end () const { return iter_t (*s, false); }
|
||||
bool operator != (const iter_t& o) const
|
||||
|
||||
@ -38,10 +38,10 @@ struct hb_bit_set_t
|
||||
~hb_bit_set_t () = default;
|
||||
|
||||
hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
|
||||
hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
|
||||
hb_bit_set_t ( hb_bit_set_t&& other) noexcept : hb_bit_set_t () { hb_swap (*this, other); }
|
||||
hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
|
||||
hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
|
||||
friend void swap (hb_bit_set_t &a, hb_bit_set_t &b)
|
||||
hb_bit_set_t& operator= (hb_bit_set_t&& other) noexcept { hb_swap (*this, other); return *this; }
|
||||
friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) noexcept
|
||||
{
|
||||
if (likely (!a.successful || !b.successful))
|
||||
return;
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -598,6 +598,11 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
|
||||
* Creates a new blob containing the data from the
|
||||
* specified binary font file.
|
||||
*
|
||||
* The filename is passed directly to the system on all platforms,
|
||||
* except on Windows, where the filename is interpreted as UTF-8.
|
||||
* Only if the filename is not valid UTF-8, it will be interpreted
|
||||
* according to the system codepage.
|
||||
*
|
||||
* Returns: An #hb_blob_t pointer with the content of the file,
|
||||
* or hb_blob_get_empty() if failed.
|
||||
*
|
||||
@ -612,10 +617,14 @@ hb_blob_create_from_file (const char *file_name)
|
||||
|
||||
/**
|
||||
* hb_blob_create_from_file_or_fail:
|
||||
* @file_name: A font filename
|
||||
* @file_name: A filename
|
||||
*
|
||||
* Creates a new blob containing the data from the
|
||||
* specified binary font file.
|
||||
* Creates a new blob containing the data from the specified file.
|
||||
*
|
||||
* The filename is passed directly to the system on all platforms,
|
||||
* except on Windows, where the filename is interpreted as UTF-8.
|
||||
* Only if the filename is not valid UTF-8, it will be interpreted
|
||||
* according to the system codepage.
|
||||
*
|
||||
* Returns: An #hb_blob_t pointer with the content of the file,
|
||||
* or `NULL` if failed.
|
||||
@ -672,10 +681,19 @@ fail_without_close:
|
||||
if (unlikely (!file)) return nullptr;
|
||||
|
||||
HANDLE fd;
|
||||
int conversion;
|
||||
unsigned int size = strlen (file_name) + 1;
|
||||
wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
|
||||
if (unlikely (!wchar_file_name)) goto fail_without_close;
|
||||
mbstowcs (wchar_file_name, file_name, size);
|
||||
|
||||
/* Assume file name is given in UTF-8 encoding */
|
||||
conversion = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size);
|
||||
if (conversion <= 0)
|
||||
{
|
||||
/* Conversion failed due to invalid UTF-8 characters,
|
||||
Repeat conversion based on system code page */
|
||||
mbstowcs(wchar_file_name, file_name, size);
|
||||
}
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
{
|
||||
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -149,7 +149,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
|
||||
}
|
||||
assert (text_start < text_end);
|
||||
|
||||
if (0)
|
||||
if (false)
|
||||
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
|
||||
|
||||
hb_buffer_clear_contents (fragment);
|
||||
@ -288,7 +288,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
|
||||
}
|
||||
assert (text_start < text_end);
|
||||
|
||||
if (0)
|
||||
if (false)
|
||||
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
|
||||
|
||||
#if 0
|
||||
@ -412,7 +412,7 @@ hb_buffer_t::verify (hb_buffer_t *text_buffer,
|
||||
&len,
|
||||
HB_BUFFER_SERIALIZE_FORMAT_TEXT,
|
||||
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS);
|
||||
buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ);
|
||||
buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ ? bytes.arrayZ : "");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -271,6 +271,7 @@ hb_buffer_t::similar (const hb_buffer_t &src)
|
||||
replacement = src.replacement;
|
||||
invisible = src.invisible;
|
||||
not_found = src.not_found;
|
||||
not_found_variation_selector = src.not_found_variation_selector;
|
||||
}
|
||||
|
||||
void
|
||||
@ -283,6 +284,7 @@ hb_buffer_t::reset ()
|
||||
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
|
||||
invisible = 0;
|
||||
not_found = 0;
|
||||
not_found_variation_selector = HB_CODEPOINT_INVALID;
|
||||
|
||||
clear ();
|
||||
}
|
||||
@ -309,6 +311,7 @@ hb_buffer_t::clear ()
|
||||
|
||||
deallocate_var_all ();
|
||||
serial = 0;
|
||||
random_state = 1;
|
||||
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
|
||||
}
|
||||
|
||||
@ -704,6 +707,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
|
||||
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
|
||||
0, /* invisible */
|
||||
0, /* not_found */
|
||||
HB_CODEPOINT_INVALID, /* not_found_variation_selector */
|
||||
|
||||
|
||||
HB_BUFFER_CONTENT_TYPE_INVALID,
|
||||
@ -1359,6 +1363,89 @@ hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
|
||||
return buffer->not_found;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_set_not_found_variation_selector_glyph:
|
||||
* @buffer: An #hb_buffer_t
|
||||
* @not_found_variation_selector: the not-found-variation-selector #hb_codepoint_t
|
||||
*
|
||||
* Sets the #hb_codepoint_t that replaces variation-selector characters not resolved
|
||||
* in the font during shaping.
|
||||
*
|
||||
* The not-found-variation-selector glyph defaults to #HB_CODEPOINT_INVALID,
|
||||
* in which case an unresolved variation-selector will be removed from the glyph
|
||||
* string during shaping. This API allows for changing that and retaining a glyph,
|
||||
* such that the situation can be detected by the client and handled accordingly
|
||||
* (e.g. by using a different font).
|
||||
*
|
||||
* Since: 10.0.0
|
||||
**/
|
||||
void
|
||||
hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t *buffer,
|
||||
hb_codepoint_t not_found_variation_selector)
|
||||
{
|
||||
buffer->not_found_variation_selector = not_found_variation_selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_get_not_found_variation_selector_glyph:
|
||||
* @buffer: An #hb_buffer_t
|
||||
*
|
||||
* See hb_buffer_set_not_found_variation_selector_glyph().
|
||||
*
|
||||
* Return value:
|
||||
* The @buffer not-found-variation-selector #hb_codepoint_t
|
||||
*
|
||||
* Since: 10.0.0
|
||||
**/
|
||||
hb_codepoint_t
|
||||
hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer)
|
||||
{
|
||||
return buffer->not_found_variation_selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_set_random_state:
|
||||
* @buffer: An #hb_buffer_t
|
||||
* @state: the new random state
|
||||
*
|
||||
* Sets the random state of the buffer. The state changes
|
||||
* every time a glyph uses randomness (eg. the `rand`
|
||||
* OpenType feature). This function together with
|
||||
* hb_buffer_get_random_state() allow for transferring
|
||||
* the current random state to a subsequent buffer, to
|
||||
* get better randomness distribution.
|
||||
*
|
||||
* Defaults to 1 and when buffer contents are cleared.
|
||||
* A value of 0 disables randomness during shaping.
|
||||
*
|
||||
* Since: 8.4.0
|
||||
**/
|
||||
void
|
||||
hb_buffer_set_random_state (hb_buffer_t *buffer,
|
||||
unsigned state)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->random_state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_get_random_state:
|
||||
* @buffer: An #hb_buffer_t
|
||||
*
|
||||
* See hb_buffer_set_random_state().
|
||||
*
|
||||
* Return value:
|
||||
* The @buffer random state
|
||||
*
|
||||
* Since: 8.4.0
|
||||
**/
|
||||
unsigned
|
||||
hb_buffer_get_random_state (const hb_buffer_t *buffer)
|
||||
{
|
||||
return buffer->random_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_clear_contents:
|
||||
@ -1896,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.
|
||||
*
|
||||
|
||||
@ -487,6 +487,19 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
|
||||
HB_EXTERN hb_codepoint_t
|
||||
hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t *buffer,
|
||||
hb_codepoint_t not_found_variation_selector);
|
||||
|
||||
HB_EXTERN hb_codepoint_t
|
||||
hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_buffer_set_random_state (hb_buffer_t *buffer,
|
||||
unsigned state);
|
||||
|
||||
HB_EXTERN unsigned
|
||||
hb_buffer_get_random_state (const hb_buffer_t *buffer);
|
||||
|
||||
/*
|
||||
* Content API.
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-unicode.hh"
|
||||
#include "hb-set-digest.hh"
|
||||
|
||||
|
||||
static_assert ((sizeof (hb_glyph_info_t) == 20), "");
|
||||
@ -52,6 +51,7 @@ enum hb_buffer_scratch_flags_t {
|
||||
HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u,
|
||||
HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u,
|
||||
HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000040u,
|
||||
HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000080u,
|
||||
|
||||
/* Reserved for shapers' internal use. */
|
||||
HB_BUFFER_SCRATCH_FLAG_SHAPER0 = 0x01000000u,
|
||||
@ -80,6 +80,7 @@ struct hb_buffer_t
|
||||
hb_codepoint_t replacement; /* U+FFFD or something else. */
|
||||
hb_codepoint_t invisible; /* 0 or something else. */
|
||||
hb_codepoint_t not_found; /* 0 or something else. */
|
||||
hb_codepoint_t not_found_variation_selector; /* HB_CODEPOINT_INVALID or something else. */
|
||||
|
||||
/*
|
||||
* Buffer contents
|
||||
@ -116,6 +117,7 @@ struct hb_buffer_t
|
||||
|
||||
uint8_t allocated_var_bits;
|
||||
uint8_t serial;
|
||||
uint32_t random_state;
|
||||
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
|
||||
unsigned int max_len; /* Maximum allowed len. */
|
||||
int max_ops; /* Maximum allowed operations. */
|
||||
@ -179,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 ();
|
||||
|
||||
@ -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 ())
|
||||
@ -624,7 +624,6 @@ struct opset_t
|
||||
} else {
|
||||
/* invalid unknown operator */
|
||||
env.clear_args ();
|
||||
env.set_error ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -54,8 +54,8 @@ struct top_dict_values_t : dict_values_t<OPSTR>
|
||||
}
|
||||
void fini () { dict_values_t<OPSTR>::fini (); }
|
||||
|
||||
unsigned int charStringsOffset;
|
||||
unsigned int FDArrayOffset;
|
||||
int charStringsOffset;
|
||||
int FDArrayOffset;
|
||||
};
|
||||
|
||||
struct dict_opset_t : opset_t<number_t>
|
||||
@ -84,7 +84,7 @@ struct dict_opset_t : opset_t<number_t>
|
||||
|
||||
enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
|
||||
|
||||
char buf[32];
|
||||
char buf[32] = {0};
|
||||
unsigned char byte = 0;
|
||||
for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count)
|
||||
{
|
||||
@ -157,11 +157,11 @@ struct top_dict_opset_t : dict_opset_t
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_CharStrings:
|
||||
dictval.charStringsOffset = env.argStack.pop_uint ();
|
||||
dictval.charStringsOffset = env.argStack.pop_int ();
|
||||
env.clear_args ();
|
||||
break;
|
||||
case OpCode_FDArray:
|
||||
dictval.FDArrayOffset = env.argStack.pop_uint ();
|
||||
dictval.FDArrayOffset = env.argStack.pop_int ();
|
||||
env.clear_args ();
|
||||
break;
|
||||
case OpCode_FontMatrix:
|
||||
|
||||
@ -76,16 +76,12 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
|
||||
coords = coords_;
|
||||
num_coords = num_coords_;
|
||||
varStore = acc.varStore;
|
||||
seen_blend = false;
|
||||
seen_vsindex_ = false;
|
||||
scalars.init ();
|
||||
do_blend = num_coords && coords && varStore->size;
|
||||
set_ivs (acc.privateDicts[fd].ivs);
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
scalars.fini ();
|
||||
SUPER::fini ();
|
||||
}
|
||||
|
||||
@ -168,13 +164,13 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
|
||||
protected:
|
||||
const int *coords;
|
||||
unsigned int num_coords;
|
||||
const CFF2VariationStore *varStore;
|
||||
const CFF2ItemVariationStore *varStore;
|
||||
unsigned int region_count;
|
||||
unsigned int ivs;
|
||||
hb_vector_t<float> scalars;
|
||||
bool do_blend;
|
||||
bool seen_vsindex_;
|
||||
bool seen_blend;
|
||||
bool seen_vsindex_ = false;
|
||||
bool seen_blend = false;
|
||||
|
||||
typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -996,7 +999,7 @@ hb_feature_to_string (hb_feature_t *feature,
|
||||
if (feature->value > 1)
|
||||
{
|
||||
s[len++] = '=';
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32, feature->value));
|
||||
}
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = hb_min (len, size - 1);
|
||||
|
||||
@ -47,14 +47,10 @@
|
||||
# endif /* !__cplusplus */
|
||||
#endif
|
||||
|
||||
#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
|
||||
defined (_sgi) || defined (__sun) || defined (sun) || \
|
||||
defined (__digital__) || defined (__HP_cc)
|
||||
# include <inttypes.h>
|
||||
#elif defined (_AIX)
|
||||
#if defined (_AIX)
|
||||
# include <sys/inttypes.h>
|
||||
#elif defined (_MSC_VER) && _MSC_VER < 1600
|
||||
/* VS 2010 (_MSC_VER 1600) has stdint.h */
|
||||
/* VS 2010 (_MSC_VER 1600) has stdint.h */
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
@ -63,10 +59,11 @@ typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined (__KERNEL__)
|
||||
# include <linux/types.h>
|
||||
#else
|
||||
#elif defined (_MSC_VER) && _MSC_VER < 1800
|
||||
/* VS 2013 (_MSC_VER 1800) has inttypes.h */
|
||||
# include <stdint.h>
|
||||
#else
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
@ -507,6 +504,13 @@ hb_language_matches (hb_language_t language,
|
||||
* @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
|
||||
* @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
|
||||
* @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
|
||||
* @HB_SCRIPT_GARAY: `Gara`, Since: 10.0.0
|
||||
* @HB_SCRIPT_GURUNG_KHEMA: `Gukh`, Since: 10.0.0
|
||||
* @HB_SCRIPT_KIRAT_RAI: `Krai`, Since: 10.0.0
|
||||
* @HB_SCRIPT_OL_ONAL: `Onao`, Since: 10.0.0
|
||||
* @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0
|
||||
* @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0
|
||||
* @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0
|
||||
* @HB_SCRIPT_INVALID: No script set
|
||||
*
|
||||
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
|
||||
@ -734,6 +738,17 @@ typedef enum
|
||||
HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/
|
||||
HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/
|
||||
|
||||
/*
|
||||
* Since 10.0.0
|
||||
*/
|
||||
HB_SCRIPT_GARAY = HB_TAG ('G','a','r','a'), /*16.0*/
|
||||
HB_SCRIPT_GURUNG_KHEMA = HB_TAG ('G','u','k','h'), /*16.0*/
|
||||
HB_SCRIPT_KIRAT_RAI = HB_TAG ('K','r','a','i'), /*16.0*/
|
||||
HB_SCRIPT_OL_ONAL = HB_TAG ('O','n','a','o'), /*16.0*/
|
||||
HB_SCRIPT_SUNUWAR = HB_TAG ('S','u','n','u'), /*16.0*/
|
||||
HB_SCRIPT_TODHRI = HB_TAG ('T','o','d','r'), /*16.0*/
|
||||
HB_SCRIPT_TULU_TIGALARI = HB_TAG ('T','u','t','g'), /*16.0*/
|
||||
|
||||
/* No script set. */
|
||||
HB_SCRIPT_INVALID = HB_TAG_NONE,
|
||||
|
||||
|
||||
@ -56,7 +56,6 @@
|
||||
|
||||
#ifdef HB_LEAN
|
||||
#define HB_DISABLE_DEPRECATED
|
||||
#define HB_NDEBUG
|
||||
#define HB_NO_ATEXIT
|
||||
#define HB_NO_BUFFER_MESSAGE
|
||||
#define HB_NO_BUFFER_SERIALIZE
|
||||
@ -69,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
|
||||
@ -118,6 +115,10 @@
|
||||
#define HB_NO_VAR_COMPOSITES
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_VAR
|
||||
#define HB_NO_VAR_COMPOSITES
|
||||
#endif
|
||||
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
#define HB_IF_NOT_DEPRECATED(x)
|
||||
#else
|
||||
@ -156,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
|
||||
|
||||
|
||||
@ -27,9 +27,6 @@
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
HB_END_DECLS
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <functional>
|
||||
@ -56,15 +53,15 @@ struct shared_ptr
|
||||
|
||||
explicit shared_ptr (T *p = nullptr) : p (p) {}
|
||||
shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {}
|
||||
shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; }
|
||||
shared_ptr (shared_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
|
||||
shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; }
|
||||
shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
|
||||
shared_ptr& operator = (shared_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
|
||||
~shared_ptr () { v::destroy (p); p = nullptr; }
|
||||
|
||||
T* get() const { return p; }
|
||||
|
||||
void swap (shared_ptr &o) { std::swap (p, o.p); }
|
||||
friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); }
|
||||
void swap (shared_ptr &o) noexcept { std::swap (p, o.p); }
|
||||
friend void swap (shared_ptr &a, shared_ptr &b) noexcept { std::swap (a.p, b.p); }
|
||||
|
||||
operator T * () const { return p; }
|
||||
T& operator * () const { return *get (); }
|
||||
@ -98,16 +95,16 @@ struct unique_ptr
|
||||
|
||||
explicit unique_ptr (T *p = nullptr) : p (p) {}
|
||||
unique_ptr (const unique_ptr &o) = delete;
|
||||
unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; }
|
||||
unique_ptr (unique_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
|
||||
unique_ptr& operator = (const unique_ptr &o) = delete;
|
||||
unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
|
||||
unique_ptr& operator = (unique_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
|
||||
~unique_ptr () { v::destroy (p); p = nullptr; }
|
||||
|
||||
T* get() const { return p; }
|
||||
T* release () { T* v = p; p = nullptr; return v; }
|
||||
|
||||
void swap (unique_ptr &o) { std::swap (p, o.p); }
|
||||
friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); }
|
||||
void swap (unique_ptr &o) noexcept { std::swap (p, o.p); }
|
||||
friend void swap (unique_ptr &a, unique_ptr &b) noexcept { std::swap (a.p, b.p); }
|
||||
|
||||
operator T * () const { return p; }
|
||||
T& operator * () const { return *get (); }
|
||||
|
||||
164
src/java.desktop/share/native/libharfbuzz/hb-decycler.hh
Normal file
164
src/java.desktop/share/native/libharfbuzz/hb-decycler.hh
Normal 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 */
|
||||
@ -56,7 +56,7 @@ HB_BEGIN_DECLS
|
||||
/**
|
||||
* HB_SCRIPT_CANADIAN_ABORIGINAL:
|
||||
*
|
||||
* Use #HB_SCRIPT_CANADIAN_SYLLABICS instead:
|
||||
* Use #HB_SCRIPT_CANADIAN_SYLLABICS instead.
|
||||
*
|
||||
* Deprecated: 0.9.20
|
||||
*/
|
||||
@ -301,6 +301,15 @@ hb_font_get_glyph_shape (hb_font_t *font,
|
||||
hb_draw_funcs_t *dfuncs, void *draw_data);
|
||||
|
||||
|
||||
/**
|
||||
* HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION:
|
||||
*
|
||||
* Use #HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION instead.
|
||||
*
|
||||
* Deprecated: 8.3.0
|
||||
*/
|
||||
#define HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -70,7 +70,7 @@ typedef struct hb_draw_state_t {
|
||||
*
|
||||
* The default #hb_draw_state_t at the start of glyph drawing.
|
||||
*/
|
||||
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}}
|
||||
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -232,7 +232,7 @@ struct hb_draw_session_t
|
||||
funcs->close_path (draw_data, st);
|
||||
}
|
||||
|
||||
protected:
|
||||
public:
|
||||
float slant;
|
||||
bool not_slanted;
|
||||
hb_draw_funcs_t *funcs;
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
struct face_table_info_t
|
||||
{
|
||||
hb_blob_t* data;
|
||||
signed order;
|
||||
unsigned order;
|
||||
};
|
||||
|
||||
struct hb_face_builder_data_t
|
||||
@ -153,6 +153,50 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
|
||||
return hb_blob_reference (data->tables[tag].data);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
_hb_face_builder_get_table_tags (const hb_face_t *face HB_UNUSED,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count,
|
||||
hb_tag_t *table_tags,
|
||||
void *user_data)
|
||||
{
|
||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
|
||||
|
||||
unsigned population = data->tables.get_population ();
|
||||
|
||||
if (!table_count)
|
||||
return population;
|
||||
|
||||
if (unlikely (start_offset >= population))
|
||||
{
|
||||
if (table_count)
|
||||
*table_count = 0;
|
||||
return population;
|
||||
}
|
||||
|
||||
// Sort the tags.
|
||||
hb_vector_t<hb_tag_t> sorted_tags;
|
||||
data->tables.keys () | hb_sink (sorted_tags);
|
||||
if (unlikely (sorted_tags.in_error ()))
|
||||
{
|
||||
// Not much to do...
|
||||
}
|
||||
sorted_tags.qsort ([] (const void* a, const void* b) {
|
||||
return * (hb_tag_t *) a < * (hb_tag_t *) b ? -1 :
|
||||
* (hb_tag_t *) a == * (hb_tag_t *) b ? 0 :
|
||||
+1;
|
||||
});
|
||||
|
||||
auto array = sorted_tags.as_array ().sub_array (start_offset, table_count);
|
||||
auto out = hb_array (table_tags, *table_count);
|
||||
|
||||
+ array.iter ()
|
||||
| hb_sink (out)
|
||||
;
|
||||
|
||||
return population;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_builder_create:
|
||||
@ -171,9 +215,16 @@ hb_face_builder_create ()
|
||||
hb_face_builder_data_t *data = _hb_face_builder_data_create ();
|
||||
if (unlikely (!data)) return hb_face_get_empty ();
|
||||
|
||||
return hb_face_create_for_tables (_hb_face_builder_reference_table,
|
||||
data,
|
||||
_hb_face_builder_data_destroy);
|
||||
hb_face_t *face = hb_face_create_for_tables (_hb_face_builder_reference_table,
|
||||
data,
|
||||
_hb_face_builder_data_destroy);
|
||||
|
||||
hb_face_set_get_table_tags_func (face,
|
||||
_hb_face_builder_get_table_tags,
|
||||
data,
|
||||
nullptr);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,7 +250,7 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
|
||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
|
||||
|
||||
hb_blob_t* previous = data->tables.get (tag).data;
|
||||
if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
|
||||
if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), (unsigned) -1}))
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
return false;
|
||||
|
||||
@ -90,10 +90,6 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
nullptr, /* reference_table_func */
|
||||
nullptr, /* user_data */
|
||||
nullptr, /* destroy */
|
||||
|
||||
0, /* index */
|
||||
1000, /* upem */
|
||||
0, /* num_glyphs */
|
||||
@ -110,8 +106,9 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
|
||||
*
|
||||
* Variant of hb_face_create(), built for those cases where it is more
|
||||
* convenient to provide data for individual tables instead of the whole font
|
||||
* data. With the caveat that hb_face_get_table_tags() does not currently work
|
||||
* with faces created this way.
|
||||
* data. With the caveat that hb_face_get_table_tags() would not work
|
||||
* with faces created this way. You can address that by calling the
|
||||
* hb_face_set_get_table_tags_func() function and setting the appropriate callback.
|
||||
*
|
||||
* Creates a new face object from the specified @user_data and @reference_table_func,
|
||||
* with the @destroy callback.
|
||||
@ -194,6 +191,22 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
|
||||
return blob;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
_hb_face_for_data_get_table_tags (const hb_face_t *face HB_UNUSED,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count,
|
||||
hb_tag_t *table_tags,
|
||||
void *user_data)
|
||||
{
|
||||
hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
|
||||
|
||||
const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
|
||||
const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
|
||||
|
||||
return ot_face.get_table_tags (start_offset, table_count, table_tags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_create:
|
||||
* @blob: #hb_blob_t to work upon
|
||||
@ -240,12 +253,73 @@ hb_face_create (hb_blob_t *blob,
|
||||
face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
|
||||
closure,
|
||||
_hb_face_for_data_closure_destroy);
|
||||
hb_face_set_get_table_tags_func (face,
|
||||
_hb_face_for_data_get_table_tags,
|
||||
closure,
|
||||
nullptr);
|
||||
|
||||
face->index = index;
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_create_or_fail:
|
||||
* @blob: #hb_blob_t to work upon
|
||||
* @index: The index of the face within @blob
|
||||
*
|
||||
* Like hb_face_create(), but returns `NULL` if the blob data
|
||||
* contains no usable font face at the specified index.
|
||||
*
|
||||
* Return value: (transfer full): The new face object, or `NULL` if
|
||||
* no face is found at the specified index.
|
||||
*
|
||||
* Since: 10.1.0
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_face_create_or_fail (hb_blob_t *blob,
|
||||
unsigned int index)
|
||||
{
|
||||
unsigned num_faces = hb_face_count (blob);
|
||||
if (index >= num_faces)
|
||||
return nullptr;
|
||||
|
||||
hb_face_t *face = hb_face_create (blob, index);
|
||||
if (hb_object_is_immutable (face))
|
||||
return nullptr;
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_OPEN
|
||||
/**
|
||||
* hb_face_create_from_file_or_fail:
|
||||
* @file_name: A font filename
|
||||
* @index: The index of the face within the file
|
||||
*
|
||||
* A thin wrapper around hb_blob_create_from_file_or_fail()
|
||||
* followed by hb_face_create_or_fail().
|
||||
*
|
||||
* Return value: (transfer full): The new face object, or `NULL` if
|
||||
* no face is found at the specified index or the file cannot be read.
|
||||
*
|
||||
* Since: 10.1.0
|
||||
**/
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index)
|
||||
{
|
||||
hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
|
||||
if (unlikely (!blob))
|
||||
return nullptr;
|
||||
|
||||
hb_face_t *face = hb_face_create_or_fail (blob, index);
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
return face;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hb_face_get_empty:
|
||||
*
|
||||
@ -306,6 +380,9 @@ hb_face_destroy (hb_face_t *face)
|
||||
face->data.fini ();
|
||||
face->table.fini ();
|
||||
|
||||
if (face->get_table_tags_destroy)
|
||||
face->get_table_tags_destroy (face->get_table_tags_user_data);
|
||||
|
||||
if (face->destroy)
|
||||
face->destroy (face->user_data);
|
||||
|
||||
@ -395,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
|
||||
*
|
||||
@ -415,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
|
||||
*
|
||||
@ -426,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -547,6 +660,38 @@ hb_face_get_glyph_count (const hb_face_t *face)
|
||||
return face->get_num_glyphs ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_set_get_table_tags_func:
|
||||
* @face: A face object
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified): The table-tag-fetching function
|
||||
* @user_data: A pointer to the user data, to be destroyed by @destroy when not needed anymore
|
||||
* @destroy: (nullable): A callback to call when @func is not needed anymore
|
||||
*
|
||||
* Sets the table-tag-fetching function for the specified face object.
|
||||
*
|
||||
* Since: 10.0.0
|
||||
*/
|
||||
HB_EXTERN void
|
||||
hb_face_set_get_table_tags_func (hb_face_t *face,
|
||||
hb_get_table_tags_func_t func,
|
||||
void *user_data,
|
||||
hb_destroy_func_t destroy)
|
||||
{
|
||||
if (hb_object_is_immutable (face))
|
||||
{
|
||||
if (destroy)
|
||||
destroy (user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (face->get_table_tags_destroy)
|
||||
face->get_table_tags_destroy (face->get_table_tags_user_data);
|
||||
|
||||
face->get_table_tags_func = func;
|
||||
face->get_table_tags_user_data = user_data;
|
||||
face->get_table_tags_destroy = destroy;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_get_table_tags:
|
||||
* @face: A face object
|
||||
@ -568,19 +713,14 @@ hb_face_get_table_tags (const hb_face_t *face,
|
||||
unsigned int *table_count, /* IN/OUT */
|
||||
hb_tag_t *table_tags /* OUT */)
|
||||
{
|
||||
if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
|
||||
if (!face->get_table_tags_func)
|
||||
{
|
||||
if (table_count)
|
||||
*table_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
|
||||
|
||||
const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
|
||||
const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
|
||||
|
||||
return ot_face.get_table_tags (start_offset, table_count, table_tags);
|
||||
return face->get_table_tags_func (face, start_offset, table_count, table_tags, face->get_table_tags_user_data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -59,15 +59,28 @@ HB_EXTERN hb_face_t *
|
||||
hb_face_create (hb_blob_t *blob,
|
||||
unsigned int index);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_face_create_or_fail (hb_blob_t *blob,
|
||||
unsigned int index);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index);
|
||||
|
||||
/**
|
||||
* hb_reference_table_func_t:
|
||||
* @face: an #hb_face_t to reference table for
|
||||
* @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
|
||||
*/
|
||||
@ -135,6 +148,34 @@ hb_face_set_glyph_count (hb_face_t *face,
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_glyph_count (const hb_face_t *face);
|
||||
|
||||
|
||||
/**
|
||||
* hb_get_table_tags_func_t:
|
||||
* @face: A face object
|
||||
* @start_offset: The index of first table tag to retrieve
|
||||
* @table_count: (inout): Input = the maximum number of table tags to return;
|
||||
* Output = the actual number of table tags returned (may be zero)
|
||||
* @table_tags: (out) (array length=table_count): The array of table tags found
|
||||
* @user_data: User data pointer passed by the caller
|
||||
*
|
||||
* Callback function for hb_face_get_table_tags().
|
||||
*
|
||||
* Return value: Total number of tables, or zero if it is not possible to list
|
||||
*
|
||||
* Since: 10.0.0
|
||||
*/
|
||||
typedef unsigned int (*hb_get_table_tags_func_t) (const hb_face_t *face,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count, /* IN/OUT */
|
||||
hb_tag_t *table_tags /* OUT */,
|
||||
void *user_data);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_set_get_table_tags_func (hb_face_t *face,
|
||||
hb_get_table_tags_func_t func,
|
||||
void *user_data,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_table_tags (const hb_face_t *face,
|
||||
unsigned int start_offset,
|
||||
|
||||
@ -48,13 +48,17 @@ struct hb_face_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
|
||||
unsigned int index; /* Face index in a collection, zero-based. */
|
||||
mutable hb_atomic_int_t upem; /* Units-per-EM. */
|
||||
mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */
|
||||
|
||||
hb_reference_table_func_t reference_table_func;
|
||||
void *user_data;
|
||||
hb_destroy_func_t destroy;
|
||||
|
||||
unsigned int index; /* Face index in a collection, zero-based. */
|
||||
mutable hb_atomic_int_t upem; /* Units-per-EM. */
|
||||
mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */
|
||||
hb_get_table_tags_func_t get_table_tags_func;
|
||||
void *get_table_tags_user_data;
|
||||
hb_destroy_func_t get_table_tags_destroy;
|
||||
|
||||
hb_shaper_object_dataset_t<hb_face_t> data;/* Various shaper data. */
|
||||
hb_ot_face_t table; /* All the face's tables. */
|
||||
|
||||
@ -231,7 +231,7 @@ hb_font_get_glyph_v_advance_nil (hb_font_t *font,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
/* TODO use font_extents.ascender+descender */
|
||||
return font->y_scale;
|
||||
return -font->y_scale;
|
||||
}
|
||||
|
||||
static hb_position_t
|
||||
|
||||
@ -651,7 +651,7 @@ struct hb_font_t
|
||||
{
|
||||
if (get_glyph_name (glyph, s, size)) return;
|
||||
|
||||
if (size && snprintf (s, size, "gid%u", glyph) < 0)
|
||||
if (size && snprintf (s, size, "gid%" PRIu32, glyph) < 0)
|
||||
*s = '\0';
|
||||
}
|
||||
|
||||
|
||||
@ -37,10 +37,15 @@
|
||||
#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"
|
||||
|
||||
#include FT_MODULE_H
|
||||
#include FT_ADVANCES_H
|
||||
#include FT_MULTIPLE_MASTERS_H
|
||||
#include FT_OUTLINE_H
|
||||
@ -225,7 +230,7 @@ _hb_ft_hb_font_check_changed (hb_font_t *font,
|
||||
* Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
|
||||
*
|
||||
* For more information, see
|
||||
* https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
|
||||
* <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
|
||||
*
|
||||
* This function works with #hb_font_t objects created by
|
||||
* hb_ft_font_create() or hb_ft_font_create_referenced().
|
||||
@ -253,7 +258,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
|
||||
* Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
|
||||
*
|
||||
* For more information, see
|
||||
* https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
|
||||
* <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
|
||||
*
|
||||
* This function works with #hb_font_t objects created by
|
||||
* hb_ft_font_create() or hb_ft_font_create_referenced().
|
||||
@ -273,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
|
||||
@ -286,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
|
||||
@ -501,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
|
||||
@ -537,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
|
||||
|
||||
@ -930,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)
|
||||
@ -1104,6 +1171,45 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
|
||||
buffer, hb_free);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
_hb_ft_get_table_tags (const hb_face_t *face HB_UNUSED,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count,
|
||||
hb_tag_t *table_tags,
|
||||
void *user_data)
|
||||
{
|
||||
FT_Face ft_face = (FT_Face) user_data;
|
||||
|
||||
FT_ULong population = 0;
|
||||
FT_Sfnt_Table_Info (ft_face,
|
||||
0, // table_index; ignored
|
||||
nullptr,
|
||||
&population);
|
||||
|
||||
if (!table_count)
|
||||
return population;
|
||||
else
|
||||
*table_count = 0;
|
||||
|
||||
if (unlikely (start_offset >= population))
|
||||
return population;
|
||||
|
||||
unsigned end_offset = hb_min (start_offset + *table_count, (unsigned) population);
|
||||
if (unlikely (end_offset < start_offset))
|
||||
return population;
|
||||
|
||||
*table_count = end_offset - start_offset;
|
||||
for (unsigned i = start_offset; i < end_offset; i++)
|
||||
{
|
||||
FT_ULong tag = 0, length;
|
||||
FT_Sfnt_Table_Info (ft_face, i, &tag, &length);
|
||||
table_tags[i - start_offset] = tag;
|
||||
}
|
||||
|
||||
return population;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_ft_face_create:
|
||||
* @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
|
||||
@ -1145,6 +1251,7 @@ hb_ft_face_create (FT_Face ft_face,
|
||||
hb_blob_destroy (blob);
|
||||
} else {
|
||||
face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
|
||||
hb_face_set_get_table_tags_func (face, _hb_ft_get_table_tags, ft_face, nullptr);
|
||||
}
|
||||
|
||||
hb_face_set_index (face, ft_face->face_index);
|
||||
@ -1215,7 +1322,7 @@ hb_ft_face_finalize (void *arg)
|
||||
hb_face_t *
|
||||
hb_ft_face_create_cached (FT_Face ft_face)
|
||||
{
|
||||
if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
|
||||
if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize))
|
||||
{
|
||||
if (ft_face->generic.finalizer)
|
||||
ft_face->generic.finalizer (ft_face);
|
||||
@ -1245,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
|
||||
@ -1392,6 +1499,24 @@ hb_ft_font_create_referenced (FT_Face ft_face)
|
||||
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
|
||||
}
|
||||
|
||||
|
||||
static void * _hb_ft_alloc (FT_Memory memory, long size)
|
||||
{ return hb_malloc (size); }
|
||||
|
||||
static void _hb_ft_free (FT_Memory memory, void *block)
|
||||
{ hb_free (block); }
|
||||
|
||||
static void * _hb_ft_realloc (FT_Memory memory, long cur_size, long new_size, void *block)
|
||||
{ return hb_realloc (block, new_size); }
|
||||
|
||||
static FT_MemoryRec_ m =
|
||||
{
|
||||
nullptr,
|
||||
_hb_ft_alloc,
|
||||
_hb_ft_free,
|
||||
_hb_ft_realloc
|
||||
};
|
||||
|
||||
static inline void free_static_ft_library ();
|
||||
|
||||
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
|
||||
@ -1400,16 +1525,19 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<F
|
||||
static FT_Library create ()
|
||||
{
|
||||
FT_Library l;
|
||||
if (FT_Init_FreeType (&l))
|
||||
if (FT_New_Library (&m, &l))
|
||||
return nullptr;
|
||||
|
||||
FT_Add_Default_Modules (l);
|
||||
FT_Set_Default_Properties (l);
|
||||
|
||||
hb_atexit (free_static_ft_library);
|
||||
|
||||
return l;
|
||||
}
|
||||
static void destroy (FT_Library l)
|
||||
{
|
||||
FT_Done_FreeType (l);
|
||||
FT_Done_Library (l);
|
||||
}
|
||||
static FT_Library get_null ()
|
||||
{
|
||||
@ -1424,9 +1552,76 @@ void free_static_ft_library ()
|
||||
}
|
||||
|
||||
static FT_Library
|
||||
get_ft_library ()
|
||||
reference_ft_library ()
|
||||
{
|
||||
return static_ft_library.get_unconst ();
|
||||
FT_Library l = static_ft_library.get_unconst ();
|
||||
if (unlikely (FT_Reference_Library (l)))
|
||||
{
|
||||
DEBUG_MSG (FT, l, "FT_Reference_Library() failed");
|
||||
return nullptr;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
static hb_user_data_key_t ft_library_key = {0};
|
||||
|
||||
static void
|
||||
finalize_ft_library (void *arg)
|
||||
{
|
||||
FT_Face ft_face = (FT_Face) arg;
|
||||
FT_Done_Library ((FT_Library) ft_face->generic.data);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_ft_library (void *arg)
|
||||
{
|
||||
FT_Done_Library ((FT_Library) arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_face_create_from_file_or_fail:
|
||||
* @file_name: A font filename
|
||||
* @index: The index of the face within the file
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified
|
||||
* font file and face index.
|
||||
*
|
||||
* This is similar in functionality to hb_face_create_from_file_or_fail(),
|
||||
* but uses the FreeType library for loading the font file.
|
||||
*
|
||||
* Return value: (transfer full): The new face object, or `NULL` if
|
||||
* no face is found at the specified index or the file cannot be read.
|
||||
*
|
||||
* Since: 10.1.0
|
||||
*/
|
||||
hb_face_t *
|
||||
hb_ft_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index)
|
||||
{
|
||||
FT_Library ft_library = reference_ft_library ();
|
||||
if (unlikely (!ft_library))
|
||||
{
|
||||
DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FT_Face ft_face;
|
||||
if (unlikely (FT_New_Face (ft_library,
|
||||
file_name,
|
||||
index,
|
||||
&ft_face)))
|
||||
return nullptr;
|
||||
|
||||
hb_face_t *face = hb_ft_face_create_referenced (ft_face);
|
||||
FT_Done_Face (ft_face);
|
||||
|
||||
ft_face->generic.data = ft_library;
|
||||
ft_face->generic.finalizer = finalize_ft_library;
|
||||
|
||||
if (hb_face_is_immutable (face))
|
||||
return nullptr;
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1465,32 +1660,47 @@ _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);
|
||||
if (unlikely (!blob_length))
|
||||
DEBUG_MSG (FT, font, "Font face has empty blob");
|
||||
|
||||
FT_Face ft_face = nullptr;
|
||||
FT_Error err = FT_New_Memory_Face (get_ft_library (),
|
||||
(const FT_Byte *) blob_data,
|
||||
blob_length,
|
||||
hb_face_get_index (font->face),
|
||||
&ft_face);
|
||||
|
||||
if (unlikely (err)) {
|
||||
FT_Library ft_library = reference_ft_library ();
|
||||
if (unlikely (!ft_library))
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
|
||||
DEBUG_MSG (FT, font, "reference_ft_library failed");
|
||||
return;
|
||||
}
|
||||
|
||||
FT_Face ft_face = nullptr;
|
||||
if (unlikely (FT_New_Memory_Face (ft_library,
|
||||
(const FT_Byte *) blob_data,
|
||||
blob_length,
|
||||
hb_face_get_index (font->face),
|
||||
&ft_face)))
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
DEBUG_MSG (FT, font, "FT_New_Memory_Face() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
|
||||
FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
|
||||
|
||||
|
||||
// Hook the blob to the FT_Face
|
||||
ft_face->generic.data = blob;
|
||||
ft_face->generic.finalizer = _release_blob;
|
||||
|
||||
// And the FT_Library to the blob
|
||||
hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true);
|
||||
|
||||
_hb_ft_font_set_funcs (font, ft_face, true);
|
||||
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
|
||||
|
||||
|
||||
@ -84,6 +84,9 @@ hb_ft_face_create_cached (FT_Face ft_face);
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_ft_face_create_referenced (FT_Face ft_face);
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_ft_face_create_from_file_or_fail (const char *file_name,
|
||||
unsigned int index);
|
||||
|
||||
/*
|
||||
* hb-font from ft-face.
|
||||
@ -108,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);
|
||||
@ -139,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
|
||||
|
||||
|
||||
293
src/java.desktop/share/native/libharfbuzz/hb-geometry.hh
Normal file
293
src/java.desktop/share/native/libharfbuzz/hb-geometry.hh
Normal file
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright © 2022 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
#ifndef HB_GEOMETRY_HH
|
||||
#define HB_GEOMETRY_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
struct hb_extents_t
|
||||
{
|
||||
hb_extents_t () {}
|
||||
hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
|
||||
xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
|
||||
|
||||
bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
|
||||
bool is_void () const { return xmin > xmax; }
|
||||
|
||||
void union_ (const hb_extents_t &o)
|
||||
{
|
||||
xmin = hb_min (xmin, o.xmin);
|
||||
ymin = hb_min (ymin, o.ymin);
|
||||
xmax = hb_max (xmax, o.xmax);
|
||||
ymax = hb_max (ymax, o.ymax);
|
||||
}
|
||||
|
||||
void intersect (const hb_extents_t &o)
|
||||
{
|
||||
xmin = hb_max (xmin, o.xmin);
|
||||
ymin = hb_max (ymin, o.ymin);
|
||||
xmax = hb_min (xmax, o.xmax);
|
||||
ymax = hb_min (ymax, o.ymax);
|
||||
}
|
||||
|
||||
void
|
||||
add_point (float x, float y)
|
||||
{
|
||||
if (unlikely (is_void ()))
|
||||
{
|
||||
xmin = xmax = x;
|
||||
ymin = ymax = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
xmin = hb_min (xmin, x);
|
||||
ymin = hb_min (ymin, y);
|
||||
xmax = hb_max (xmax, x);
|
||||
ymax = hb_max (ymax, y);
|
||||
}
|
||||
}
|
||||
|
||||
float xmin = 0.f;
|
||||
float ymin = 0.f;
|
||||
float xmax = -1.f;
|
||||
float ymax = -1.f;
|
||||
};
|
||||
|
||||
struct hb_transform_t
|
||||
{
|
||||
hb_transform_t () {}
|
||||
hb_transform_t (float xx, float yx,
|
||||
float xy, float yy,
|
||||
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. */
|
||||
hb_transform_t r;
|
||||
|
||||
r.xx = o.xx * xx + o.yx * xy;
|
||||
r.yx = o.xx * yx + o.yx * yy;
|
||||
|
||||
r.xy = o.xy * xx + o.yy * xy;
|
||||
r.yy = o.xy * yx + o.yy * yy;
|
||||
|
||||
r.x0 = o.x0 * xx + o.y0 * xy + x0;
|
||||
r.y0 = o.x0 * yx + o.y0 * yy + y0;
|
||||
|
||||
*this = r;
|
||||
}
|
||||
|
||||
void transform_distance (float &dx, float &dy) const
|
||||
{
|
||||
float new_x = xx * dx + xy * dy;
|
||||
float new_y = yx * dx + yy * dy;
|
||||
dx = new_x;
|
||||
dy = new_y;
|
||||
}
|
||||
|
||||
void transform_point (float &x, float &y) const
|
||||
{
|
||||
transform_distance (x, y);
|
||||
x += x0;
|
||||
y += y0;
|
||||
}
|
||||
|
||||
void transform_extents (hb_extents_t &extents) const
|
||||
{
|
||||
float quad_x[4], quad_y[4];
|
||||
|
||||
quad_x[0] = extents.xmin;
|
||||
quad_y[0] = extents.ymin;
|
||||
quad_x[1] = extents.xmin;
|
||||
quad_y[1] = extents.ymax;
|
||||
quad_x[2] = extents.xmax;
|
||||
quad_y[2] = extents.ymin;
|
||||
quad_x[3] = extents.xmax;
|
||||
quad_y[3] = extents.ymax;
|
||||
|
||||
extents = hb_extents_t {};
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
transform_point (quad_x[i], quad_y[i]);
|
||||
extents.add_point (quad_x[i], quad_y[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void transform (const hb_transform_t &o) { multiply (o); }
|
||||
|
||||
void translate (float x, float y)
|
||||
{
|
||||
if (x == 0.f && y == 0.f)
|
||||
return;
|
||||
|
||||
x0 += xx * x + xy * y;
|
||||
y0 += yx * x + yy * y;
|
||||
}
|
||||
|
||||
void scale (float scaleX, float scaleY)
|
||||
{
|
||||
if (scaleX == 1.f && scaleY == 1.f)
|
||||
return;
|
||||
|
||||
xx *= scaleX;
|
||||
yx *= scaleX;
|
||||
xy *= scaleY;
|
||||
yy *= scaleY;
|
||||
}
|
||||
|
||||
void rotate (float rotation)
|
||||
{
|
||||
if (rotation == 0.f)
|
||||
return;
|
||||
|
||||
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
|
||||
rotation = rotation * HB_PI;
|
||||
float c;
|
||||
float s;
|
||||
#ifdef HAVE_SINCOSF
|
||||
sincosf (rotation, &s, &c);
|
||||
#else
|
||||
c = cosf (rotation);
|
||||
s = sinf (rotation);
|
||||
#endif
|
||||
auto other = hb_transform_t{c, s, -s, c, 0.f, 0.f};
|
||||
transform (other);
|
||||
}
|
||||
|
||||
void skew (float skewX, float skewY)
|
||||
{
|
||||
if (skewX == 0.f && skewY == 0.f)
|
||||
return;
|
||||
|
||||
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
|
||||
skewX = skewX * HB_PI;
|
||||
skewY = skewY * HB_PI;
|
||||
auto other = hb_transform_t{1.f,
|
||||
skewY ? tanf (skewY) : 0.f,
|
||||
skewX ? tanf (skewX) : 0.f,
|
||||
1.f,
|
||||
0.f, 0.f};
|
||||
transform (other);
|
||||
}
|
||||
|
||||
float xx = 1.f;
|
||||
float yx = 0.f;
|
||||
float xy = 0.f;
|
||||
float yy = 1.f;
|
||||
float x0 = 0.f;
|
||||
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 {
|
||||
UNBOUNDED,
|
||||
BOUNDED,
|
||||
EMPTY,
|
||||
};
|
||||
|
||||
hb_bounds_t (status_t status) : status (status) {}
|
||||
hb_bounds_t (const hb_extents_t &extents) :
|
||||
status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
|
||||
|
||||
void union_ (const hb_bounds_t &o)
|
||||
{
|
||||
if (o.status == UNBOUNDED)
|
||||
status = UNBOUNDED;
|
||||
else if (o.status == BOUNDED)
|
||||
{
|
||||
if (status == EMPTY)
|
||||
*this = o;
|
||||
else if (status == BOUNDED)
|
||||
extents.union_ (o.extents);
|
||||
}
|
||||
}
|
||||
|
||||
void intersect (const hb_bounds_t &o)
|
||||
{
|
||||
if (o.status == EMPTY)
|
||||
status = EMPTY;
|
||||
else if (o.status == BOUNDED)
|
||||
{
|
||||
if (status == UNBOUNDED)
|
||||
*this = o;
|
||||
else if (status == BOUNDED)
|
||||
{
|
||||
extents.intersect (o.extents);
|
||||
if (extents.is_empty ())
|
||||
status = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status_t status;
|
||||
hb_extents_t extents;
|
||||
};
|
||||
|
||||
struct hb_transform_decomposed_t
|
||||
{
|
||||
float translateX = 0;
|
||||
float translateY = 0;
|
||||
float rotation = 0; // in degrees, counter-clockwise
|
||||
float scaleX = 1;
|
||||
float scaleY = 1;
|
||||
float skewX = 0; // in degrees, counter-clockwise
|
||||
float skewY = 0; // in degrees, counter-clockwise
|
||||
float tCenterX = 0;
|
||||
float tCenterY = 0;
|
||||
|
||||
operator bool () const
|
||||
{
|
||||
return translateX || translateY ||
|
||||
rotation ||
|
||||
scaleX != 1 || scaleY != 1 ||
|
||||
skewX || skewY ||
|
||||
tCenterX || tCenterY;
|
||||
}
|
||||
|
||||
hb_transform_t to_transform () const
|
||||
{
|
||||
hb_transform_t t;
|
||||
t.translate (translateX + tCenterX, translateY + tCenterY);
|
||||
t.rotate (rotation);
|
||||
t.scale (scaleX, scaleY);
|
||||
t.skew (-skewX, skewY);
|
||||
t.translate (-tCenterX, -tCenterY);
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_GEOMETRY_HH */
|
||||
@ -324,6 +324,16 @@ struct hb_is_sink_of
|
||||
(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
|
||||
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
|
||||
|
||||
unsigned operator () (unsigned _) const { return _; }
|
||||
}
|
||||
HB_FUNCOBJ (hb_len_of);
|
||||
|
||||
/* Range-based 'for' for iterables. */
|
||||
|
||||
template <typename Iterable,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user