mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1853822
- Update harfbuzz to 8.2.1 r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D188542
This commit is contained in:
parent
28a5efa435
commit
7beb9aa584
@ -1,12 +1,55 @@
|
||||
Overview of changes leading to 8.2.1
|
||||
Monday, September 18, 2023
|
||||
====================================
|
||||
- Unicode 15.1 support.
|
||||
|
||||
|
||||
Overview of changes leading to 8.2.0
|
||||
Friday, September 8, 2023
|
||||
====================================
|
||||
- Various build and fuzzing fixes
|
||||
- Improvements to COLRv1 painting.
|
||||
|
||||
- New API:
|
||||
+hb_paint_color_glyph_func_t
|
||||
+hb_paint_funcs_set_color_glyph_func
|
||||
+hb_paint_color_glyph
|
||||
|
||||
|
||||
Overview of changes leading to 8.1.1
|
||||
Wednesday, August 2, 2023
|
||||
====================================
|
||||
- Fix shaping of contextual rules at the end of string, introduced in 8.1.0
|
||||
- Fix stack-overflow in repacker with malicious fonts.
|
||||
- 30% speed up loading Noto Duployan font.
|
||||
|
||||
|
||||
Overview of changes leading to 8.1.0
|
||||
Tuesday, August 1, 2023
|
||||
====================================
|
||||
- Fix long-standing build issue with the AIX compiler and older Apple clang.
|
||||
|
||||
- Revert optimization that could cause timeout during subsetting with malicious fonts.
|
||||
|
||||
- More optimization work:
|
||||
- 45% speed up in shaping Noto Duployan font.
|
||||
- 10% speed up in subsetting Noto Duployan font.
|
||||
- Another 8% speed up in shaping Gulzar.
|
||||
- 5% speed up in loading Roboto.
|
||||
|
||||
- New API:
|
||||
+hb_ot_layout_collect_features_map()
|
||||
|
||||
|
||||
Overview of changes leading to 8.0.1
|
||||
Wednesday, July 12, 2023
|
||||
====================================
|
||||
- Build fix on 32-bit arm.
|
||||
- Build fix on 32-bit ARM.
|
||||
|
||||
- More speed optimizations:
|
||||
- 60% speedup in retaingids subsetting SourceHanSans-VF.
|
||||
- 38% speed up in subsetting (beyond-64k) mega-merged Noto.
|
||||
- 60% speed up in retain-gid (used for IFT) subsetting of SourceHanSans-VF.
|
||||
- 16% speed up in retain-gid (used for IFT) subsetting of NotoSansCJKkr.
|
||||
- 38% speed up in subsetting (beyond-64k) mega-merged Noto.
|
||||
|
||||
|
||||
Overview of changes leading to 8.0.0
|
||||
@ -21,7 +64,7 @@ Sunday, July 9, 2023
|
||||
|
||||
For example fonts making use of the WASM shaper, see:
|
||||
|
||||
https://github.com/simoncozens/wasm-examples
|
||||
https://github.com/harfbuzz/harfbuzz-wasm-examples
|
||||
|
||||
- Improvements to Experimental features introduced in earlier releases:
|
||||
- Support for subsetting beyond-64k and VarComposites fonts.
|
||||
|
@ -12,8 +12,9 @@
|
||||
|
||||
HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also
|
||||
[Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome,
|
||||
ChromeOS, Firefox, GNOME, GTK+, KDE, LibreOffice, OpenJDK, PlayStation, Qt,
|
||||
XeTeX, and other places.
|
||||
ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX,
|
||||
PlayStation, Microsoft Edge, Photoshop, Illustrator, InDesign,
|
||||
and other places.
|
||||
|
||||
For bug reports, mailing list, and other information please visit:
|
||||
|
||||
@ -28,8 +29,8 @@ For user manual as well as API documentation, check: https://harfbuzz.github.io
|
||||
## Download
|
||||
|
||||
For tarball releases of HarfBuzz, look [here][3]. At the same place you
|
||||
will also find Win32/Win64 binary bundles that include libharfbuzz DLL,
|
||||
hb-view.exe, hb-shape.exe, and all dependencies.
|
||||
will also find Win32/Win64 binary bundles that include `libharfbuzz` DLL,
|
||||
`hb-view.exe`, `hb-shape.exe`, and all dependencies.
|
||||
|
||||
The canonical source tree is available on [github][4].
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[8.0.1],
|
||||
[8.2.1],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
@ -20,11 +20,11 @@ origin:
|
||||
|
||||
# Human-readable identifier for this version/release
|
||||
# Generally "version NNN", "tag SSS", "bookmark SSS"
|
||||
release: 8.0.1 (2023-07-12T08:27:25+03:00).
|
||||
release: 8.2.1 (2023-09-18T21:18:49+03:00).
|
||||
|
||||
# Revision to pull in
|
||||
# Must be a long or short commit SHA (long preferred)
|
||||
revision: 8.0.1
|
||||
revision: 8.2.1
|
||||
|
||||
# The package's license, where possible using the mnemonic from
|
||||
# https://spdx.org/licenses/
|
||||
|
@ -53,6 +53,7 @@ struct Paint;
|
||||
struct hb_paint_context_t :
|
||||
hb_dispatch_context_t<hb_paint_context_t>
|
||||
{
|
||||
const char *get_name () { return "PAINT"; }
|
||||
template <typename T>
|
||||
return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
|
||||
static return_t default_return_value () { return hb_empty_t (); }
|
||||
@ -68,6 +69,8 @@ public:
|
||||
unsigned int palette_index;
|
||||
hb_color_t foreground;
|
||||
VarStoreInstancer &instancer;
|
||||
hb_map_t current_glyphs;
|
||||
hb_map_t current_layers;
|
||||
int depth_left = HB_MAX_NESTING_LEVEL;
|
||||
int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
|
||||
|
||||
@ -261,6 +264,7 @@ struct Variable
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
value.paint_glyph (c, varIdxBase);
|
||||
}
|
||||
|
||||
@ -281,7 +285,7 @@ struct Variable
|
||||
public:
|
||||
VarIdx varIdxBase;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4 + T::static_size);
|
||||
DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -315,6 +319,7 @@ struct NoVariable
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
value.paint_glyph (c, varIdxBase);
|
||||
}
|
||||
|
||||
@ -332,7 +337,7 @@ struct NoVariable
|
||||
|
||||
T value;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (T::static_size);
|
||||
DEFINE_SIZE_MIN (T::min_size);
|
||||
};
|
||||
|
||||
// Color structures
|
||||
@ -558,6 +563,7 @@ struct Affine2x3
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
c->funcs->push_transform (c->data,
|
||||
xx.to_float (c->instancer (varIdxBase, 0)),
|
||||
yx.to_float (c->instancer (varIdxBase, 1)),
|
||||
@ -639,6 +645,7 @@ struct PaintSolid
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
hb_bool_t is_foreground;
|
||||
hb_color_t color;
|
||||
|
||||
@ -693,6 +700,7 @@ struct PaintLinearGradient
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
hb_color_line_t cl = {
|
||||
(void *) &(this+colorLine),
|
||||
(this+colorLine).static_get_color_stops, c,
|
||||
@ -759,6 +767,7 @@ struct PaintRadialGradient
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
hb_color_line_t cl = {
|
||||
(void *) &(this+colorLine),
|
||||
(this+colorLine).static_get_color_stops, c,
|
||||
@ -823,6 +832,7 @@ struct PaintSweepGradient
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
hb_color_line_t cl = {
|
||||
(void *) &(this+colorLine),
|
||||
(this+colorLine).static_get_color_stops, c,
|
||||
@ -874,6 +884,7 @@ struct PaintGlyph
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
c->funcs->push_inverse_root_transform (c->data, c->font);
|
||||
c->funcs->push_clip_glyph (c->data, gid, c->font);
|
||||
c->funcs->push_root_transform (c->data, c->font);
|
||||
@ -946,6 +957,7 @@ struct PaintTransform
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
(this+transform).paint_glyph (c);
|
||||
c->recurse (this+src);
|
||||
c->funcs->pop_transform (c->data);
|
||||
@ -990,6 +1002,7 @@ struct PaintTranslate
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float ddx = dx + c->instancer (varIdxBase, 0);
|
||||
float ddy = dy + c->instancer (varIdxBase, 1);
|
||||
|
||||
@ -1038,6 +1051,7 @@ struct PaintScale
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
|
||||
float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
|
||||
|
||||
@ -1088,6 +1102,7 @@ struct PaintScaleAroundCenter
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
|
||||
float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
|
||||
float tCenterX = centerX + c->instancer (varIdxBase, 2);
|
||||
@ -1141,6 +1156,7 @@ struct PaintScaleUniform
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float s = scale.to_float (c->instancer (varIdxBase, 0));
|
||||
|
||||
bool p1 = c->funcs->push_scale (c->data, s, s);
|
||||
@ -1188,6 +1204,7 @@ struct PaintScaleUniformAroundCenter
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float s = scale.to_float (c->instancer (varIdxBase, 0));
|
||||
float tCenterX = centerX + c->instancer (varIdxBase, 1);
|
||||
float tCenterY = centerY + c->instancer (varIdxBase, 2);
|
||||
@ -1239,6 +1256,7 @@ struct PaintRotate
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float a = angle.to_float (c->instancer (varIdxBase, 0));
|
||||
|
||||
bool p1 = c->funcs->push_rotate (c->data, a);
|
||||
@ -1286,6 +1304,7 @@ struct PaintRotateAroundCenter
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float a = angle.to_float (c->instancer (varIdxBase, 0));
|
||||
float tCenterX = centerX + c->instancer (varIdxBase, 1);
|
||||
float tCenterY = centerY + c->instancer (varIdxBase, 2);
|
||||
@ -1340,6 +1359,7 @@ struct PaintSkew
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
|
||||
float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
|
||||
|
||||
@ -1390,6 +1410,7 @@ struct PaintSkewAroundCenter
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
|
||||
float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
|
||||
float tCenterX = centerX + c->instancer (varIdxBase, 2);
|
||||
@ -1425,8 +1446,10 @@ struct PaintComposite
|
||||
auto *out = c->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
if (!out->src.serialize_subset (c, src, this, instancer)) return_trace (false);
|
||||
return_trace (out->backdrop.serialize_subset (c, backdrop, this, instancer));
|
||||
bool ret = false;
|
||||
ret |= out->src.serialize_subset (c, src, this, instancer);
|
||||
ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -1440,6 +1463,7 @@ struct PaintComposite
|
||||
|
||||
void paint_glyph (hb_paint_context_t *c) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
c->recurse (this+backdrop);
|
||||
c->funcs->push_group (c->data);
|
||||
c->recurse (this+src);
|
||||
@ -1898,15 +1922,16 @@ struct LayerList : Array32OfOffset32To<Paint>
|
||||
auto *out = c->serializer->start_embed (this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
bool ret = false;
|
||||
for (const auto& _ : + hb_enumerate (*this)
|
||||
| hb_filter (c->plan->colrv1_layers, hb_first))
|
||||
|
||||
{
|
||||
auto *o = out->serialize_append (c->serializer);
|
||||
if (unlikely (!o) || !o->serialize_subset (c, _.second, this, instancer))
|
||||
return_trace (false);
|
||||
if (unlikely (!o)) return_trace (false);
|
||||
ret |= o->serialize_subset (c, _.second, this, instancer);
|
||||
}
|
||||
return_trace (true);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -2284,6 +2309,7 @@ struct COLR
|
||||
&(this+varIdxMap),
|
||||
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)
|
||||
{
|
||||
@ -2399,18 +2425,42 @@ hb_paint_context_t::recurse (const Paint &paint)
|
||||
|
||||
void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
|
||||
for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
|
||||
{
|
||||
if (unlikely (c->current_layers.has (i)))
|
||||
continue;
|
||||
|
||||
c->current_layers.add (i);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
|
||||
{
|
||||
TRACE_PAINT (this);
|
||||
|
||||
if (unlikely (c->current_glyphs.has (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);
|
||||
|
||||
const COLR *colr_table = c->get_colr_table ();
|
||||
const Paint *paint = colr_table->get_base_glyph_paint (gid);
|
||||
|
||||
@ -2429,6 +2479,8 @@ 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 */
|
||||
|
@ -439,6 +439,16 @@ 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; }
|
||||
|
||||
template <typename set_t>
|
||||
void collect_coverage (hb_vector_t<set_t> &sets) const
|
||||
{
|
||||
for (const auto &offset : coverage)
|
||||
{
|
||||
const auto &cov = this+offset;
|
||||
cov.collect_coverage (sets.push ());
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -492,6 +502,15 @@ struct MarkGlyphSets
|
||||
}
|
||||
}
|
||||
|
||||
template <typename set_t>
|
||||
void collect_coverage (hb_vector_t<set_t> &sets) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1: u.format1.collect_coverage (sets); return;
|
||||
default:return;
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
@ -856,6 +875,10 @@ struct GDEF
|
||||
hb_blob_destroy (table.get_blob ());
|
||||
table = hb_blob_get_empty ();
|
||||
}
|
||||
|
||||
#ifndef HB_NO_GDEF_CACHE
|
||||
table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
|
||||
#endif
|
||||
}
|
||||
~accelerator_t () { table.destroy (); }
|
||||
|
||||
@ -879,8 +902,18 @@ struct GDEF
|
||||
|
||||
}
|
||||
|
||||
bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
|
||||
{
|
||||
return
|
||||
#ifndef HB_NO_GDEF_CACHE
|
||||
mark_glyph_set_digests[set_index].may_have (glyph_id) &&
|
||||
#endif
|
||||
table->mark_set_covers (set_index, glyph_id);
|
||||
}
|
||||
|
||||
hb_blob_ptr_t<GDEF> table;
|
||||
#ifndef HB_NO_GDEF_CACHE
|
||||
hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
|
||||
mutable hb_cache_t<21, 3, 8> glyph_props_cache;
|
||||
#endif
|
||||
};
|
||||
|
@ -65,14 +65,15 @@ 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);
|
||||
offset->serialize_subset (c, matrixZ[i], this);
|
||||
ret |= offset->serialize_subset (c, matrixZ[i], this);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
return_trace (ret);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -24,16 +24,17 @@ struct EntryExitRecord
|
||||
(src_base+exitAnchor).collect_variation_indices (c);
|
||||
}
|
||||
|
||||
EntryExitRecord* subset (hb_subset_context_t *c,
|
||||
const void *src_base) const
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const void *src_base) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (nullptr);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
|
||||
out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
|
||||
return_trace (out);
|
||||
bool ret = false;
|
||||
ret |= out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
|
||||
ret |= out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -91,7 +92,13 @@ struct CursivePosFormat1
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
|
||||
if (unlikely (!coverage.sanitize (c, this)))
|
||||
return_trace (false);
|
||||
|
||||
if (c->lazy_some_gpos)
|
||||
return_trace (entryExitRecord.sanitize_shallow (c));
|
||||
else
|
||||
return_trace (entryExitRecord.sanitize (c, this));
|
||||
}
|
||||
|
||||
bool intersects (const hb_set_t *glyphs) const
|
||||
@ -119,10 +126,11 @@ struct CursivePosFormat1
|
||||
hb_buffer_t *buffer = c->buffer;
|
||||
|
||||
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
|
||||
if (!this_record.entryAnchor) return_trace (false);
|
||||
if (!this_record.entryAnchor ||
|
||||
unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
|
||||
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
|
||||
skippy_iter.reset_fast (buffer->idx, 1);
|
||||
skippy_iter.reset_fast (buffer->idx);
|
||||
unsigned unsafe_from;
|
||||
if (unlikely (!skippy_iter.prev (&unsafe_from)))
|
||||
{
|
||||
@ -131,7 +139,8 @@ struct CursivePosFormat1
|
||||
}
|
||||
|
||||
const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
|
||||
if (!prev_record.exitAnchor)
|
||||
if (!prev_record.exitAnchor ||
|
||||
unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this)))
|
||||
{
|
||||
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
|
||||
return_trace (false);
|
||||
@ -200,8 +209,8 @@ struct CursivePosFormat1
|
||||
* Arabic. */
|
||||
unsigned int child = i;
|
||||
unsigned int parent = j;
|
||||
hb_position_t x_offset = entry_x - exit_x;
|
||||
hb_position_t y_offset = entry_y - exit_y;
|
||||
hb_position_t x_offset = roundf (entry_x - exit_x);
|
||||
hb_position_t y_offset = roundf (entry_y - exit_y);
|
||||
if (!(c->lookup_props & LookupFlag::RightToLeft))
|
||||
{
|
||||
unsigned int k = child;
|
||||
|
@ -27,6 +27,7 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
|
||||
auto *out = c->serializer->start_embed (this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
bool ret = false;
|
||||
for (const auto _ : + hb_zip (coverage, *this)
|
||||
| hb_filter (glyphset, hb_first))
|
||||
{
|
||||
@ -38,13 +39,13 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
|
||||
+ hb_range (src.rows * class_count)
|
||||
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
|
||||
;
|
||||
matrix->serialize_subset (c,
|
||||
_.second,
|
||||
this,
|
||||
src.rows,
|
||||
indexes);
|
||||
ret |= matrix->serialize_subset (c,
|
||||
_.second,
|
||||
this,
|
||||
src.rows,
|
||||
indexes);
|
||||
}
|
||||
return_trace (this->len);
|
||||
return_trace (ret);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -82,10 +82,10 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
|
||||
| hb_map (hb_second)
|
||||
;
|
||||
|
||||
bool ret = false;
|
||||
unsigned new_length = 0;
|
||||
for (const auto& mark_record : mark_iter) {
|
||||
if (unlikely (!mark_record.subset (c, this, klass_mapping)))
|
||||
return_trace (false);
|
||||
ret |= mark_record.subset (c, this, klass_mapping);
|
||||
new_length++;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
|
||||
HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
|
||||
return_trace (false);
|
||||
|
||||
return_trace (true);
|
||||
return_trace (ret);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -197,9 +197,10 @@ struct MarkBasePosFormat1_2
|
||||
if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
|
||||
return_trace (false);
|
||||
|
||||
out->markArray.serialize_subset (c, markArray, this,
|
||||
(this+markCoverage).iter (),
|
||||
&klass_mapping);
|
||||
if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
|
||||
(this+markCoverage).iter (),
|
||||
&klass_mapping)))
|
||||
return_trace (false);
|
||||
|
||||
unsigned basecount = (this+baseArray).rows;
|
||||
auto base_iter =
|
||||
@ -228,11 +229,9 @@ struct MarkBasePosFormat1_2
|
||||
;
|
||||
}
|
||||
|
||||
out->baseArray.serialize_subset (c, baseArray, this,
|
||||
base_iter.len (),
|
||||
base_indexes.iter ());
|
||||
|
||||
return_trace (true);
|
||||
return_trace (out->baseArray.serialize_subset (c, baseArray, this,
|
||||
base_iter.len (),
|
||||
base_indexes.iter ()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -195,9 +195,10 @@ struct MarkLigPosFormat1_2
|
||||
if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
|
||||
return_trace (false);
|
||||
|
||||
out->markArray.serialize_subset (c, markArray, this,
|
||||
(this+markCoverage).iter (),
|
||||
&klass_mapping);
|
||||
if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
|
||||
(this+markCoverage).iter (),
|
||||
&klass_mapping)))
|
||||
return_trace (false);
|
||||
|
||||
auto new_ligature_coverage =
|
||||
+ hb_iter (this + ligatureCoverage)
|
||||
@ -208,10 +209,9 @@ struct MarkLigPosFormat1_2
|
||||
if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
|
||||
return_trace (false);
|
||||
|
||||
out->ligatureArray.serialize_subset (c, ligatureArray, this,
|
||||
hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
|
||||
|
||||
return_trace (true);
|
||||
return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this,
|
||||
hb_iter (this+ligatureCoverage),
|
||||
classCount, &klass_mapping));
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -100,7 +100,7 @@ struct MarkMarkPosFormat1_2
|
||||
|
||||
/* now we search backwards for a suitable mark glyph until a non-mark glyph */
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
|
||||
skippy_iter.reset_fast (buffer->idx, 1);
|
||||
skippy_iter.reset_fast (buffer->idx);
|
||||
skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
|
||||
unsigned unsafe_from;
|
||||
if (unlikely (!skippy_iter.prev (&unsafe_from)))
|
||||
@ -183,9 +183,10 @@ struct MarkMarkPosFormat1_2
|
||||
if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
|
||||
return_trace (false);
|
||||
|
||||
out->mark1Array.serialize_subset (c, mark1Array, this,
|
||||
(this+mark1Coverage).iter (),
|
||||
&klass_mapping);
|
||||
if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this,
|
||||
(this+mark1Coverage).iter (),
|
||||
&klass_mapping)))
|
||||
return_trace (false);
|
||||
|
||||
unsigned mark2count = (this+mark2Array).rows;
|
||||
auto mark2_iter =
|
||||
@ -214,9 +215,10 @@ struct MarkMarkPosFormat1_2
|
||||
;
|
||||
}
|
||||
|
||||
out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
|
||||
return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
|
||||
mark2_iter.len (),
|
||||
mark2_indexes.iter ()));
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -24,17 +24,16 @@ struct MarkRecord
|
||||
return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
|
||||
}
|
||||
|
||||
MarkRecord *subset (hb_subset_context_t *c,
|
||||
const void *src_base,
|
||||
const hb_map_t *klass_mapping) const
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const void *src_base,
|
||||
const hb_map_t *klass_mapping) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (nullptr);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->klass = klass_mapping->get (klass);
|
||||
out->markAnchor.serialize_subset (c, markAnchor, src_base);
|
||||
return_trace (out);
|
||||
return_trace (out->markAnchor.serialize_subset (c, markAnchor, src_base));
|
||||
}
|
||||
|
||||
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
|
||||
|
@ -110,7 +110,7 @@ struct PairPosFormat1_3
|
||||
if (likely (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, 1);
|
||||
skippy_iter.reset_fast (buffer->idx);
|
||||
unsigned unsafe_to;
|
||||
if (unlikely (!skippy_iter.next (&unsafe_to)))
|
||||
{
|
||||
|
@ -131,7 +131,7 @@ struct PairPosFormat2_4
|
||||
if (likely (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, 1);
|
||||
skippy_iter.reset_fast (buffer->idx);
|
||||
unsigned unsafe_to;
|
||||
if (unlikely (!skippy_iter.next (&unsafe_to)))
|
||||
{
|
||||
@ -163,7 +163,7 @@ struct PairPosFormat2_4
|
||||
|
||||
|
||||
/* Isolate simple kerning and apply it half to each side.
|
||||
* Results in better cursor positinoing / underline drawing.
|
||||
* Results in better cursor positioning / underline drawing.
|
||||
*
|
||||
* Disabled, because causes issues... :-(
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/3408
|
||||
|
@ -23,7 +23,6 @@ struct PairValueRecord
|
||||
* followed by for second glyph */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (Types::HBGlyphID::static_size, values);
|
||||
DEFINE_SIZE_MAX (Types::HBGlyphID::static_size + 2 * Value::static_size * 8 * sizeof (ValueFormat));
|
||||
|
||||
int cmp (hb_codepoint_t k) const
|
||||
{ return secondGlyph.cmp (k); }
|
||||
|
@ -19,7 +19,6 @@ struct Ligature
|
||||
* in writing direction */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (Types::size + 2, component);
|
||||
DEFINE_SIZE_MAX (65536 * Types::HBGlyphID::static_size);
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
|
@ -72,19 +72,14 @@ struct LigatureSet
|
||||
;
|
||||
}
|
||||
|
||||
static bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
|
||||
unsigned int num_ligs = ligature.len;
|
||||
|
||||
#ifndef HB_NO_OT_LIGATURES_FAST_PATH
|
||||
if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 2)
|
||||
#ifndef HB_NO_OT_RULESETS_FAST_PATH
|
||||
if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4)
|
||||
#endif
|
||||
{
|
||||
slow:
|
||||
@ -97,10 +92,12 @@ struct LigatureSet
|
||||
}
|
||||
|
||||
/* This version is optimized for speed by matching the first component
|
||||
* of the ligature here, instead of calling into the ligation code. */
|
||||
* of the ligature here, instead of calling into the ligation code.
|
||||
*
|
||||
* This is replicated in ChainRuleSet and RuleSet. */
|
||||
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
|
||||
skippy_iter.reset (c->buffer->idx, 1);
|
||||
skippy_iter.reset (c->buffer->idx);
|
||||
skippy_iter.set_match_func (match_always, nullptr);
|
||||
skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
|
||||
unsigned unsafe_to;
|
||||
@ -118,6 +115,8 @@ struct LigatureSet
|
||||
goto slow;
|
||||
}
|
||||
}
|
||||
else
|
||||
goto slow;
|
||||
|
||||
bool unsafe_to_concat = false;
|
||||
|
||||
@ -125,7 +124,7 @@ struct LigatureSet
|
||||
{
|
||||
const auto &lig = this+ligature.arrayZ[i];
|
||||
if (unlikely (lig.component.lenP1 <= 1) ||
|
||||
lig.component[1] == first)
|
||||
lig.component.arrayZ[0] == first)
|
||||
{
|
||||
if (lig.apply (c))
|
||||
{
|
||||
|
@ -103,6 +103,63 @@ struct Glyph
|
||||
}
|
||||
}
|
||||
|
||||
bool get_all_points_without_var (const hb_face_t *face,
|
||||
contour_point_vector_t &points /* OUT */) const
|
||||
{
|
||||
switch (type) {
|
||||
case SIMPLE:
|
||||
if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points)))
|
||||
return false;
|
||||
break;
|
||||
case COMPOSITE:
|
||||
{
|
||||
for (auto &item : get_composite_iterator ())
|
||||
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;
|
||||
}
|
||||
|
||||
/* Init phantom points */
|
||||
if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
|
||||
hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
|
||||
{
|
||||
int lsb = 0;
|
||||
int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
|
||||
(int) header->xMin - lsb : 0;
|
||||
HB_UNUSED int tsb = 0;
|
||||
int v_orig = (int) header->yMax +
|
||||
#ifndef HB_NO_VERTICAL
|
||||
((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
;
|
||||
unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid);
|
||||
unsigned v_adv =
|
||||
#ifndef HB_NO_VERTICAL
|
||||
face->table.vmtx->get_advance_without_var_unscaled (gid)
|
||||
#else
|
||||
- face->get_upem ()
|
||||
#endif
|
||||
;
|
||||
phantoms[PHANTOM_LEFT].x = h_delta;
|
||||
phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
|
||||
phantoms[PHANTOM_TOP].y = v_orig;
|
||||
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void update_mtx (const hb_subset_plan_t *plan,
|
||||
int xMin, int xMax,
|
||||
int yMin, int yMax,
|
||||
@ -293,6 +350,7 @@ struct Glyph
|
||||
bool use_my_metrics = true,
|
||||
bool phantom_only = false,
|
||||
hb_array_t<int> coords = hb_array_t<int> (),
|
||||
hb_map_t *current_glyphs = nullptr,
|
||||
unsigned int depth = 0,
|
||||
unsigned *edge_count = nullptr) const
|
||||
{
|
||||
@ -302,6 +360,10 @@ struct Glyph
|
||||
if (unlikely (*edge_count > HB_GLYF_MAX_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);
|
||||
@ -396,10 +458,17 @@ struct Glyph
|
||||
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)))
|
||||
continue;
|
||||
|
||||
current_glyphs->add (item_gid);
|
||||
|
||||
unsigned old_count = all_points.length;
|
||||
|
||||
if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
|
||||
!glyf_accelerator.glyph_for_gid (item.get_gid ())
|
||||
!glyf_accelerator.glyph_for_gid (item_gid)
|
||||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
all_points,
|
||||
@ -410,9 +479,13 @@ struct Glyph
|
||||
use_my_metrics,
|
||||
phantom_only,
|
||||
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);
|
||||
|
||||
@ -448,9 +521,13 @@ struct Glyph
|
||||
all_points.resize (all_points.length - PHANTOM_COUNT);
|
||||
|
||||
if (all_points.length > HB_GLYF_MAX_POINTS)
|
||||
{
|
||||
current_glyphs->del (item_gid);
|
||||
return false;
|
||||
}
|
||||
|
||||
comp_index++;
|
||||
current_glyphs->del (item_gid);
|
||||
}
|
||||
|
||||
if (head_maxp_info && depth == 0)
|
||||
@ -468,6 +545,13 @@ struct Glyph
|
||||
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);
|
||||
@ -485,7 +569,7 @@ struct Glyph
|
||||
unsigned old_count = all_points.length;
|
||||
|
||||
if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
|
||||
!glyf_accelerator.glyph_for_gid (item.get_gid ())
|
||||
!glyf_accelerator.glyph_for_gid (item_gid)
|
||||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
all_points,
|
||||
@ -496,9 +580,13 @@ struct Glyph
|
||||
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);
|
||||
|
||||
@ -514,9 +602,14 @@ struct Glyph
|
||||
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;
|
||||
|
@ -140,6 +140,10 @@ property_names = [
|
||||
'Symbol_Modifier',
|
||||
'Hieroglyph',
|
||||
'Hieroglyph_Joiner',
|
||||
'Hieroglyph_Mark_Begin',
|
||||
'Hieroglyph_Mark_End',
|
||||
'Hieroglyph_Mirror',
|
||||
'Hieroglyph_Modifier',
|
||||
'Hieroglyph_Segment_Begin',
|
||||
'Hieroglyph_Segment_End',
|
||||
# Indic_Positional_Category
|
||||
@ -234,10 +238,14 @@ def is_HIEROGLYPH(U, UISC, UDI, UGC, AJT):
|
||||
return UISC == Hieroglyph
|
||||
def is_HIEROGLYPH_JOINER(U, UISC, UDI, UGC, AJT):
|
||||
return UISC == Hieroglyph_Joiner
|
||||
def is_HIEROGLYPH_MIRROR(U, UISC, UDI, UGC, AJT):
|
||||
return UISC == Hieroglyph_Mirror
|
||||
def is_HIEROGLYPH_MOD(U, UISC, UDI, UGC, AJT):
|
||||
return UISC == Hieroglyph_Modifier
|
||||
def is_HIEROGLYPH_SEGMENT_BEGIN(U, UISC, UDI, UGC, AJT):
|
||||
return UISC == Hieroglyph_Segment_Begin
|
||||
return UISC in [Hieroglyph_Mark_Begin, Hieroglyph_Segment_Begin]
|
||||
def is_HIEROGLYPH_SEGMENT_END(U, UISC, UDI, UGC, AJT):
|
||||
return UISC == Hieroglyph_Segment_End
|
||||
return UISC in [Hieroglyph_Mark_End, Hieroglyph_Segment_End]
|
||||
def is_INVISIBLE_STACKER(U, UISC, UDI, UGC, AJT):
|
||||
# Split off of HALANT
|
||||
return (UISC == Invisible_Stacker
|
||||
@ -290,6 +298,8 @@ use_mapping = {
|
||||
'HN': is_HALANT_NUM,
|
||||
'IS': is_INVISIBLE_STACKER,
|
||||
'G': is_HIEROGLYPH,
|
||||
'HM': is_HIEROGLYPH_MOD,
|
||||
'HR': is_HIEROGLYPH_MIRROR,
|
||||
'J': is_HIEROGLYPH_JOINER,
|
||||
'SB': is_HIEROGLYPH_SEGMENT_BEGIN,
|
||||
'SE': is_HIEROGLYPH_SEGMENT_END,
|
||||
@ -336,6 +346,8 @@ use_positions = {
|
||||
'Blw': [Bottom],
|
||||
},
|
||||
'H': None,
|
||||
'HM': None,
|
||||
'HR': None,
|
||||
'HVM': None,
|
||||
'IS': None,
|
||||
'B': None,
|
||||
|
@ -72,7 +72,7 @@ struct ClassDef : public OT::ClassDef
|
||||
class_def_link->width = SmallTypes::size;
|
||||
class_def_link->objidx = class_def_prime_id;
|
||||
class_def_link->position = link_position;
|
||||
class_def_prime_vertex.parents.push (parent_id);
|
||||
class_def_prime_vertex.add_parent (parent_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ struct Coverage : public OT::Layout::Common::Coverage
|
||||
coverage_link->width = SmallTypes::size;
|
||||
coverage_link->objidx = coverage_prime_id;
|
||||
coverage_link->position = link_position;
|
||||
coverage_prime_vertex.parents.push (parent_id);
|
||||
coverage_prime_vertex.add_parent (parent_id);
|
||||
|
||||
return (Coverage*) coverage_prime_vertex.obj.head;
|
||||
}
|
||||
|
@ -43,12 +43,28 @@ struct graph_t
|
||||
{
|
||||
hb_serialize_context_t::object_t obj;
|
||||
int64_t distance = 0 ;
|
||||
int64_t space = 0 ;
|
||||
hb_vector_t<unsigned> parents;
|
||||
unsigned space = 0 ;
|
||||
unsigned start = 0;
|
||||
unsigned end = 0;
|
||||
unsigned priority = 0;
|
||||
private:
|
||||
unsigned incoming_edges_ = 0;
|
||||
unsigned single_parent = (unsigned) -1;
|
||||
hb_hashmap_t<unsigned, unsigned> parents;
|
||||
public:
|
||||
|
||||
auto parents_iter () const HB_AUTO_RETURN
|
||||
(
|
||||
hb_concat (
|
||||
hb_iter (&single_parent, single_parent != (unsigned) -1),
|
||||
parents.keys_ref ()
|
||||
)
|
||||
)
|
||||
|
||||
bool in_error () const
|
||||
{
|
||||
return parents.in_error ();
|
||||
}
|
||||
|
||||
bool link_positions_valid (unsigned num_objects, bool removed_nil)
|
||||
{
|
||||
@ -143,7 +159,9 @@ struct graph_t
|
||||
hb_swap (a.obj, b.obj);
|
||||
hb_swap (a.distance, b.distance);
|
||||
hb_swap (a.space, b.space);
|
||||
hb_swap (a.single_parent, b.single_parent);
|
||||
hb_swap (a.parents, b.parents);
|
||||
hb_swap (a.incoming_edges_, b.incoming_edges_);
|
||||
hb_swap (a.start, b.start);
|
||||
hb_swap (a.end, b.end);
|
||||
hb_swap (a.priority, b.priority);
|
||||
@ -154,6 +172,7 @@ struct graph_t
|
||||
{
|
||||
hb_hashmap_t<unsigned, unsigned> result;
|
||||
|
||||
result.alloc (obj.real_links.length);
|
||||
for (const auto& l : obj.real_links) {
|
||||
result.set (l.position, l.objidx);
|
||||
}
|
||||
@ -163,22 +182,76 @@ struct graph_t
|
||||
|
||||
bool is_shared () const
|
||||
{
|
||||
return parents.length > 1;
|
||||
return parents.get_population () > 1;
|
||||
}
|
||||
|
||||
unsigned incoming_edges () const
|
||||
{
|
||||
return parents.length;
|
||||
if (HB_DEBUG_SUBSET_REPACK)
|
||||
{
|
||||
assert (incoming_edges_ == (single_parent != (unsigned) -1) +
|
||||
(parents.values_ref () | hb_reduce (hb_add, 0)));
|
||||
}
|
||||
return incoming_edges_;
|
||||
}
|
||||
|
||||
void reset_parents ()
|
||||
{
|
||||
incoming_edges_ = 0;
|
||||
single_parent = (unsigned) -1;
|
||||
parents.reset ();
|
||||
}
|
||||
|
||||
void add_parent (unsigned parent_index)
|
||||
{
|
||||
assert (parent_index != (unsigned) -1);
|
||||
if (incoming_edges_ == 0)
|
||||
{
|
||||
single_parent = parent_index;
|
||||
incoming_edges_ = 1;
|
||||
return;
|
||||
}
|
||||
else if (single_parent != (unsigned) -1)
|
||||
{
|
||||
assert (incoming_edges_ == 1);
|
||||
if (!parents.set (single_parent, 1))
|
||||
return;
|
||||
single_parent = (unsigned) -1;
|
||||
}
|
||||
|
||||
unsigned *v;
|
||||
if (parents.has (parent_index, &v))
|
||||
{
|
||||
(*v)++;
|
||||
incoming_edges_++;
|
||||
}
|
||||
else if (parents.set (parent_index, 1))
|
||||
incoming_edges_++;
|
||||
}
|
||||
|
||||
void remove_parent (unsigned parent_index)
|
||||
{
|
||||
unsigned count = parents.length;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
if (parent_index == single_parent)
|
||||
{
|
||||
if (parents.arrayZ[i] != parent_index) continue;
|
||||
parents.remove_unordered (i);
|
||||
break;
|
||||
single_parent = (unsigned) -1;
|
||||
incoming_edges_--;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned *v;
|
||||
if (parents.has (parent_index, &v))
|
||||
{
|
||||
incoming_edges_--;
|
||||
if (*v > 1)
|
||||
(*v)--;
|
||||
else
|
||||
parents.del (parent_index);
|
||||
|
||||
if (incoming_edges_ == 1)
|
||||
{
|
||||
single_parent = *parents.keys ();
|
||||
parents.reset ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,20 +272,53 @@ struct graph_t
|
||||
}
|
||||
}
|
||||
|
||||
void remap_parents (const hb_vector_t<unsigned>& id_map)
|
||||
bool remap_parents (const hb_vector_t<unsigned>& id_map)
|
||||
{
|
||||
unsigned count = parents.length;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
parents.arrayZ[i] = id_map[parents.arrayZ[i]];
|
||||
if (single_parent != (unsigned) -1)
|
||||
{
|
||||
assert (single_parent < id_map.length);
|
||||
single_parent = id_map[single_parent];
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_hashmap_t<unsigned, unsigned> new_parents;
|
||||
new_parents.alloc (parents.get_population ());
|
||||
for (auto _ : parents)
|
||||
{
|
||||
assert (_.first < id_map.length);
|
||||
assert (!new_parents.has (id_map[_.first]));
|
||||
new_parents.set (id_map[_.first], _.second);
|
||||
}
|
||||
|
||||
if (parents.in_error() || new_parents.in_error ())
|
||||
return false;
|
||||
|
||||
parents = std::move (new_parents);
|
||||
return true;
|
||||
}
|
||||
|
||||
void remap_parent (unsigned old_index, unsigned new_index)
|
||||
{
|
||||
unsigned count = parents.length;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
if (single_parent != (unsigned) -1)
|
||||
{
|
||||
if (parents.arrayZ[i] == old_index)
|
||||
parents.arrayZ[i] = new_index;
|
||||
if (single_parent == old_index)
|
||||
single_parent = new_index;
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned *pv;
|
||||
if (parents.has (old_index, &pv))
|
||||
{
|
||||
unsigned v = *pv;
|
||||
if (!parents.set (new_index, v))
|
||||
incoming_edges_ -= v;
|
||||
parents.del (old_index);
|
||||
|
||||
if (incoming_edges_ == 1)
|
||||
{
|
||||
single_parent = *parents.keys ();
|
||||
parents.reset ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,6 +474,18 @@ struct graph_t
|
||||
return root ().equals (other.root (), *this, other, 0);
|
||||
}
|
||||
|
||||
void print () const {
|
||||
for (int i = vertices_.length - 1; i >= 0; i--)
|
||||
{
|
||||
const auto& v = vertices_[i];
|
||||
printf("%d: %u [", i, (unsigned int)v.table_size());
|
||||
for (const auto &l : v.obj.real_links) {
|
||||
printf("%u, ", l.objidx);
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Sorts links of all objects in a consistent manner and zeroes all offsets.
|
||||
void normalize ()
|
||||
{
|
||||
@ -419,7 +537,7 @@ struct graph_t
|
||||
link->width = 2;
|
||||
link->objidx = child_id;
|
||||
link->position = (char*) offset - (char*) v.obj.head;
|
||||
vertices_[child_id].parents.push (parent_id);
|
||||
vertices_[child_id].add_parent (parent_id);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -465,7 +583,7 @@ struct graph_t
|
||||
{
|
||||
unsigned next_id = queue.pop_minimum().second;
|
||||
|
||||
hb_swap (sorted_graph[new_id], vertices_[next_id]);
|
||||
sorted_graph[new_id] = std::move (vertices_[next_id]);
|
||||
const vertex_t& next = sorted_graph[new_id];
|
||||
|
||||
if (unlikely (!check_success(new_id >= 0))) {
|
||||
@ -493,8 +611,8 @@ struct graph_t
|
||||
check_success (!queue.in_error ());
|
||||
check_success (!sorted_graph.in_error ());
|
||||
|
||||
remap_all_obj_indices (id_map, &sorted_graph);
|
||||
hb_swap (vertices_, sorted_graph);
|
||||
check_success (remap_all_obj_indices (id_map, &sorted_graph));
|
||||
vertices_ = std::move (sorted_graph);
|
||||
|
||||
if (!check_success (new_id == -1))
|
||||
print_orphaned_nodes ();
|
||||
@ -605,7 +723,7 @@ struct graph_t
|
||||
{
|
||||
unsigned child_idx = index_for_offset (node_idx, offset);
|
||||
auto& child = vertices_[child_idx];
|
||||
for (unsigned p : child.parents)
|
||||
for (unsigned p : child.parents_iter ())
|
||||
{
|
||||
if (p != node_idx) {
|
||||
return duplicate (node_idx, child_idx);
|
||||
@ -688,12 +806,15 @@ struct graph_t
|
||||
subgraph.set (root_idx, wide_parents (root_idx, parents));
|
||||
find_subgraph (root_idx, subgraph);
|
||||
}
|
||||
if (subgraph.in_error ())
|
||||
return false;
|
||||
|
||||
unsigned original_root_idx = root_idx ();
|
||||
hb_map_t index_map;
|
||||
bool made_changes = false;
|
||||
for (auto entry : subgraph.iter ())
|
||||
{
|
||||
assert (entry.first < vertices_.length);
|
||||
const auto& node = vertices_[entry.first];
|
||||
unsigned subgraph_incoming_edges = entry.second;
|
||||
|
||||
@ -749,10 +870,10 @@ struct graph_t
|
||||
{
|
||||
for (const auto& link : vertices_[node_idx].obj.all_links ())
|
||||
{
|
||||
const uint32_t *v;
|
||||
hb_codepoint_t *v;
|
||||
if (subgraph.has (link.objidx, &v))
|
||||
{
|
||||
subgraph.set (link.objidx, *v + 1);
|
||||
(*v)++;
|
||||
continue;
|
||||
}
|
||||
subgraph.set (link.objidx, 1);
|
||||
@ -824,7 +945,7 @@ struct graph_t
|
||||
new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
|
||||
|
||||
auto& child = vertices_[child_id];
|
||||
child.parents.push (new_parent_idx);
|
||||
child.add_parent (new_parent_idx);
|
||||
|
||||
old_v.remove_real_link (child_id, old_offset);
|
||||
child.remove_parent (old_parent_idx);
|
||||
@ -868,18 +989,18 @@ struct graph_t
|
||||
clone->obj.tail = child.obj.tail;
|
||||
clone->distance = child.distance;
|
||||
clone->space = child.space;
|
||||
clone->parents.reset ();
|
||||
clone->reset_parents ();
|
||||
|
||||
unsigned clone_idx = vertices_.length - 2;
|
||||
for (const auto& l : child.obj.real_links)
|
||||
{
|
||||
clone->obj.real_links.push (l);
|
||||
vertices_[l.objidx].parents.push (clone_idx);
|
||||
vertices_[l.objidx].add_parent (clone_idx);
|
||||
}
|
||||
for (const auto& l : child.obj.virtual_links)
|
||||
{
|
||||
clone->obj.virtual_links.push (l);
|
||||
vertices_[l.objidx].parents.push (clone_idx);
|
||||
vertices_[l.objidx].add_parent (clone_idx);
|
||||
}
|
||||
|
||||
check_success (!clone->obj.real_links.in_error ());
|
||||
@ -1008,13 +1129,13 @@ struct graph_t
|
||||
{
|
||||
update_parents();
|
||||
|
||||
if (root().parents)
|
||||
if (root().incoming_edges ())
|
||||
// Root cannot have parents.
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < root_idx (); i++)
|
||||
{
|
||||
if (!vertices_[i].parents)
|
||||
if (!vertices_[i].incoming_edges ())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -1078,14 +1199,14 @@ struct graph_t
|
||||
parents_invalid = true;
|
||||
update_parents();
|
||||
|
||||
if (root().parents) {
|
||||
if (root().incoming_edges ()) {
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges.");
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < root_idx (); i++)
|
||||
{
|
||||
const auto& v = vertices_[i];
|
||||
if (!v.parents)
|
||||
if (!v.incoming_edges ())
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i);
|
||||
}
|
||||
}
|
||||
@ -1117,6 +1238,8 @@ struct graph_t
|
||||
|
||||
unsigned space_for (unsigned index, unsigned* root = nullptr) const
|
||||
{
|
||||
loop:
|
||||
assert (index < vertices_.length);
|
||||
const auto& node = vertices_[index];
|
||||
if (node.space)
|
||||
{
|
||||
@ -1125,14 +1248,15 @@ struct graph_t
|
||||
return node.space;
|
||||
}
|
||||
|
||||
if (!node.parents)
|
||||
if (!node.incoming_edges ())
|
||||
{
|
||||
if (root)
|
||||
*root = index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return space_for (node.parents[0], root);
|
||||
index = *node.parents_iter ();
|
||||
goto loop;
|
||||
}
|
||||
|
||||
void err_other_error () { this->successful = false; }
|
||||
@ -1156,12 +1280,8 @@ struct graph_t
|
||||
unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
|
||||
{
|
||||
unsigned count = 0;
|
||||
hb_set_t visited;
|
||||
for (unsigned p : vertices_[node_idx].parents)
|
||||
for (unsigned p : vertices_[node_idx].parents_iter ())
|
||||
{
|
||||
if (visited.has (p)) continue;
|
||||
visited.add (p);
|
||||
|
||||
// Only real links can be wide
|
||||
for (const auto& l : vertices_[p].obj.real_links)
|
||||
{
|
||||
@ -1191,20 +1311,18 @@ struct graph_t
|
||||
unsigned count = vertices_.length;
|
||||
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
vertices_.arrayZ[i].parents.reset ();
|
||||
vertices_.arrayZ[i].reset_parents ();
|
||||
|
||||
for (unsigned p = 0; p < count; p++)
|
||||
{
|
||||
for (auto& l : vertices_.arrayZ[p].obj.all_links ())
|
||||
{
|
||||
vertices_[l.objidx].parents.push (p);
|
||||
}
|
||||
vertices_[l.objidx].add_parent (p);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
// parents arrays must be accurate or downstream operations like cycle detection
|
||||
// and sorting won't work correctly.
|
||||
check_success (!vertices_.arrayZ[i].parents.in_error ());
|
||||
check_success (!vertices_.arrayZ[i].in_error ());
|
||||
|
||||
parents_invalid = false;
|
||||
}
|
||||
@ -1248,12 +1366,8 @@ struct graph_t
|
||||
// (such as a fibonacci queue) with a fast decrease priority.
|
||||
unsigned count = vertices_.length;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
if (i == vertices_.length - 1)
|
||||
vertices_.arrayZ[i].distance = 0;
|
||||
else
|
||||
vertices_.arrayZ[i].distance = hb_int_max (int64_t);
|
||||
}
|
||||
vertices_.arrayZ[i].distance = hb_int_max (int64_t);
|
||||
vertices_.tail ().distance = 0;
|
||||
|
||||
hb_priority_queue_t queue;
|
||||
queue.insert (0, vertices_.length - 1);
|
||||
@ -1273,15 +1387,15 @@ struct graph_t
|
||||
{
|
||||
if (visited[link.objidx]) continue;
|
||||
|
||||
const auto& child = vertices_[link.objidx].obj;
|
||||
const auto& child = vertices_.arrayZ[link.objidx].obj;
|
||||
unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
|
||||
int64_t child_weight = (child.tail - child.head) +
|
||||
((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1);
|
||||
((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1);
|
||||
int64_t child_distance = next_distance + child_weight;
|
||||
|
||||
if (child_distance < vertices_[link.objidx].distance)
|
||||
if (child_distance < vertices_.arrayZ[link.objidx].distance)
|
||||
{
|
||||
vertices_[link.objidx].distance = child_distance;
|
||||
vertices_.arrayZ[link.objidx].distance = child_distance;
|
||||
queue.insert (child_distance, link.objidx);
|
||||
}
|
||||
}
|
||||
@ -1309,7 +1423,7 @@ struct graph_t
|
||||
unsigned old_idx = link.objidx;
|
||||
link.objidx = new_idx;
|
||||
vertices_[old_idx].remove_parent (parent_idx);
|
||||
vertices_[new_idx].parents.push (parent_idx);
|
||||
vertices_[new_idx].add_parent (parent_idx);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1337,18 +1451,20 @@ struct graph_t
|
||||
/*
|
||||
* Updates all objidx's in all links using the provided mapping.
|
||||
*/
|
||||
void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
|
||||
bool remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
|
||||
hb_vector_t<vertex_t>* sorted_graph) const
|
||||
{
|
||||
unsigned count = sorted_graph->length;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
(*sorted_graph)[i].remap_parents (id_map);
|
||||
if (!(*sorted_graph)[i].remap_parents (id_map))
|
||||
return false;
|
||||
for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
|
||||
{
|
||||
link.objidx = id_map[link.objidx];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1379,7 +1495,7 @@ struct graph_t
|
||||
for (const auto& l : v.obj.all_links ())
|
||||
find_connected_nodes (l.objidx, targets, visited, connected);
|
||||
|
||||
for (unsigned p : v.parents)
|
||||
for (unsigned p : v.parents_iter ())
|
||||
find_connected_nodes (p, targets, visited, connected);
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ struct gsubgpos_graph_context_t
|
||||
graph_t& graph;
|
||||
unsigned lookup_list_index;
|
||||
hb_hashmap_t<unsigned, graph::Lookup*> lookups;
|
||||
|
||||
hb_hashmap_t<unsigned, unsigned> subtable_to_extension;
|
||||
|
||||
HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
|
||||
graph_t& graph_);
|
||||
|
@ -225,7 +225,7 @@ struct Lookup : public OT::Lookup
|
||||
if (is_ext)
|
||||
{
|
||||
unsigned ext_id = create_extension_subtable (c, subtable_id, type);
|
||||
c.graph.vertices_[subtable_id].parents.push (ext_id);
|
||||
c.graph.vertices_[subtable_id].add_parent (ext_id);
|
||||
subtable_id = ext_id;
|
||||
}
|
||||
|
||||
@ -234,7 +234,7 @@ struct Lookup : public OT::Lookup
|
||||
link->objidx = subtable_id;
|
||||
link->position = (char*) &new_lookup->subTable[offset_index++] -
|
||||
(char*) new_lookup;
|
||||
c.graph.vertices_[subtable_id].parents.push (this_index);
|
||||
c.graph.vertices_[subtable_id].add_parent (this_index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,24 +299,35 @@ struct Lookup : public OT::Lookup
|
||||
unsigned subtable_index)
|
||||
{
|
||||
unsigned type = lookupType;
|
||||
unsigned ext_index = -1;
|
||||
unsigned* existing_ext_index = nullptr;
|
||||
if (c.subtable_to_extension.has(subtable_index, &existing_ext_index)) {
|
||||
ext_index = *existing_ext_index;
|
||||
} else {
|
||||
ext_index = create_extension_subtable(c, subtable_index, type);
|
||||
c.subtable_to_extension.set(subtable_index, ext_index);
|
||||
}
|
||||
|
||||
unsigned ext_index = create_extension_subtable(c, subtable_index, type);
|
||||
if (ext_index == (unsigned) -1)
|
||||
return false;
|
||||
|
||||
auto& subtable_vertex = c.graph.vertices_[subtable_index];
|
||||
auto& lookup_vertex = c.graph.vertices_[lookup_index];
|
||||
for (auto& l : lookup_vertex.obj.real_links.writer ())
|
||||
{
|
||||
if (l.objidx == subtable_index)
|
||||
if (l.objidx == subtable_index) {
|
||||
// Change lookup to point at the extension.
|
||||
l.objidx = ext_index;
|
||||
if (existing_ext_index)
|
||||
subtable_vertex.remove_parent(lookup_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Make extension point at the subtable.
|
||||
auto& ext_vertex = c.graph.vertices_[ext_index];
|
||||
auto& subtable_vertex = c.graph.vertices_[subtable_index];
|
||||
ext_vertex.parents.push (lookup_index);
|
||||
subtable_vertex.remap_parent (lookup_index, ext_index);
|
||||
ext_vertex.add_parent (lookup_index);
|
||||
if (!existing_ext_index)
|
||||
subtable_vertex.remap_parent (lookup_index, ext_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -318,7 +318,9 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
|
||||
{
|
||||
hb_vector_t<class_info_t> class_to_info;
|
||||
|
||||
unsigned class_count= classCount;
|
||||
unsigned class_count = classCount;
|
||||
if (!class_count) return class_to_info;
|
||||
|
||||
if (!class_to_info.resize (class_count))
|
||||
return hb_vector_t<class_info_t>();
|
||||
|
||||
|
@ -419,7 +419,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
|
||||
class_def_link->width = SmallTypes::size;
|
||||
class_def_link->objidx = class_def_2_id;
|
||||
class_def_link->position = 10;
|
||||
graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id);
|
||||
graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id);
|
||||
graph.duplicate (pair_pos_prime_id, class_def_2_id);
|
||||
|
||||
return pair_pos_prime_id;
|
||||
|
@ -851,43 +851,41 @@ struct StateTableDriver
|
||||
*
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/2860
|
||||
*/
|
||||
const EntryT *wouldbe_entry;
|
||||
bool safe_to_break =
|
||||
/* 1. */
|
||||
!c->is_actionable (this, entry)
|
||||
&&
|
||||
/* 2. */
|
||||
(
|
||||
/* 2a. */
|
||||
state == StateTableT::STATE_START_OF_TEXT
|
||||
||
|
||||
/* 2b. */
|
||||
(
|
||||
(entry.flags & context_t::DontAdvance) &&
|
||||
next_state == StateTableT::STATE_START_OF_TEXT
|
||||
)
|
||||
||
|
||||
/* 2c. */
|
||||
(
|
||||
wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass)
|
||||
,
|
||||
/* 2c'. */
|
||||
!c->is_actionable (this, *wouldbe_entry)
|
||||
&&
|
||||
/* 2c". */
|
||||
(
|
||||
next_state == machine.new_state (wouldbe_entry->newState)
|
||||
&&
|
||||
(entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance)
|
||||
)
|
||||
)
|
||||
)
|
||||
&&
|
||||
/* 3. */
|
||||
!c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT))
|
||||
;
|
||||
|
||||
if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
|
||||
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 = [&]()
|
||||
{
|
||||
/* 1. */
|
||||
if (c->is_actionable (this, entry))
|
||||
return false;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 3. */
|
||||
return !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT));
|
||||
};
|
||||
|
||||
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);
|
||||
|
@ -111,13 +111,13 @@ struct TrackData
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!trackTableEntry) return 0.;
|
||||
if (!trackTableEntry) return 0;
|
||||
|
||||
/*
|
||||
* Choose size.
|
||||
*/
|
||||
unsigned int sizes = nSizes;
|
||||
if (!sizes) return 0.;
|
||||
if (!sizes) return 0;
|
||||
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
|
||||
|
||||
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
|
@ -367,6 +367,10 @@ struct
|
||||
hb_enable_if (std::is_integral<T>::value && sizeof (T) > sizeof (uint32_t))> constexpr auto
|
||||
impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */)
|
||||
|
||||
template <typename T,
|
||||
hb_enable_if (std::is_floating_point<T>::value)> constexpr auto
|
||||
impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, fasthash32 (std::addressof (v), sizeof (T), 0xf437ffe6))
|
||||
|
||||
template <typename T> constexpr auto
|
||||
impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v)))
|
||||
|
||||
|
@ -93,7 +93,7 @@ struct hb_bimap_t
|
||||
auto iter () const HB_AUTO_RETURN (+ forw_map.iter())
|
||||
};
|
||||
|
||||
/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
|
||||
/* Incremental bimap: only lhs is given, rhs is incrementally assigned */
|
||||
struct hb_inc_bimap_t
|
||||
{
|
||||
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
|
||||
|
@ -97,6 +97,7 @@ struct hb_bit_page_t
|
||||
static inline constexpr unsigned len ()
|
||||
{ return ARRAY_LENGTH_CONST (v); }
|
||||
|
||||
operator bool () const { return !is_empty (); }
|
||||
bool is_empty () const
|
||||
{
|
||||
if (has_population ()) return !population;
|
||||
@ -218,6 +219,7 @@ struct hb_bit_page_t
|
||||
return count;
|
||||
}
|
||||
|
||||
bool operator == (const hb_bit_page_t &other) const { return is_equal (other); }
|
||||
bool is_equal (const hb_bit_page_t &other) const
|
||||
{
|
||||
for (unsigned i = 0; i < len (); i++)
|
||||
@ -225,6 +227,7 @@ struct hb_bit_page_t
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
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
|
||||
{
|
||||
if (has_population () && larger_page.has_population () &&
|
||||
|
@ -30,7 +30,6 @@
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-bit-page.hh"
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
|
||||
struct hb_bit_set_t
|
||||
@ -183,6 +182,16 @@ struct hb_bit_set_t
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Duplicated here from hb-machinery.hh to avoid including it. */
|
||||
template<typename Type>
|
||||
static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
return * reinterpret_cast<const Type*> ((const char *) P + offset);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||
{
|
||||
@ -904,7 +913,7 @@ struct hb_bit_set_t
|
||||
|
||||
/* The extra page_map length is necessary; can't just rely on vector here,
|
||||
* since the next check would be tricked because a null page also has
|
||||
* major==0, which we can't distinguish from an actualy major==0 page... */
|
||||
* major==0, which we can't distinguish from an actually major==0 page... */
|
||||
unsigned i = last_page_lookup;
|
||||
if (likely (i < page_map.length))
|
||||
{
|
||||
@ -938,7 +947,7 @@ struct hb_bit_set_t
|
||||
|
||||
/* The extra page_map length is necessary; can't just rely on vector here,
|
||||
* since the next check would be tricked because a null page also has
|
||||
* major==0, which we can't distinguish from an actualy major==0 page... */
|
||||
* major==0, which we can't distinguish from an actually major==0 page... */
|
||||
unsigned i = last_page_lookup;
|
||||
if (likely (i < page_map.length))
|
||||
{
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
#line 33 "hb-buffer-deserialize-json.hh"
|
||||
#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,
|
||||
@ -555,12 +555,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
|
||||
hb_glyph_info_t info = {0};
|
||||
hb_glyph_position_t pos = {0};
|
||||
|
||||
#line 552 "hb-buffer-deserialize-json.hh"
|
||||
#line 559 "hb-buffer-deserialize-json.hh"
|
||||
{
|
||||
cs = deserialize_json_start;
|
||||
}
|
||||
|
||||
#line 555 "hb-buffer-deserialize-json.hh"
|
||||
#line 564 "hb-buffer-deserialize-json.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
@ -772,7 +772,7 @@ _resume:
|
||||
*end_ptr = p;
|
||||
}
|
||||
break;
|
||||
#line 733 "hb-buffer-deserialize-json.hh"
|
||||
#line 776 "hb-buffer-deserialize-json.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
#line 33 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
#line 36 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
static const unsigned char _deserialize_text_glyphs_trans_keys[] = {
|
||||
0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u,
|
||||
48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u,
|
||||
@ -349,12 +349,12 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
|
||||
hb_glyph_info_t info = {0};
|
||||
hb_glyph_position_t pos = {0};
|
||||
|
||||
#line 346 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
#line 353 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
{
|
||||
cs = deserialize_text_glyphs_start;
|
||||
}
|
||||
|
||||
#line 349 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
#line 358 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
@ -550,7 +550,7 @@ _resume:
|
||||
*end_ptr = p;
|
||||
}
|
||||
break;
|
||||
#line 516 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
#line 554 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
@ -667,7 +667,7 @@ _again:
|
||||
*end_ptr = p;
|
||||
}
|
||||
break;
|
||||
#line 616 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
#line 671 "hb-buffer-deserialize-text-glyphs.hh"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
#line 33 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 36 "hb-buffer-deserialize-text-unicode.hh"
|
||||
static const unsigned char _deserialize_text_unicode_trans_keys[] = {
|
||||
0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u,
|
||||
9u, 124u, 0
|
||||
@ -197,12 +197,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
|
||||
hb_glyph_info_t info = {0};
|
||||
const hb_glyph_position_t pos = {0};
|
||||
|
||||
#line 194 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 201 "hb-buffer-deserialize-text-unicode.hh"
|
||||
{
|
||||
cs = deserialize_text_unicode_start;
|
||||
}
|
||||
|
||||
#line 197 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 206 "hb-buffer-deserialize-text-unicode.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
@ -269,7 +269,7 @@ _resume:
|
||||
*end_ptr = p;
|
||||
}
|
||||
break;
|
||||
#line 256 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 273 "hb-buffer-deserialize-text-unicode.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
@ -307,7 +307,7 @@ _again:
|
||||
*end_ptr = p;
|
||||
}
|
||||
break;
|
||||
#line 289 "hb-buffer-deserialize-text-unicode.hh"
|
||||
#line 311 "hb-buffer-deserialize-text-unicode.hh"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -499,12 +499,12 @@ hb_buffer_t::set_masks (hb_mask_t value,
|
||||
unsigned int cluster_start,
|
||||
unsigned int cluster_end)
|
||||
{
|
||||
hb_mask_t not_mask = ~mask;
|
||||
value &= mask;
|
||||
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
hb_mask_t not_mask = ~mask;
|
||||
value &= mask;
|
||||
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
|
||||
@ -1327,7 +1327,7 @@ hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)
|
||||
* Sets the #hb_codepoint_t that replaces characters not found in
|
||||
* the font during shaping.
|
||||
*
|
||||
* The not-found glyph defaults to zero, sometimes knows as the
|
||||
* The not-found glyph defaults to zero, sometimes known as the
|
||||
* ".notdef" glyph. This API allows for differentiating the two.
|
||||
*
|
||||
* Since: 3.1.0
|
||||
@ -2076,7 +2076,7 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
|
||||
* hb_buffer_diff:
|
||||
* @buffer: a buffer.
|
||||
* @reference: other buffer to compare to.
|
||||
* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
|
||||
* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1.
|
||||
* @position_fuzz: allowed absolute difference in position values.
|
||||
*
|
||||
* If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
|
||||
|
@ -99,7 +99,7 @@ typedef struct hb_glyph_info_t {
|
||||
* layout, by avoiding re-shaping of each line
|
||||
* after line-breaking, by limiting the
|
||||
* reshaping to a small piece around the
|
||||
* breaking positin only, even if the breaking
|
||||
* breaking position only, even if the breaking
|
||||
* position carries the
|
||||
* #HB_GLYPH_FLAG_UNSAFE_TO_BREAK or when
|
||||
* hyphenation or other text transformation
|
||||
|
@ -464,13 +464,16 @@ struct hb_buffer_t
|
||||
start, end,
|
||||
true);
|
||||
}
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
HB_ALWAYS_INLINE
|
||||
#endif
|
||||
void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
|
||||
{
|
||||
if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
|
||||
return;
|
||||
_set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
|
||||
start, end,
|
||||
true);
|
||||
false);
|
||||
}
|
||||
void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
|
||||
{
|
||||
@ -478,6 +481,9 @@ struct hb_buffer_t
|
||||
start, end,
|
||||
true, true);
|
||||
}
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
HB_ALWAYS_INLINE
|
||||
#endif
|
||||
void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
|
||||
{
|
||||
if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
|
||||
|
@ -166,6 +166,32 @@ hb_cairo_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_cairo_paint_color_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
|
||||
void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_font_t *font,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
|
||||
cairo_t *cr = c->cr;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
hb_position_t x_scale, y_scale;
|
||||
hb_font_get_scale (font, &x_scale, &y_scale);
|
||||
cairo_scale (cr, x_scale, y_scale);
|
||||
|
||||
cairo_glyph_t cairo_glyph = { glyph, 0, 0 };
|
||||
cairo_set_scaled_font (cr, c->scaled_font);
|
||||
cairo_set_font_size (cr, 1);
|
||||
cairo_show_glyphs (cr, &cairo_glyph, 1);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
|
||||
void *paint_data,
|
||||
@ -397,6 +423,7 @@ static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<
|
||||
|
||||
hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr);
|
||||
hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr);
|
||||
hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr);
|
||||
hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr);
|
||||
hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr);
|
||||
hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr);
|
||||
|
@ -815,7 +815,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag)
|
||||
}
|
||||
|
||||
const char *p = *pp;
|
||||
while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
|
||||
while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '['))
|
||||
(*pp)++;
|
||||
|
||||
if (p == *pp || *pp - p > 4)
|
||||
|
@ -183,7 +183,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef HB_OPTIMIZE_SIZE_MORE
|
||||
#define HB_NO_OT_LIGATURES_FAST_PATH
|
||||
#define HB_NO_OT_RULESETS_FAST_PATH
|
||||
#endif
|
||||
|
||||
#ifdef HB_MINIMIZE_MEMORY_USAGE
|
||||
|
@ -265,8 +265,9 @@ static inline void _hb_warn_no_return (bool returned)
|
||||
}
|
||||
}
|
||||
template <>
|
||||
/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
|
||||
{}
|
||||
/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED) {}
|
||||
template <>
|
||||
/*static*/ inline void _hb_warn_no_return<void> (bool returned HB_UNUSED) {}
|
||||
|
||||
template <int max_level, typename ret_t>
|
||||
struct hb_auto_trace_t
|
||||
@ -450,12 +451,26 @@ struct hb_no_trace_t {
|
||||
#define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0)
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_PAINT
|
||||
#define HB_DEBUG_PAINT (HB_DEBUG+0)
|
||||
#endif
|
||||
#if HB_DEBUG_PAINT
|
||||
#define TRACE_PAINT(this) \
|
||||
HB_UNUSED hb_auto_trace_t<HB_DEBUG_PAINT, void> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_PAINT(this) HB_UNUSED hb_no_trace_t<void> trace
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HB_DEBUG_DISPATCH
|
||||
#define HB_DEBUG_DISPATCH ( \
|
||||
HB_DEBUG_APPLY + \
|
||||
HB_DEBUG_SANITIZE + \
|
||||
HB_DEBUG_SERIALIZE + \
|
||||
HB_DEBUG_SUBSET + \
|
||||
HB_DEBUG_PAINT + \
|
||||
0)
|
||||
#endif
|
||||
#if HB_DEBUG_DISPATCH
|
||||
|
@ -1066,7 +1066,7 @@ hb_font_get_nominal_glyph (hb_font_t *font,
|
||||
* @glyph_stride: The stride between successive glyph IDs
|
||||
*
|
||||
* Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
|
||||
* IDs must be returned in a #hb_codepoint_t output parameter. Stopes at the
|
||||
* IDs must be returned in a #hb_codepoint_t output parameter. Stops at the
|
||||
* first unsupported glyph ID.
|
||||
*
|
||||
* Return value: the number of code points processed
|
||||
|
@ -105,6 +105,8 @@ struct hb_ft_paint_context_t
|
||||
FT_Color *palette;
|
||||
unsigned palette_index;
|
||||
hb_color_t foreground;
|
||||
hb_map_t current_glyphs;
|
||||
hb_map_t current_layers;
|
||||
int depth_left = HB_MAX_NESTING_LEVEL;
|
||||
int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
|
||||
};
|
||||
@ -220,9 +222,18 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
|
||||
&paint.u.colr_layers.layer_iterator,
|
||||
&other_paint))
|
||||
{
|
||||
unsigned i = paint.u.colr_layers.layer_iterator.layer;
|
||||
|
||||
if (unlikely (c->current_layers.has (i)))
|
||||
continue;
|
||||
|
||||
c->current_layers.add (i);
|
||||
|
||||
c->funcs->push_group (c->data);
|
||||
c->recurse (other_paint);
|
||||
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
|
||||
|
||||
c->current_layers.del (i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -320,8 +331,27 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
|
||||
break;
|
||||
case FT_COLR_PAINTFORMAT_COLR_GLYPH:
|
||||
{
|
||||
hb_codepoint_t gid = paint.u.colr_glyph.glyphID;
|
||||
|
||||
if (unlikely (c->current_glyphs.has (gid)))
|
||||
return;
|
||||
|
||||
c->current_glyphs.add (gid);
|
||||
|
||||
c->funcs->push_inverse_root_transform (c->data, c->font);
|
||||
c->ft_font->lock.unlock ();
|
||||
if (c->funcs->color_glyph (c->data, gid, c->font))
|
||||
{
|
||||
c->ft_font->lock.lock ();
|
||||
c->funcs->pop_transform (c->data);
|
||||
c->current_glyphs.del (gid);
|
||||
return;
|
||||
}
|
||||
c->ft_font->lock.lock ();
|
||||
c->funcs->pop_transform (c->data);
|
||||
|
||||
FT_OpaquePaint other_paint = {0};
|
||||
if (FT_Get_Color_Glyph_Paint (ft_face, paint.u.colr_glyph.glyphID,
|
||||
if (FT_Get_Color_Glyph_Paint (ft_face, gid,
|
||||
FT_COLOR_NO_ROOT_TRANSFORM,
|
||||
&other_paint))
|
||||
{
|
||||
@ -350,6 +380,8 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
|
||||
|
||||
if (has_clip_box)
|
||||
c->funcs->pop_clip (c->data);
|
||||
|
||||
c->current_glyphs.del (gid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -474,6 +506,7 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
|
||||
hb_ft_paint_context_t c (ft_font, font,
|
||||
paint_funcs, paint_data,
|
||||
palette, palette_index, foreground);
|
||||
c.current_glyphs.add (gid);
|
||||
|
||||
bool is_bounded = true;
|
||||
FT_ClipBox clip_box;
|
||||
@ -497,6 +530,7 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
|
||||
hb_ft_paint_context_t ce (ft_font, font,
|
||||
extents_funcs, &extents_data,
|
||||
palette, palette_index, foreground);
|
||||
ce.current_glyphs.add (gid);
|
||||
ce.funcs->push_root_transform (ce.data, font);
|
||||
ce.recurse (paint);
|
||||
ce.funcs->pop_transform (ce.data);
|
||||
|
@ -70,7 +70,7 @@ struct hb_kern_machine_t
|
||||
continue;
|
||||
}
|
||||
|
||||
skippy_iter.reset (idx, 1);
|
||||
skippy_iter.reset (idx);
|
||||
unsigned unsafe_to;
|
||||
if (!skippy_iter.next (&unsafe_to))
|
||||
{
|
||||
|
@ -106,7 +106,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef HB_COLRV1_MAX_EDGE_COUNT
|
||||
#define HB_COLRV1_MAX_EDGE_COUNT 1024
|
||||
#define HB_COLRV1_MAX_EDGE_COUNT 65536
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -131,10 +131,6 @@ static inline Type& StructAfter(TObject &X)
|
||||
unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \
|
||||
DEFINE_SIZE_ARRAY(size, array)
|
||||
|
||||
#define DEFINE_SIZE_MAX(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) <= (size)) \
|
||||
static constexpr unsigned max_size = (size)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
@ -365,7 +365,7 @@ hb_map_update (hb_map_t *map,
|
||||
* @key: (out): Key retrieved
|
||||
* @value: (out): Value retrieved
|
||||
*
|
||||
* Fetches the next key/value paire in @map.
|
||||
* Fetches the next key/value pair in @map.
|
||||
*
|
||||
* Set @idx to -1 to get started.
|
||||
*
|
||||
|
@ -78,6 +78,10 @@ struct hb_hashmap_t
|
||||
hash (0),
|
||||
value () {}
|
||||
|
||||
// Needed for https://github.com/harfbuzz/harfbuzz/issues/4138
|
||||
K& get_key () { return key; }
|
||||
V& get_value () { return value; }
|
||||
|
||||
bool is_used () const { return is_used_; }
|
||||
void set_used (bool is_used) { is_used_ = is_used; }
|
||||
void set_real (bool is_real) { is_real_ = is_real; }
|
||||
@ -272,6 +276,11 @@ struct hb_hashmap_t
|
||||
uint32_t hash = hb_hash (key);
|
||||
return set_with_hash (std::move (key), hash, std::forward<VV> (value), overwrite);
|
||||
}
|
||||
bool add (const K &key)
|
||||
{
|
||||
uint32_t hash = hb_hash (key);
|
||||
return set_with_hash (key, hash, item_t::default_value ());
|
||||
}
|
||||
|
||||
const V& get_with_hash (const K &key, uint32_t hash) const
|
||||
{
|
||||
@ -405,23 +414,21 @@ struct hb_hashmap_t
|
||||
auto keys_ref () const HB_AUTO_RETURN
|
||||
(
|
||||
+ iter_items ()
|
||||
| hb_map (&item_t::key)
|
||||
| hb_map (&item_t::get_key)
|
||||
)
|
||||
auto keys () const HB_AUTO_RETURN
|
||||
(
|
||||
+ iter_items ()
|
||||
| hb_map (&item_t::key)
|
||||
+ keys_ref ()
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
auto values_ref () const HB_AUTO_RETURN
|
||||
(
|
||||
+ iter_items ()
|
||||
| hb_map (&item_t::value)
|
||||
| hb_map (&item_t::get_value)
|
||||
)
|
||||
auto values () const HB_AUTO_RETURN
|
||||
(
|
||||
+ iter_items ()
|
||||
| hb_map (&item_t::value)
|
||||
+ values_ref ()
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
/* Global nul-content Null pool. Enlarge as necessary. */
|
||||
|
||||
#define HB_NULL_POOL_SIZE 520
|
||||
#define HB_NULL_POOL_SIZE 640
|
||||
|
||||
template <typename T, typename>
|
||||
struct _hb_has_min_size : hb_false_type {};
|
||||
@ -48,15 +48,6 @@ template <typename T>
|
||||
using hb_has_min_size = _hb_has_min_size<T, void>;
|
||||
#define hb_has_min_size(T) hb_has_min_size<T>::value
|
||||
|
||||
template <typename T, typename>
|
||||
struct _hb_has_max_size : hb_false_type {};
|
||||
template <typename T>
|
||||
struct _hb_has_max_size<T, hb_void_t<decltype (T::max_size)>>
|
||||
: hb_true_type {};
|
||||
template <typename T>
|
||||
using hb_has_max_size = _hb_has_max_size<T, void>;
|
||||
#define hb_has_max_size(T) hb_has_max_size<T>::value
|
||||
|
||||
template <typename T, typename>
|
||||
struct _hb_has_null_size : hb_false_type {};
|
||||
template <typename T>
|
||||
@ -94,7 +85,7 @@ using hb_null_size = _hb_null_size<T, void>;
|
||||
template <typename T, typename>
|
||||
struct _hb_static_size : hb_integral_constant<unsigned, sizeof (T)> {};
|
||||
template <typename T>
|
||||
struct _hb_static_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::static_size> {};
|
||||
struct _hb_static_size<T, hb_void_t<decltype (T::static_size)>> : hb_integral_constant<unsigned, T::static_size> {};
|
||||
template <typename T>
|
||||
using hb_static_size = _hb_static_size<T, void>;
|
||||
#define hb_static_size(T) hb_static_size<T>::value
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
#line 32 "hb-number-parser.hh"
|
||||
#line 35 "hb-number-parser.hh"
|
||||
static const unsigned char _double_parser_trans_keys[] = {
|
||||
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
|
||||
46u, 101u, 0
|
||||
@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
|
||||
|
||||
int cs;
|
||||
|
||||
#line 132 "hb-number-parser.hh"
|
||||
#line 139 "hb-number-parser.hh"
|
||||
{
|
||||
cs = double_parser_start;
|
||||
}
|
||||
|
||||
#line 135 "hb-number-parser.hh"
|
||||
#line 144 "hb-number-parser.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
@ -198,7 +198,7 @@ _resume:
|
||||
exp_overflow = true;
|
||||
}
|
||||
break;
|
||||
#line 187 "hb-number-parser.hh"
|
||||
#line 202 "hb-number-parser.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
|
@ -718,30 +718,6 @@ struct ArrayOf
|
||||
return_trace (out);
|
||||
}
|
||||
|
||||
/* Special-case ArrayOf Offset16To structs with a maximum size. */
|
||||
template <typename T = Type,
|
||||
typename Base = void,
|
||||
hb_enable_if (hb_has_max_size (typename T::target_t) &&
|
||||
sizeof (T) == 2)>
|
||||
HB_ALWAYS_INLINE
|
||||
bool sanitize (hb_sanitize_context_t *c, const Base *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
unsigned max_len = 65536 + Type::target_t::max_size;
|
||||
|
||||
if (unlikely (c->check_range_fast (base, max_len)))
|
||||
return_trace (true);
|
||||
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!c->dispatch (arrayZ[i], base)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
HB_ALWAYS_INLINE
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
|
@ -1937,13 +1937,22 @@ struct ClassDefFormat2_4
|
||||
{
|
||||
/* Match if there's any glyph that is not listed! */
|
||||
hb_codepoint_t g = HB_SET_VALUE_INVALID;
|
||||
for (auto &range : rangeRecord)
|
||||
hb_codepoint_t last = HB_SET_VALUE_INVALID;
|
||||
auto it = hb_iter (rangeRecord);
|
||||
for (auto &range : it)
|
||||
{
|
||||
if (it->first == last + 1)
|
||||
{
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!glyphs->next (&g))
|
||||
break;
|
||||
if (g < range.first)
|
||||
return true;
|
||||
g = range.last;
|
||||
last = g;
|
||||
}
|
||||
if (g != HB_SET_VALUE_INVALID && glyphs->next (&g))
|
||||
return true;
|
||||
@ -2928,9 +2937,29 @@ struct ConditionFormat1
|
||||
const hb_map_t *index_map = &c->plan->axes_index_map;
|
||||
if (index_map->is_empty ()) return_trace (true);
|
||||
|
||||
if (!index_map->has (axisIndex))
|
||||
const hb_map_t& axes_old_index_tag_map = c->plan->axes_old_index_tag_map;
|
||||
hb_codepoint_t *axis_tag;
|
||||
if (!axes_old_index_tag_map.has (axisIndex, &axis_tag) ||
|
||||
!index_map->has (axisIndex))
|
||||
return_trace (false);
|
||||
|
||||
const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location;
|
||||
Triple axis_limit{-1.f, 0.f, 1.f};
|
||||
Triple *normalized_limit;
|
||||
if (normalized_axes_location.has (*axis_tag, &normalized_limit))
|
||||
axis_limit = *normalized_limit;
|
||||
|
||||
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances;
|
||||
TripleDistances axis_triple_distances{1.f, 1.f};
|
||||
TripleDistances *triple_dists;
|
||||
if (axes_triple_distances.has (*axis_tag, &triple_dists))
|
||||
axis_triple_distances = *triple_dists;
|
||||
|
||||
float normalized_min = renormalizeValue (filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
|
||||
float normalized_max = renormalizeValue (filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
|
||||
out->filterRangeMinValue.set_float (normalized_min);
|
||||
out->filterRangeMaxValue.set_float (normalized_max);
|
||||
|
||||
return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||
}
|
||||
@ -2946,15 +2975,16 @@ struct ConditionFormat1
|
||||
hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
|
||||
|
||||
Triple axis_range (-1.f, 0.f, 1.f);
|
||||
if (c->axes_location->has (axis_tag))
|
||||
axis_range = c->axes_location->get (axis_tag);
|
||||
Triple *axis_limit;
|
||||
if (c->axes_location->has (axis_tag, &axis_limit))
|
||||
axis_range = *axis_limit;
|
||||
|
||||
int axis_min_val = axis_range.minimum;
|
||||
int axis_default_val = axis_range.middle;
|
||||
int axis_max_val = axis_range.maximum;
|
||||
float axis_min_val = axis_range.minimum;
|
||||
float axis_default_val = axis_range.middle;
|
||||
float axis_max_val = axis_range.maximum;
|
||||
|
||||
int16_t filter_min_val = filterRangeMinValue.to_int ();
|
||||
int16_t filter_max_val = filterRangeMaxValue.to_int ();
|
||||
float filter_min_val = filterRangeMinValue.to_float ();
|
||||
float filter_max_val = filterRangeMaxValue.to_float ();
|
||||
|
||||
if (axis_default_val < filter_min_val ||
|
||||
axis_default_val > filter_max_val)
|
||||
@ -2974,7 +3004,9 @@ struct ConditionFormat1
|
||||
{
|
||||
// add axisIndex->value into the hashmap so we can check if the record is
|
||||
// unique with variations
|
||||
hb_codepoint_t val = (filter_max_val << 16) + filter_min_val;
|
||||
int16_t int_filter_max_val = filterRangeMaxValue.to_int ();
|
||||
int16_t int_filter_min_val = filterRangeMinValue.to_int ();
|
||||
hb_codepoint_t val = (int_filter_max_val << 16) + int_filter_min_val;
|
||||
|
||||
condition_map->set (axisIndex, val);
|
||||
return KEEP_COND_WITH_VAR;
|
||||
@ -3183,8 +3215,7 @@ struct FeatureTableSubstitutionRecord
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->featureIndex = c->feature_index_map->get (featureIndex);
|
||||
bool ret = out->feature.serialize_subset (c->subset_context, feature, base, c);
|
||||
return_trace (ret);
|
||||
return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
|
@ -402,16 +402,6 @@ struct hb_ot_apply_context_t :
|
||||
{
|
||||
struct matcher_t
|
||||
{
|
||||
matcher_t () :
|
||||
lookup_props (0),
|
||||
mask (-1),
|
||||
ignore_zwnj (false),
|
||||
ignore_zwj (false),
|
||||
per_syllable (false),
|
||||
syllable {0},
|
||||
match_func (nullptr),
|
||||
match_data (nullptr) {}
|
||||
|
||||
typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
|
||||
|
||||
void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
|
||||
@ -470,14 +460,14 @@ struct hb_ot_apply_context_t :
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int lookup_props;
|
||||
hb_mask_t mask;
|
||||
bool ignore_zwnj;
|
||||
bool ignore_zwj;
|
||||
bool per_syllable;
|
||||
uint8_t syllable;
|
||||
match_func_t match_func;
|
||||
const void *match_data;
|
||||
unsigned int lookup_props = 0;
|
||||
hb_mask_t mask = -1;
|
||||
bool ignore_zwnj = false;
|
||||
bool ignore_zwj = false;
|
||||
bool per_syllable = false;
|
||||
uint8_t syllable = 0;
|
||||
match_func_t match_func = nullptr;
|
||||
const void *match_data = nullptr;
|
||||
};
|
||||
|
||||
struct skipping_iterator_t
|
||||
@ -528,11 +518,9 @@ struct hb_ot_apply_context_t :
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
HB_ALWAYS_INLINE
|
||||
#endif
|
||||
void reset (unsigned int start_index_,
|
||||
unsigned int num_items_)
|
||||
void reset (unsigned int start_index_)
|
||||
{
|
||||
idx = start_index_;
|
||||
num_items = num_items_;
|
||||
end = c->buffer->len;
|
||||
matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
|
||||
}
|
||||
@ -540,17 +528,14 @@ struct hb_ot_apply_context_t :
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
HB_ALWAYS_INLINE
|
||||
#endif
|
||||
void reset_fast (unsigned int start_index_,
|
||||
unsigned int num_items_)
|
||||
void reset_fast (unsigned int start_index_)
|
||||
{
|
||||
// Doesn't set end or syllable. Used by GPOS which doesn't care / change.
|
||||
idx = start_index_;
|
||||
num_items = num_items_;
|
||||
}
|
||||
|
||||
void reject ()
|
||||
{
|
||||
num_items++;
|
||||
backup_glyph_data ();
|
||||
}
|
||||
|
||||
@ -593,12 +578,7 @@ struct hb_ot_apply_context_t :
|
||||
#endif
|
||||
bool next (unsigned *unsafe_to = nullptr)
|
||||
{
|
||||
assert (num_items > 0);
|
||||
/* The alternate condition below is faster at string boundaries,
|
||||
* but produces subpar "unsafe-to-concat" values. */
|
||||
signed stop = (signed) end - (signed) num_items;
|
||||
if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
|
||||
stop = (signed) end - 1;
|
||||
const signed stop = (signed) end - 1;
|
||||
while ((signed) idx < stop)
|
||||
{
|
||||
idx++;
|
||||
@ -606,7 +586,6 @@ struct hb_ot_apply_context_t :
|
||||
{
|
||||
case MATCH:
|
||||
{
|
||||
num_items--;
|
||||
advance_glyph_data ();
|
||||
return true;
|
||||
}
|
||||
@ -629,12 +608,7 @@ struct hb_ot_apply_context_t :
|
||||
#endif
|
||||
bool prev (unsigned *unsafe_from = nullptr)
|
||||
{
|
||||
assert (num_items > 0);
|
||||
/* The alternate condition below is faster at string boundaries,
|
||||
* but produces subpar "unsafe-to-concat" values. */
|
||||
unsigned stop = num_items - 1;
|
||||
if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
|
||||
stop = 1 - 1;
|
||||
const unsigned stop = 0;
|
||||
while (idx > stop)
|
||||
{
|
||||
idx--;
|
||||
@ -642,7 +616,6 @@ struct hb_ot_apply_context_t :
|
||||
{
|
||||
case MATCH:
|
||||
{
|
||||
num_items--;
|
||||
advance_glyph_data ();
|
||||
return true;
|
||||
}
|
||||
@ -661,6 +634,7 @@ struct hb_ot_apply_context_t :
|
||||
return false;
|
||||
}
|
||||
|
||||
HB_ALWAYS_INLINE
|
||||
hb_codepoint_t
|
||||
get_glyph_data ()
|
||||
{
|
||||
@ -671,6 +645,7 @@ struct hb_ot_apply_context_t :
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
HB_ALWAYS_INLINE
|
||||
void
|
||||
advance_glyph_data ()
|
||||
{
|
||||
@ -699,7 +674,6 @@ struct hb_ot_apply_context_t :
|
||||
const HBUINT24 *match_glyph_data24;
|
||||
#endif
|
||||
|
||||
unsigned int num_items;
|
||||
unsigned int end;
|
||||
};
|
||||
|
||||
@ -826,7 +800,7 @@ struct hb_ot_apply_context_t :
|
||||
* match_props has the set index.
|
||||
*/
|
||||
if (match_props & LookupFlag::UseMarkFilteringSet)
|
||||
return gdef.mark_set_covers (match_props >> 16, glyph);
|
||||
return gdef_accel.mark_set_covers (match_props >> 16, glyph);
|
||||
|
||||
/* The second byte of match_props has the meaning
|
||||
* "ignore marks of attachment type different than
|
||||
@ -1198,6 +1172,10 @@ static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
static inline bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
static inline bool match_glyph (hb_glyph_info_t &info, unsigned value, const void *data HB_UNUSED)
|
||||
{
|
||||
return info.codepoint == value;
|
||||
@ -1218,6 +1196,28 @@ static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, co
|
||||
info.syllable() = klass;
|
||||
return klass == value;
|
||||
}
|
||||
static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data)
|
||||
{
|
||||
unsigned klass = info.syllable() & 0x0F;
|
||||
if (klass < 15)
|
||||
return klass == value;
|
||||
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
|
||||
klass = class_def.get_class (info.codepoint);
|
||||
if (likely (klass < 15))
|
||||
info.syllable() = (info.syllable() & 0xF0) | klass;
|
||||
return klass == value;
|
||||
}
|
||||
static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data)
|
||||
{
|
||||
unsigned klass = (info.syllable() & 0xF0) >> 4;
|
||||
if (klass < 15)
|
||||
return klass == value;
|
||||
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
|
||||
klass = class_def.get_class (info.codepoint);
|
||||
if (likely (klass < 15))
|
||||
info.syllable() = (info.syllable() & 0x0F) | (klass << 4);
|
||||
return klass == value;
|
||||
}
|
||||
static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
|
||||
{
|
||||
Offset16To<Coverage> coverage;
|
||||
@ -1265,7 +1265,7 @@ static bool match_input (hb_ot_apply_context_t *c,
|
||||
hb_buffer_t *buffer = c->buffer;
|
||||
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
|
||||
skippy_iter.reset (buffer->idx, count - 1);
|
||||
skippy_iter.reset (buffer->idx);
|
||||
skippy_iter.set_match_func (match_func, match_data);
|
||||
skippy_iter.set_glyph_data (input);
|
||||
|
||||
@ -1505,7 +1505,7 @@ static bool match_backtrack (hb_ot_apply_context_t *c,
|
||||
TRACE_APPLY (nullptr);
|
||||
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
|
||||
skippy_iter.reset (c->buffer->backtrack_len (), count);
|
||||
skippy_iter.reset (c->buffer->backtrack_len ());
|
||||
skippy_iter.set_match_func (match_func, match_data);
|
||||
skippy_iter.set_glyph_data (backtrack);
|
||||
|
||||
@ -1538,7 +1538,7 @@ static bool match_lookahead (hb_ot_apply_context_t *c,
|
||||
TRACE_APPLY (nullptr);
|
||||
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
|
||||
skippy_iter.reset (start_index - 1, count);
|
||||
skippy_iter.reset (start_index - 1);
|
||||
skippy_iter.set_match_func (match_func, match_data);
|
||||
skippy_iter.set_glyph_data (lookahead);
|
||||
|
||||
@ -1913,12 +1913,13 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
|
||||
}
|
||||
|
||||
template <typename HBUINT>
|
||||
static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
|
||||
unsigned int inputCount, /* Including the first glyph (not matched) */
|
||||
const HBUINT input[], /* Array of input values--start with second glyph */
|
||||
unsigned int lookupCount,
|
||||
const LookupRecord lookupRecord[],
|
||||
const ContextApplyLookupContext &lookup_context)
|
||||
HB_ALWAYS_INLINE
|
||||
static bool context_apply_lookup (hb_ot_apply_context_t *c,
|
||||
unsigned int inputCount, /* Including the first glyph (not matched) */
|
||||
const HBUINT input[], /* Array of input values--start with second glyph */
|
||||
unsigned int lookupCount,
|
||||
const LookupRecord lookupRecord[],
|
||||
const ContextApplyLookupContext &lookup_context)
|
||||
{
|
||||
unsigned match_end = 0;
|
||||
unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
|
||||
@ -1944,6 +1945,9 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
|
||||
template <typename Types>
|
||||
struct Rule
|
||||
{
|
||||
template <typename T>
|
||||
friend struct RuleSet;
|
||||
|
||||
bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
return context_intersects (glyphs,
|
||||
@ -2065,7 +2069,6 @@ struct Rule
|
||||
* design order */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (4, inputZ);
|
||||
DEFINE_SIZE_MAX (65536 * (Types::HBUINT::static_size + LookupRecord::static_size));
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
@ -2131,13 +2134,105 @@ struct RuleSet
|
||||
const ContextApplyLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
return_trace (
|
||||
+ hb_iter (rule)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
|
||||
| hb_any
|
||||
)
|
||||
;
|
||||
|
||||
unsigned num_rules = rule.len;
|
||||
|
||||
#ifndef HB_NO_OT_RULESETS_FAST_PATH
|
||||
if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4)
|
||||
#endif
|
||||
{
|
||||
slow:
|
||||
return_trace (
|
||||
+ hb_iter (rule)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
|
||||
| hb_any
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/* This version is optimized for speed by matching the first & second
|
||||
* components of the rule here, instead of calling into the matching code.
|
||||
*
|
||||
* Replicated from LigatureSet::apply(). */
|
||||
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
|
||||
skippy_iter.reset (c->buffer->idx);
|
||||
skippy_iter.set_match_func (match_always, nullptr);
|
||||
skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
|
||||
unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0;
|
||||
hb_glyph_info_t *first = nullptr, *second = nullptr;
|
||||
bool matched = skippy_iter.next ();
|
||||
if (likely (matched))
|
||||
{
|
||||
first = &c->buffer->info[skippy_iter.idx];
|
||||
unsafe_to = skippy_iter.idx + 1;
|
||||
|
||||
if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
|
||||
{
|
||||
/* Can't use the fast path if eg. the next char is a default-ignorable
|
||||
* or other skippable. */
|
||||
goto slow;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Failed to match a next glyph. Only try applying rules that have
|
||||
* no further input. */
|
||||
return_trace (
|
||||
+ hb_iter (rule)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_filter ([&] (const Rule &_) { return _.inputCount <= 1; })
|
||||
| hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
|
||||
| hb_any
|
||||
)
|
||||
;
|
||||
}
|
||||
matched = skippy_iter.next ();
|
||||
if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
|
||||
{
|
||||
second = &c->buffer->info[skippy_iter.idx];
|
||||
unsafe_to2 = skippy_iter.idx + 1;
|
||||
}
|
||||
|
||||
auto match_input = lookup_context.funcs.match;
|
||||
auto *input_data = lookup_context.match_data;
|
||||
for (unsigned int i = 0; i < num_rules; i++)
|
||||
{
|
||||
const auto &r = this+rule.arrayZ[i];
|
||||
|
||||
const auto &input = r.inputZ;
|
||||
|
||||
if (r.inputCount <= 1 ||
|
||||
(!match_input ||
|
||||
match_input (*first, input.arrayZ[0], input_data)))
|
||||
{
|
||||
if (!second ||
|
||||
(r.inputCount <= 2 ||
|
||||
(!match_input ||
|
||||
match_input (*second, input.arrayZ[1], input_data)))
|
||||
)
|
||||
{
|
||||
if (r.apply (c, lookup_context))
|
||||
{
|
||||
if (unsafe_to != (unsigned) -1)
|
||||
c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
|
||||
return_trace (true);
|
||||
}
|
||||
}
|
||||
else
|
||||
unsafe_to = unsafe_to2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unsafe_to == (unsigned) -1)
|
||||
unsafe_to = unsafe_to1;
|
||||
}
|
||||
}
|
||||
if (likely (unsafe_to != (unsigned) -1))
|
||||
c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
|
||||
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
@ -2516,11 +2611,7 @@ struct ContextFormat2_5
|
||||
if (cached && c->buffer->cur().syllable() < 255)
|
||||
index = c->buffer->cur().syllable ();
|
||||
else
|
||||
{
|
||||
index = class_def.get_class (c->buffer->cur().codepoint);
|
||||
if (cached && index < 255)
|
||||
c->buffer->cur().syllable() = index;
|
||||
}
|
||||
const RuleSet &rule_set = this+ruleSet[index];
|
||||
return_trace (rule_set.apply (c, lookup_context));
|
||||
}
|
||||
@ -2914,16 +3005,17 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c
|
||||
}
|
||||
|
||||
template <typename HBUINT>
|
||||
static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
|
||||
unsigned int backtrackCount,
|
||||
const HBUINT backtrack[],
|
||||
unsigned int inputCount, /* Including the first glyph (not matched) */
|
||||
const HBUINT input[], /* Array of input values--start with second glyph */
|
||||
unsigned int lookaheadCount,
|
||||
const HBUINT lookahead[],
|
||||
unsigned int lookupCount,
|
||||
const LookupRecord lookupRecord[],
|
||||
const ChainContextApplyLookupContext &lookup_context)
|
||||
HB_ALWAYS_INLINE
|
||||
static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
|
||||
unsigned int backtrackCount,
|
||||
const HBUINT backtrack[],
|
||||
unsigned int inputCount, /* Including the first glyph (not matched) */
|
||||
const HBUINT input[], /* Array of input values--start with second glyph */
|
||||
unsigned int lookaheadCount,
|
||||
const HBUINT lookahead[],
|
||||
unsigned int lookupCount,
|
||||
const LookupRecord lookupRecord[],
|
||||
const ChainContextApplyLookupContext &lookup_context)
|
||||
{
|
||||
unsigned end_index = c->buffer->idx;
|
||||
unsigned match_end = 0;
|
||||
@ -2962,6 +3054,9 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
|
||||
template <typename Types>
|
||||
struct ChainRule
|
||||
{
|
||||
template <typename T>
|
||||
friend struct ChainRuleSet;
|
||||
|
||||
bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
const auto &input = StructAfter<decltype (inputX)> (backtrack);
|
||||
@ -3148,7 +3243,6 @@ struct ChainRule
|
||||
* design order) */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
DEFINE_SIZE_MAX (65536 * (3 * Types::HBUINT::static_size + LookupRecord::static_size));
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
@ -3211,13 +3305,119 @@ struct ChainRuleSet
|
||||
const ChainContextApplyLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
return_trace (
|
||||
+ hb_iter (rule)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
|
||||
| hb_any
|
||||
)
|
||||
;
|
||||
|
||||
unsigned num_rules = rule.len;
|
||||
|
||||
#ifndef HB_NO_OT_RULESETS_FAST_PATH
|
||||
if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4)
|
||||
#endif
|
||||
{
|
||||
slow:
|
||||
return_trace (
|
||||
+ hb_iter (rule)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
|
||||
| hb_any
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/* This version is optimized for speed by matching the first & second
|
||||
* components of the rule here, instead of calling into the matching code.
|
||||
*
|
||||
* Replicated from LigatureSet::apply(). */
|
||||
|
||||
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
|
||||
skippy_iter.reset (c->buffer->idx);
|
||||
skippy_iter.set_match_func (match_always, nullptr);
|
||||
skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
|
||||
unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0;
|
||||
hb_glyph_info_t *first = nullptr, *second = nullptr;
|
||||
bool matched = skippy_iter.next ();
|
||||
if (likely (matched))
|
||||
{
|
||||
first = &c->buffer->info[skippy_iter.idx];
|
||||
unsafe_to1 = skippy_iter.idx + 1;
|
||||
|
||||
if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
|
||||
{
|
||||
/* Can't use the fast path if eg. the next char is a default-ignorable
|
||||
* or other skippable. */
|
||||
goto slow;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Failed to match a next glyph. Only try applying rules that have
|
||||
* no further input and lookahead. */
|
||||
return_trace (
|
||||
+ hb_iter (rule)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_filter ([&] (const ChainRule &_)
|
||||
{
|
||||
const auto &input = StructAfter<decltype (_.inputX)> (_.backtrack);
|
||||
const auto &lookahead = StructAfter<decltype (_.lookaheadX)> (input);
|
||||
return input.lenP1 <= 1 && lookahead.len == 0;
|
||||
})
|
||||
| hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
|
||||
| hb_any
|
||||
)
|
||||
;
|
||||
}
|
||||
matched = skippy_iter.next ();
|
||||
if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
|
||||
{
|
||||
second = &c->buffer->info[skippy_iter.idx];
|
||||
unsafe_to2 = skippy_iter.idx + 1;
|
||||
}
|
||||
|
||||
auto match_input = lookup_context.funcs.match[1];
|
||||
auto match_lookahead = lookup_context.funcs.match[2];
|
||||
auto *input_data = lookup_context.match_data[1];
|
||||
auto *lookahead_data = lookup_context.match_data[2];
|
||||
for (unsigned int i = 0; i < num_rules; i++)
|
||||
{
|
||||
const auto &r = this+rule.arrayZ[i];
|
||||
|
||||
const auto &input = StructAfter<decltype (r.inputX)> (r.backtrack);
|
||||
const auto &lookahead = StructAfter<decltype (r.lookaheadX)> (input);
|
||||
|
||||
unsigned lenP1 = hb_max ((unsigned) input.lenP1, 1u);
|
||||
if (lenP1 > 1 ?
|
||||
(!match_input ||
|
||||
match_input (*first, input.arrayZ[0], input_data))
|
||||
:
|
||||
(!lookahead.len || !match_lookahead ||
|
||||
match_lookahead (*first, lookahead.arrayZ[0], lookahead_data)))
|
||||
{
|
||||
if (!second ||
|
||||
(lenP1 > 2 ?
|
||||
(!match_input ||
|
||||
match_input (*second, input.arrayZ[1], input_data))
|
||||
:
|
||||
(lookahead.len <= 2 - lenP1 || !match_lookahead ||
|
||||
match_lookahead (*second, lookahead.arrayZ[2 - lenP1], lookahead_data))))
|
||||
{
|
||||
if (r.apply (c, lookup_context))
|
||||
{
|
||||
if (unsafe_to != (unsigned) -1)
|
||||
c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
|
||||
return_trace (true);
|
||||
}
|
||||
}
|
||||
else
|
||||
unsafe_to = unsafe_to2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unsafe_to == (unsigned) -1)
|
||||
unsafe_to = unsafe_to1;
|
||||
}
|
||||
}
|
||||
if (likely (unsafe_to != (unsigned) -1))
|
||||
c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
|
||||
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
@ -3616,26 +3816,22 @@ struct ChainContextFormat2_5
|
||||
const ClassDef &input_class_def = this+inputClassDef;
|
||||
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
|
||||
|
||||
/* For ChainContextFormat2_5 we cache the LookaheadClassDef instead of InputClassDef.
|
||||
* The reason is that most heavy fonts want to identify a glyph in context and apply
|
||||
* a lookup to it. In this scenario, the length of the input sequence is one, whereas
|
||||
* the lookahead / backtrack are typically longer. The one glyph in input sequence is
|
||||
* looked-up below and no input glyph is looked up in individual rules, whereas the
|
||||
* lookahead and backtrack glyphs are tried. Since we match lookahead before backtrack,
|
||||
* we should cache lookahead. This decisions showed a 20% improvement in shaping of
|
||||
* the Gulzar font.
|
||||
*/
|
||||
|
||||
/* match_class_caches1 is slightly faster. Use it for lookahead,
|
||||
* which is typically longer. */
|
||||
struct ChainContextApplyLookupContext lookup_context = {
|
||||
{{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached : match_class,
|
||||
cached && &input_class_def == &lookahead_class_def ? match_class_cached : match_class,
|
||||
cached ? match_class_cached : match_class}},
|
||||
{{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached1 : match_class,
|
||||
cached ? match_class_cached2 : match_class,
|
||||
cached ? match_class_cached1 : match_class}},
|
||||
{&backtrack_class_def,
|
||||
&input_class_def,
|
||||
&lookahead_class_def}
|
||||
};
|
||||
|
||||
index = input_class_def.get_class (c->buffer->cur().codepoint);
|
||||
// Note: Corresponds to match_class_cached2
|
||||
if (cached && ((c->buffer->cur().syllable() & 0xF0) >> 4) < 15)
|
||||
index = (c->buffer->cur().syllable () & 0xF0) >> 4;
|
||||
else
|
||||
index = input_class_def.get_class (c->buffer->cur().codepoint);
|
||||
const ChainRuleSet &rule_set = this+ruleSet[index];
|
||||
return_trace (rule_set.apply (c, lookup_context));
|
||||
}
|
||||
@ -4139,6 +4335,9 @@ struct hb_ot_layout_lookup_accelerator_t
|
||||
bool may_have (hb_codepoint_t g) const
|
||||
{ return digest.may_have (g); }
|
||||
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
HB_ALWAYS_INLINE
|
||||
#endif
|
||||
bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const
|
||||
{
|
||||
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
|
||||
|
@ -1241,7 +1241,7 @@ script_collect_features (hb_collect_features_context_t *c,
|
||||
* terminated by %HB_TAG_NONE
|
||||
* @features: (nullable) (array zero-terminated=1): The array of features to collect,
|
||||
* terminated by %HB_TAG_NONE
|
||||
* @feature_indexes: (out): The array of feature indexes found for the query
|
||||
* @feature_indexes: (out): The set of feature indexes found for the query
|
||||
*
|
||||
* Fetches a list of all feature indexes in the specified face's GSUB table
|
||||
* or GPOS table, underneath the specified scripts, languages, and features.
|
||||
@ -1282,6 +1282,44 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_layout_collect_features_map:
|
||||
* @face: #hb_face_t to work upon
|
||||
* @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
|
||||
* @script_index: The index of the requested script tag
|
||||
* @language_index: The index of the requested language tag
|
||||
* @feature_map: (out): The map of feature tag to feature index.
|
||||
*
|
||||
* Fetches the mapping from feature tags to feature indexes for
|
||||
* the specified script and language.
|
||||
*
|
||||
* Since: 8.1.0
|
||||
**/
|
||||
void
|
||||
hb_ot_layout_collect_features_map (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned script_index,
|
||||
unsigned language_index,
|
||||
hb_map_t *feature_map /* OUT */)
|
||||
{
|
||||
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
||||
|
||||
unsigned int count = l.get_feature_indexes (0, nullptr, nullptr);
|
||||
feature_map->alloc (count);
|
||||
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
unsigned feature_index = 0;
|
||||
unsigned feature_count = 1;
|
||||
l.get_feature_indexes (i, &feature_count, &feature_index);
|
||||
if (!feature_count)
|
||||
break;
|
||||
hb_tag_t feature_tag = g.get_feature_tag (feature_index);
|
||||
feature_map->set (feature_tag, feature_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_ot_layout_collect_lookups:
|
||||
|
@ -324,6 +324,13 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *feature_indexes /* OUT */);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_layout_collect_features_map (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned script_index,
|
||||
unsigned language_index,
|
||||
hb_map_t *feature_map /* OUT */);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_layout_collect_lookups (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
|
@ -239,6 +239,13 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
||||
feature_infos.shrink (j + 1);
|
||||
}
|
||||
|
||||
hb_map_t feature_indices[2];
|
||||
for (unsigned int table_index = 0; table_index < 2; table_index++)
|
||||
hb_ot_layout_collect_features_map (face,
|
||||
table_tags[table_index],
|
||||
script_index[table_index],
|
||||
language_index[table_index],
|
||||
&feature_indices[table_index]);
|
||||
|
||||
/* Allocate bits now */
|
||||
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
|
||||
@ -261,7 +268,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
||||
if (!info->max_value || next_bit + bits_needed >= global_bit_shift)
|
||||
continue; /* Feature disabled, or not enough bits. */
|
||||
|
||||
|
||||
bool found = false;
|
||||
unsigned int feature_index[2];
|
||||
for (unsigned int table_index = 0; table_index < 2; table_index++)
|
||||
@ -269,12 +275,14 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
||||
if (required_feature_tag[table_index] == info->tag)
|
||||
required_feature_stage[table_index] = info->stage[table_index];
|
||||
|
||||
found |= (bool) hb_ot_layout_language_find_feature (face,
|
||||
table_tags[table_index],
|
||||
script_index[table_index],
|
||||
language_index[table_index],
|
||||
info->tag,
|
||||
&feature_index[table_index]);
|
||||
hb_codepoint_t *index;
|
||||
if (feature_indices[table_index].has (info->tag, &index))
|
||||
{
|
||||
feature_index[table_index] = *index;
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
feature_index[table_index] = HB_OT_LAYOUT_NO_FEATURE_INDEX;
|
||||
}
|
||||
if (!found && (info->flags & F_GLOBAL_SEARCH))
|
||||
{
|
||||
|
@ -476,9 +476,18 @@ hb_set_unicode_props (hb_buffer_t *buffer)
|
||||
{
|
||||
_hb_glyph_info_set_unicode_props (&info[i], buffer);
|
||||
|
||||
unsigned gen_cat = _hb_glyph_info_get_general_category (&info[i]);
|
||||
if (FLAG_UNSAFE (gen_cat) &
|
||||
(FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |
|
||||
FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |
|
||||
FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |
|
||||
FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
|
||||
FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR)))
|
||||
continue;
|
||||
|
||||
/* Marks are already set as continuation by the above line.
|
||||
* Handle Emoji_Modifier and ZWJ-continuation. */
|
||||
if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
|
||||
if (unlikely (gen_cat == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
|
||||
hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
|
||||
{
|
||||
_hb_glyph_info_set_continuation (&info[i]);
|
||||
@ -756,6 +765,14 @@ hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
|
||||
_hb_glyph_info_get_general_category (&info[end]) ==
|
||||
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
|
||||
end++;
|
||||
if (start == i || end == i + 1)
|
||||
{
|
||||
if (start == i)
|
||||
buffer->unsafe_to_concat (start, start + 1);
|
||||
if (end == i + 1)
|
||||
buffer->unsafe_to_concat (end - 1, end);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer->unsafe_to_break (start, end);
|
||||
|
||||
@ -1037,7 +1054,7 @@ hb_ot_position_plan (const hb_ot_shape_context_t *c)
|
||||
* direction is backward we don't shift and it will end up
|
||||
* hanging over the next glyph after the final reordering.
|
||||
*
|
||||
* Note: If fallback positinoing happens, we don't care about
|
||||
* Note: If fallback positioning happens, we don't care about
|
||||
* this as it will be overridden.
|
||||
*/
|
||||
bool adjust_offsets_when_zeroing = c->plan->adjust_mark_positioning_when_zeroing &&
|
||||
|
@ -6,10 +6,10 @@
|
||||
*
|
||||
* on files with these headers:
|
||||
*
|
||||
* # ArabicShaping-15.0.0.txt
|
||||
* # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
|
||||
* # Scripts-15.0.0.txt
|
||||
* # Date: 2022-04-26, 23:15:02 GMT
|
||||
* # ArabicShaping-15.1.0.txt
|
||||
* # Date: 2023-01-05
|
||||
* # Scripts-15.1.0.txt
|
||||
* # Date: 2023-07-28, 16:01:07 GMT
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH
|
||||
|
@ -6,10 +6,10 @@
|
||||
*
|
||||
* on files with these headers:
|
||||
*
|
||||
* # ArabicShaping-15.0.0.txt
|
||||
* # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
|
||||
* # Blocks-15.0.0.txt
|
||||
* # Date: 2022-01-28, 20:58:00 GMT [KW]
|
||||
* # ArabicShaping-15.1.0.txt
|
||||
* # Date: 2023-01-05
|
||||
* # Blocks-15.1.0.txt
|
||||
* # Date: 2023-07-28, 15:47:20 GMT
|
||||
* UnicodeData.txt does not have a header.
|
||||
*/
|
||||
|
||||
|
@ -486,8 +486,10 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
|
||||
return;
|
||||
|
||||
/* The Arabic shaper currently always processes in RTL mode, so we should
|
||||
* stretch / position the stretched pieces to the left / preceding glyphs. */
|
||||
bool rtl = buffer->props.direction == HB_DIRECTION_RTL;
|
||||
|
||||
if (!rtl)
|
||||
buffer->reverse ();
|
||||
|
||||
/* We do a two pass implementation:
|
||||
* First pass calculates the exact number of extra glyphs we need,
|
||||
@ -577,7 +579,10 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
++n_copies;
|
||||
hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
|
||||
if (excess > 0)
|
||||
{
|
||||
extra_repeat_overlap = excess / (n_copies * n_repeating);
|
||||
w_remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (step == MEASURE)
|
||||
@ -588,7 +593,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
else
|
||||
{
|
||||
buffer->unsafe_to_break (context, end);
|
||||
hb_position_t x_offset = 0;
|
||||
hb_position_t x_offset = w_remaining / 2;
|
||||
for (unsigned int k = end; k > start; k--)
|
||||
{
|
||||
hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
|
||||
@ -599,16 +604,27 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
|
||||
DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %u; j=%u",
|
||||
repeat, info[k - 1].codepoint, j);
|
||||
pos[k - 1].x_advance = 0;
|
||||
for (unsigned int n = 0; n < repeat; n++)
|
||||
{
|
||||
x_offset -= width;
|
||||
if (n > 0)
|
||||
x_offset += extra_repeat_overlap;
|
||||
if (rtl)
|
||||
{
|
||||
x_offset -= width;
|
||||
if (n > 0)
|
||||
x_offset += extra_repeat_overlap;
|
||||
}
|
||||
pos[k - 1].x_offset = x_offset;
|
||||
/* Append copy. */
|
||||
--j;
|
||||
info[j] = info[k - 1];
|
||||
pos[j] = pos[k - 1];
|
||||
|
||||
if (!rtl)
|
||||
{
|
||||
x_offset += width;
|
||||
if (n > 0)
|
||||
x_offset -= extra_repeat_overlap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -625,6 +641,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
buffer->len = new_len;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rtl)
|
||||
buffer->reverse ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -53,7 +53,7 @@ enum indic_syllable_type_t {
|
||||
};
|
||||
|
||||
|
||||
#line 54 "hb-ot-shaper-indic-machine.hh"
|
||||
#line 57 "hb-ot-shaper-indic-machine.hh"
|
||||
#define indic_syllable_machine_ex_A 9u
|
||||
#define indic_syllable_machine_ex_C 1u
|
||||
#define indic_syllable_machine_ex_CM 16u
|
||||
@ -76,7 +76,7 @@ enum indic_syllable_type_t {
|
||||
#define indic_syllable_machine_ex_ZWNJ 5u
|
||||
|
||||
|
||||
#line 75 "hb-ot-shaper-indic-machine.hh"
|
||||
#line 80 "hb-ot-shaper-indic-machine.hh"
|
||||
static const unsigned char _indic_syllable_machine_trans_keys[] = {
|
||||
8u, 8u, 4u, 13u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
|
||||
8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
|
||||
@ -460,7 +460,7 @@ find_syllables_indic (hb_buffer_t *buffer)
|
||||
int cs;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
#line 453 "hb-ot-shaper-indic-machine.hh"
|
||||
#line 464 "hb-ot-shaper-indic-machine.hh"
|
||||
{
|
||||
cs = indic_syllable_machine_start;
|
||||
ts = 0;
|
||||
@ -476,7 +476,7 @@ find_syllables_indic (hb_buffer_t *buffer)
|
||||
|
||||
unsigned int syllable_serial = 1;
|
||||
|
||||
#line 465 "hb-ot-shaper-indic-machine.hh"
|
||||
#line 480 "hb-ot-shaper-indic-machine.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
@ -490,7 +490,7 @@ _resume:
|
||||
#line 1 "NONE"
|
||||
{ts = p;}
|
||||
break;
|
||||
#line 477 "hb-ot-shaper-indic-machine.hh"
|
||||
#line 494 "hb-ot-shaper-indic-machine.hh"
|
||||
}
|
||||
|
||||
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
|
||||
@ -593,7 +593,7 @@ _eof_trans:
|
||||
#line 114 "hb-ot-shaper-indic-machine.rl"
|
||||
{act = 6;}
|
||||
break;
|
||||
#line 559 "hb-ot-shaper-indic-machine.hh"
|
||||
#line 597 "hb-ot-shaper-indic-machine.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
@ -602,7 +602,7 @@ _again:
|
||||
#line 1 "NONE"
|
||||
{ts = 0;}
|
||||
break;
|
||||
#line 566 "hb-ot-shaper-indic-machine.hh"
|
||||
#line 606 "hb-ot-shaper-indic-machine.hh"
|
||||
}
|
||||
|
||||
if ( ++p != pe )
|
||||
|
@ -6,12 +6,12 @@
|
||||
*
|
||||
* on files with these headers:
|
||||
*
|
||||
* # IndicSyllabicCategory-15.0.0.txt
|
||||
* # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
|
||||
* # IndicPositionalCategory-15.0.0.txt
|
||||
* # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
|
||||
* # Blocks-15.0.0.txt
|
||||
* # Date: 2022-01-28, 20:58:00 GMT [KW]
|
||||
* # IndicSyllabicCategory-15.1.0.txt
|
||||
* # Date: 2023-01-05
|
||||
* # IndicPositionalCategory-15.1.0.txt
|
||||
* # Date: 2023-01-05
|
||||
* # Blocks-15.1.0.txt
|
||||
* # Date: 2023-07-28, 15:47:20 GMT
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
@ -48,7 +48,7 @@ enum khmer_syllable_type_t {
|
||||
};
|
||||
|
||||
|
||||
#line 49 "hb-ot-shaper-khmer-machine.hh"
|
||||
#line 52 "hb-ot-shaper-khmer-machine.hh"
|
||||
#define khmer_syllable_machine_ex_C 1u
|
||||
#define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
|
||||
#define khmer_syllable_machine_ex_H 4u
|
||||
@ -66,7 +66,7 @@ enum khmer_syllable_type_t {
|
||||
#define khmer_syllable_machine_ex_ZWNJ 5u
|
||||
|
||||
|
||||
#line 65 "hb-ot-shaper-khmer-machine.hh"
|
||||
#line 70 "hb-ot-shaper-khmer-machine.hh"
|
||||
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
|
||||
5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u,
|
||||
5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u,
|
||||
@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
|
||||
int cs;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
#line 287 "hb-ot-shaper-khmer-machine.hh"
|
||||
#line 298 "hb-ot-shaper-khmer-machine.hh"
|
||||
{
|
||||
cs = khmer_syllable_machine_start;
|
||||
ts = 0;
|
||||
@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
|
||||
|
||||
unsigned int syllable_serial = 1;
|
||||
|
||||
#line 299 "hb-ot-shaper-khmer-machine.hh"
|
||||
#line 314 "hb-ot-shaper-khmer-machine.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
@ -324,7 +324,7 @@ _resume:
|
||||
#line 1 "NONE"
|
||||
{ts = p;}
|
||||
break;
|
||||
#line 311 "hb-ot-shaper-khmer-machine.hh"
|
||||
#line 328 "hb-ot-shaper-khmer-machine.hh"
|
||||
}
|
||||
|
||||
_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
|
||||
@ -394,7 +394,7 @@ _eof_trans:
|
||||
#line 98 "hb-ot-shaper-khmer-machine.rl"
|
||||
{act = 3;}
|
||||
break;
|
||||
#line 368 "hb-ot-shaper-khmer-machine.hh"
|
||||
#line 398 "hb-ot-shaper-khmer-machine.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
@ -403,7 +403,7 @@ _again:
|
||||
#line 1 "NONE"
|
||||
{ts = 0;}
|
||||
break;
|
||||
#line 375 "hb-ot-shaper-khmer-machine.hh"
|
||||
#line 407 "hb-ot-shaper-khmer-machine.hh"
|
||||
}
|
||||
|
||||
if ( ++p != pe )
|
||||
|
@ -50,7 +50,7 @@ enum myanmar_syllable_type_t {
|
||||
};
|
||||
|
||||
|
||||
#line 51 "hb-ot-shaper-myanmar-machine.hh"
|
||||
#line 54 "hb-ot-shaper-myanmar-machine.hh"
|
||||
#define myanmar_syllable_machine_ex_A 9u
|
||||
#define myanmar_syllable_machine_ex_As 32u
|
||||
#define myanmar_syllable_machine_ex_C 1u
|
||||
@ -77,7 +77,7 @@ enum myanmar_syllable_type_t {
|
||||
#define myanmar_syllable_machine_ex_ZWNJ 5u
|
||||
|
||||
|
||||
#line 76 "hb-ot-shaper-myanmar-machine.hh"
|
||||
#line 81 "hb-ot-shaper-myanmar-machine.hh"
|
||||
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
|
||||
1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u,
|
||||
5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u,
|
||||
@ -443,7 +443,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
|
||||
int cs;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
#line 436 "hb-ot-shaper-myanmar-machine.hh"
|
||||
#line 447 "hb-ot-shaper-myanmar-machine.hh"
|
||||
{
|
||||
cs = myanmar_syllable_machine_start;
|
||||
ts = 0;
|
||||
@ -459,7 +459,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
|
||||
|
||||
unsigned int syllable_serial = 1;
|
||||
|
||||
#line 448 "hb-ot-shaper-myanmar-machine.hh"
|
||||
#line 463 "hb-ot-shaper-myanmar-machine.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
@ -473,7 +473,7 @@ _resume:
|
||||
#line 1 "NONE"
|
||||
{ts = p;}
|
||||
break;
|
||||
#line 460 "hb-ot-shaper-myanmar-machine.hh"
|
||||
#line 477 "hb-ot-shaper-myanmar-machine.hh"
|
||||
}
|
||||
|
||||
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
|
||||
@ -519,7 +519,7 @@ _eof_trans:
|
||||
#line 113 "hb-ot-shaper-myanmar-machine.rl"
|
||||
{te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
|
||||
break;
|
||||
#line 498 "hb-ot-shaper-myanmar-machine.hh"
|
||||
#line 523 "hb-ot-shaper-myanmar-machine.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
@ -528,7 +528,7 @@ _again:
|
||||
#line 1 "NONE"
|
||||
{ts = 0;}
|
||||
break;
|
||||
#line 505 "hb-ot-shaper-myanmar-machine.hh"
|
||||
#line 532 "hb-ot-shaper-myanmar-machine.hh"
|
||||
}
|
||||
|
||||
if ( ++p != pe )
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -83,6 +83,8 @@ export J = 50; # HIEROGLYPH_JOINER
|
||||
export SB = 51; # HIEROGLYPH_SEGMENT_BEGIN
|
||||
export SE = 52; # HIEROGLYPH_SEGMENT_END
|
||||
export HVM = 53; # HALANT_OR_VOWEL_MODIFIER
|
||||
export HM = 54; # HIEROGLYPH_MOD
|
||||
export HR = 55; # HIEROGLYPH_MIRROR
|
||||
|
||||
export FAbv = 24; # CONS_FINAL_ABOVE
|
||||
export FBlw = 25; # CONS_FINAL_BELOW
|
||||
@ -162,8 +164,8 @@ broken_cluster =
|
||||
|
||||
number_joiner_terminated_cluster = N number_joiner_terminated_cluster_tail;
|
||||
numeral_cluster = N numeral_cluster_tail?;
|
||||
symbol_cluster = (O | GB) tail?;
|
||||
hieroglyph_cluster = SB+ | SB* G SE* (J SE* (G SE*)?)*;
|
||||
symbol_cluster = (O | GB | SB) tail?;
|
||||
hieroglyph_cluster = SB* G HR? HM? SE* (J SB* (G HR? HM? SE*)?)*;
|
||||
other = any;
|
||||
|
||||
main := |*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,8 +10,8 @@
|
||||
* # Date: 2015-03-12, 21:17:00 GMT [AG]
|
||||
* # Date: 2019-11-08, 23:22:00 GMT [AG]
|
||||
*
|
||||
* # Scripts-15.0.0.txt
|
||||
* # Date: 2022-04-26, 23:15:02 GMT
|
||||
* # Scripts-15.1.0.txt
|
||||
* # Date: 2023-07-28, 16:01:07 GMT
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
@ -6,8 +6,8 @@
|
||||
*
|
||||
* on files with these headers:
|
||||
*
|
||||
* <meta name="updated_at" content="2022-01-28 10:00 PM" />
|
||||
* File-Date: 2022-03-02
|
||||
* <meta name="updated_at" content="2022-09-30 11:47 PM" />
|
||||
* File-Date: 2023-08-02
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_TAG_TABLE_HH
|
||||
@ -257,7 +257,7 @@ static const LangTag ot_languages3[] = {
|
||||
{HB_TAG('a','i','i',' '), HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */
|
||||
/*{HB_TAG('a','i','o',' '), HB_TAG('A','I','O',' ')},*/ /* Aiton */
|
||||
{HB_TAG('a','i','w',' '), HB_TAG('A','R','I',' ')}, /* Aari */
|
||||
{HB_TAG('a','j','p',' '), HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */
|
||||
{HB_TAG('a','j','p',' '), HB_TAG('A','R','A',' ')}, /* South Levantine Arabic (retired code) -> Arabic */
|
||||
{HB_TAG('a','j','t',' '), HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> Arabic */
|
||||
{HB_TAG('a','k','b',' '), HB_TAG('A','K','B',' ')}, /* Batak Angkola */
|
||||
{HB_TAG('a','k','b',' '), HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */
|
||||
@ -269,7 +269,7 @@ static const LangTag ot_languages3[] = {
|
||||
/*{HB_TAG('a','n','g',' '), HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */
|
||||
{HB_TAG('a','o','a',' '), HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */
|
||||
{HB_TAG('a','p','a',' '), HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */
|
||||
{HB_TAG('a','p','c',' '), HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */
|
||||
{HB_TAG('a','p','c',' '), HB_TAG('A','R','A',' ')}, /* Levantine Arabic -> Arabic */
|
||||
{HB_TAG('a','p','d',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */
|
||||
{HB_TAG('a','p','j',' '), HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */
|
||||
{HB_TAG('a','p','k',' '), HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */
|
||||
@ -1211,6 +1211,7 @@ static const LangTag ot_languages3[] = {
|
||||
{HB_TAG('p','p','a',' '), HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */
|
||||
{HB_TAG('p','r','e',' '), HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */
|
||||
/*{HB_TAG('p','r','o',' '), HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */
|
||||
{HB_TAG('p','r','p',' '), HB_TAG('G','U','J',' ')}, /* Parsi (retired code) -> Gujarati */
|
||||
{HB_TAG('p','r','s',' '), HB_TAG('D','R','I',' ')}, /* Dari */
|
||||
{HB_TAG('p','r','s',' '), HB_TAG('F','A','R',' ')}, /* Dari -> Persian */
|
||||
{HB_TAG('p','s','e',' '), HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */
|
||||
@ -1439,7 +1440,7 @@ static const LangTag ot_languages3[] = {
|
||||
{HB_TAG('t','c','h',' '), HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */
|
||||
{HB_TAG('t','c','p',' '), HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */
|
||||
{HB_TAG('t','c','s',' '), HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */
|
||||
{HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */
|
||||
{HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu */
|
||||
{HB_TAG('t','c','z',' '), HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */
|
||||
/*{HB_TAG('t','d','d',' '), HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */
|
||||
{HB_TAG('t','d','x',' '), HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */
|
||||
@ -1495,8 +1496,8 @@ static const LangTag ot_languages3[] = {
|
||||
{HB_TAG('t','t','q',' '), HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */
|
||||
{HB_TAG('t','t','q',' '), HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */
|
||||
{HB_TAG('t','u','a',' '), HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */
|
||||
{HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tumbuka */
|
||||
/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */
|
||||
{HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tulu */
|
||||
/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka */
|
||||
{HB_TAG('t','u','u',' '), HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */
|
||||
{HB_TAG('t','u','v',' '), HB_TAG_NONE }, /* Turkana != Tuvin */
|
||||
{HB_TAG('t','u','y',' '), HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */
|
||||
@ -1581,6 +1582,7 @@ static const LangTag ot_languages3[] = {
|
||||
{HB_TAG('y','b','a',' '), HB_TAG_NONE }, /* Yala != Yoruba */
|
||||
{HB_TAG('y','b','b',' '), HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */
|
||||
{HB_TAG('y','b','d',' '), HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */
|
||||
{HB_TAG('y','c','r',' '), HB_TAG_NONE }, /* Yilan Creole != Y-Cree */
|
||||
{HB_TAG('y','d','d',' '), HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */
|
||||
/*{HB_TAG('y','g','p',' '), HB_TAG('Y','G','P',' ')},*/ /* Gepo */
|
||||
{HB_TAG('y','i','h',' '), HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */
|
||||
@ -1602,6 +1604,7 @@ static const LangTag ot_languages3[] = {
|
||||
{HB_TAG('z','g','n',' '), HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */
|
||||
{HB_TAG('z','h','d',' '), HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */
|
||||
{HB_TAG('z','h','n',' '), HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */
|
||||
{HB_TAG('z','k','b',' '), HB_TAG('K','H','A',' ')}, /* Koibal (retired code) -> Khakass */
|
||||
{HB_TAG('z','l','j',' '), HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */
|
||||
{HB_TAG('z','l','m',' '), HB_TAG('M','L','Y',' ')}, /* Malay */
|
||||
{HB_TAG('z','l','n',' '), HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */
|
||||
|
@ -72,6 +72,65 @@ struct AxisValueMap
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
void set_mapping (float from_coord, float to_coord)
|
||||
{
|
||||
coords[0].set_float (from_coord);
|
||||
coords[1].set_float (to_coord);
|
||||
}
|
||||
|
||||
bool is_outside_axis_range (const Triple& axis_range) const
|
||||
{
|
||||
float from_coord = coords[0].to_float ();
|
||||
return !axis_range.contains (from_coord);
|
||||
}
|
||||
|
||||
bool must_include () const
|
||||
{
|
||||
float from_coord = coords[0].to_float ();
|
||||
float to_coord = coords[1].to_float ();
|
||||
return (from_coord == -1.f && to_coord == -1.f) ||
|
||||
(from_coord == 0.f && to_coord == 0.f) ||
|
||||
(from_coord == 1.f && to_coord == 1.f);
|
||||
}
|
||||
|
||||
void instantiate (const Triple& axis_range,
|
||||
const Triple& unmapped_range,
|
||||
const TripleDistances& triple_distances)
|
||||
{
|
||||
float from_coord = coords[0].to_float ();
|
||||
float to_coord = coords[1].to_float ();
|
||||
|
||||
from_coord = renormalizeValue (from_coord, unmapped_range, triple_distances);
|
||||
to_coord = renormalizeValue (to_coord, axis_range, triple_distances);
|
||||
|
||||
coords[0].set_float (from_coord);
|
||||
coords[1].set_float (to_coord);
|
||||
}
|
||||
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
const AxisValueMap *a = (const AxisValueMap *) pa;
|
||||
const AxisValueMap *b = (const AxisValueMap *) pb;
|
||||
|
||||
int a_from = a->coords[0].to_int ();
|
||||
int b_from = b->coords[0].to_int ();
|
||||
if (a_from != b_from)
|
||||
return a_from - b_from;
|
||||
|
||||
/* this should never be reached. according to the spec, all of the axis
|
||||
* value map records for a given axis must have different fromCoord values
|
||||
* */
|
||||
int a_to = a->coords[1].to_int ();
|
||||
int b_to = b->coords[1].to_int ();
|
||||
return a_to - b_to;
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
return_trace (c->embed (this));
|
||||
}
|
||||
|
||||
public:
|
||||
F2DOT14 coords[2];
|
||||
// F2DOT14 fromCoord; /* A normalized coordinate value obtained using
|
||||
@ -122,6 +181,78 @@ struct SegmentMaps : Array16Of<AxisValueMap>
|
||||
|
||||
int unmap (int value) const { return map (value, 1, 0); }
|
||||
|
||||
Triple unmap_axis_range (const Triple& axis_range) const
|
||||
{
|
||||
F2DOT14 val, unmapped_val;
|
||||
|
||||
val.set_float (axis_range.minimum);
|
||||
unmapped_val.set_int (unmap (val.to_int ()));
|
||||
float unmapped_min = unmapped_val.to_float ();
|
||||
|
||||
val.set_float (axis_range.middle);
|
||||
unmapped_val.set_int (unmap (val.to_int ()));
|
||||
float unmapped_middle = unmapped_val.to_float ();
|
||||
|
||||
val.set_float (axis_range.maximum);
|
||||
unmapped_val.set_int (unmap (val.to_int ()));
|
||||
float unmapped_max = unmapped_val.to_float ();
|
||||
|
||||
return Triple{unmapped_min, unmapped_middle, unmapped_max};
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
/* avar mapped normalized axis range*/
|
||||
Triple *axis_range;
|
||||
if (!c->plan->axes_location.has (axis_tag, &axis_range))
|
||||
return c->serializer->embed (*this);
|
||||
|
||||
TripleDistances *axis_triple_distances;
|
||||
if (!c->plan->axes_triple_distances.has (axis_tag, &axis_triple_distances))
|
||||
return_trace (false);
|
||||
|
||||
auto *out = c->serializer->start_embed (this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
Triple unmapped_range = unmap_axis_range (*axis_range);
|
||||
|
||||
/* create a vector of retained mappings and sort */
|
||||
hb_vector_t<AxisValueMap> value_mappings;
|
||||
for (const auto& _ : as_array ())
|
||||
{
|
||||
if (_.is_outside_axis_range (unmapped_range))
|
||||
continue;
|
||||
AxisValueMap mapping;
|
||||
mapping = _;
|
||||
mapping.instantiate (*axis_range, unmapped_range, *axis_triple_distances);
|
||||
/* (-1, -1), (0, 0), (1, 1) mappings will be added later, so avoid
|
||||
* duplicates here */
|
||||
if (mapping.must_include ())
|
||||
continue;
|
||||
value_mappings.push (std::move (mapping));
|
||||
}
|
||||
|
||||
AxisValueMap m;
|
||||
m.set_mapping (-1.f, -1.f);
|
||||
value_mappings.push (m);
|
||||
|
||||
m.set_mapping (0.f, 0.f);
|
||||
value_mappings.push (m);
|
||||
|
||||
m.set_mapping (1.f, 1.f);
|
||||
value_mappings.push (m);
|
||||
|
||||
value_mappings.qsort ();
|
||||
|
||||
for (const auto& _ : value_mappings)
|
||||
{
|
||||
if (!_.serialize (c->serializer))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (c->serializer->check_assign (out->len, value_mappings.length, HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||
}
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (2, *this);
|
||||
};
|
||||
@ -225,6 +356,39 @@ struct avar
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
unsigned retained_axis_count = c->plan->axes_index_map.get_population ();
|
||||
if (!retained_axis_count) //all axes are pinned/dropped
|
||||
return_trace (false);
|
||||
|
||||
avar *out = c->serializer->allocate_min<avar> ();
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->version.major = 1;
|
||||
out->version.minor = 0;
|
||||
if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
|
||||
const hb_map_t& axes_index_map = c->plan->axes_index_map;
|
||||
const SegmentMaps *map = &firstAxisSegmentMaps;
|
||||
unsigned count = axisCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (axes_index_map.has (i))
|
||||
{
|
||||
hb_tag_t *axis_tag;
|
||||
if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag))
|
||||
return_trace (false);
|
||||
if (!map->subset (c, *axis_tag))
|
||||
return_trace (false);
|
||||
}
|
||||
map = &StructAfter<SegmentMaps> (*map);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version of the avar table
|
||||
* initially set to 0x00010000u */
|
||||
|
@ -230,7 +230,7 @@ struct VarStoreInstancer
|
||||
/* according to the spec, if colr table has varStore but does not have
|
||||
* varIdxMap, then an implicit identity mapping is used */
|
||||
float operator() (uint32_t varIdx, unsigned short offset = 0) const
|
||||
{ return varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords); }
|
||||
{ return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
|
||||
|
||||
const VariationStore *varStore;
|
||||
const DeltaSetIndexMap *varIdxMap;
|
||||
@ -424,25 +424,6 @@ struct TupleVariationHeader
|
||||
DEFINE_SIZE_MIN (4);
|
||||
};
|
||||
|
||||
/* not using hb_bytes_t: avoid potential build issues with some compilers */
|
||||
struct byte_data_t
|
||||
{
|
||||
hb_bytes_t bytes;
|
||||
|
||||
byte_data_t () = default;
|
||||
byte_data_t (const char *p_, unsigned len_) : bytes (hb_bytes_t (p_, len_)) {}
|
||||
|
||||
void fini () { bytes.fini (); }
|
||||
|
||||
bool operator == (const byte_data_t& o) const
|
||||
{ return bytes.arrayZ == o.bytes.arrayZ && bytes.length == o.bytes.length; }
|
||||
|
||||
explicit operator bool () const { return bytes.length; }
|
||||
|
||||
void copy (hb_serialize_context_t *c) const
|
||||
{ c->embed (bytes.arrayZ, bytes.length); }
|
||||
};
|
||||
|
||||
enum packed_delta_flag_t
|
||||
{
|
||||
DELTAS_ARE_ZERO = 0x80,
|
||||
@ -468,17 +449,26 @@ struct tuple_delta_t
|
||||
hb_vector_t<char> compiled_tuple_header;
|
||||
hb_vector_t<char> compiled_deltas;
|
||||
|
||||
/* compiled peak coords, empty for non-gvar tuples */
|
||||
hb_vector_t<char> compiled_peak_coords;
|
||||
|
||||
tuple_delta_t () = default;
|
||||
tuple_delta_t (const tuple_delta_t& o) = default;
|
||||
|
||||
tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
|
||||
friend void swap (tuple_delta_t& a, tuple_delta_t& b)
|
||||
{
|
||||
axis_tuples = std::move (o.axis_tuples);
|
||||
indices = std::move (o.indices);
|
||||
deltas_x = std::move (o.deltas_x);
|
||||
deltas_y = std::move (o.deltas_y);
|
||||
hb_swap (a.axis_tuples, b.axis_tuples);
|
||||
hb_swap (a.indices, b.indices);
|
||||
hb_swap (a.deltas_x, b.deltas_x);
|
||||
hb_swap (a.deltas_y, b.deltas_y);
|
||||
hb_swap (a.compiled_tuple_header, b.compiled_tuple_header);
|
||||
hb_swap (a.compiled_deltas, b.compiled_deltas);
|
||||
hb_swap (a.compiled_peak_coords, b.compiled_peak_coords);
|
||||
}
|
||||
|
||||
tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
|
||||
{ hb_swap (*this, o); }
|
||||
|
||||
tuple_delta_t& operator = (tuple_delta_t&& o)
|
||||
{
|
||||
hb_swap (*this, o);
|
||||
@ -508,6 +498,7 @@ struct tuple_delta_t
|
||||
else
|
||||
{
|
||||
if (!o.indices.arrayZ[i]) continue;
|
||||
indices.arrayZ[i] = true;
|
||||
deltas_x[i] = o.deltas_x[i];
|
||||
if (deltas_y && o.deltas_y)
|
||||
deltas_y[i] = o.deltas_y[i];
|
||||
@ -533,7 +524,8 @@ struct tuple_delta_t
|
||||
return *this;
|
||||
}
|
||||
|
||||
hb_vector_t<tuple_delta_t> change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit) const
|
||||
hb_vector_t<tuple_delta_t> change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit,
|
||||
TripleDistances axis_triple_distances) const
|
||||
{
|
||||
hb_vector_t<tuple_delta_t> out;
|
||||
Triple *tent;
|
||||
@ -553,7 +545,7 @@ struct tuple_delta_t
|
||||
return out;
|
||||
}
|
||||
|
||||
result_t solutions = rebase_tent (*tent, axis_limit);
|
||||
result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
|
||||
for (auto t : solutions)
|
||||
{
|
||||
tuple_delta_t new_var = *this;
|
||||
@ -569,13 +561,43 @@ struct tuple_delta_t
|
||||
return out;
|
||||
}
|
||||
|
||||
bool compile_peak_coords (const hb_map_t& axes_index_map,
|
||||
const hb_map_t& axes_old_index_tag_map)
|
||||
{
|
||||
unsigned axis_count = axes_index_map.get_population ();
|
||||
if (unlikely (!compiled_peak_coords.alloc (axis_count * F2DOT14::static_size)))
|
||||
return false;
|
||||
|
||||
unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
|
||||
for (unsigned i = 0; i < orig_axis_count; i++)
|
||||
{
|
||||
if (!axes_index_map.has (i))
|
||||
continue;
|
||||
|
||||
hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
|
||||
Triple *coords;
|
||||
F2DOT14 peak_coord;
|
||||
if (axis_tuples.has (axis_tag, &coords))
|
||||
peak_coord.set_float (coords->middle);
|
||||
else
|
||||
peak_coord.set_int (0);
|
||||
|
||||
/* push F2DOT14 value into char vector */
|
||||
int16_t val = peak_coord.to_int ();
|
||||
compiled_peak_coords.push (static_cast<char> (val >> 8));
|
||||
compiled_peak_coords.push (static_cast<char> (val & 0xFF));
|
||||
}
|
||||
|
||||
return !compiled_peak_coords.in_error ();
|
||||
}
|
||||
|
||||
/* deltas should be compiled already before we compile tuple
|
||||
* variation header cause we need to fill in the size of the
|
||||
* serialized data for this tuple variation */
|
||||
//TODO(qxliu):add option to use sharedTuples in gvar
|
||||
bool compile_tuple_var_header (const hb_map_t& axes_index_map,
|
||||
unsigned points_data_length,
|
||||
const hb_map_t& axes_old_index_tag_map)
|
||||
const hb_map_t& axes_old_index_tag_map,
|
||||
const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map)
|
||||
{
|
||||
if (!compiled_deltas) return false;
|
||||
|
||||
@ -591,14 +613,25 @@ struct tuple_delta_t
|
||||
hb_array_t<F2DOT14> coords (p, end - p);
|
||||
|
||||
/* encode peak coords */
|
||||
unsigned peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map);
|
||||
if (!peak_count) return false;
|
||||
unsigned peak_count = 0;
|
||||
unsigned *shared_tuple_idx;
|
||||
if (shared_tuples_idx_map &&
|
||||
shared_tuples_idx_map->has (&compiled_peak_coords, &shared_tuple_idx))
|
||||
{
|
||||
flag = *shared_tuple_idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map);
|
||||
if (!peak_count) return false;
|
||||
}
|
||||
|
||||
/* encode interim coords, it's optional so returned num could be 0 */
|
||||
unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map);
|
||||
|
||||
//TODO(qxliu): add option to use shared_points in gvar
|
||||
flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers;
|
||||
/* pointdata length = 0 implies "use shared points" */
|
||||
if (points_data_length)
|
||||
flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers;
|
||||
|
||||
unsigned serialized_data_size = points_data_length + compiled_deltas.length;
|
||||
TupleVariationHeader *o = reinterpret_cast<TupleVariationHeader *> (compiled_tuple_header.begin ());
|
||||
@ -718,6 +751,8 @@ struct tuple_delta_t
|
||||
}
|
||||
|
||||
if (j != rounded_deltas.length) return false;
|
||||
/* reset i because we reuse rounded_deltas for deltas_y */
|
||||
i = 0;
|
||||
encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
|
||||
}
|
||||
return compiled_deltas.resize (encoded_len);
|
||||
@ -873,6 +908,7 @@ struct tuple_delta_t
|
||||
if (run_length)
|
||||
{
|
||||
*it++ = (DELTAS_ARE_WORDS | (run_length - 1));
|
||||
encoded_len++;
|
||||
while (start < i)
|
||||
{
|
||||
int16_t delta_val = deltas[start++];
|
||||
@ -884,6 +920,111 @@ struct tuple_delta_t
|
||||
}
|
||||
return encoded_len;
|
||||
}
|
||||
|
||||
bool calc_inferred_deltas (const contour_point_vector_t& orig_points)
|
||||
{
|
||||
unsigned point_count = orig_points.length;
|
||||
if (point_count != indices.length)
|
||||
return false;
|
||||
|
||||
unsigned ref_count = 0;
|
||||
hb_vector_t<unsigned> end_points;
|
||||
|
||||
for (unsigned i = 0; i < point_count; i++)
|
||||
{
|
||||
if (indices.arrayZ[i])
|
||||
ref_count++;
|
||||
if (orig_points.arrayZ[i].is_end_point)
|
||||
end_points.push (i);
|
||||
}
|
||||
/* all points are referenced, nothing to do */
|
||||
if (ref_count == point_count)
|
||||
return true;
|
||||
if (unlikely (end_points.in_error ())) return false;
|
||||
|
||||
hb_set_t inferred_idxes;
|
||||
unsigned start_point = 0;
|
||||
for (unsigned end_point : end_points)
|
||||
{
|
||||
/* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
|
||||
unsigned unref_count = 0;
|
||||
for (unsigned i = start_point; i < end_point + 1; i++)
|
||||
unref_count += indices.arrayZ[i];
|
||||
unref_count = (end_point - start_point + 1) - unref_count;
|
||||
|
||||
unsigned j = start_point;
|
||||
if (unref_count == 0 || unref_count > end_point - start_point)
|
||||
goto no_more_gaps;
|
||||
for (;;)
|
||||
{
|
||||
/* Locate the next gap of unreferenced points between two referenced points prev and next.
|
||||
* Note that a gap may wrap around at left (start_point) and/or at right (end_point).
|
||||
*/
|
||||
unsigned int prev, next, i;
|
||||
for (;;)
|
||||
{
|
||||
i = j;
|
||||
j = next_index (i, start_point, end_point);
|
||||
if (indices.arrayZ[i] && !indices.arrayZ[j]) break;
|
||||
}
|
||||
prev = j = i;
|
||||
for (;;)
|
||||
{
|
||||
i = j;
|
||||
j = next_index (i, start_point, end_point);
|
||||
if (!indices.arrayZ[i] && indices.arrayZ[j]) break;
|
||||
}
|
||||
next = j;
|
||||
/* Infer deltas for all unref points in the gap between prev and next */
|
||||
i = prev;
|
||||
for (;;)
|
||||
{
|
||||
i = next_index (i, start_point, end_point);
|
||||
if (i == next) break;
|
||||
deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, orig_points.arrayZ[prev].x, orig_points.arrayZ[next].x,
|
||||
deltas_x.arrayZ[prev], deltas_x.arrayZ[next]);
|
||||
deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, orig_points.arrayZ[prev].y, orig_points.arrayZ[next].y,
|
||||
deltas_y.arrayZ[prev], deltas_y.arrayZ[next]);
|
||||
inferred_idxes.add (i);
|
||||
if (--unref_count == 0) goto no_more_gaps;
|
||||
}
|
||||
}
|
||||
no_more_gaps:
|
||||
start_point = end_point + 1;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < point_count; i++)
|
||||
{
|
||||
/* if points are not referenced and deltas are not inferred, set to 0.
|
||||
* reference all points for gvar */
|
||||
if ( !indices[i])
|
||||
{
|
||||
if (!inferred_idxes.has (i))
|
||||
{
|
||||
deltas_x.arrayZ[i] = 0.f;
|
||||
deltas_y.arrayZ[i] = 0.f;
|
||||
}
|
||||
indices[i] = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta)
|
||||
{
|
||||
if (prev_val == next_val)
|
||||
return (prev_delta == next_delta) ? prev_delta : 0.f;
|
||||
else if (target_val <= hb_min (prev_val, next_val))
|
||||
return (prev_val < next_val) ? prev_delta : next_delta;
|
||||
else if (target_val >= hb_max (prev_val, next_val))
|
||||
return (prev_val > next_val) ? prev_delta : next_delta;
|
||||
|
||||
float r = (target_val - prev_val) / (next_val - prev_val);
|
||||
return prev_delta + r * (next_delta - prev_delta);
|
||||
}
|
||||
|
||||
static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
|
||||
{ return (i >= end) ? start : (i + 1); }
|
||||
};
|
||||
|
||||
struct TupleVariationData
|
||||
@ -920,11 +1061,26 @@ struct TupleVariationData
|
||||
|
||||
private:
|
||||
/* referenced point set->compiled point data map */
|
||||
hb_hashmap_t<const hb_vector_t<bool>*, byte_data_t> point_data_map;
|
||||
hb_hashmap_t<const hb_vector_t<bool>*, hb_bytes_t> point_data_map;
|
||||
/* referenced point set-> count map, used in finding shared points */
|
||||
hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
|
||||
|
||||
/* empty for non-gvar tuples.
|
||||
* shared_points_bytes is just a copy of some value in the point_data_map,
|
||||
* which will be freed during map destruction. Save it for serialization, so
|
||||
* no need to do find_shared_points () again */
|
||||
hb_bytes_t shared_points_bytes;
|
||||
|
||||
/* total compiled byte size as TupleVariationData format, initialized to its
|
||||
* min_size: 4 */
|
||||
unsigned compiled_byte_size = 4;
|
||||
|
||||
public:
|
||||
tuple_variations_t () = default;
|
||||
tuple_variations_t (const tuple_variations_t&) = delete;
|
||||
tuple_variations_t& operator=(const tuple_variations_t&) = delete;
|
||||
tuple_variations_t (tuple_variations_t&&) = default;
|
||||
tuple_variations_t& operator=(tuple_variations_t&&) = default;
|
||||
~tuple_variations_t () { fini (); }
|
||||
void fini ()
|
||||
{
|
||||
@ -935,8 +1091,17 @@ struct TupleVariationData
|
||||
tuple_vars.fini ();
|
||||
}
|
||||
|
||||
explicit operator bool () const { return bool (tuple_vars); }
|
||||
unsigned get_var_count () const
|
||||
{ return tuple_vars.length; }
|
||||
{
|
||||
unsigned count = tuple_vars.length;
|
||||
if (shared_points_bytes.length)
|
||||
count |= TupleVarCount::SharedPointNumbers;
|
||||
return count;
|
||||
}
|
||||
|
||||
unsigned get_compiled_byte_size () const
|
||||
{ return compiled_byte_size; }
|
||||
|
||||
bool create_from_tuple_var_data (tuple_iterator_t iterator,
|
||||
unsigned tuple_var_count,
|
||||
@ -1006,16 +1171,22 @@ struct TupleVariationData
|
||||
return true;
|
||||
}
|
||||
|
||||
void change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple> *normalized_axes_location)
|
||||
private:
|
||||
void change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
|
||||
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
|
||||
{
|
||||
for (auto _ : *normalized_axes_location)
|
||||
for (auto _ : normalized_axes_location)
|
||||
{
|
||||
hb_tag_t axis_tag = _.first;
|
||||
Triple axis_limit = _.second;
|
||||
TripleDistances axis_triple_distances{1.f, 1.f};
|
||||
if (axes_triple_distances.has (axis_tag))
|
||||
axis_triple_distances = axes_triple_distances.get (axis_tag);
|
||||
|
||||
hb_vector_t<tuple_delta_t> new_vars;
|
||||
for (const tuple_delta_t& var : tuple_vars)
|
||||
{
|
||||
hb_vector_t<tuple_delta_t> out = var.change_tuple_var_axis_limit (axis_tag, axis_limit);
|
||||
hb_vector_t<tuple_delta_t> out = var.change_tuple_var_axis_limit (axis_tag, axis_limit, axis_triple_distances);
|
||||
if (!out) continue;
|
||||
unsigned new_len = new_vars.length + out.length;
|
||||
|
||||
@ -1034,7 +1205,7 @@ struct TupleVariationData
|
||||
void merge_tuple_variations ()
|
||||
{
|
||||
hb_vector_t<tuple_delta_t> new_vars;
|
||||
hb_hashmap_t<hb_hashmap_t<hb_tag_t, Triple>, unsigned> m;
|
||||
hb_hashmap_t<const hb_hashmap_t<hb_tag_t, Triple>*, unsigned> m;
|
||||
unsigned i = 0;
|
||||
for (const tuple_delta_t& var : tuple_vars)
|
||||
{
|
||||
@ -1042,14 +1213,14 @@ struct TupleVariationData
|
||||
if (var.axis_tuples.is_empty ()) continue;
|
||||
|
||||
unsigned *idx;
|
||||
if (m.has (var.axis_tuples, &idx))
|
||||
if (m.has (&(var.axis_tuples), &idx))
|
||||
{
|
||||
new_vars[*idx] += var;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_vars.push (var);
|
||||
m.set (var.axis_tuples, i);
|
||||
m.set (&(var.axis_tuples), i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@ -1057,7 +1228,7 @@ struct TupleVariationData
|
||||
tuple_vars = std::move (new_vars);
|
||||
}
|
||||
|
||||
byte_data_t compile_point_set (const hb_vector_t<bool> &point_indices)
|
||||
hb_bytes_t compile_point_set (const hb_vector_t<bool> &point_indices)
|
||||
{
|
||||
unsigned num_points = 0;
|
||||
for (bool i : point_indices)
|
||||
@ -1069,15 +1240,15 @@ struct TupleVariationData
|
||||
if (num_points == indices_length)
|
||||
{
|
||||
char *p = (char *) hb_calloc (1, sizeof (char));
|
||||
if (unlikely (!p)) return byte_data_t ();
|
||||
if (unlikely (!p)) return hb_bytes_t ();
|
||||
|
||||
return byte_data_t (p, 1);
|
||||
return hb_bytes_t (p, 1);
|
||||
}
|
||||
|
||||
/* allocate enough memories: 2 bytes for count + 3 bytes for each point */
|
||||
unsigned num_bytes = 2 + 3 *num_points;
|
||||
char *p = (char *) hb_calloc (num_bytes, sizeof (char));
|
||||
if (unlikely (!p)) return byte_data_t ();
|
||||
if (unlikely (!p)) return hb_bytes_t ();
|
||||
|
||||
unsigned pos = 0;
|
||||
/* binary data starts with the total number of reference points */
|
||||
@ -1140,10 +1311,10 @@ struct TupleVariationData
|
||||
else
|
||||
p[header_pos] = (run_length - 1) | 0x80;
|
||||
}
|
||||
return byte_data_t (p, pos);
|
||||
return hb_bytes_t (p, pos);
|
||||
}
|
||||
|
||||
/* compile all point set and store byte data in a point_set->byte_data_t hashmap,
|
||||
/* compile all point set and store byte data in a point_set->hb_bytes_t hashmap,
|
||||
* also update point_set->count map, which will be used in finding shared
|
||||
* point set*/
|
||||
bool compile_all_point_sets ()
|
||||
@ -1160,8 +1331,8 @@ struct TupleVariationData
|
||||
continue;
|
||||
}
|
||||
|
||||
byte_data_t compiled_data = compile_point_set (*points_set);
|
||||
if (unlikely (compiled_data == byte_data_t ()))
|
||||
hb_bytes_t compiled_data = compile_point_set (*points_set);
|
||||
if (unlikely (compiled_data == hb_bytes_t ()))
|
||||
return false;
|
||||
|
||||
if (!point_data_map.set (points_set, compiled_data) ||
|
||||
@ -1172,19 +1343,19 @@ struct TupleVariationData
|
||||
}
|
||||
|
||||
/* find shared points set which saves most bytes */
|
||||
byte_data_t find_shared_points ()
|
||||
hb_bytes_t find_shared_points ()
|
||||
{
|
||||
unsigned max_saved_bytes = 0;
|
||||
byte_data_t res{};
|
||||
hb_bytes_t res{};
|
||||
|
||||
for (const auto& _ : point_data_map.iter ())
|
||||
{
|
||||
const hb_vector_t<bool>* points_set = _.first;
|
||||
unsigned data_length = _.second.bytes.length;
|
||||
unsigned data_length = _.second.length;
|
||||
unsigned *count;
|
||||
if (unlikely (!point_set_count_map.has (points_set, &count) ||
|
||||
*count <= 1))
|
||||
return byte_data_t ();
|
||||
return hb_bytes_t ();
|
||||
|
||||
unsigned saved_bytes = data_length * ((*count) -1);
|
||||
if (saved_bytes > max_saved_bytes)
|
||||
@ -1196,31 +1367,61 @@ struct TupleVariationData
|
||||
return res;
|
||||
}
|
||||
|
||||
void instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location)
|
||||
bool calc_inferred_deltas (contour_point_vector_t& contour_points)
|
||||
{
|
||||
change_tuple_variations_axis_limits (&normalized_axes_location);
|
||||
for (tuple_delta_t& var : tuple_vars)
|
||||
if (!var.calc_inferred_deltas (contour_points))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
bool instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
|
||||
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
|
||||
contour_point_vector_t* contour_points = nullptr)
|
||||
{
|
||||
if (!tuple_vars) return true;
|
||||
change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances);
|
||||
/* compute inferred deltas only for gvar */
|
||||
if (contour_points)
|
||||
if (!calc_inferred_deltas (*contour_points))
|
||||
return false;
|
||||
|
||||
merge_tuple_variations ();
|
||||
return !tuple_vars.in_error ();
|
||||
}
|
||||
|
||||
bool compile_bytes (const hb_map_t& axes_index_map,
|
||||
const hb_map_t& axes_old_index_tag_map)
|
||||
const hb_map_t& axes_old_index_tag_map,
|
||||
bool use_shared_points,
|
||||
const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map = nullptr)
|
||||
{
|
||||
// compile points set and store data in hashmap
|
||||
if (!compile_all_point_sets ())
|
||||
return false;
|
||||
|
||||
if (use_shared_points)
|
||||
{
|
||||
shared_points_bytes = find_shared_points ();
|
||||
compiled_byte_size += shared_points_bytes.length;
|
||||
}
|
||||
// compile delta and tuple var header for each tuple variation
|
||||
for (auto& tuple: tuple_vars)
|
||||
{
|
||||
const hb_vector_t<bool>* points_set = &(tuple.indices);
|
||||
byte_data_t *points_data;
|
||||
hb_bytes_t *points_data;
|
||||
if (unlikely (!point_data_map.has (points_set, &points_data)))
|
||||
return false;
|
||||
|
||||
if (!tuple.compile_deltas ())
|
||||
return false;
|
||||
|
||||
if (!tuple.compile_tuple_var_header (axes_index_map, points_data->bytes.length, axes_old_index_tag_map))
|
||||
unsigned points_data_length = (*points_data != shared_points_bytes) ? points_data->length : 0;
|
||||
if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
|
||||
shared_tuples_idx_map))
|
||||
return false;
|
||||
compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1230,29 +1431,40 @@ struct TupleVariationData
|
||||
TRACE_SERIALIZE (this);
|
||||
for (const auto& tuple: tuple_vars)
|
||||
{
|
||||
byte_data_t compiled_bytes {tuple.compiled_tuple_header.arrayZ, tuple.compiled_tuple_header.length};
|
||||
compiled_bytes.copy (c);
|
||||
tuple.compiled_tuple_header.as_array ().copy (c);
|
||||
if (c->in_error ()) return_trace (false);
|
||||
total_header_len += tuple.compiled_tuple_header.length;
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool serialize_var_data (hb_serialize_context_t *c) const
|
||||
bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (is_gvar)
|
||||
shared_points_bytes.copy (c);
|
||||
|
||||
for (const auto& tuple: tuple_vars)
|
||||
{
|
||||
const hb_vector_t<bool>* points_set = &(tuple.indices);
|
||||
byte_data_t *point_data;
|
||||
hb_bytes_t *point_data;
|
||||
if (!point_data_map.has (points_set, &point_data))
|
||||
return_trace (false);
|
||||
|
||||
point_data->copy (c);
|
||||
byte_data_t compiled_bytes {tuple.compiled_deltas.arrayZ, tuple.compiled_deltas.length};
|
||||
compiled_bytes.copy (c);
|
||||
if (!is_gvar || *point_data != shared_points_bytes)
|
||||
point_data->copy (c);
|
||||
|
||||
tuple.compiled_deltas.as_array ().copy (c);
|
||||
if (c->in_error ()) return_trace (false);
|
||||
}
|
||||
|
||||
/* padding for gvar */
|
||||
if (is_gvar && (compiled_byte_size % 2))
|
||||
{
|
||||
HBUINT8 pad;
|
||||
pad = 0;
|
||||
if (!c->embed (pad)) return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
};
|
||||
@ -1438,9 +1650,12 @@ struct TupleVariationData
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
bool is_gvar,
|
||||
tuple_variations_t& tuple_variations) const
|
||||
const tuple_variations_t& tuple_variations) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
/* empty tuple variations, just return and skip serialization. */
|
||||
if (!tuple_variations) return_trace (true);
|
||||
|
||||
auto *out = c->start_embed (this);
|
||||
if (unlikely (!c->extend_min (out))) return_trace (false);
|
||||
|
||||
@ -1456,15 +1671,17 @@ struct TupleVariationData
|
||||
if (!is_gvar) data_offset += 4;
|
||||
if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
|
||||
|
||||
return tuple_variations.serialize_var_data (c);
|
||||
return tuple_variations.serialize_var_data (c, is_gvar);
|
||||
}
|
||||
|
||||
protected:
|
||||
struct TupleVarCount : HBUINT16
|
||||
{
|
||||
friend struct tuple_variations_t;
|
||||
bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
|
||||
unsigned int get_count () const { return (*this) & CountMask; }
|
||||
TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
|
||||
explicit operator bool () const { return get_count (); }
|
||||
|
||||
protected:
|
||||
enum Flags
|
||||
|
@ -131,6 +131,7 @@ struct cvar
|
||||
TupleVariationData::tuple_variations_t& tuple_variations) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (!tuple_variations) return_trace (false);
|
||||
if (unlikely (!c->embed (version))) return_trace (false);
|
||||
|
||||
return_trace (tupleVariationData.serialize (c, false, tuple_variations));
|
||||
@ -161,14 +162,18 @@ struct cvar
|
||||
const hb_tag_t cvt = HB_TAG('c','v','t',' ');
|
||||
hb_blob_t *cvt_blob = hb_face_reference_table (c->plan->source, cvt);
|
||||
unsigned point_count = hb_blob_get_length (cvt_blob) / FWORD::static_size;
|
||||
hb_blob_destroy (cvt_blob);
|
||||
|
||||
if (!decompile_tuple_variations (axis_count, point_count, false,
|
||||
&(c->plan->axes_old_index_tag_map),
|
||||
tuple_variations))
|
||||
return_trace (false);
|
||||
|
||||
tuple_variations.instantiate (c->plan->axes_location);
|
||||
if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map))
|
||||
if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances))
|
||||
return_trace (false);
|
||||
|
||||
if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map,
|
||||
false /* do not use shared points */))
|
||||
return_trace (false);
|
||||
|
||||
return_trace (serialize (c->serializer, tuple_variations));
|
||||
|
@ -99,16 +99,16 @@ struct InstanceRecord
|
||||
for (unsigned i = 0 ; i < axis_count; i++)
|
||||
{
|
||||
uint32_t *axis_tag;
|
||||
Triple *axis_limit;
|
||||
// only keep instances whose coordinates == pinned axis location
|
||||
if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) continue;
|
||||
if (axes_location->has (*axis_tag))
|
||||
if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) return_trace (false);
|
||||
if (axes_location->has (*axis_tag, &axis_limit))
|
||||
{
|
||||
Triple axis_limit = axes_location->get (*axis_tag);
|
||||
if (!axis_coord_pinned_or_within_axis_range (coords, i, axis_limit))
|
||||
if (!axis_coord_pinned_or_within_axis_range (coords, i, *axis_limit))
|
||||
return_trace (false);
|
||||
|
||||
//skip pinned axis
|
||||
if (axis_limit.is_point ())
|
||||
if (axis_limit->is_point ())
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -228,6 +228,30 @@ struct AxisRecord
|
||||
return defaultValue.to_float ();
|
||||
}
|
||||
|
||||
TripleDistances get_triple_distances () const
|
||||
{
|
||||
float min, default_, max;
|
||||
get_coordinates (min, default_, max);
|
||||
return TripleDistances (min, default_, max);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
const hb_hashmap_t<hb_tag_t, Triple>& user_axes_location = c->plan->user_axes_location;
|
||||
Triple *axis_limit;
|
||||
if (user_axes_location.has (axisTag, &axis_limit))
|
||||
{
|
||||
out->minValue.set_float (axis_limit->minimum);
|
||||
out->defaultValue.set_float (axis_limit->middle);
|
||||
out->maxValue.set_float (axis_limit->maximum);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
public:
|
||||
Tag axisTag; /* Tag identifying the design variation for the axis. */
|
||||
protected:
|
||||
@ -416,21 +440,25 @@ struct fvar
|
||||
for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
|
||||
{
|
||||
if (!c->plan->axes_index_map.has (i)) continue;
|
||||
if (unlikely (!c->serializer->embed (axes_records[i])))
|
||||
if (unlikely (!axes_records[i].subset (c)))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
|
||||
unsigned num_retained_instances = 0;
|
||||
for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
|
||||
{
|
||||
const InstanceRecord *instance = get_instance (i);
|
||||
auto snap = c->serializer->snapshot ();
|
||||
if (!instance->subset (c, axisCount, has_postscript_nameid))
|
||||
c->serializer->revert (snap);
|
||||
else
|
||||
num_retained_instances++;
|
||||
}
|
||||
return_trace (true);
|
||||
|
||||
return_trace (c->serializer->check_assign (out->instanceCount, num_retained_instances, HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -39,43 +39,256 @@
|
||||
|
||||
namespace OT {
|
||||
|
||||
struct contour_point_t
|
||||
{
|
||||
void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
|
||||
{ flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
|
||||
|
||||
void transform (const float (&matrix)[4])
|
||||
{
|
||||
float x_ = x * matrix[0] + y * matrix[2];
|
||||
y = x * matrix[1] + y * matrix[3];
|
||||
x = x_;
|
||||
}
|
||||
HB_ALWAYS_INLINE
|
||||
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
|
||||
|
||||
|
||||
float x;
|
||||
float y;
|
||||
uint8_t flag;
|
||||
bool is_end_point;
|
||||
};
|
||||
|
||||
struct contour_point_vector_t : hb_vector_t<contour_point_t>
|
||||
{
|
||||
void extend (const hb_array_t<contour_point_t> &a)
|
||||
{
|
||||
unsigned int old_len = length;
|
||||
if (unlikely (!resize (old_len + a.length, false)))
|
||||
return;
|
||||
auto arrayZ = this->arrayZ + old_len;
|
||||
unsigned count = a.length;
|
||||
hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
|
||||
}
|
||||
};
|
||||
|
||||
struct GlyphVariationData : TupleVariationData
|
||||
{};
|
||||
|
||||
struct glyph_variations_t
|
||||
{
|
||||
using tuple_variations_t = TupleVariationData::tuple_variations_t;
|
||||
hb_vector_t<tuple_variations_t> glyph_variations;
|
||||
|
||||
hb_vector_t<char> compiled_shared_tuples;
|
||||
private:
|
||||
unsigned shared_tuples_count = 0;
|
||||
|
||||
/* shared coords-> index map after instantiation */
|
||||
hb_hashmap_t<const hb_vector_t<char>*, unsigned> shared_tuples_idx_map;
|
||||
|
||||
public:
|
||||
unsigned compiled_shared_tuples_count () const
|
||||
{ return shared_tuples_count; }
|
||||
|
||||
unsigned compiled_byte_size () const
|
||||
{
|
||||
unsigned byte_size = 0;
|
||||
for (const auto& _ : glyph_variations)
|
||||
byte_size += _.get_compiled_byte_size ();
|
||||
|
||||
return byte_size;
|
||||
}
|
||||
|
||||
bool create_from_glyphs_var_data (unsigned axis_count,
|
||||
const hb_array_t<const F2DOT14> shared_tuples,
|
||||
const hb_subset_plan_t *plan,
|
||||
const hb_hashmap_t<hb_codepoint_t, hb_bytes_t>& new_gid_var_data_map)
|
||||
{
|
||||
if (unlikely (!glyph_variations.alloc (plan->new_to_old_gid_list.length, true)))
|
||||
return false;
|
||||
|
||||
auto it = hb_iter (plan->new_to_old_gid_list);
|
||||
for (auto &_ : it)
|
||||
{
|
||||
hb_codepoint_t new_gid = _.first;
|
||||
contour_point_vector_t *all_contour_points;
|
||||
if (!new_gid_var_data_map.has (new_gid) ||
|
||||
!plan->new_gid_contour_points_map.has (new_gid, &all_contour_points))
|
||||
return false;
|
||||
hb_bytes_t var_data = new_gid_var_data_map.get (new_gid);
|
||||
|
||||
const GlyphVariationData* p = reinterpret_cast<const GlyphVariationData*> (var_data.arrayZ);
|
||||
hb_vector_t<unsigned> shared_indices;
|
||||
GlyphVariationData::tuple_iterator_t iterator;
|
||||
tuple_variations_t tuple_vars;
|
||||
|
||||
/* in case variation data is empty, push an empty struct into the vector,
|
||||
* keep the vector in sync with the new_to_old_gid_list */
|
||||
if (!var_data || ! p->has_data () || !all_contour_points->length ||
|
||||
!GlyphVariationData::get_tuple_iterator (var_data, axis_count,
|
||||
var_data.arrayZ,
|
||||
shared_indices, &iterator))
|
||||
{
|
||||
glyph_variations.push (std::move (tuple_vars));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */,
|
||||
iterator, &(plan->axes_old_index_tag_map),
|
||||
shared_indices, shared_tuples,
|
||||
tuple_vars /* OUT */))
|
||||
return false;
|
||||
glyph_variations.push (std::move (tuple_vars));
|
||||
}
|
||||
return !glyph_variations.in_error () && glyph_variations.length == plan->new_to_old_gid_list.length;
|
||||
}
|
||||
|
||||
bool instantiate (const hb_subset_plan_t *plan)
|
||||
{
|
||||
unsigned count = plan->new_to_old_gid_list.length;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first;
|
||||
contour_point_vector_t *all_points;
|
||||
if (!plan->new_gid_contour_points_map.has (new_gid, &all_points))
|
||||
return false;
|
||||
if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compile_bytes (const hb_map_t& axes_index_map,
|
||||
const hb_map_t& axes_old_index_tag_map)
|
||||
{
|
||||
if (!compile_shared_tuples (axes_index_map, axes_old_index_tag_map))
|
||||
return false;
|
||||
for (tuple_variations_t& vars: glyph_variations)
|
||||
if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map,
|
||||
true, /* use shared points*/
|
||||
&shared_tuples_idx_map))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compile_shared_tuples (const hb_map_t& axes_index_map,
|
||||
const hb_map_t& axes_old_index_tag_map)
|
||||
{
|
||||
/* key is pointer to compiled_peak_coords inside each tuple, hashing
|
||||
* function will always deref pointers first */
|
||||
hb_hashmap_t<const hb_vector_t<char>*, unsigned> coords_count_map;
|
||||
|
||||
/* count the num of shared coords */
|
||||
for (tuple_variations_t& vars: glyph_variations)
|
||||
{
|
||||
for (tuple_delta_t& var : vars.tuple_vars)
|
||||
{
|
||||
if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map))
|
||||
return false;
|
||||
unsigned* count;
|
||||
if (coords_count_map.has (&(var.compiled_peak_coords), &count))
|
||||
coords_count_map.set (&(var.compiled_peak_coords), *count + 1);
|
||||
else
|
||||
coords_count_map.set (&(var.compiled_peak_coords), 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!coords_count_map || coords_count_map.in_error ())
|
||||
return false;
|
||||
|
||||
/* add only those coords that are used more than once into the vector and sort */
|
||||
hb_vector_t<const hb_vector_t<char>*> shared_coords;
|
||||
if (unlikely (!shared_coords.alloc (coords_count_map.get_population ())))
|
||||
return false;
|
||||
|
||||
for (const auto _ : coords_count_map.iter ())
|
||||
{
|
||||
if (_.second == 1) continue;
|
||||
shared_coords.push (_.first);
|
||||
}
|
||||
|
||||
/* no shared tuples: no coords are used more than once */
|
||||
if (!shared_coords) return true;
|
||||
/* sorting based on the coords frequency first (high to low), then compare
|
||||
* the coords bytes */
|
||||
hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t<char>*), _cmp_coords, (void *) (&coords_count_map));
|
||||
|
||||
/* build shared_coords->idx map and shared tuples byte array */
|
||||
|
||||
shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length);
|
||||
unsigned len = shared_tuples_count * (shared_coords[0]->length);
|
||||
if (unlikely (!compiled_shared_tuples.alloc (len)))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < shared_tuples_count; i++)
|
||||
{
|
||||
shared_tuples_idx_map.set (shared_coords[i], i);
|
||||
/* add a concat() in hb_vector_t? */
|
||||
for (char c : shared_coords[i]->iter ())
|
||||
compiled_shared_tuples.push (c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int _cmp_coords (const void *pa, const void *pb, void *arg)
|
||||
{
|
||||
const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* coords_count_map =
|
||||
reinterpret_cast<const hb_hashmap_t<const hb_vector_t<char>*, unsigned>*> (arg);
|
||||
|
||||
/* shared_coords is hb_vector_t<const hb_vector_t<char>*> so casting pa/pb
|
||||
* to be a pointer to a pointer */
|
||||
const hb_vector_t<char>** a = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pa));
|
||||
const hb_vector_t<char>** b = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pb));
|
||||
|
||||
bool has_a = coords_count_map->has (*a);
|
||||
bool has_b = coords_count_map->has (*b);
|
||||
|
||||
if (has_a && has_b)
|
||||
{
|
||||
unsigned a_num = coords_count_map->get (*a);
|
||||
unsigned b_num = coords_count_map->get (*b);
|
||||
|
||||
if (a_num != b_num)
|
||||
return b_num - a_num;
|
||||
|
||||
return (*b)->as_array().cmp ((*a)->as_array ());
|
||||
}
|
||||
else if (has_a) return -1;
|
||||
else if (has_b) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize_glyph_var_data (hb_serialize_context_t *c,
|
||||
Iterator it,
|
||||
bool long_offset,
|
||||
unsigned num_glyphs,
|
||||
char* glyph_var_data_offsets /* OUT: glyph var data offsets array */) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (long_offset)
|
||||
{
|
||||
((HBUINT32 *) glyph_var_data_offsets)[0] = 0;
|
||||
glyph_var_data_offsets += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
((HBUINT16 *) glyph_var_data_offsets)[0] = 0;
|
||||
glyph_var_data_offsets += 2;
|
||||
}
|
||||
unsigned glyph_offset = 0;
|
||||
hb_codepoint_t last_gid = 0;
|
||||
unsigned idx = 0;
|
||||
|
||||
TupleVariationData* cur_glyph = c->start_embed<TupleVariationData> ();
|
||||
if (!cur_glyph) return_trace (false);
|
||||
for (auto &_ : it)
|
||||
{
|
||||
hb_codepoint_t gid = _.first;
|
||||
if (long_offset)
|
||||
for (; last_gid < gid; last_gid++)
|
||||
((HBUINT32 *) glyph_var_data_offsets)[last_gid] = glyph_offset;
|
||||
else
|
||||
for (; last_gid < gid; last_gid++)
|
||||
((HBUINT16 *) glyph_var_data_offsets)[last_gid] = glyph_offset / 2;
|
||||
|
||||
if (idx >= glyph_variations.length) return_trace (false);
|
||||
if (!cur_glyph->serialize (c, true, glyph_variations[idx])) return_trace (false);
|
||||
TupleVariationData* next_glyph = c->start_embed<TupleVariationData> ();
|
||||
glyph_offset += (char *) next_glyph - (char *) cur_glyph;
|
||||
|
||||
if (long_offset)
|
||||
((HBUINT32 *) glyph_var_data_offsets)[gid] = glyph_offset;
|
||||
else
|
||||
((HBUINT16 *) glyph_var_data_offsets)[gid] = glyph_offset / 2;
|
||||
|
||||
last_gid++;
|
||||
idx++;
|
||||
cur_glyph = next_glyph;
|
||||
}
|
||||
|
||||
if (long_offset)
|
||||
for (; last_gid < num_glyphs; last_gid++)
|
||||
((HBUINT32 *) glyph_var_data_offsets)[last_gid] = glyph_offset;
|
||||
else
|
||||
for (; last_gid < num_glyphs; last_gid++)
|
||||
((HBUINT16 *) glyph_var_data_offsets)[last_gid] = glyph_offset / 2;
|
||||
return_trace (true);
|
||||
}
|
||||
};
|
||||
|
||||
struct gvar
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar;
|
||||
@ -94,9 +307,101 @@ struct gvar
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{ return sanitize_shallow (c); }
|
||||
|
||||
bool decompile_glyph_variations (hb_subset_context_t *c,
|
||||
glyph_variations_t& glyph_vars /* OUT */) const
|
||||
{
|
||||
hb_hashmap_t<hb_codepoint_t, hb_bytes_t> new_gid_var_data_map;
|
||||
auto it = hb_iter (c->plan->new_to_old_gid_list);
|
||||
if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
|
||||
{
|
||||
new_gid_var_data_map.set (0, hb_bytes_t ());
|
||||
it++;
|
||||
}
|
||||
|
||||
for (auto &_ : it)
|
||||
{
|
||||
hb_codepoint_t new_gid = _.first;
|
||||
hb_codepoint_t old_gid = _.second;
|
||||
hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob, glyphCountX, old_gid);
|
||||
new_gid_var_data_map.set (new_gid, var_data_bytes);
|
||||
}
|
||||
|
||||
if (new_gid_var_data_map.in_error ()) return false;
|
||||
|
||||
hb_array_t<const F2DOT14> shared_tuples = (this+sharedTuples).as_array ((unsigned) sharedTupleCount * (unsigned) axisCount);
|
||||
return glyph_vars.create_from_glyphs_var_data (axisCount, shared_tuples, c->plan, new_gid_var_data_map);
|
||||
}
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const glyph_variations_t& glyph_vars,
|
||||
Iterator it,
|
||||
unsigned axis_count,
|
||||
unsigned num_glyphs) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
gvar *out = c->allocate_min<gvar> ();
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->version.major = 1;
|
||||
out->version.minor = 0;
|
||||
out->axisCount = axis_count;
|
||||
out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
|
||||
|
||||
unsigned glyph_var_data_size = glyph_vars.compiled_byte_size ();
|
||||
bool long_offset = glyph_var_data_size & ~0xFFFFu;
|
||||
out->flags = long_offset ? 1 : 0;
|
||||
|
||||
HBUINT8 *glyph_var_data_offsets = c->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
|
||||
if (!glyph_var_data_offsets) return_trace (false);
|
||||
|
||||
/* shared tuples */
|
||||
unsigned shared_tuple_count = glyph_vars.compiled_shared_tuples_count ();
|
||||
out->sharedTupleCount = shared_tuple_count;
|
||||
|
||||
if (!shared_tuple_count)
|
||||
out->sharedTuples = 0;
|
||||
else
|
||||
{
|
||||
hb_array_t<const char> shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c);
|
||||
if (!shared_tuples.arrayZ) return_trace (false);
|
||||
out->sharedTuples = shared_tuples.arrayZ - (char *) out;
|
||||
}
|
||||
|
||||
char *glyph_var_data = c->start_embed<char> ();
|
||||
if (!glyph_var_data) return_trace (false);
|
||||
out->dataZ = glyph_var_data - (char *) out;
|
||||
|
||||
return_trace (glyph_vars.serialize_glyph_var_data (c, it, long_offset, num_glyphs,
|
||||
(char *) glyph_var_data_offsets));
|
||||
}
|
||||
|
||||
bool instantiate (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
glyph_variations_t glyph_vars;
|
||||
if (!decompile_glyph_variations (c, glyph_vars))
|
||||
return_trace (false);
|
||||
|
||||
if (!glyph_vars.instantiate (c->plan)) return_trace (false);
|
||||
if (!glyph_vars.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map))
|
||||
return_trace (false);
|
||||
|
||||
unsigned axis_count = c->plan->axes_index_map.get_population ();
|
||||
unsigned num_glyphs = c->plan->num_output_glyphs ();
|
||||
auto it = hb_iter (c->plan->new_to_old_gid_list);
|
||||
return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs));
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
if (c->plan->all_axes_pinned)
|
||||
return_trace (false);
|
||||
|
||||
if (c->plan->normalized_coords)
|
||||
return_trace (instantiate (c));
|
||||
|
||||
unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0;
|
||||
|
||||
|
@ -54,6 +54,12 @@ static void
|
||||
hb_paint_pop_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
|
||||
void *user_data) {}
|
||||
|
||||
static hb_bool_t
|
||||
hb_paint_color_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_font_t *font,
|
||||
void *user_data) { return false; }
|
||||
|
||||
static void
|
||||
hb_paint_push_clip_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
@ -473,6 +479,25 @@ hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data)
|
||||
funcs->pop_transform (paint_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_paint_color_glyph:
|
||||
* @funcs: paint functions
|
||||
* @paint_data: associated data passed by the caller
|
||||
* @glyph: the glyph ID
|
||||
* @font: the font
|
||||
*
|
||||
* Perform a "color-glyph" paint operation.
|
||||
*
|
||||
* Since: 8.2.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_font_t *font)
|
||||
{
|
||||
return funcs->color_glyph (paint_data, glyph, font);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_paint_push_clip_glyph:
|
||||
* @funcs: paint functions
|
||||
|
@ -136,6 +136,26 @@ typedef void (*hb_paint_pop_transform_func_t) (hb_paint_funcs_t *funcs,
|
||||
void *paint_data,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* hb_paint_color_glyph_func_t:
|
||||
* @funcs: paint functions object
|
||||
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
|
||||
* @glyph: the glyph ID
|
||||
* @font: the font
|
||||
* @user_data: User data pointer passed to hb_paint_funcs_set_color_glyph_func()
|
||||
*
|
||||
* A virtual method for the #hb_paint_funcs_t to render a color glyph by glyph index.
|
||||
*
|
||||
* Return value: %true if the glyph was painted, %false otherwise.
|
||||
*
|
||||
* Since: 8.2.0
|
||||
*/
|
||||
typedef hb_bool_t (*hb_paint_color_glyph_func_t) (hb_paint_funcs_t *funcs,
|
||||
void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_font_t *font,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* hb_paint_push_clip_glyph_func_t:
|
||||
* @funcs: paint functions object
|
||||
@ -723,6 +743,23 @@ hb_paint_funcs_set_pop_transform_func (hb_paint_funcs_t *funcs,
|
||||
void *user_data,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_paint_funcs_set_color_glyph_func:
|
||||
* @funcs: A paint functions struct
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified): The color-glyph callback
|
||||
* @user_data: Data to pass to @func
|
||||
* @destroy: (nullable): Function to call when @user_data is no longer needed
|
||||
*
|
||||
* Sets the color-glyph callback on the paint functions struct.
|
||||
*
|
||||
* Since: 8.2.0
|
||||
*/
|
||||
HB_EXTERN void
|
||||
hb_paint_funcs_set_color_glyph_func (hb_paint_funcs_t *funcs,
|
||||
hb_paint_color_glyph_func_t func,
|
||||
void *user_data,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_paint_funcs_set_push_clip_glyph_func:
|
||||
* @funcs: A paint functions struct
|
||||
@ -922,6 +959,11 @@ hb_paint_push_transform (hb_paint_funcs_t *funcs, void *paint_data,
|
||||
HB_EXTERN void
|
||||
hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_font_t *font);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_paint_push_clip_glyph (hb_paint_funcs_t *funcs, void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS \
|
||||
HB_PAINT_FUNC_IMPLEMENT (push_transform) \
|
||||
HB_PAINT_FUNC_IMPLEMENT (pop_transform) \
|
||||
HB_PAINT_FUNC_IMPLEMENT (color_glyph) \
|
||||
HB_PAINT_FUNC_IMPLEMENT (push_clip_glyph) \
|
||||
HB_PAINT_FUNC_IMPLEMENT (push_clip_rectangle) \
|
||||
HB_PAINT_FUNC_IMPLEMENT (pop_clip) \
|
||||
@ -77,6 +78,13 @@ struct hb_paint_funcs_t
|
||||
void pop_transform (void *paint_data)
|
||||
{ func.pop_transform (this, paint_data,
|
||||
!user_data ? nullptr : user_data->pop_transform); }
|
||||
bool color_glyph (void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_font_t *font)
|
||||
{ return func.color_glyph (this, paint_data,
|
||||
glyph,
|
||||
font,
|
||||
!user_data ? nullptr : user_data->push_clip_glyph); }
|
||||
void push_clip_glyph (void *paint_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_font_t *font)
|
||||
|
@ -54,6 +54,9 @@ struct hb_priority_queue_t
|
||||
|
||||
bool in_error () const { return heap.in_error (); }
|
||||
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
HB_ALWAYS_INLINE
|
||||
#endif
|
||||
void insert (int64_t priority, unsigned value)
|
||||
{
|
||||
heap.push (item_t (priority, value));
|
||||
@ -139,6 +142,7 @@ struct hb_priority_queue_t
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
HB_ALWAYS_INLINE
|
||||
void bubble_up (unsigned index)
|
||||
{
|
||||
repeat:
|
||||
|
@ -79,7 +79,12 @@ bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context
|
||||
// pass after this processing is done. Not super necessary as splits are
|
||||
// only done where overflow is likely, so de-dup probably will get undone
|
||||
// later anyways.
|
||||
for (unsigned lookup_index : ext_context.lookups.keys ())
|
||||
|
||||
// The loop below can modify the contents of ext_context.lookups if new subtables are added
|
||||
// to a lookup during a split. So save the initial set of lookup indices so the iteration doesn't
|
||||
// risk access free'd memory if ext_context.lookups gets resized.
|
||||
hb_set_t lookup_indices(ext_context.lookups.keys ());
|
||||
for (unsigned lookup_index : lookup_indices)
|
||||
{
|
||||
graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
|
||||
if (!lookup->split_subtables_if_needed (ext_context, lookup_index))
|
||||
@ -114,11 +119,15 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context
|
||||
// TODO(grieger): skip this for the 24 bit case.
|
||||
if (!ext_context.lookups) return true;
|
||||
|
||||
unsigned total_lookup_table_sizes = 0;
|
||||
hb_vector_t<lookup_size_t> lookup_sizes;
|
||||
lookup_sizes.alloc (ext_context.lookups.get_population (), true);
|
||||
|
||||
for (unsigned lookup_index : ext_context.lookups.keys ())
|
||||
{
|
||||
const auto& lookup_v = ext_context.graph.vertices_[lookup_index];
|
||||
total_lookup_table_sizes += lookup_v.table_size ();
|
||||
|
||||
const graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
|
||||
hb_set_t visited;
|
||||
lookup_sizes.push (lookup_size_t {
|
||||
@ -131,14 +140,16 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context
|
||||
lookup_sizes.qsort ();
|
||||
|
||||
size_t lookup_list_size = ext_context.graph.vertices_[ext_context.lookup_list_index].table_size ();
|
||||
size_t l2_l3_size = lookup_list_size; // Lookup List + Lookups
|
||||
size_t l3_l4_size = 0; // Lookups + SubTables
|
||||
size_t l2_l3_size = lookup_list_size + total_lookup_table_sizes; // Lookup List + Lookups
|
||||
size_t l3_l4_size = total_lookup_table_sizes; // Lookups + SubTables
|
||||
size_t l4_plus_size = 0; // SubTables + their descendants
|
||||
|
||||
// Start by assuming all lookups are using extension subtables, this size will be removed later
|
||||
// if it's decided to not make a lookup extension.
|
||||
for (auto p : lookup_sizes)
|
||||
{
|
||||
// TODO(garretrieger): this overestimates the extension subtables size because some extension subtables may be
|
||||
// reused. However, we can't correct this until we have connected component analysis in place.
|
||||
unsigned subtables_size = p.num_subtables * 8;
|
||||
l3_l4_size += subtables_size;
|
||||
l4_plus_size += subtables_size;
|
||||
@ -159,8 +170,7 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context
|
||||
size_t subtables_size = ext_context.graph.find_subgraph_size (p.lookup_index, visited, 1) - lookup_size;
|
||||
size_t remaining_size = p.size - subtables_size - lookup_size;
|
||||
|
||||
l2_l3_size += lookup_size;
|
||||
l3_l4_size += lookup_size + subtables_size;
|
||||
l3_l4_size += subtables_size;
|
||||
l3_l4_size -= p.num_subtables * 8;
|
||||
l4_plus_size += subtables_size + remaining_size;
|
||||
|
||||
|
@ -258,7 +258,8 @@ struct hb_sanitize_context_t :
|
||||
this->max_ops = -1;
|
||||
return false;
|
||||
}
|
||||
return (this->max_ops -= (int) count) > 0;
|
||||
this->max_ops -= (int) count;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
@ -381,6 +382,9 @@ struct hb_sanitize_context_t :
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
HB_ALWAYS_INLINE
|
||||
#endif
|
||||
bool check_struct (const Type *obj) const
|
||||
{
|
||||
if (sizeof (uintptr_t) == sizeof (uint32_t))
|
||||
@ -449,7 +453,7 @@ struct hb_sanitize_context_t :
|
||||
edit_count = 0;
|
||||
sane = t->sanitize (this);
|
||||
if (edit_count) {
|
||||
DEBUG_MSG_FUNC (SANITIZE, start, "requested %u edits in second round; FAILLING", edit_count);
|
||||
DEBUG_MSG_FUNC (SANITIZE, start, "requested %u edits in second round; FAILING", edit_count);
|
||||
sane = false;
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ hb_set_copy (const hb_set_t *set)
|
||||
void
|
||||
hb_set_clear (hb_set_t *set)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->clear ();
|
||||
}
|
||||
|
||||
@ -251,7 +251,7 @@ void
|
||||
hb_set_add (hb_set_t *set,
|
||||
hb_codepoint_t codepoint)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->add (codepoint);
|
||||
}
|
||||
|
||||
@ -272,7 +272,7 @@ hb_set_add_sorted_array (hb_set_t *set,
|
||||
const hb_codepoint_t *sorted_codepoints,
|
||||
unsigned int num_codepoints)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->add_sorted_array (sorted_codepoints,
|
||||
num_codepoints,
|
||||
sizeof(hb_codepoint_t));
|
||||
@ -294,7 +294,7 @@ hb_set_add_range (hb_set_t *set,
|
||||
hb_codepoint_t first,
|
||||
hb_codepoint_t last)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->add_range (first, last);
|
||||
}
|
||||
|
||||
@ -311,7 +311,7 @@ void
|
||||
hb_set_del (hb_set_t *set,
|
||||
hb_codepoint_t codepoint)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->del (codepoint);
|
||||
}
|
||||
|
||||
@ -334,7 +334,7 @@ hb_set_del_range (hb_set_t *set,
|
||||
hb_codepoint_t first,
|
||||
hb_codepoint_t last)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->del_range (first, last);
|
||||
}
|
||||
|
||||
@ -405,7 +405,7 @@ void
|
||||
hb_set_set (hb_set_t *set,
|
||||
const hb_set_t *other)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->set (*other);
|
||||
}
|
||||
|
||||
@ -422,7 +422,7 @@ void
|
||||
hb_set_union (hb_set_t *set,
|
||||
const hb_set_t *other)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->union_ (*other);
|
||||
}
|
||||
|
||||
@ -439,7 +439,7 @@ void
|
||||
hb_set_intersect (hb_set_t *set,
|
||||
const hb_set_t *other)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->intersect (*other);
|
||||
}
|
||||
|
||||
@ -456,7 +456,7 @@ void
|
||||
hb_set_subtract (hb_set_t *set,
|
||||
const hb_set_t *other)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->subtract (*other);
|
||||
}
|
||||
|
||||
@ -474,7 +474,7 @@ void
|
||||
hb_set_symmetric_difference (hb_set_t *set,
|
||||
const hb_set_t *other)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->symmetric_difference (*other);
|
||||
}
|
||||
|
||||
@ -489,7 +489,7 @@ hb_set_symmetric_difference (hb_set_t *set,
|
||||
void
|
||||
hb_set_invert (hb_set_t *set)
|
||||
{
|
||||
/* Immutible-safe. */
|
||||
/* Immutable-safe. */
|
||||
set->invert ();
|
||||
}
|
||||
|
||||
|
@ -69,14 +69,12 @@ hb_subset_input_t::hb_subset_input_t ()
|
||||
sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
|
||||
|
||||
hb_tag_t default_no_subset_tables[] = {
|
||||
HB_TAG ('a', 'v', 'a', 'r'),
|
||||
HB_TAG ('g', 'a', 's', 'p'),
|
||||
HB_TAG ('f', 'p', 'g', 'm'),
|
||||
HB_TAG ('p', 'r', 'e', 'p'),
|
||||
HB_TAG ('V', 'D', 'M', 'X'),
|
||||
HB_TAG ('D', 'S', 'I', 'G'),
|
||||
HB_TAG ('M', 'V', 'A', 'R'),
|
||||
HB_TAG ('c', 'v', 'a', 'r'),
|
||||
};
|
||||
sets.no_subset_tables->add_array (default_no_subset_tables,
|
||||
ARRAY_LENGTH (default_no_subset_tables));
|
||||
@ -480,16 +478,21 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
|
||||
* @axis_tag: Tag of the axis
|
||||
* @axis_min_value: Minimum value of the axis variation range to set
|
||||
* @axis_max_value: Maximum value of the axis variation range to set
|
||||
* @axis_def_value: Default value of the axis variation range to set, in case of
|
||||
* null, it'll be determined automatically
|
||||
*
|
||||
* Restricting the range of variation on an axis in the given subset input object.
|
||||
* New min/max values will be clamped if they're not within the fvar axis range.
|
||||
* New min/default/max values will be clamped if they're not within the fvar axis range.
|
||||
* If the new default value is null:
|
||||
* If the fvar axis default value is within the new range, then new default
|
||||
* value is the same as original default value.
|
||||
* If the fvar axis default value is not within the new range, the new default
|
||||
* value will be changed to the new min or max value, whichever is closer to the fvar
|
||||
* axis default.
|
||||
*
|
||||
* Note: input min value can not be bigger than input max value
|
||||
* Note: currently this API does not support changing axis limits yet.It'd be only
|
||||
* used internally for setting axis limits in the internal data structures
|
||||
* Note: input min value can not be bigger than input max value. If the input
|
||||
* default value is not within the new min/max range, it'll be clamped.
|
||||
* Note: currently it supports gvar and cvar tables only.
|
||||
*
|
||||
* Return value: `true` if success, `false` otherwise
|
||||
*
|
||||
@ -500,7 +503,8 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input,
|
||||
hb_face_t *face,
|
||||
hb_tag_t axis_tag,
|
||||
float axis_min_value,
|
||||
float axis_max_value)
|
||||
float axis_max_value,
|
||||
float *axis_def_value /* IN, maybe NULL */)
|
||||
{
|
||||
if (axis_min_value > axis_max_value)
|
||||
return false;
|
||||
@ -511,7 +515,8 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input,
|
||||
|
||||
float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value);
|
||||
float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value);
|
||||
float new_default_val = hb_clamp(axis_info.default_value, new_min_val, new_max_val);
|
||||
float new_default_val = axis_def_value ? *axis_def_value : axis_info.default_value;
|
||||
new_default_val = hb_clamp(new_default_val, new_min_val, new_max_val);
|
||||
return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val));
|
||||
}
|
||||
#endif
|
||||
|
@ -253,9 +253,8 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
|
||||
* axisDef axisMax
|
||||
*/
|
||||
float newUpper = peak + (1 - gain) * (upper - peak);
|
||||
// I feel like the first condition is always true because
|
||||
// outGain >= gain.
|
||||
if (axisMax <= newUpper && newUpper <= axisDef + (axisMax - axisDef) * 2)
|
||||
assert (axisMax <= newUpper); // Because outGain >= gain
|
||||
if (newUpper <= axisDef + (axisMax - axisDef) * 2)
|
||||
{
|
||||
upper = newUpper;
|
||||
if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
|
||||
@ -362,38 +361,47 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Normalizes value based on a min/default/max triple. */
|
||||
static inline float normalizeValue (float v, const Triple &triple, bool extrapolate = false)
|
||||
static inline TripleDistances _reverse_triple_distances (const TripleDistances &v)
|
||||
{ return TripleDistances (v.positive, v.negative); }
|
||||
|
||||
float renormalizeValue (float v, const Triple &triple,
|
||||
const TripleDistances &triple_distances, bool extrapolate)
|
||||
{
|
||||
/*
|
||||
>>> normalizeValue(400, (100, 400, 900))
|
||||
0.0
|
||||
>>> normalizeValue(100, (100, 400, 900))
|
||||
-1.0
|
||||
>>> normalizeValue(650, (100, 400, 900))
|
||||
0.5
|
||||
*/
|
||||
float lower = triple.minimum, def = triple.middle, upper = triple.maximum;
|
||||
assert (lower <= def && def <= upper);
|
||||
|
||||
if (!extrapolate)
|
||||
v = hb_max (hb_min (v, upper), lower);
|
||||
|
||||
if ((v == def) || (lower == upper))
|
||||
if (v == def)
|
||||
return 0.f;
|
||||
|
||||
if ((v < def && lower != def) || (v > def && upper == def))
|
||||
return (v - def) / (def - lower);
|
||||
else
|
||||
{
|
||||
assert ((v > def && upper != def) ||
|
||||
(v < def && lower == def));
|
||||
if (def < 0.f)
|
||||
return -renormalizeValue (-v, _reverse_negate (triple),
|
||||
_reverse_triple_distances (triple_distances), extrapolate);
|
||||
|
||||
/* default >= 0 and v != default */
|
||||
if (v > def)
|
||||
return (v - def) / (upper - def);
|
||||
}
|
||||
|
||||
/* v < def */
|
||||
if (lower >= 0.f)
|
||||
return (v - def) / (def - lower);
|
||||
|
||||
/* lower < 0 and v < default */
|
||||
float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
|
||||
|
||||
float v_distance;
|
||||
if (v >= 0.f)
|
||||
v_distance = (def - v) * triple_distances.positive;
|
||||
else
|
||||
v_distance = (-v) * triple_distances.negative + triple_distances.positive * def;
|
||||
|
||||
return (-v_distance) /total_distance;
|
||||
}
|
||||
|
||||
result_t
|
||||
rebase_tent (Triple tent, Triple axisLimit)
|
||||
rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances)
|
||||
{
|
||||
assert (-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.f);
|
||||
assert (-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.f);
|
||||
@ -401,7 +409,7 @@ rebase_tent (Triple tent, Triple axisLimit)
|
||||
|
||||
result_t sols = _solve (tent, axisLimit);
|
||||
|
||||
auto n = [&axisLimit] (float v) { return normalizeValue (v, axisLimit, true); };
|
||||
auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
|
||||
|
||||
result_t out;
|
||||
for (auto &p : sols)
|
||||
|
@ -27,6 +27,21 @@
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
/* pre-normalized distances */
|
||||
struct TripleDistances
|
||||
{
|
||||
TripleDistances (): negative (1.f), positive (1.f) {}
|
||||
TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {}
|
||||
TripleDistances (float min, float default_, float max)
|
||||
{
|
||||
negative = default_ - min;
|
||||
positive = max - default_;
|
||||
}
|
||||
|
||||
float negative;
|
||||
float positive;
|
||||
};
|
||||
|
||||
struct Triple {
|
||||
|
||||
Triple () :
|
||||
@ -66,6 +81,7 @@ struct Triple {
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
float minimum;
|
||||
float middle;
|
||||
float maximum;
|
||||
@ -74,6 +90,12 @@ struct Triple {
|
||||
using result_item_t = hb_pair_t<float, Triple>;
|
||||
using result_t = hb_vector_t<result_item_t>;
|
||||
|
||||
/* renormalize a normalized value v to the range of an axis,
|
||||
* considering the prenormalized distances as well as the new axis limits.
|
||||
* Ported from fonttools */
|
||||
HB_INTERNAL float renormalizeValue (float v, const Triple &triple,
|
||||
const TripleDistances &triple_distances,
|
||||
bool extrapolate = true);
|
||||
/* Given a tuple (lower,peak,upper) "tent" and new axis limits
|
||||
* (axisMin,axisDefault,axisMax), solves how to represent the tent
|
||||
* under the new axis configuration. All values are in normalized
|
||||
@ -85,6 +107,6 @@ using result_t = hb_vector_t<result_item_t>;
|
||||
* If tent value is Triple{}, that is a special deltaset that should
|
||||
* be always-enabled (called "gain").
|
||||
*/
|
||||
HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit);
|
||||
HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances);
|
||||
|
||||
#endif /* HB_SUBSET_INSTANCER_SOLVER_HH */
|
||||
|
@ -105,6 +105,8 @@ HB_SUBSET_PLAN_MEMBER (hb_vector_t<int>, normalized_coords)
|
||||
|
||||
//user specified axes range map
|
||||
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), user_axes_location)
|
||||
//axis->TripleDistances map (distances in the pre-normalized space)
|
||||
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, TripleDistances>), axes_triple_distances)
|
||||
|
||||
//retained old axis index -> new axis index mapping in fvar axis array
|
||||
HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map)
|
||||
@ -121,6 +123,9 @@ HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_width_vec)
|
||||
//boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin
|
||||
HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_height_vec)
|
||||
|
||||
//map: new_gid -> contour points vector
|
||||
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, contour_point_vector_t>), new_gid_contour_points_map)
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
// name table overrides map: hb_ot_name_record_ids_t-> name string new value or
|
||||
// None to indicate should remove
|
||||
|
@ -605,11 +605,14 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
|
||||
|
||||
/* Add gids which where requested, but not mapped in cmap */
|
||||
unsigned num_glyphs = plan->source->get_num_glyphs ();
|
||||
for (hb_codepoint_t gid : *glyphs)
|
||||
hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
|
||||
for (; glyphs->next_range (&first, &last); )
|
||||
{
|
||||
if (gid >= num_glyphs)
|
||||
if (first >= num_glyphs)
|
||||
break;
|
||||
plan->_glyphset_gsub.add (gid);
|
||||
if (last >= num_glyphs)
|
||||
last = num_glyphs - 1;
|
||||
plan->_glyphset_gsub.add_range (first, last);
|
||||
}
|
||||
}
|
||||
|
||||
@ -927,12 +930,14 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
||||
new_axis_idx++;
|
||||
}
|
||||
|
||||
if (plan->user_axes_location.has (axis_tag))
|
||||
Triple *axis_range;
|
||||
if (plan->user_axes_location.has (axis_tag, &axis_range))
|
||||
{
|
||||
Triple axis_range = plan->user_axes_location.get (axis_tag);
|
||||
int normalized_min = axis.normalize_axis_value (axis_range.minimum);
|
||||
int normalized_default = axis.normalize_axis_value (axis_range.middle);
|
||||
int normalized_max = axis.normalize_axis_value (axis_range.maximum);
|
||||
plan->axes_triple_distances.set (axis_tag, axis.get_triple_distances ());
|
||||
|
||||
int normalized_min = axis.normalize_axis_value (axis_range->minimum);
|
||||
int normalized_default = axis.normalize_axis_value (axis_range->middle);
|
||||
int normalized_max = axis.normalize_axis_value (axis_range->maximum);
|
||||
|
||||
if (has_avar && old_axis_idx < avar_axis_count)
|
||||
{
|
||||
@ -940,9 +945,9 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
||||
normalized_default = seg_maps->map (normalized_default);
|
||||
normalized_max = seg_maps->map (normalized_max);
|
||||
}
|
||||
plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min),
|
||||
static_cast<float> (normalized_default),
|
||||
static_cast<float> (normalized_max)));
|
||||
plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min / 16384.f),
|
||||
static_cast<float> (normalized_default / 16384.f),
|
||||
static_cast<float> (normalized_max / 16384.f)));
|
||||
|
||||
if (normalized_default != 0)
|
||||
plan->pinned_at_default = false;
|
||||
@ -1040,6 +1045,36 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
|
||||
if (vvar_store_cache)
|
||||
_vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache);
|
||||
}
|
||||
|
||||
static bool
|
||||
_get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
|
||||
{
|
||||
/* contour_points vector only needed for updating gvar table (infer delta)
|
||||
* during partial instancing */
|
||||
if (plan->user_axes_location.is_empty () || plan->all_axes_pinned)
|
||||
return true;
|
||||
|
||||
OT::glyf_accelerator_t glyf (plan->source);
|
||||
|
||||
for (auto &_ : plan->new_to_old_gid_list)
|
||||
{
|
||||
hb_codepoint_t new_gid = _.first;
|
||||
contour_point_vector_t all_points;
|
||||
if (new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
|
||||
{
|
||||
if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
hb_codepoint_t old_gid = _.second;
|
||||
if (unlikely (!glyf.glyph_for_gid (old_gid).get_all_points_without_var (plan->source, all_points)))
|
||||
return false;
|
||||
if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
|
||||
@ -1143,6 +1178,8 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
_update_instance_metrics_map_from_cff2 (this);
|
||||
if (!check_success (_get_instance_glyphs_contour_points (this)))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (attach_accelerator_data)
|
||||
|
@ -67,6 +67,40 @@ struct head_maxp_info_t
|
||||
|
||||
typedef struct head_maxp_info_t head_maxp_info_t;
|
||||
|
||||
struct contour_point_t
|
||||
{
|
||||
void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
|
||||
{ flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
|
||||
|
||||
void transform (const float (&matrix)[4])
|
||||
{
|
||||
float x_ = x * matrix[0] + y * matrix[2];
|
||||
y = x * matrix[1] + y * matrix[3];
|
||||
x = x_;
|
||||
}
|
||||
HB_ALWAYS_INLINE
|
||||
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
|
||||
|
||||
|
||||
float x;
|
||||
float y;
|
||||
uint8_t flag;
|
||||
bool is_end_point;
|
||||
};
|
||||
|
||||
struct contour_point_vector_t : hb_vector_t<contour_point_t>
|
||||
{
|
||||
void extend (const hb_array_t<contour_point_t> &a)
|
||||
{
|
||||
unsigned int old_len = length;
|
||||
if (unlikely (!resize (old_len + a.length, false)))
|
||||
return;
|
||||
auto arrayZ = this->arrayZ + old_len;
|
||||
unsigned count = a.length;
|
||||
hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
|
||||
}
|
||||
};
|
||||
|
||||
namespace OT {
|
||||
struct cff1_subset_accelerator_t;
|
||||
struct cff2_subset_accelerator_t;
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "hb-ot-name-table.hh"
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
#include "hb-ot-layout-gpos-table.hh"
|
||||
#include "hb-ot-var-avar-table.hh"
|
||||
#include "hb-ot-var-cvar-table.hh"
|
||||
#include "hb-ot-var-fvar-table.hh"
|
||||
#include "hb-ot-var-gvar-table.hh"
|
||||
@ -516,10 +517,14 @@ _subset_table (hb_subset_plan_t *plan,
|
||||
case HB_OT_TAG_fvar:
|
||||
if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
|
||||
return _subset<const OT::fvar> (plan, buf);
|
||||
case HB_OT_TAG_avar:
|
||||
if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
|
||||
return _subset<const OT::avar> (plan, buf);
|
||||
case HB_OT_TAG_cvar:
|
||||
if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
|
||||
return _subset<const OT::cvar> (plan, buf);
|
||||
case HB_OT_TAG_STAT:
|
||||
/*TODO(qxliu): change the condition as we support more complex
|
||||
* instancing operation*/
|
||||
if (plan->all_axes_pinned) return _subset<const OT::STAT> (plan, buf);
|
||||
if (!plan->user_axes_location.is_empty ()) return _subset<const OT::STAT> (plan, buf);
|
||||
else return _passthrough (plan, tag);
|
||||
|
||||
case HB_TAG ('c', 'v', 't', ' '):
|
||||
|
@ -181,7 +181,8 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input,
|
||||
hb_face_t *face,
|
||||
hb_tag_t axis_tag,
|
||||
float axis_min_value,
|
||||
float axis_max_value);
|
||||
float axis_max_value,
|
||||
float *axis_def_value);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_subset_input_override_name_table (hb_subset_input_t *input,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,13 +7,13 @@
|
||||
* on file with this header:
|
||||
*
|
||||
* # emoji-data.txt
|
||||
* # Date: 2022-08-02, 00:26:10 GMT
|
||||
* # © 2022 Unicode®, Inc.
|
||||
* # Date: 2023-02-01, 02:22:54 GMT
|
||||
* # © 2023 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
|
||||
* #
|
||||
* # Emoji Data for UTS #51
|
||||
* # Used with Emoji Version 15.0 and subsequent minor revisions (if any)
|
||||
* # Used with Emoji Version 15.1 and subsequent minor revisions (if any)
|
||||
* #
|
||||
* # For documentation and usage, see https://www.unicode.org/reports/tr51
|
||||
*/
|
||||
|
@ -699,7 +699,7 @@ retry:
|
||||
script_tags,
|
||||
&item_count);
|
||||
if (unlikely (FAILED (hr)))
|
||||
FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", hr);
|
||||
FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", (unsigned long) hr);
|
||||
|
||||
#undef MAX_ITEMS
|
||||
|
||||
@ -785,7 +785,7 @@ retry:
|
||||
}
|
||||
if (unlikely (FAILED (hr)))
|
||||
{
|
||||
FAIL ("ScriptShapeOpenType() failed: 0x%08lx", hr);
|
||||
FAIL ("ScriptShapeOpenType() failed: 0x%08lx", (unsigned long) hr);
|
||||
}
|
||||
|
||||
for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
|
||||
@ -811,7 +811,7 @@ retry:
|
||||
offsets + glyphs_offset,
|
||||
nullptr);
|
||||
if (unlikely (FAILED (hr)))
|
||||
FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", hr);
|
||||
FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", (unsigned long) hr);
|
||||
|
||||
if (DEBUG_ENABLED (UNISCRIBE))
|
||||
fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
|
||||
|
@ -102,7 +102,7 @@ struct hb_vector_t
|
||||
|
||||
void fini ()
|
||||
{
|
||||
/* We allow a hack to make the vector point to a foriegn array
|
||||
/* We allow a hack to make the vector point to a foreign array
|
||||
* by the user. In that case length/arrayZ are non-zero but
|
||||
* allocated is zero. Don't free anything. */
|
||||
if (allocated)
|
||||
@ -208,25 +208,7 @@ struct hb_vector_t
|
||||
return std::addressof (Crap (Type));
|
||||
return std::addressof (arrayZ[length - 1]);
|
||||
}
|
||||
template <typename T,
|
||||
typename T2 = Type,
|
||||
hb_enable_if (!std::is_copy_constructible<T2>::value &&
|
||||
std::is_copy_assignable<T>::value)>
|
||||
Type *push (T&& v)
|
||||
{
|
||||
Type *p = push ();
|
||||
if (p == std::addressof (Crap (Type)))
|
||||
// If push failed to allocate then don't copy v, since this may cause
|
||||
// the created copy to leak memory since we won't have stored a
|
||||
// reference to it.
|
||||
return p;
|
||||
*p = std::forward<T> (v);
|
||||
return p;
|
||||
}
|
||||
template <typename T,
|
||||
typename T2 = Type,
|
||||
hb_enable_if (std::is_copy_constructible<T2>::value)>
|
||||
Type *push (T&& v)
|
||||
template <typename... Args> Type *push (Args&&... args)
|
||||
{
|
||||
if (unlikely ((int) length >= allocated && !alloc (length + 1)))
|
||||
// If push failed to allocate then don't copy v, since this may cause
|
||||
@ -236,7 +218,7 @@ struct hb_vector_t
|
||||
|
||||
/* Emplace. */
|
||||
Type *p = std::addressof (arrayZ[length++]);
|
||||
return new (p) Type (std::forward<T> (v));
|
||||
return new (p) Type (std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
bool in_error () const { return allocated < 0; }
|
||||
|
@ -47,7 +47,7 @@ HB_BEGIN_DECLS
|
||||
*
|
||||
* The minor component of the library version available at compile-time.
|
||||
*/
|
||||
#define HB_VERSION_MINOR 0
|
||||
#define HB_VERSION_MINOR 2
|
||||
/**
|
||||
* HB_VERSION_MICRO:
|
||||
*
|
||||
@ -60,7 +60,7 @@ HB_BEGIN_DECLS
|
||||
*
|
||||
* A string literal containing the library version available at compile-time.
|
||||
*/
|
||||
#define HB_VERSION_STRING "8.0.1"
|
||||
#define HB_VERSION_STRING "8.2.1"
|
||||
|
||||
/**
|
||||
* HB_VERSION_ATLEAST:
|
||||
|
@ -48,7 +48,7 @@
|
||||
*
|
||||
* - Build your font's wasm code importing the shared modules with the desired
|
||||
* name. This can be done eg.: __attribute__((import_module("graphite2")))
|
||||
* before each symbol in the the shared-module's headers.
|
||||
* before each symbol in the shared-module's headers.
|
||||
*
|
||||
* - Try shaping your font and hope for the best...
|
||||
*
|
||||
|
@ -560,7 +560,7 @@ defs_list = [harfbuzz_def]
|
||||
version = '0.@0@.0'.format(hb_version_int)
|
||||
|
||||
extra_hb_cpp_args = []
|
||||
if cpp.get_argument_syntax() == 'msvc'
|
||||
if cpp.get_define('_MSC_FULL_VER') != ''
|
||||
if get_option('default_library') != 'static'
|
||||
extra_hb_cpp_args += '-DHB_DLL_EXPORT'
|
||||
endif
|
||||
@ -680,18 +680,31 @@ endif
|
||||
if get_option('tests').enabled()
|
||||
# TODO: MSVC gives the following,
|
||||
# error LNK2019: unresolved external symbol "unsigned __int64 const * const _hb_NullPool"
|
||||
if cpp.get_argument_syntax() != 'msvc'
|
||||
if cpp.get_define('_MSC_FULL_VER') == ''
|
||||
noinst_programs = {
|
||||
'main': 'main.cc',
|
||||
'test-algs': ['test-algs.cc', 'hb-static.cc'],
|
||||
'test-basics': 'test.cc',
|
||||
'test-bimap': ['test-bimap.cc', 'hb-static.cc'],
|
||||
'test-buffer-serialize': 'test-buffer-serialize.cc',
|
||||
'test-classdef-graph': ['graph/test-classdef-graph.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
|
||||
'test-instancer-solver': ['test-subset-instancer-solver.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
|
||||
'test-iter': ['test-iter.cc', 'hb-static.cc'],
|
||||
'test-map': ['test-map.cc', 'hb-static.cc'],
|
||||
'test-multimap': ['test-multimap.cc', 'hb-static.cc'],
|
||||
'test-ot-meta': 'test-ot-meta.cc',
|
||||
'test-ot-name': 'test-ot-name.cc',
|
||||
'test-ot-glyphname': 'test-ot-glyphname.cc',
|
||||
'test-ot-gpos-size-params': 'test-gpos-size-params.cc',
|
||||
'test-ot-gsub-get-alternates': 'test-gsub-get-alternates.cc',
|
||||
'test-ot-gsub-would-substitute': 'test-gsub-would-substitute.cc',
|
||||
'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
|
||||
'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
|
||||
'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
|
||||
'test-set': ['test-set.cc', 'hb-static.cc'],
|
||||
'test-tuple-varstore': ['test-tuple-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
|
||||
'test-use-table': 'test-use-table.cc',
|
||||
'test-vector': ['test-vector.cc', 'hb-static.cc'],
|
||||
}
|
||||
foreach name, source : noinst_programs
|
||||
executable(name, source,
|
||||
@ -704,24 +717,11 @@ if get_option('tests').enabled()
|
||||
endif
|
||||
|
||||
compiled_tests = {
|
||||
'test-algs': ['test-algs.cc', 'hb-static.cc'],
|
||||
'test-array': ['test-array.cc'],
|
||||
'test-iter': ['test-iter.cc', 'hb-static.cc'],
|
||||
'test-machinery': ['test-machinery.cc', 'hb-static.cc'],
|
||||
'test-map': ['test-map.cc', 'hb-static.cc'],
|
||||
'test-multimap': ['test-multimap.cc', 'hb-static.cc'],
|
||||
'test-number': ['test-number.cc', 'hb-number.cc'],
|
||||
'test-ot-tag': ['hb-ot-tag.cc'],
|
||||
'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
|
||||
'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
|
||||
'test-classdef-graph': ['graph/test-classdef-graph.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
|
||||
'test-set': ['test-set.cc', 'hb-static.cc'],
|
||||
'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
|
||||
'test-unicode-ranges': ['test-unicode-ranges.cc'],
|
||||
'test-vector': ['test-vector.cc', 'hb-static.cc'],
|
||||
'test-bimap': ['test-bimap.cc', 'hb-static.cc'],
|
||||
'test-instancer-solver': ['test-subset-instancer-solver.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
|
||||
'test-tuple-varstore': ['test-tuple-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
|
||||
}
|
||||
foreach name, source : compiled_tests
|
||||
if cpp.get_argument_syntax() == 'msvc' and source.contains('hb-static.cc')
|
||||
|
@ -8,6 +8,7 @@
|
||||
# Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
||||
# Updated for Unicode 14.0 by Andrew Glass 2021-09-28
|
||||
# Updated for Unicode 15.0 by Andrew Glass 2022-09-16
|
||||
# Updated for Unicode 15.1 by Andrew Glass 2023-09-14
|
||||
|
||||
# ================================================
|
||||
# ================================================
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user