Merge tag 'v5.15.17-lts' into tqtc/lts-5.15-opensource

Qt 5.15.17-lts release

Change-Id: I336899856c2c660887c6877d8736787bf4622150
This commit is contained in:
Tarja Sundqvist 2024-11-20 15:56:33 +02:00
commit 5e8b3ee0ae
298 changed files with 51533 additions and 30122 deletions

View File

@ -6,4 +6,4 @@ DEFINES += QT_NO_JAVA_STYLE_ITERATORS
QT_SOURCE_TREE = $$PWD QT_SOURCE_TREE = $$PWD
QT_BUILD_TREE = $$shadowed($$PWD) QT_BUILD_TREE = $$shadowed($$PWD)
MODULE_VERSION = 5.15.16 MODULE_VERSION = 5.15.17

View File

@ -11,7 +11,7 @@ QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.13
# older SDKs we have to keep this. # older SDKs we have to keep this.
QT_MAC_SDK_VERSION_MIN = 10.14 QT_MAC_SDK_VERSION_MIN = 10.14
QT_MAC_SDK_VERSION_MAX = 13 QT_MAC_SDK_VERSION_MAX = 14
device.sdk = macosx device.sdk = macosx
device.target = device device.target = device

View File

@ -2,7 +2,7 @@
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main) [![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html) [![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz) [![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&utm_medium=referral&utm_content=harfbuzz/harfbuzz&utm_campaign=Badge_Grade) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz) [![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions) [![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
@ -13,8 +13,10 @@
HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also
[Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome, [Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome,
ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX, ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX,
PlayStation, Microsoft Edge, Photoshop, Illustrator, InDesign, PlayStation, Microsoft Edge, Adobe Photoshop, Illustrator, InDesign,
and other places. Godot Engine, and other places.
[![xkcd-derived image](xkcd.png)](https://xkcd.com/2347/)
For bug reports, mailing list, and other information please visit: For bug reports, mailing list, and other information please visit:
@ -70,9 +72,9 @@ For a comparison of old vs new HarfBuzz memory consumption see [this][10].
## Name ## Name
HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”, HarfBuzz (حرف‌باز) is the literal Persian translation of “[OpenType][1]”,
transliterated using the Latin script. It sports a second meaning, but that transliterated using the Latin script. It also means "talkative" or
aint translatable. "glib" (also a nod to the GNOME project where HarfBuzz originates from).
> Background: Originally there was this font format called TrueType. People and > Background: Originally there was this font format called TrueType. People and
> companies started calling their type engines all things ending in Type: > companies started calling their type engines all things ending in Type:

View File

@ -63,6 +63,7 @@ SOURCES += \
$$PWD/src/hb-subset-cff1.cc \ $$PWD/src/hb-subset-cff1.cc \
$$PWD/src/hb-subset-cff2.cc \ $$PWD/src/hb-subset-cff2.cc \
$$PWD/src/hb-subset-input.cc \ $$PWD/src/hb-subset-input.cc \
$$PWD/src/hb-subset-instancer-iup.cc \
$$PWD/src/hb-subset-instancer-solver.cc \ $$PWD/src/hb-subset-instancer-solver.cc \
$$PWD/src/hb-subset-plan.cc \ $$PWD/src/hb-subset-plan.cc \
$$PWD/src/hb-subset-repacker.cc \ $$PWD/src/hb-subset-repacker.cc \
@ -92,6 +93,7 @@ HEADERS += \
$$PWD/src/hb-shaper-impl.hh \ $$PWD/src/hb-shaper-impl.hh \
$$PWD/src/hb-shaper-list.hh \ $$PWD/src/hb-shaper-list.hh \
$$PWD/src/hb-string-array.hh \ $$PWD/src/hb-string-array.hh \
$$PWD/src/hb-subset-instancer-iup.hh \
$$PWD/src/hb-subset-plan-member-list.hh \ $$PWD/src/hb-subset-plan-member-list.hh \
$$PWD/src/hb-subset-repacker.h \ $$PWD/src/hb-subset-repacker.h \
$$PWD/src/hb-unicode.hh $$PWD/src/hb-unicode.hh

View File

@ -7,7 +7,7 @@
"Description": "HarfBuzz is an OpenType text shaping engine.", "Description": "HarfBuzz is an OpenType text shaping engine.",
"Homepage": "http://harfbuzz.org", "Homepage": "http://harfbuzz.org",
"Version": "8.2.2", "Version": "8.4.0",
"License": "MIT License", "License": "MIT License",
"LicenseId": "MIT", "LicenseId": "MIT",
"LicenseFile": "COPYING", "LicenseFile": "COPYING",

View File

@ -204,6 +204,7 @@ struct IndexSubtable
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.header.sanitize (c)) return_trace (false); if (!u.header.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.header.indexFormat) switch (u.header.indexFormat)
{ {
case 1: return_trace (u.format1.sanitize (c, glyph_count)); case 1: return_trace (u.format1.sanitize (c, glyph_count));
@ -378,6 +379,7 @@ struct IndexSubtableRecord
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
firstGlyphIndex <= lastGlyphIndex && firstGlyphIndex <= lastGlyphIndex &&
offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1)); offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
} }
@ -635,6 +637,7 @@ struct BitmapSizeTable
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) && indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
horizontal.sanitize (c) && horizontal.sanitize (c) &&
vertical.sanitize (c)); vertical.sanitize (c));
@ -738,7 +741,9 @@ struct CBLC
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
likely (version.major == 2 || version.major == 3) && likely (version.major == 2 || version.major == 3) &&
hb_barrier () &&
sizeTables.sanitize (c, this)); sizeTables.sanitize (c, this));
} }
@ -975,6 +980,7 @@ struct CBDT
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
likely (version.major == 2 || version.major == 3)); likely (version.major == 2 || version.major == 3));
} }

View File

@ -68,7 +68,7 @@ public:
hb_font_t *font; hb_font_t *font;
unsigned int palette_index; unsigned int palette_index;
hb_color_t foreground; hb_color_t foreground;
VarStoreInstancer &instancer; ItemVarStoreInstancer &instancer;
hb_map_t current_glyphs; hb_map_t current_glyphs;
hb_map_t current_layers; hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL; int depth_left = HB_MAX_NESTING_LEVEL;
@ -80,7 +80,7 @@ public:
hb_font_t *font_, hb_font_t *font_,
unsigned int palette_, unsigned int palette_,
hb_color_t foreground_, hb_color_t foreground_,
VarStoreInstancer &instancer_) : ItemVarStoreInstancer &instancer_) :
base (base_), base (base_),
funcs (funcs_), funcs (funcs_),
data (data_), data (data_),
@ -245,7 +245,7 @@ struct Variable
{ value.closurev1 (c); } { value.closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
if (!value.subset (c, instancer, varIdxBase)) return_trace (false); if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
@ -270,7 +270,7 @@ struct Variable
void get_color_stop (hb_paint_context_t *c, void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop, hb_color_stop_t *stop,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
value.get_color_stop (c, stop, varIdxBase, instancer); value.get_color_stop (c, stop, varIdxBase, instancer);
} }
@ -305,7 +305,7 @@ struct NoVariable
{ value.closurev1 (c); } { value.closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
return_trace (value.subset (c, instancer, varIdxBase)); return_trace (value.subset (c, instancer, varIdxBase));
@ -325,7 +325,7 @@ struct NoVariable
void get_color_stop (hb_paint_context_t *c, void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop, hb_color_stop_t *stop,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer); value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
} }
@ -348,7 +348,7 @@ struct ColorStop
{ c->add_palette_index (paletteIndex); } { c->add_palette_index (paletteIndex); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -374,7 +374,7 @@ struct ColorStop
void get_color_stop (hb_paint_context_t *c, void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *out, hb_color_stop_t *out,
uint32_t varIdx, uint32_t varIdx,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
out->offset = stopOffset.to_float(instancer (varIdx, 0)); out->offset = stopOffset.to_float(instancer (varIdx, 0));
out->color = c->get_color (paletteIndex, out->color = c->get_color (paletteIndex,
@ -410,7 +410,7 @@ struct ColorLine
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
@ -439,7 +439,7 @@ struct ColorLine
unsigned int start, unsigned int start,
unsigned int *count, unsigned int *count,
hb_color_stop_t *color_stops, hb_color_stop_t *color_stops,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
unsigned int len = stops.len; unsigned int len = stops.len;
@ -543,7 +543,7 @@ struct Affine2x3
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -588,7 +588,7 @@ struct PaintColrLayers
void closurev1 (hb_colrv1_closure_context_t* c) const; void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer HB_UNUSED) const const ItemVarStoreInstancer &instancer HB_UNUSED) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -620,7 +620,7 @@ struct PaintSolid
{ c->add_palette_index (paletteIndex); } { c->add_palette_index (paletteIndex); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -669,7 +669,7 @@ struct PaintLinearGradient
{ (this+colorLine).closurev1 (c); } { (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -736,7 +736,7 @@ struct PaintRadialGradient
{ (this+colorLine).closurev1 (c); } { (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -803,7 +803,7 @@ struct PaintSweepGradient
{ (this+colorLine).closurev1 (c); } { (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -863,7 +863,7 @@ struct PaintGlyph
void closurev1 (hb_colrv1_closure_context_t* c) const; void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -906,7 +906,7 @@ struct PaintColrGlyph
void closurev1 (hb_colrv1_closure_context_t* c) const; void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer HB_UNUSED) const const ItemVarStoreInstancer &instancer HB_UNUSED) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -936,7 +936,7 @@ struct PaintTransform
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -975,7 +975,7 @@ struct PaintTranslate
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1024,7 +1024,7 @@ struct PaintScale
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1073,7 +1073,7 @@ struct PaintScaleAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1132,7 +1132,7 @@ struct PaintScaleUniform
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1176,7 +1176,7 @@ struct PaintScaleUniformAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1232,7 +1232,7 @@ struct PaintRotate
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1276,7 +1276,7 @@ struct PaintRotateAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1332,7 +1332,7 @@ struct PaintSkew
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1381,7 +1381,7 @@ struct PaintSkewAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1440,7 +1440,7 @@ struct PaintComposite
void closurev1 (hb_colrv1_closure_context_t* c) const; void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -1491,7 +1491,7 @@ struct ClipBoxFormat1
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
{ {
clip_box.xMin = xMin; clip_box.xMin = xMin;
clip_box.yMin = yMin; clip_box.yMin = yMin;
@ -1500,7 +1500,7 @@ struct ClipBoxFormat1
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -1533,7 +1533,7 @@ struct ClipBoxFormat1
struct ClipBoxFormat2 : Variable<ClipBoxFormat1> struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
{ {
void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
{ {
value.get_clip_box(clip_box, instancer); value.get_clip_box(clip_box, instancer);
if (instancer) if (instancer)
@ -1549,7 +1549,7 @@ struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
struct ClipBox struct ClipBox
{ {
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
switch (u.format) { switch (u.format) {
@ -1572,7 +1572,7 @@ struct ClipBox
} }
bool get_extents (hb_glyph_extents_t *extents, bool get_extents (hb_glyph_extents_t *extents,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
ClipBoxData clip_box; ClipBoxData clip_box;
switch (u.format) { switch (u.format) {
@ -1608,7 +1608,7 @@ struct ClipRecord
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const void *base, const void *base,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this); auto *out = c->serializer->embed (*this);
@ -1625,7 +1625,7 @@ struct ClipRecord
bool get_extents (hb_glyph_extents_t *extents, bool get_extents (hb_glyph_extents_t *extents,
const void *base, const void *base,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
return (base+clipBox).get_extents (extents, instancer); return (base+clipBox).get_extents (extents, instancer);
} }
@ -1642,7 +1642,7 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
struct ClipList struct ClipList
{ {
unsigned serialize_clip_records (hb_subset_context_t *c, unsigned serialize_clip_records (hb_subset_context_t *c,
const VarStoreInstancer &instancer, const ItemVarStoreInstancer &instancer,
const hb_set_t& gids, const hb_set_t& gids,
const hb_map_t& gid_offset_map) const const hb_map_t& gid_offset_map) const
{ {
@ -1695,7 +1695,7 @@ struct ClipList
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -1735,7 +1735,7 @@ struct ClipList
bool bool
get_extents (hb_codepoint_t gid, get_extents (hb_codepoint_t gid,
hb_glyph_extents_t *extents, hb_glyph_extents_t *extents,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
auto *rec = clips.as_array ().bsearch (gid); auto *rec = clips.as_array ().bsearch (gid);
if (rec) if (rec)
@ -1855,7 +1855,7 @@ struct BaseGlyphPaintRecord
bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map, bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
const void* src_base, hb_subset_context_t *c, const void* src_base, hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
auto *out = s->embed (this); auto *out = s->embed (this);
@ -1884,7 +1884,7 @@ struct BaseGlyphPaintRecord
struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord> struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
{ {
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
@ -1916,7 +1916,7 @@ struct LayerList : Array32OfOffset32To<Paint>
{ return this+(*this)[i]; } { return this+(*this)[i]; }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const VarStoreInstancer &instancer) const const ItemVarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
@ -1948,10 +1948,11 @@ struct COLR
bool has_v0_data () const { return numBaseGlyphs; } bool has_v0_data () const { return numBaseGlyphs; }
bool has_v1_data () const bool has_v1_data () const
{ {
if (version == 1) if (version != 1)
return (this+baseGlyphList).len > 0; return false;
hb_barrier ();
return false; return (this+baseGlyphList).len > 0;
} }
unsigned int get_glyph_layers (hb_codepoint_t glyph, unsigned int get_glyph_layers (hb_codepoint_t glyph,
@ -2032,6 +2033,8 @@ struct COLR
hb_set_t *palette_indices) const hb_set_t *palette_indices) const
{ {
if (version != 1) return; if (version != 1) return;
hb_barrier ();
hb_set_t visited_glyphs; hb_set_t visited_glyphs;
hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices); hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
@ -2058,10 +2061,12 @@ struct COLR
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
(this+layersZ).sanitize (c, numLayers) && (this+layersZ).sanitize (c, numLayers) &&
(version == 0 || (version == 0 ||
(version == 1 && (hb_barrier () &&
version == 1 &&
baseGlyphList.sanitize (c, this) && baseGlyphList.sanitize (c, this) &&
layerList.sanitize (c, this) && layerList.sanitize (c, this) &&
clipList.sanitize (c, this) && clipList.sanitize (c, this) &&
@ -2201,7 +2206,7 @@ struct COLR
auto snap = c->serializer->snapshot (); auto snap = c->serializer->snapshot ();
if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false); if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr, ItemVarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
varIdxMap ? &(this+varIdxMap) : nullptr, varIdxMap ? &(this+varIdxMap) : nullptr,
c->plan->normalized_coords.as_array ()); c->plan->normalized_coords.as_array ());
@ -2245,7 +2250,7 @@ struct COLR
if (version != 1) if (version != 1)
return false; return false;
VarStoreInstancer instancer (&(this+varStore), ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap), &(this+varIdxMap),
hb_array (font->coords, font->num_coords)); hb_array (font->coords, font->num_coords));
@ -2284,6 +2289,8 @@ struct COLR
{ {
if (version == 1) if (version == 1)
{ {
hb_barrier ();
const Paint *paint = get_base_glyph_paint (glyph); const Paint *paint = get_base_glyph_paint (glyph);
return paint != nullptr; return paint != nullptr;
@ -2294,7 +2301,7 @@ struct COLR
bool get_clip (hb_codepoint_t glyph, bool get_clip (hb_codepoint_t glyph,
hb_glyph_extents_t *extents, hb_glyph_extents_t *extents,
const VarStoreInstancer instancer) const const ItemVarStoreInstancer instancer) const
{ {
return (this+clipList).get_extents (glyph, return (this+clipList).get_extents (glyph,
extents, extents,
@ -2305,7 +2312,7 @@ struct COLR
bool bool
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
{ {
VarStoreInstancer instancer (&(this+varStore), ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap), &(this+varIdxMap),
hb_array (font->coords, font->num_coords)); hb_array (font->coords, font->num_coords));
hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer); hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
@ -2313,12 +2320,14 @@ struct COLR
if (version == 1) if (version == 1)
{ {
hb_barrier ();
const Paint *paint = get_base_glyph_paint (glyph); const Paint *paint = get_base_glyph_paint (glyph);
if (paint) if (paint)
{ {
// COLRv1 glyph // COLRv1 glyph
VarStoreInstancer instancer (&(this+varStore), ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap), &(this+varIdxMap),
hb_array (font->coords, font->num_coords)); hb_array (font->coords, font->num_coords));
@ -2404,7 +2413,7 @@ struct COLR
Offset32To<LayerList> layerList; Offset32To<LayerList> layerList;
Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL) Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL)
Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL) Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL)
Offset32To<VariationStore> varStore; Offset32To<ItemVariationStore> varStore;
public: public:
DEFINE_SIZE_MIN (14); DEFINE_SIZE_MIN (14);
}; };

View File

@ -214,13 +214,17 @@ struct CPAL
hb_set_t *nameids_to_retain /* OUT */) const hb_set_t *nameids_to_retain /* OUT */) const
{ {
if (version == 1) if (version == 1)
{
hb_barrier ();
v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain); v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
}
} }
private: private:
const CPALV1Tail& v1 () const const CPALV1Tail& v1 () const
{ {
if (version == 0) return Null (CPALV1Tail); if (version == 0) return Null (CPALV1Tail);
hb_barrier ();
return StructAfter<CPALV1Tail> (*this); return StructAfter<CPALV1Tail> (*this);
} }
@ -312,7 +316,10 @@ struct CPAL
return_trace (false); return_trace (false);
if (version == 1) if (version == 1)
{
hb_barrier ();
return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map)); return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
}
return_trace (true); return_trace (true);
} }
@ -321,6 +328,7 @@ struct CPAL
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
(this+colorRecordsZ).sanitize (c, numColorRecords) && (this+colorRecordsZ).sanitize (c, numColorRecords) &&
colorRecordIndicesZ.sanitize (c, numPalettes) && colorRecordIndicesZ.sanitize (c, numPalettes) &&
(version == 0 || v1 ().sanitize (c, this, numPalettes, numColors))); (version == 0 || v1 ().sanitize (c, this, numPalettes, numColors)));

View File

@ -368,6 +368,7 @@ struct sbix
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
version >= 1 && version >= 1 &&
strikes.sanitize (c, this))); strikes.sanitize (c, this)));
} }

View File

@ -56,6 +56,7 @@ struct SVGDocumentIndexEntry
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
svgDoc.sanitize (c, base, svgDocLength)); svgDoc.sanitize (c, base, svgDocLength));
} }

View File

@ -64,6 +64,7 @@ struct Coverage
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) switch (u.format)
{ {
case 1: return_trace (u.format1.sanitize (c)); case 1: return_trace (u.format1.sanitize (c));

View File

@ -189,7 +189,7 @@ struct CaretValueFormat3
friend struct CaretValue; friend struct CaretValue;
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
const VariationStore &var_store) const const ItemVariationStore &var_store) const
{ {
return HB_DIRECTION_IS_HORIZONTAL (direction) ? return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
@ -251,7 +251,7 @@ struct CaretValue
hb_position_t get_caret_value (hb_font_t *font, hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction, hb_direction_t direction,
hb_codepoint_t glyph_id, hb_codepoint_t glyph_id,
const VariationStore &var_store) const const ItemVariationStore &var_store) const
{ {
switch (u.format) { switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction); case 1: return u.format1.get_caret_value (font, direction);
@ -291,6 +291,7 @@ struct CaretValue
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 1: return_trace (u.format1.sanitize (c)); case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c)); case 2: return_trace (u.format2.sanitize (c));
@ -315,7 +316,7 @@ struct LigGlyph
unsigned get_lig_carets (hb_font_t *font, unsigned get_lig_carets (hb_font_t *font,
hb_direction_t direction, hb_direction_t direction,
hb_codepoint_t glyph_id, hb_codepoint_t glyph_id,
const VariationStore &var_store, const ItemVariationStore &var_store,
unsigned start_offset, unsigned start_offset,
unsigned *caret_count /* IN/OUT */, unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const hb_position_t *caret_array /* OUT */) const
@ -371,7 +372,7 @@ struct LigCaretList
unsigned int get_lig_carets (hb_font_t *font, unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction, hb_direction_t direction,
hb_codepoint_t glyph_id, hb_codepoint_t glyph_id,
const VariationStore &var_store, const ItemVariationStore &var_store,
unsigned int start_offset, unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */, unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const hb_position_t *caret_array /* OUT */) const
@ -441,6 +442,20 @@ struct MarkGlyphSetsFormat1
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
void collect_used_mark_sets (const hb_set_t& glyph_set,
hb_set_t& used_mark_sets /* OUT */) const
{
unsigned i = 0;
for (const auto &offset : coverage)
{
const auto &cov = this+offset;
if (cov.intersects (&glyph_set))
used_mark_sets.add (i);
i++;
}
}
template <typename set_t> template <typename set_t>
void collect_coverage (hb_vector_t<set_t> &sets) const void collect_coverage (hb_vector_t<set_t> &sets) const
{ {
@ -461,6 +476,7 @@ struct MarkGlyphSetsFormat1
bool ret = true; bool ret = true;
for (const Offset32To<Coverage>& offset : coverage.iter ()) for (const Offset32To<Coverage>& offset : coverage.iter ())
{ {
auto snap = c->serializer->snapshot ();
auto *o = out->coverage.serialize_append (c->serializer); auto *o = out->coverage.serialize_append (c->serializer);
if (unlikely (!o)) if (unlikely (!o))
{ {
@ -468,11 +484,17 @@ struct MarkGlyphSetsFormat1
break; break;
} }
//not using o->serialize_subset (c, offset, this, out) here because //skip empty coverage
//OTS doesn't allow null offset.
//See issue: https://github.com/khaledhosny/ots/issues/172
c->serializer->push (); c->serializer->push ();
c->dispatch (this+offset); bool res = false;
if (offset) res = c->dispatch (this+offset);
if (!res)
{
c->serializer->pop_discard ();
c->serializer->revert (snap);
(out->coverage.len)--;
continue;
}
c->serializer->add_link (*o, c->serializer->pop_pack ()); c->serializer->add_link (*o, c->serializer->pop_pack ());
} }
@ -513,6 +535,15 @@ struct MarkGlyphSets
} }
} }
void collect_used_mark_sets (const hb_set_t& glyph_set,
hb_set_t& used_mark_sets /* OUT */) const
{
switch (u.format) {
case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
default:return;
}
}
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -526,6 +557,7 @@ struct MarkGlyphSets
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 1: return_trace (u.format1.sanitize (c)); case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true); default:return_trace (true);
@ -577,7 +609,7 @@ struct GDEFVersion1_2
* definitions--from beginning of GDEF * definitions--from beginning of GDEF
* header (may be NULL). Introduced * header (may be NULL). Introduced
* in version 0x00010002. */ * in version 0x00010002. */
Offset32To<VariationStore> Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF * Store--from beginning of GDEF
* header (may be NULL). Introduced * header (may be NULL). Introduced
@ -600,6 +632,7 @@ struct GDEFVersion1_2
attachList.sanitize (c, this) && attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) && ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) && markAttachClassDef.sanitize (c, this) &&
hb_barrier () &&
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
(version.to_int () < 0x00010003u || varStore.sanitize (c, this))); (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
} }
@ -627,23 +660,23 @@ struct GDEFVersion1_2
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this); auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true); // Push var store first (if it's needed) so that it's last in the
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); // serialization order. Some font consumers assume that varstore runs to
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); // the end of the GDEF table.
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true); // See: https://github.com/harfbuzz/harfbuzz/issues/4636
auto snapshot_version0 = c->serializer->snapshot ();
bool subset_markglyphsetsdef = false; if (unlikely (version.to_int () >= 0x00010002u && !c->serializer->embed (markGlyphSetsDef)))
if (version.to_int () >= 0x00010002u) return_trace (false);
{
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
}
bool subset_varstore = false; bool subset_varstore = false;
unsigned varstore_index = (unsigned) -1;
auto snapshot_version2 = c->serializer->snapshot ();
if (version.to_int () >= 0x00010003u) if (version.to_int () >= 0x00010003u)
{ {
if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
if (c->plan->all_axes_pinned) if (c->plan->all_axes_pinned)
out->varStore = 0; out->varStore = 0;
else if (c->plan->normalized_coords) else if (c->plan->normalized_coords)
@ -652,27 +685,56 @@ struct GDEFVersion1_2
{ {
item_variations_t item_vars; item_variations_t item_vars;
if (item_vars.instantiate (this+varStore, c->plan, true, true, if (item_vars.instantiate (this+varStore, c->plan, true, true,
c->plan->gdef_varstore_inner_maps.as_array ())) c->plan->gdef_varstore_inner_maps.as_array ())) {
subset_varstore = out->varStore.serialize_serialize (c->serializer, subset_varstore = out->varStore.serialize_serialize (c->serializer,
item_vars.has_long_word (), item_vars.has_long_word (),
c->plan->axis_tags, c->plan->axis_tags,
item_vars.get_region_list (), item_vars.get_region_list (),
item_vars.get_vardata_encodings ()); item_vars.get_vardata_encodings ());
varstore_index = c->serializer->last_added_child_index();
}
remap_varidx_after_instantiation (item_vars.get_varidx_map (), remap_varidx_after_instantiation (item_vars.get_varidx_map (),
c->plan->layout_variation_idx_delta_map); c->plan->layout_variation_idx_delta_map);
} }
} }
else else
{
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ()); subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
varstore_index = c->serializer->last_added_child_index();
}
}
out->version.major = version.major;
out->version.minor = version.minor;
if (!subset_varstore && version.to_int () >= 0x00010002u) {
c->serializer->revert (snapshot_version2);
}
bool subset_markglyphsetsdef = false;
if (version.to_int () >= 0x00010002u)
{
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
} }
if (subset_varstore) if (subset_varstore)
{ {
out->version.minor = 3; out->version.minor = 3;
c->plan->has_gdef_varstore = true;
} else if (subset_markglyphsetsdef) { } else if (subset_markglyphsetsdef) {
out->version.minor = 2; out->version.minor = 2;
} else { } else {
out->version.minor = 0; out->version.minor = 0;
c->serializer->revert (snapshot_version0);
}
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
if (subset_varstore && varstore_index != (unsigned) -1) {
c->serializer->repack_last(varstore_index);
} }
return_trace (subset_glyphclassdef || subset_attachlist || return_trace (subset_glyphclassdef || subset_attachlist ||
@ -709,6 +771,7 @@ struct GDEF
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!u.version.sanitize (c))) return_trace (false); if (unlikely (!u.version.sanitize (c))) return_trace (false);
hb_barrier ();
switch (u.version.major) { switch (u.version.major) {
case 1: return_trace (u.version1.sanitize (c)); case 1: return_trace (u.version1.sanitize (c));
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K
@ -839,14 +902,14 @@ struct GDEF
default: return false; default: return false;
} }
} }
const VariationStore &get_var_store () const const ItemVariationStore &get_var_store () const
{ {
switch (u.version.major) { switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore); case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(ItemVariationStore);
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.varStore; case 2: return this+u.version2.varStore;
#endif #endif
default: return Null(VariationStore); default: return Null(ItemVariationStore);
} }
} }
@ -966,9 +1029,9 @@ struct GDEF
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{ {
if (!has_var_store ()) return; if (!has_var_store ()) return;
const VariationStore &var_store = get_var_store (); const ItemVariationStore &var_store = get_var_store ();
float *store_cache = var_store.create_cache (); float *store_cache = var_store.create_cache ();
unsigned new_major = 0, new_minor = 0; unsigned new_major = 0, new_minor = 0;
unsigned last_major = (layout_variation_indices->get_min ()) >> 16; unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
for (unsigned idx : layout_variation_indices->iter ()) for (unsigned idx : layout_variation_indices->iter ())

View File

@ -25,6 +25,7 @@ struct Anchor
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 1: return_trace (u.format1.sanitize (c)); case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c)); case 2: return_trace (u.format2.sanitize (c));

View File

@ -38,9 +38,15 @@ struct AnchorFormat3
*y = font->em_fscale_y (yCoordinate); *y = font->em_fscale_y (yCoordinate);
if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this)) if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
{
hb_barrier ();
*x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
}
if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this)) if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
{
hb_barrier ();
*y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
}
} }
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const

View File

@ -8,7 +8,7 @@ namespace GPOS_impl {
struct AnchorMatrix struct AnchorMatrix
{ {
HBUINT16 rows; /* Number of rows */ HBUINT16 rows; /* Number of rows */
UnsizedArrayOf<Offset16To<Anchor>> UnsizedArrayOf<Offset16To<Anchor, AnchorMatrix>>
matrixZ; /* Matrix of offsets to Anchor tables-- matrixZ; /* Matrix of offsets to Anchor tables--
* from beginning of AnchorMatrix table */ * from beginning of AnchorMatrix table */
public: public:
@ -18,6 +18,7 @@ struct AnchorMatrix
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false); if (!c->check_struct (this)) return_trace (false);
hb_barrier ();
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false); if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols; unsigned int count = rows * cols;
if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false); if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
@ -25,6 +26,7 @@ struct AnchorMatrix
if (c->lazy_some_gpos) if (c->lazy_some_gpos)
return_trace (true); return_trace (true);
hb_barrier ();
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (!matrixZ[i].sanitize (c, this)) return_trace (false); if (!matrixZ[i].sanitize (c, this)) return_trace (false);
return_trace (true); return_trace (true);
@ -38,6 +40,7 @@ struct AnchorMatrix
if (unlikely (row >= rows || col >= cols)) return Null (Anchor); if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
auto &offset = matrixZ[row * cols + col]; auto &offset = matrixZ[row * cols + col];
if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor); if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor);
hb_barrier ();
*found = !offset.is_null (); *found = !offset.is_null ();
return this+offset; return this+offset;
} }
@ -65,15 +68,14 @@ struct AnchorMatrix
if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->rows = num_rows; out->rows = num_rows;
bool ret = false;
for (const unsigned i : index_iter) for (const unsigned i : index_iter)
{ {
auto *offset = c->serializer->embed (matrixZ[i]); auto *offset = c->serializer->embed (matrixZ[i]);
if (!offset) return_trace (false); if (!offset) return_trace (false);
ret |= offset->serialize_subset (c, matrixZ[i], this); offset->serialize_subset (c, matrixZ[i], this);
} }
return_trace (ret); return_trace (true);
} }
}; };

View File

@ -23,7 +23,7 @@ static void SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src, const SrcLookup *src,
Iterator it, Iterator it,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
bool all_axes_pinned); unsigned new_format);
} }

View File

@ -11,21 +11,21 @@ struct EntryExitRecord
{ {
friend struct CursivePosFormat1; friend struct CursivePosFormat1;
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1 *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
} }
void collect_variation_indices (hb_collect_variation_indices_context_t *c, void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const void *src_base) const const struct CursivePosFormat1 *src_base) const
{ {
(src_base+entryAnchor).collect_variation_indices (c); (src_base+entryAnchor).collect_variation_indices (c);
(src_base+exitAnchor).collect_variation_indices (c); (src_base+exitAnchor).collect_variation_indices (c);
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
const void *src_base) const const struct CursivePosFormat1 *src_base) const
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -38,11 +38,11 @@ struct EntryExitRecord
} }
protected: protected:
Offset16To<Anchor> Offset16To<Anchor, struct CursivePosFormat1>
entryAnchor; /* Offset to EntryAnchor table--from entryAnchor; /* Offset to EntryAnchor table--from
* beginning of CursivePos * beginning of CursivePos
* subtable--may be NULL */ * subtable--may be NULL */
Offset16To<Anchor> Offset16To<Anchor, struct CursivePosFormat1>
exitAnchor; /* Offset to ExitAnchor table--from exitAnchor; /* Offset to ExitAnchor table--from
* beginning of CursivePos * beginning of CursivePos
* subtable--may be NULL */ * subtable--may be NULL */
@ -128,6 +128,7 @@ struct CursivePosFormat1
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
if (!this_record.entryAnchor || if (!this_record.entryAnchor ||
unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false); unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
hb_barrier ();
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset_fast (buffer->idx); skippy_iter.reset_fast (buffer->idx);
@ -145,6 +146,7 @@ struct CursivePosFormat1
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false); return_trace (false);
} }
hb_barrier ();
unsigned int i = skippy_iter.idx; unsigned int i = skippy_iter.idx;
unsigned int j = buffer->idx; unsigned int j = buffer->idx;
@ -262,7 +264,7 @@ struct CursivePosFormat1
hb_requires (hb_is_iterator (Iterator))> hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_subset_context_t *c, void serialize (hb_subset_context_t *c,
Iterator it, Iterator it,
const void *src_base) const struct CursivePosFormat1 *src_base)
{ {
if (unlikely (!c->serializer->extend_min ((*this)))) return; if (unlikely (!c->serializer->extend_min ((*this)))) return;
this->format = 1; this->format = 1;

View File

@ -42,6 +42,7 @@ struct MarkMarkPosFormat1_2
mark1Coverage.sanitize (c, this) && mark1Coverage.sanitize (c, this) &&
mark2Coverage.sanitize (c, this) && mark2Coverage.sanitize (c, this) &&
mark1Array.sanitize (c, this) && mark1Array.sanitize (c, this) &&
hb_barrier () &&
mark2Array.sanitize (c, this, (unsigned int) classCount)); mark2Array.sanitize (c, this, (unsigned int) classCount));
} }

View File

@ -36,6 +36,7 @@ struct PairPosFormat1_3
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false); if (!c->check_struct (this)) return_trace (false);
hb_barrier ();
unsigned int len1 = valueFormat[0].get_len (); unsigned int len1 = valueFormat[0].get_len ();
unsigned int len2 = valueFormat[1].get_len (); unsigned int len2 = valueFormat[1].get_len ();
@ -131,20 +132,33 @@ struct PairPosFormat1_3
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format; out->format = format;
out->valueFormat[0] = valueFormat[0];
out->valueFormat[1] = valueFormat[1];
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
out->valueFormat[0] = newFormats.first;
out->valueFormat[1] = newFormats.second;
}
if (c->plan->all_axes_pinned) hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]);
if (c->plan->normalized_coords)
{ {
out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags (); /* all device flags will be dropped when full instancing, no need to strip
out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags (); * hints, also do not strip emtpy cause we don't compute the new default
* value during stripping */
newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map);
} }
/* do not strip hints for VF */
else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
bool has_fvar = (blob != hb_blob_get_empty ());
hb_blob_destroy (blob);
bool strip = !has_fvar;
/* special case: strip hints when a VF has no GDEF varstore after
* subsetting*/
if (has_fvar && !c->plan->has_gdef_varstore)
strip = true;
newFormats = compute_effective_value_formats (glyphset, strip, true);
}
out->valueFormat[0] = newFormats.first;
out->valueFormat[1] = newFormats.second;
hb_sorted_vector_t<hb_codepoint_t> new_coverage; hb_sorted_vector_t<hb_codepoint_t> new_coverage;
@ -175,7 +189,9 @@ struct PairPosFormat1_3
} }
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset,
bool strip_hints, bool strip_empty,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
{ {
unsigned record_size = PairSet::get_size (valueFormat); unsigned record_size = PairSet::get_size (valueFormat);
@ -195,8 +211,8 @@ struct PairPosFormat1_3
{ {
if (record->intersects (glyphset)) if (record->intersects (glyphset))
{ {
format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ()); format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map);
format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0])); format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map);
} }
record = &StructAtOffset<const PairValueRecord> (record, record_size); record = &StructAtOffset<const PairValueRecord> (record, record_size);
} }

View File

@ -8,7 +8,7 @@ namespace Layout {
namespace GPOS_impl { namespace GPOS_impl {
template <typename Types> template <typename Types>
struct PairPosFormat2_4 struct PairPosFormat2_4 : ValueBase
{ {
protected: protected:
HBUINT16 format; /* Format identifier--format = 2 */ HBUINT16 format; /* Format identifier--format = 2 */
@ -287,18 +287,31 @@ struct PairPosFormat2_4
unsigned len2 = valueFormat2.get_len (); unsigned len2 = valueFormat2.get_len ();
hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2); hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
newFormats = compute_effective_value_formats (klass1_map, klass2_map); if (c->plan->normalized_coords)
{
/* in case of full instancing, all var device flags will be dropped so no
* need to strip hints here */
newFormats = compute_effective_value_formats (klass1_map, klass2_map, false, false, &c->plan->layout_variation_idx_delta_map);
}
/* do not strip hints for VF */
else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
bool has_fvar = (blob != hb_blob_get_empty ());
hb_blob_destroy (blob);
bool strip = !has_fvar;
/* special case: strip hints when a VF has no GDEF varstore after
* subsetting*/
if (has_fvar && !c->plan->has_gdef_varstore)
strip = true;
newFormats = compute_effective_value_formats (klass1_map, klass2_map, strip, true);
}
out->valueFormat1 = newFormats.first; out->valueFormat1 = newFormats.first;
out->valueFormat2 = newFormats.second; out->valueFormat2 = newFormats.second;
if (c->plan->all_axes_pinned)
{
out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
}
unsigned total_len = len1 + len2; unsigned total_len = len1 + len2;
hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map)); hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map));
for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
@ -311,22 +324,15 @@ struct PairPosFormat2_4
} }
} }
const hb_set_t &glyphset = *c->plan->glyphset_gsub (); bool ret = out->coverage.serialize_subset(c, coverage, this);
const hb_map_t &glyph_map = *c->plan->glyph_map; return_trace (out->class1Count && out->class2Count && ret);
auto it =
+ hb_iter (this+coverage)
| hb_filter (glyphset)
| hb_map_retains_sorting (glyph_map)
;
out->coverage.serialize_serialize (c->serializer, it);
return_trace (out->class1Count && out->class2Count && bool (it));
} }
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map, hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
const hb_map_t& klass2_map) const const hb_map_t& klass2_map,
bool strip_hints, bool strip_empty,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
{ {
unsigned len1 = valueFormat1.get_len (); unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len (); unsigned len2 = valueFormat2.get_len ();
@ -340,8 +346,8 @@ struct PairPosFormat2_4
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{ {
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size; unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
format1 = format1 | valueFormat1.get_effective_format (&values[idx]); format1 = format1 | valueFormat1.get_effective_format (&values[idx], strip_hints, strip_empty, this, varidx_delta_map);
format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]); format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1], strip_hints, strip_empty, this, varidx_delta_map);
} }
if (format1 == valueFormat1 && format2 == valueFormat2) if (format1 == valueFormat1 && format2 == valueFormat2)

View File

@ -9,7 +9,7 @@ namespace GPOS_impl {
template <typename Types> template <typename Types>
struct PairSet struct PairSet : ValueBase
{ {
template <typename Types2> template <typename Types2>
friend struct PairPosFormat1_3; friend struct PairPosFormat1_3;
@ -45,10 +45,12 @@ struct PairSet
bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!(c->check_struct (this) if (!(c->check_struct (this) &&
&& c->check_range (&firstPairValueRecord, hb_barrier () &&
c->check_range (&firstPairValueRecord,
len, len,
closure->stride))) return_trace (false); closure->stride))) return_trace (false);
hb_barrier ();
unsigned int count = len; unsigned int count = len;
const PairValueRecord *record = &firstPairValueRecord; const PairValueRecord *record = &firstPairValueRecord;

View File

@ -29,7 +29,7 @@ struct PairValueRecord
struct context_t struct context_t
{ {
const void *base; const ValueBase *base;
const ValueFormat *valueFormats; const ValueFormat *valueFormats;
const ValueFormat *newFormats; const ValueFormat *newFormats;
unsigned len1; /* valueFormats[0].get_len() */ unsigned len1; /* valueFormats[0].get_len() */
@ -62,7 +62,7 @@ struct PairValueRecord
void collect_variation_indices (hb_collect_variation_indices_context_t *c, void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const ValueFormat *valueFormats, const ValueFormat *valueFormats,
const void *base) const const ValueBase *base) const
{ {
unsigned record1_len = valueFormats[0].get_len (); unsigned record1_len = valueFormats[0].get_len ();
unsigned record2_len = valueFormats[1].get_len (); unsigned record2_len = valueFormats[1].get_len ();

View File

@ -39,14 +39,12 @@ struct SinglePos
const SrcLookup* src, const SrcLookup* src,
Iterator glyph_val_iter_pairs, Iterator glyph_val_iter_pairs,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
bool all_axes_pinned) unsigned newFormat)
{ {
if (unlikely (!c->extend_min (u.format))) return; if (unlikely (!c->extend_min (u.format))) return;
unsigned format = 2; unsigned format = 2;
ValueFormat new_format = src->get_value_format (); ValueFormat new_format;
new_format = newFormat;
if (all_axes_pinned)
new_format = new_format.drop_device_table_flags ();
if (glyph_val_iter_pairs) if (glyph_val_iter_pairs)
format = get_format (glyph_val_iter_pairs); format = get_format (glyph_val_iter_pairs);
@ -89,8 +87,8 @@ SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src, const SrcLookup *src,
Iterator it, Iterator it,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
bool all_axes_pinned) unsigned new_format)
{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); } { c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, new_format); }
} }

View File

@ -8,7 +8,7 @@ namespace OT {
namespace Layout { namespace Layout {
namespace GPOS_impl { namespace GPOS_impl {
struct SinglePosFormat1 struct SinglePosFormat1 : ValueBase
{ {
protected: protected:
HBUINT16 format; /* Format identifier--format = 1 */ HBUINT16 format; /* Format identifier--format = 1 */
@ -28,6 +28,7 @@ struct SinglePosFormat1
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) && coverage.sanitize (c, this) &&
hb_barrier () &&
/* The coverage table may use a range to represent a set /* The coverage table may use a range to represent a set
* of glyphs, which means a small number of bytes can * of glyphs, which means a small number of bytes can
* generate a large glyph set. Manually modify the * generate a large glyph set. Manually modify the
@ -146,6 +147,30 @@ struct SinglePosFormat1
hb_set_t intersection; hb_set_t intersection;
(this+coverage).intersect_set (glyphset, intersection); (this+coverage).intersect_set (glyphset, intersection);
unsigned new_format = valueFormat;
if (c->plan->normalized_coords)
{
new_format = valueFormat.get_effective_format (values.arrayZ, false, false, this, &c->plan->layout_variation_idx_delta_map);
}
/* do not strip hints for VF */
else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
bool has_fvar = (blob != hb_blob_get_empty ());
hb_blob_destroy (blob);
bool strip = !has_fvar;
/* special case: strip hints when a VF has no GDEF varstore after
* subsetting*/
if (has_fvar && !c->plan->has_gdef_varstore)
strip = true;
new_format = valueFormat.get_effective_format (values.arrayZ,
strip, /* strip hints */
true, /* strip empty */
this, nullptr);
}
auto it = auto it =
+ hb_iter (intersection) + hb_iter (intersection)
| hb_map_retains_sorting (glyph_map) | hb_map_retains_sorting (glyph_map)
@ -153,7 +178,7 @@ struct SinglePosFormat1
; ;
bool ret = bool (it); bool ret = bool (it);
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
return_trace (ret); return_trace (ret);
} }
}; };

View File

@ -7,7 +7,7 @@ namespace OT {
namespace Layout { namespace Layout {
namespace GPOS_impl { namespace GPOS_impl {
struct SinglePosFormat2 struct SinglePosFormat2 : ValueBase
{ {
protected: protected:
HBUINT16 format; /* Format identifier--format = 2 */ HBUINT16 format; /* Format identifier--format = 2 */
@ -143,6 +143,37 @@ struct SinglePosFormat2
coverage.serialize_serialize (c, glyphs); coverage.serialize_serialize (c, glyphs);
} }
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
unsigned compute_effective_format (const hb_face_t *face,
Iterator it,
bool is_instancing, bool strip_hints,
bool has_gdef_varstore,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
{
hb_blob_t* blob = hb_face_reference_table (face, HB_TAG ('f','v','a','r'));
bool has_fvar = (blob != hb_blob_get_empty ());
hb_blob_destroy (blob);
unsigned new_format = 0;
if (is_instancing)
{
new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), false, false, this, varidx_delta_map);
}
/* do not strip hints for VF */
else if (strip_hints)
{
bool strip = !has_fvar;
if (has_fvar && !has_gdef_varstore)
strip = true;
new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), strip, true, this, nullptr);
}
else
new_format = valueFormat;
return new_format;
}
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -163,8 +194,13 @@ struct SinglePosFormat2
}) })
; ;
unsigned new_format = compute_effective_format (c->plan->source, it,
bool (c->plan->normalized_coords),
bool (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING),
c->plan->has_gdef_varstore,
&c->plan->layout_variation_idx_delta_map);
bool ret = bool (it); bool ret = bool (it);
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
return_trace (ret); return_trace (ret);
} }
}; };

View File

@ -9,6 +9,8 @@ namespace GPOS_impl {
typedef HBUINT16 Value; typedef HBUINT16 Value;
struct ValueBase {}; // Dummy base class tag for OffsetTo<Value> bases.
typedef UnsizedArrayOf<Value> ValueRecord; typedef UnsizedArrayOf<Value> ValueRecord;
struct ValueFormat : HBUINT16 struct ValueFormat : HBUINT16
@ -78,7 +80,7 @@ struct ValueFormat : HBUINT16
} }
bool apply_value (hb_ot_apply_context_t *c, bool apply_value (hb_ot_apply_context_t *c,
const void *base, const ValueBase *base,
const Value *values, const Value *values,
hb_glyph_position_t &glyph_pos) const hb_glyph_position_t &glyph_pos) const
{ {
@ -114,7 +116,7 @@ struct ValueFormat : HBUINT16
if (!use_x_device && !use_y_device) return ret; if (!use_x_device && !use_y_device) return ret;
const VariationStore &store = c->var_store; const ItemVariationStore &store = c->var_store;
auto *cache = c->var_store_cache; auto *cache = c->var_store_cache;
/* pixel -> fractional pixel */ /* pixel -> fractional pixel */
@ -142,11 +144,29 @@ struct ValueFormat : HBUINT16
return ret; return ret;
} }
unsigned int get_effective_format (const Value *values) const unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
{ {
unsigned int format = *this; unsigned int format = *this;
for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
if (format & flag) should_drop (*values++, (Flags) flag, &format); if (format & flag)
{
if (strip_hints && flag >= xPlaDevice)
{
format = format & ~flag;
values++;
continue;
}
if (varidx_delta_map && flag >= xPlaDevice)
{
update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map);
continue;
}
/* do not strip empty when instancing, cause we don't know whether the new
* default value is 0 or not */
if (strip_empty) should_drop (*values, (Flags) flag, &format);
values++;
}
} }
return format; return format;
@ -154,18 +174,19 @@ struct ValueFormat : HBUINT16
template<typename Iterator, template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))> hb_requires (hb_is_iterator (Iterator))>
unsigned int get_effective_format (Iterator it) const { unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const {
unsigned int new_format = 0; unsigned int new_format = 0;
for (const hb_array_t<const Value>& values : it) for (const hb_array_t<const Value>& values : it)
new_format = new_format | get_effective_format (&values); new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map);
return new_format; return new_format;
} }
void copy_values (hb_serialize_context_t *c, void copy_values (hb_serialize_context_t *c,
unsigned int new_format, unsigned int new_format,
const void *base, const ValueBase *base,
const Value *values, const Value *values,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{ {
@ -217,7 +238,7 @@ struct ValueFormat : HBUINT16
} }
void collect_variation_indices (hb_collect_variation_indices_context_t *c, void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const void *base, const ValueBase *base,
const hb_array_t<const Value>& values) const const hb_array_t<const Value>& values) const
{ {
unsigned format = *this; unsigned format = *this;
@ -251,17 +272,8 @@ struct ValueFormat : HBUINT16
} }
} }
unsigned drop_device_table_flags () const
{
unsigned format = *this;
for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
format = format & ~flag;
return format;
}
private: private:
bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
{ {
unsigned int format = *this; unsigned int format = *this;
@ -278,17 +290,17 @@ struct ValueFormat : HBUINT16
return true; return true;
} }
static inline Offset16To<Device>& get_device (Value* value) static inline Offset16To<Device, ValueBase>& get_device (Value* value)
{ {
return *static_cast<Offset16To<Device> *> (value); return *static_cast<Offset16To<Device, ValueBase> *> (value);
} }
static inline const Offset16To<Device>& get_device (const Value* value) static inline const Offset16To<Device, ValueBase>& get_device (const Value* value)
{ {
return *static_cast<const Offset16To<Device> *> (value); return *static_cast<const Offset16To<Device, ValueBase> *> (value);
} }
static inline const Device& get_device (const Value* value, static inline const Device& get_device (const Value* value,
bool *worked, bool *worked,
const void *base, const ValueBase *base,
hb_sanitize_context_t &c) hb_sanitize_context_t &c)
{ {
if (worked) *worked |= bool (*value); if (worked) *worked |= bool (*value);
@ -296,12 +308,13 @@ struct ValueFormat : HBUINT16
if (unlikely (!offset.sanitize (&c, base))) if (unlikely (!offset.sanitize (&c, base)))
return Null(Device); return Null(Device);
hb_barrier ();
return base + offset; return base + offset;
} }
void add_delta_to_value (HBINT16 *value, void add_delta_to_value (HBINT16 *value,
const void *base, const ValueBase *base,
const Value *src_value, const Value *src_value,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{ {
@ -313,7 +326,8 @@ struct ValueFormat : HBUINT16
*value += hb_second (*varidx_delta); *value += hb_second (*varidx_delta);
} }
bool copy_device (hb_serialize_context_t *c, const void *base, bool copy_device (hb_serialize_context_t *c,
const ValueBase *base,
const Value *src_value, const Value *src_value,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
unsigned int new_format, Flags flag) const unsigned int new_format, Flags flag) const
@ -354,7 +368,7 @@ struct ValueFormat : HBUINT16
return (format & devices) != 0; return (format & devices) != 0;
} }
bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -366,7 +380,7 @@ struct ValueFormat : HBUINT16
return_trace (!has_device () || sanitize_value_devices (c, base, values)); return_trace (!has_device () || sanitize_value_devices (c, base, values));
} }
bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
unsigned size = get_size (); unsigned size = get_size ();
@ -376,11 +390,12 @@ struct ValueFormat : HBUINT16
if (c->lazy_some_gpos) if (c->lazy_some_gpos)
return_trace (true); return_trace (true);
hb_barrier ();
return_trace (sanitize_values_stride_unsafe (c, base, values, count, size)); return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
} }
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */ /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -403,6 +418,20 @@ struct ValueFormat : HBUINT16
*format = *format & ~flag; *format = *format & ~flag;
} }
void update_var_flag (const Value* value, Flags flag,
unsigned int* format, const ValueBase *base,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
{
if (*value)
{
unsigned varidx = (base + get_device (value)).get_variation_index ();
hb_pair_t<unsigned, int> *varidx_delta;
if (varidx_delta_map->has (varidx, &varidx_delta) &&
varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return;
}
*format = *format & ~flag;
}
}; };
} }

View File

@ -33,9 +33,11 @@ struct ReverseChainSingleSubstFormat1
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
return_trace (false); return_trace (false);
hb_barrier ();
const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
if (!lookahead.sanitize (c, this)) if (!lookahead.sanitize (c, this))
return_trace (false); return_trace (false);
hb_barrier ();
const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
return_trace (substitute.sanitize (c)); return_trace (substitute.sanitize (c));
} }
@ -109,12 +111,12 @@ struct ReverseChainSingleSubstFormat1
bool apply (hb_ot_apply_context_t *c) const bool apply (hb_ot_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
return_trace (false); /* No chaining to this type */
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false); if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
return_trace (false); /* No chaining to this type */
const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);

View File

@ -38,8 +38,8 @@ struct SmallTypes {
using HBUINT = HBUINT16; using HBUINT = HBUINT16;
using HBGlyphID = HBGlyphID16; using HBGlyphID = HBGlyphID16;
using Offset = Offset16; using Offset = Offset16;
template <typename Type, bool has_null=true> template <typename Type, typename BaseType=void, bool has_null=true>
using OffsetTo = OT::Offset16To<Type, has_null>; using OffsetTo = OT::Offset16To<Type, BaseType, has_null>;
template <typename Type> template <typename Type>
using ArrayOf = OT::Array16Of<Type>; using ArrayOf = OT::Array16Of<Type>;
template <typename Type> template <typename Type>
@ -52,8 +52,8 @@ struct MediumTypes {
using HBUINT = HBUINT24; using HBUINT = HBUINT24;
using HBGlyphID = HBGlyphID24; using HBGlyphID = HBGlyphID24;
using Offset = Offset24; using Offset = Offset24;
template <typename Type, bool has_null=true> template <typename Type, typename BaseType=void, bool has_null=true>
using OffsetTo = OT::Offset24To<Type, has_null>; using OffsetTo = OT::Offset24To<Type, BaseType, has_null>;
template <typename Type> template <typename Type>
using ArrayOf = OT::Array24Of<Type>; using ArrayOf = OT::Array24Of<Type>;
template <typename Type> template <typename Type>

View File

@ -240,7 +240,8 @@ struct CompositeGlyphRecord
} }
if (is_anchored ()) tx = ty = 0; if (is_anchored ()) tx = ty = 0;
trans.init ((float) tx, (float) ty); /* set is_end_point flag to true, used by IUP delta optimization */
trans.init ((float) tx, (float) ty, true);
{ {
const F2DOT14 *points = (const F2DOT14 *) p; const F2DOT14 *points = (const F2DOT14 *) p;

View File

@ -103,6 +103,9 @@ struct Glyph
} }
} }
bool is_composite () const
{ return type == COMPOSITE; }
bool get_all_points_without_var (const hb_face_t *face, bool get_all_points_without_var (const hb_face_t *face,
contour_point_vector_t &points /* OUT */) const contour_point_vector_t &points /* OUT */) const
{ {

View File

@ -38,7 +38,7 @@ _write_loca (IteratorIn&& it,
unsigned padded_size = *it++; unsigned padded_size = *it++;
offset += padded_size; offset += padded_size;
DEBUG_MSG (SUBSET, nullptr, "loca entry gid %u offset %u padded-size %u", gid, offset, padded_size); DEBUG_MSG (SUBSET, nullptr, "loca entry gid %" PRIu32 " offset %u padded-size %u", gid, offset, padded_size);
value = offset >> right_shift; value = offset >> right_shift;
*dest++ = value; *dest++ = value;

View File

@ -242,7 +242,9 @@ struct NameRecord
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && offset.sanitize (c, base, length)); return_trace (c->check_struct (this) &&
hb_barrier () &&
offset.sanitize (c, base, length));
} }
HBUINT16 platformID; /* Platform ID. */ HBUINT16 platformID; /* Platform ID. */
@ -465,6 +467,7 @@ struct name
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
likely (format == 0 || format == 1) && likely (format == 0 || format == 1) &&
c->check_array (nameRecordZ.arrayZ, count) && c->check_array (nameRecordZ.arrayZ, count) &&
c->check_range (this, stringOffset) && c->check_range (this, stringOffset) &&

View File

@ -39,6 +39,7 @@ struct ClassDefFormat1 : public OT::ClassDefFormat1_3<SmallTypes>
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::min_size; constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::min_size;
if (vertex_len < min_size) return false; if (vertex_len < min_size) return false;
hb_barrier ();
return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size (); return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size ();
} }
}; };
@ -50,6 +51,7 @@ struct ClassDefFormat2 : public OT::ClassDefFormat2_4<SmallTypes>
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size; constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size;
if (vertex_len < min_size) return false; if (vertex_len < min_size) return false;
hb_barrier ();
return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
} }
}; };
@ -114,6 +116,7 @@ struct ClassDef : public OT::ClassDef
{ {
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::ClassDef::min_size) return false; if (vertex_len < OT::ClassDef::min_size) return false;
hb_barrier ();
switch (u.format) switch (u.format)
{ {
case 1: return ((ClassDefFormat1*)this)->sanitize (vertex); case 1: return ((ClassDefFormat1*)this)->sanitize (vertex);
@ -131,20 +134,23 @@ struct ClassDef : public OT::ClassDef
struct class_def_size_estimator_t struct class_def_size_estimator_t
{ {
// TODO(garretrieger): update to support beyond64k coverage/classdef tables.
constexpr static unsigned class_def_format1_base_size = 6;
constexpr static unsigned class_def_format2_base_size = 4;
constexpr static unsigned coverage_base_size = 4;
constexpr static unsigned bytes_per_range = 6;
constexpr static unsigned bytes_per_glyph = 2;
template<typename It> template<typename It>
class_def_size_estimator_t (It glyph_and_class) class_def_size_estimator_t (It glyph_and_class)
: gids_consecutive (true), num_ranges_per_class (), glyphs_per_class () : num_ranges_per_class (), glyphs_per_class ()
{ {
unsigned last_gid = (unsigned) -1; reset();
for (auto p : + glyph_and_class) for (auto p : + glyph_and_class)
{ {
unsigned gid = p.first; unsigned gid = p.first;
unsigned klass = p.second; unsigned klass = p.second;
if (last_gid != (unsigned) -1 && gid != last_gid + 1)
gids_consecutive = false;
last_gid = gid;
hb_set_t* glyphs; hb_set_t* glyphs;
if (glyphs_per_class.has (klass, &glyphs) && glyphs) { if (glyphs_per_class.has (klass, &glyphs) && glyphs) {
glyphs->add (gid); glyphs->add (gid);
@ -174,28 +180,54 @@ struct class_def_size_estimator_t
} }
} }
// Incremental increase in the Coverage and ClassDef table size void reset() {
// (worst case) if all glyphs associated with 'klass' were added. class_def_1_size = class_def_format1_base_size;
unsigned incremental_coverage_size (unsigned klass) const class_def_2_size = class_def_format2_base_size;
{ included_glyphs.clear();
// Coverage takes 2 bytes per glyph worst case, included_classes.clear();
return 2 * glyphs_per_class.get (klass).get_population ();
} }
// Incremental increase in the Coverage and ClassDef table size // Compute the size of coverage for all glyphs added via 'add_class_def_size'.
// (worst case) if all glyphs associated with 'klass' were added. unsigned coverage_size () const
unsigned incremental_class_def_size (unsigned klass) const
{ {
// ClassDef takes 6 bytes per range unsigned format1_size = coverage_base_size + bytes_per_glyph * included_glyphs.get_population();
unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass); unsigned format2_size = coverage_base_size + bytes_per_range * num_glyph_ranges();
if (gids_consecutive) return hb_min(format1_size, format2_size);
{ }
// ClassDef1 takes 2 bytes per glyph, but only can be used
// when gids are consecutive. // Compute the new size of the ClassDef table if all glyphs associated with 'klass' were added.
return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size); unsigned add_class_def_size (unsigned klass)
{
if (!included_classes.has(klass)) {
hb_set_t* glyphs = nullptr;
if (glyphs_per_class.has(klass, &glyphs)) {
included_glyphs.union_(*glyphs);
}
class_def_1_size = class_def_format1_base_size;
if (!included_glyphs.is_empty()) {
unsigned min_glyph = included_glyphs.get_min();
unsigned max_glyph = included_glyphs.get_max();
class_def_1_size += bytes_per_glyph * (max_glyph - min_glyph + 1);
}
class_def_2_size += bytes_per_range * num_ranges_per_class.get (klass);
included_classes.add(klass);
} }
return class_def_2_size; return hb_min (class_def_1_size, class_def_2_size);
}
unsigned num_glyph_ranges() const {
hb_codepoint_t start = HB_SET_VALUE_INVALID;
hb_codepoint_t end = HB_SET_VALUE_INVALID;
unsigned count = 0;
while (included_glyphs.next_range (&start, &end)) {
count++;
}
return count;
} }
bool in_error () bool in_error ()
@ -211,9 +243,12 @@ struct class_def_size_estimator_t
} }
private: private:
bool gids_consecutive;
hb_hashmap_t<unsigned, unsigned> num_ranges_per_class; hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class; hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class;
hb_set_t included_classes;
hb_set_t included_glyphs;
unsigned class_def_1_size;
unsigned class_def_2_size;
}; };

View File

@ -39,6 +39,7 @@ struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3<SmallTypes
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size; constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size;
if (vertex_len < min_size) return false; if (vertex_len < min_size) return false;
hb_barrier ();
return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size (); return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
} }
}; };
@ -50,6 +51,7 @@ struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size; constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
if (vertex_len < min_size) return false; if (vertex_len < min_size) return false;
hb_barrier ();
return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
} }
}; };
@ -138,6 +140,7 @@ struct Coverage : public OT::Layout::Common::Coverage
{ {
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::Layout::Common::Coverage::min_size) return false; if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
hb_barrier ();
switch (u.format) switch (u.format)
{ {
case 1: return ((CoverageFormat1*)this)->sanitize (vertex); case 1: return ((CoverageFormat1*)this)->sanitize (vertex);

View File

@ -195,6 +195,15 @@ struct graph_t
return incoming_edges_; return incoming_edges_;
} }
unsigned incoming_edges_from_parent (unsigned parent_index) const {
if (single_parent != (unsigned) -1) {
return single_parent == parent_index ? 1 : 0;
}
unsigned* count;
return parents.has(parent_index, &count) ? *count : 0;
}
void reset_parents () void reset_parents ()
{ {
incoming_edges_ = 0; incoming_edges_ = 0;
@ -334,6 +343,16 @@ struct graph_t
return true; return true;
} }
bool give_max_priority ()
{
bool result = false;
while (!has_max_priority()) {
result = true;
priority++;
}
return result;
}
bool has_max_priority () const { bool has_max_priority () const {
return priority >= 3; return priority >= 3;
} }
@ -567,6 +586,7 @@ struct graph_t
update_distances (); update_distances ();
hb_priority_queue_t<int64_t> queue; hb_priority_queue_t<int64_t> queue;
queue.alloc (vertices_.length);
hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_; hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
hb_vector_t<unsigned> id_map; hb_vector_t<unsigned> id_map;
@ -1022,6 +1042,11 @@ struct graph_t
* Creates a copy of child and re-assigns the link from * Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects * parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated. * linked from child are not duplicated.
*
* Returns the index of the newly created duplicate.
*
* If the child_idx only has incoming edges from parent_idx, this
* will do nothing and return the original child_idx.
*/ */
unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx) unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
{ {
@ -1035,18 +1060,20 @@ struct graph_t
* Creates a copy of child and re-assigns the link from * Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects * parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated. * linked from child are not duplicated.
*
* Returns the index of the newly created duplicate.
*
* If the child_idx only has incoming edges from parent_idx,
* duplication isn't possible and this will return -1.
*/ */
unsigned duplicate (unsigned parent_idx, unsigned child_idx) unsigned duplicate (unsigned parent_idx, unsigned child_idx)
{ {
update_parents (); update_parents ();
unsigned links_to_child = 0; const auto& child = vertices_[child_idx];
for (const auto& l : vertices_[parent_idx].obj.all_links ()) unsigned links_to_child = child.incoming_edges_from_parent(parent_idx);
{
if (l.objidx == child_idx) links_to_child++;
}
if (vertices_[child_idx].incoming_edges () <= links_to_child) if (child.incoming_edges () <= links_to_child)
{ {
// Can't duplicate this node, doing so would orphan the original one as all remaining links // Can't duplicate this node, doing so would orphan the original one as all remaining links
// to child are from parent. // to child are from parent.
@ -1059,7 +1086,7 @@ struct graph_t
parent_idx, child_idx); parent_idx, child_idx);
unsigned clone_idx = duplicate (child_idx); unsigned clone_idx = duplicate (child_idx);
if (clone_idx == (unsigned) -1) return false; if (clone_idx == (unsigned) -1) return -1;
// duplicate shifts the root node idx, so if parent_idx was root update it. // duplicate shifts the root node idx, so if parent_idx was root update it.
if (parent_idx == clone_idx) parent_idx++; if (parent_idx == clone_idx) parent_idx++;
@ -1075,6 +1102,62 @@ struct graph_t
return clone_idx; return clone_idx;
} }
/*
* Creates a copy of child and re-assigns the links from
* parents to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
*
* Returns the index of the newly created duplicate.
*
* If the child_idx only has incoming edges from parents,
* duplication isn't possible or duplication fails and this will
* return -1.
*/
unsigned duplicate (const hb_set_t* parents, unsigned child_idx)
{
if (parents->is_empty()) {
return -1;
}
update_parents ();
const auto& child = vertices_[child_idx];
unsigned links_to_child = 0;
unsigned last_parent = parents->get_max();
unsigned first_parent = parents->get_min();
for (unsigned parent_idx : *parents) {
links_to_child += child.incoming_edges_from_parent(parent_idx);
}
if (child.incoming_edges () <= links_to_child)
{
// Can't duplicate this node, doing so would orphan the original one as all remaining links
// to child are from parent.
DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
return -1;
}
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
unsigned clone_idx = duplicate (child_idx);
if (clone_idx == (unsigned) -1) return false;
for (unsigned parent_idx : *parents) {
// duplicate shifts the root node idx, so if parent_idx was root update it.
if (parent_idx == clone_idx) parent_idx++;
auto& parent = vertices_[parent_idx];
for (auto& l : parent.obj.all_links_writer ())
{
if (l.objidx != child_idx)
continue;
reassign_link (l, parent_idx, clone_idx);
}
}
return clone_idx;
}
/* /*
* Adds a new node to the graph, not connected to anything. * Adds a new node to the graph, not connected to anything.
@ -1370,6 +1453,7 @@ struct graph_t
vertices_.tail ().distance = 0; vertices_.tail ().distance = 0;
hb_priority_queue_t<int64_t> queue; hb_priority_queue_t<int64_t> queue;
queue.alloc (count);
queue.insert (0, vertices_.length - 1); queue.insert (0, vertices_.length - 1);
hb_vector_t<bool> visited; hb_vector_t<bool> visited;

View File

@ -76,6 +76,7 @@ struct Lookup : public OT::Lookup
{ {
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::Lookup::min_size) return false; if (vertex_len < OT::Lookup::min_size) return false;
hb_barrier ();
return vertex_len >= this->get_size (); return vertex_len >= this->get_size ();
} }
@ -351,6 +352,7 @@ struct LookupList : public OT::LookupList<T>
{ {
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::LookupList<T>::min_size) return false; if (vertex_len < OT::LookupList<T>::min_size) return false;
hb_barrier ();
return vertex_len >= OT::LookupList<T>::item_size * this->len; return vertex_len >= OT::LookupList<T>::item_size * this->len;
} }
}; };
@ -364,6 +366,7 @@ struct GSTAR : public OT::GSUBGPOS
GSTAR* gstar = (GSTAR*) r.obj.head; GSTAR* gstar = (GSTAR*) r.obj.head;
if (!gstar || !gstar->sanitize (r)) if (!gstar || !gstar->sanitize (r))
return nullptr; return nullptr;
hb_barrier ();
return gstar; return gstar;
} }
@ -383,6 +386,7 @@ struct GSTAR : public OT::GSUBGPOS
{ {
int64_t len = vertex.obj.tail - vertex.obj.head; int64_t len = vertex.obj.tail - vertex.obj.head;
if (len < OT::GSUBGPOS::min_size) return false; if (len < OT::GSUBGPOS::min_size) return false;
hb_barrier ();
return len >= get_size (); return len >= get_size ();
} }

View File

@ -40,6 +40,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix
{ {
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < AnchorMatrix::min_size) return false; if (vertex_len < AnchorMatrix::min_size) return false;
hb_barrier ();
return vertex_len >= AnchorMatrix::min_size + return vertex_len >= AnchorMatrix::min_size +
OT::Offset16::static_size * class_count * this->rows; OT::Offset16::static_size * class_count * this->rows;
@ -128,6 +129,7 @@ struct MarkArray : public OT::Layout::GPOS_impl::MarkArray
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
unsigned min_size = MarkArray::min_size; unsigned min_size = MarkArray::min_size;
if (vertex_len < min_size) return false; if (vertex_len < min_size) return false;
hb_barrier ();
return vertex_len >= get_size (); return vertex_len >= get_size ();
} }
@ -495,6 +497,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
{ {
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < u.format.get_size ()) return false; if (vertex_len < u.format.get_size ()) return false;
hb_barrier ();
switch (u.format) { switch (u.format) {
case 1: case 1:

View File

@ -42,6 +42,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size; unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
if (vertex_len < min_size) return false; if (vertex_len < min_size) return false;
hb_barrier ();
return vertex_len >= return vertex_len >=
min_size + pairSet.get_size () - pairSet.len.get_size(); min_size + pairSet.get_size () - pairSet.len.get_size();
@ -198,6 +199,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
size_t vertex_len = vertex.table_size (); size_t vertex_len = vertex.table_size ();
unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size; unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
if (vertex_len < min_size) return false; if (vertex_len < min_size) return false;
hb_barrier ();
const unsigned class1_count = class1Count; const unsigned class1_count = class1Count;
return vertex_len >= return vertex_len >=
@ -245,8 +247,8 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
for (unsigned i = 0; i < class1_count; i++) for (unsigned i = 0; i < class1_count; i++)
{ {
unsigned accumulated_delta = class1_record_size; unsigned accumulated_delta = class1_record_size;
coverage_size += estimator.incremental_coverage_size (i); class_def_1_size = estimator.add_class_def_size (i);
class_def_1_size += estimator.incremental_class_def_size (i); coverage_size = estimator.coverage_size ();
max_coverage_size = hb_max (max_coverage_size, coverage_size); max_coverage_size = hb_max (max_coverage_size, coverage_size);
max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size); max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
@ -278,8 +280,10 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
split_points.push (i); split_points.push (i);
// split does not include i, so add the size for i when we reset the size counters. // split does not include i, so add the size for i when we reset the size counters.
accumulated = base_size + accumulated_delta; accumulated = base_size + accumulated_delta;
coverage_size = 4 + estimator.incremental_coverage_size (i);
class_def_1_size = 4 + estimator.incremental_class_def_size (i); estimator.reset();
class_def_1_size = estimator.add_class_def_size(i);
coverage_size = estimator.coverage_size();
visited.clear (); // node sharing isn't allowed between splits. visited.clear (); // node sharing isn't allowed between splits.
} }
} }
@ -625,6 +629,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos
{ {
int64_t vertex_len = vertex.obj.tail - vertex.obj.head; int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < u.format.get_size ()) return false; if (vertex_len < u.format.get_size ()) return false;
hb_barrier ();
switch (u.format) { switch (u.format) {
case 1: case 1:

View File

@ -26,27 +26,119 @@
#include "gsubgpos-context.hh" #include "gsubgpos-context.hh"
#include "classdef-graph.hh" #include "classdef-graph.hh"
#include "hb-iter.hh"
#include "hb-serialize.hh"
typedef hb_codepoint_pair_t gid_and_class_t; typedef hb_codepoint_pair_t gid_and_class_t;
typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t; typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
template<typename It>
static unsigned actual_class_def_size(It glyph_and_class) {
char buffer[100];
hb_serialize_context_t serializer(buffer, 100);
OT::ClassDef_serialize (&serializer, glyph_and_class);
serializer.end_serialize ();
assert(!serializer.in_error());
static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass, hb_blob_t* blob = serializer.copy_blob();
unsigned cov_expected, unsigned class_def_expected) unsigned size = hb_blob_get_length(blob);
hb_blob_destroy(blob);
return size;
}
static unsigned actual_class_def_size(gid_and_class_list_t consecutive_map, hb_vector_t<unsigned> classes) {
auto filtered_it =
+ consecutive_map.as_sorted_array().iter()
| hb_filter([&] (unsigned c) {
for (unsigned klass : classes) {
if (c == klass) {
return true;
}
}
return false;
}, hb_second);
return actual_class_def_size(+ filtered_it);
}
template<typename It>
static unsigned actual_coverage_size(It glyphs) {
char buffer[100];
hb_serialize_context_t serializer(buffer, 100);
OT::Layout::Common::Coverage_serialize (&serializer, glyphs);
serializer.end_serialize ();
assert(!serializer.in_error());
hb_blob_t* blob = serializer.copy_blob();
unsigned size = hb_blob_get_length(blob);
hb_blob_destroy(blob);
return size;
}
static unsigned actual_coverage_size(gid_and_class_list_t consecutive_map, hb_vector_t<unsigned> classes) {
auto filtered_it =
+ consecutive_map.as_sorted_array().iter()
| hb_filter([&] (unsigned c) {
for (unsigned klass : classes) {
if (c == klass) {
return true;
}
}
return false;
}, hb_second);
return actual_coverage_size(+ filtered_it | hb_map_retains_sorting(hb_first));
}
static bool check_coverage_size(graph::class_def_size_estimator_t& estimator,
const gid_and_class_list_t& map,
hb_vector_t<unsigned> klasses)
{ {
graph::class_def_size_estimator_t estimator (list.iter ()); unsigned result = estimator.coverage_size();
unsigned expected = actual_coverage_size(map, klasses);
if (result != expected) {
printf ("FAIL: estimated coverage expected size %u but was %u\n", expected, result);
return false;
}
return true;
}
unsigned result = estimator.incremental_coverage_size (klass); static bool check_add_class_def_size(graph::class_def_size_estimator_t& estimator,
if (result != cov_expected) const gid_and_class_list_t& map,
{ unsigned klass, hb_vector_t<unsigned> klasses)
printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result); {
unsigned result = estimator.add_class_def_size(klass);
unsigned expected = actual_class_def_size(map, klasses);
if (result != expected) {
printf ("FAIL: estimated class def expected size %u but was %u\n", expected, result);
return false; return false;
} }
result = estimator.incremental_class_def_size (klass); return check_coverage_size(estimator, map, klasses);
if (result != class_def_expected) }
static bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass)
{
graph::class_def_size_estimator_t estimator (list.iter ());
unsigned result = estimator.add_class_def_size (klass);
auto filtered_it =
+ list.as_sorted_array().iter()
| hb_filter([&] (unsigned c) {
return c == klass;
}, hb_second);
unsigned expected = actual_class_def_size(filtered_it);
if (result != expected)
{ {
printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result); printf ("FAIL: class def expected size %u but was %u\n", expected, result);
return false;
}
auto cov_it = + filtered_it | hb_map_retains_sorting(hb_first);
result = estimator.coverage_size ();
expected = actual_coverage_size(cov_it);
if (result != expected)
{
printf ("FAIL: coverage expected size %u but was %u\n", expected, result);
return false; return false;
} }
@ -57,43 +149,45 @@ static void test_class_and_coverage_size_estimates ()
{ {
gid_and_class_list_t empty = { gid_and_class_list_t empty = {
}; };
assert (incremental_size_is (empty, 0, 0, 0)); assert (check_add_class_def_size (empty, 0));
assert (incremental_size_is (empty, 1, 0, 0)); assert (check_add_class_def_size (empty, 1));
gid_and_class_list_t class_zero = { gid_and_class_list_t class_zero = {
{5, 0}, {5, 0},
}; };
assert (incremental_size_is (class_zero, 0, 2, 0)); assert (check_add_class_def_size (class_zero, 0));
gid_and_class_list_t consecutive = { gid_and_class_list_t consecutive = {
{4, 0}, {4, 0},
{5, 0}, {5, 0},
{6, 1}, {6, 1},
{7, 1}, {7, 1},
{8, 2}, {8, 2},
{9, 2}, {9, 2},
{10, 2}, {10, 2},
{11, 2}, {11, 2},
}; };
assert (incremental_size_is (consecutive, 0, 4, 0)); assert (check_add_class_def_size (consecutive, 0));
assert (incremental_size_is (consecutive, 1, 4, 4)); assert (check_add_class_def_size (consecutive, 1));
assert (incremental_size_is (consecutive, 2, 8, 6)); assert (check_add_class_def_size (consecutive, 2));
gid_and_class_list_t non_consecutive = { gid_and_class_list_t non_consecutive = {
{4, 0}, {4, 0},
{5, 0}, {6, 0},
{6, 1}, {8, 1},
{7, 1}, {10, 1},
{9, 2}, {9, 2},
{10, 2}, {10, 2},
{11, 2}, {11, 2},
{12, 2}, {13, 2},
}; };
assert (incremental_size_is (non_consecutive, 0, 4, 0)); assert (check_add_class_def_size (non_consecutive, 0));
assert (incremental_size_is (non_consecutive, 1, 4, 6)); assert (check_add_class_def_size (non_consecutive, 1));
assert (incremental_size_is (non_consecutive, 2, 8, 6)); assert (check_add_class_def_size (non_consecutive, 2));
gid_and_class_list_t multiple_ranges = { gid_and_class_list_t multiple_ranges = {
{4, 0}, {4, 0},
@ -108,12 +202,95 @@ static void test_class_and_coverage_size_estimates ()
{12, 1}, {12, 1},
{13, 1}, {13, 1},
}; };
assert (incremental_size_is (multiple_ranges, 0, 4, 0)); assert (check_add_class_def_size (multiple_ranges, 0));
assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6)); assert (check_add_class_def_size (multiple_ranges, 1));
}
static void test_running_class_and_coverage_size_estimates () {
// #### With consecutive gids: switches formats ###
gid_and_class_list_t consecutive_map = {
// range 1-4 (f1: 8 bytes), (f2: 6 bytes)
{1, 1},
{2, 1},
{3, 1},
{4, 1},
// (f1: 2 bytes), (f2: 6 bytes)
{5, 2},
// (f1: 14 bytes), (f2: 6 bytes)
{6, 3},
{7, 3},
{8, 3},
{9, 3},
{10, 3},
{11, 3},
{12, 3},
};
graph::class_def_size_estimator_t estimator1(consecutive_map.iter());
assert(check_add_class_def_size(estimator1, consecutive_map, 1, {1}));
assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2}));
assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); // check that adding the same class again works
assert(check_add_class_def_size(estimator1, consecutive_map, 3, {1, 2, 3}));
estimator1.reset();
assert(check_add_class_def_size(estimator1, consecutive_map, 2, {2}));
assert(check_add_class_def_size(estimator1, consecutive_map, 3, {2, 3}));
// #### With non-consecutive gids: always uses format 2 ###
gid_and_class_list_t non_consecutive_map = {
// range 1-4 (f1: 8 bytes), (f2: 6 bytes)
{1, 1},
{2, 1},
{3, 1},
{4, 1},
// (f1: 2 bytes), (f2: 12 bytes)
{6, 2},
{8, 2},
// (f1: 14 bytes), (f2: 6 bytes)
{9, 3},
{10, 3},
{11, 3},
{12, 3},
{13, 3},
{14, 3},
{15, 3},
};
graph::class_def_size_estimator_t estimator2(non_consecutive_map.iter());
assert(check_add_class_def_size(estimator2, non_consecutive_map, 1, {1}));
assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {1, 2}));
assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {1, 2, 3}));
estimator2.reset();
assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {2}));
assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {2, 3}));
}
static void test_running_class_size_estimates_with_locally_consecutive_glyphs () {
gid_and_class_list_t map = {
{1, 1},
{6, 2},
{7, 3},
};
graph::class_def_size_estimator_t estimator(map.iter());
assert(check_add_class_def_size(estimator, map, 1, {1}));
assert(check_add_class_def_size(estimator, map, 2, {1, 2}));
assert(check_add_class_def_size(estimator, map, 3, {1, 2, 3}));
estimator.reset();
assert(check_add_class_def_size(estimator, map, 2, {2}));
assert(check_add_class_def_size(estimator, map, 3, {2, 3}));
} }
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
test_class_and_coverage_size_estimates (); test_class_and_coverage_size_estimates ();
test_running_class_and_coverage_size_estimates ();
test_running_class_size_estimates_with_locally_consecutive_glyphs ();
} }

View File

@ -54,6 +54,7 @@
#include "hb-subset-cff1.cc" #include "hb-subset-cff1.cc"
#include "hb-subset-cff2.cc" #include "hb-subset-cff2.cc"
#include "hb-subset-input.cc" #include "hb-subset-input.cc"
#include "hb-subset-instancer-iup.cc"
#include "hb-subset-instancer-solver.cc" #include "hb-subset-instancer-solver.cc"
#include "hb-subset-plan.cc" #include "hb-subset-plan.cc"
#include "hb-subset-repacker.cc" #include "hb-subset-repacker.cc"

View File

@ -75,6 +75,7 @@ struct ankr
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
version == 0 && version == 0 &&
c->check_range (this, anchorData) && c->check_range (this, anchorData) &&
lookupTable.sanitize (c, this, &(this+anchorData)))); lookupTable.sanitize (c, this, &(this+anchorData))));

View File

@ -123,6 +123,7 @@ struct bsln
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && defaultBaseline < 32))) if (unlikely (!(c->check_struct (this) && defaultBaseline < 32)))
return_trace (false); return_trace (false);
hb_barrier ();
switch (format) switch (format)
{ {

View File

@ -191,6 +191,7 @@ struct LookupSegmentArray
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
first <= last && first <= last &&
valuesZ.sanitize (c, base, last - first + 1)); valuesZ.sanitize (c, base, last - first + 1));
} }
@ -199,6 +200,7 @@ struct LookupSegmentArray
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
first <= last && first <= last &&
valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...)); valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...));
} }
@ -360,6 +362,7 @@ struct LookupFormat10
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
valueSize <= 4 && valueSize <= 4 &&
valueArrayZ.sanitize (c, glyphCount * valueSize)); valueArrayZ.sanitize (c, glyphCount * valueSize));
} }
@ -415,6 +418,7 @@ struct Lookup
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 0: return_trace (u.format0.sanitize (c)); case 0: return_trace (u.format0.sanitize (c));
case 2: return_trace (u.format2.sanitize (c)); case 2: return_trace (u.format2.sanitize (c));
@ -429,6 +433,7 @@ struct Lookup
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 0: return_trace (u.format0.sanitize (c, base)); case 0: return_trace (u.format0.sanitize (c, base));
case 2: return_trace (u.format2.sanitize (c, base)); case 2: return_trace (u.format2.sanitize (c, base));
@ -558,6 +563,7 @@ struct StateTable
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && if (unlikely (!(c->check_struct (this) &&
hb_barrier () &&
nClasses >= 4 /* Ensure pre-defined classes fit. */ && nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
classTable.sanitize (c, this)))) return_trace (false); classTable.sanitize (c, this)))) return_trace (false);

View File

@ -138,6 +138,7 @@ struct FeatureName
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
(base+settingTableZ).sanitize (c, nSettings))); (base+settingTableZ).sanitize (c, nSettings)));
} }
@ -200,6 +201,7 @@ struct feat
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
version.major == 1 && version.major == 1 &&
namesZ.sanitize (c, featureNameCount, this))); namesZ.sanitize (c, featureNameCount, this)));
} }

View File

@ -185,6 +185,7 @@ struct ActionSubrecord
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
switch (u.header.actionType) switch (u.header.actionType)
{ {
@ -220,6 +221,7 @@ struct PostcompensationActionChain
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
unsigned int offset = min_size; unsigned int offset = min_size;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
@ -389,6 +391,7 @@ struct just
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
version.major == 1 && version.major == 1 &&
horizData.sanitize (c, this, this) && horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this))); vertData.sanitize (c, this, this)));

View File

@ -54,6 +54,7 @@ kerxTupleKern (int value,
unsigned int offset = value; unsigned int offset = value;
const FWORD *pv = &StructAtOffset<FWORD> (base, offset); const FWORD *pv = &StructAtOffset<FWORD> (base, offset);
if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0; if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0;
hb_barrier ();
return *pv; return *pv;
} }
@ -259,6 +260,7 @@ struct KerxSubTableFormat1
depth = 0; depth = 0;
return; return;
} }
hb_barrier ();
hb_mask_t kern_mask = c->plan->kern_mask; hb_mask_t kern_mask = c->plan->kern_mask;
@ -389,6 +391,7 @@ struct KerxSubTableFormat2
kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ); kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
const FWORD *v = &arrayZ[kern_idx]; const FWORD *v = &arrayZ[kern_idx];
if (unlikely (!v->sanitize (&c->sanitizer))) return 0; if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
hb_barrier ();
return kerxTupleKern (*v, header.tuple_count (), this, c); return kerxTupleKern (*v, header.tuple_count (), this, c);
} }
@ -429,6 +432,7 @@ struct KerxSubTableFormat2
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
leftClassTable.sanitize (c, this) && leftClassTable.sanitize (c, this) &&
rightClassTable.sanitize (c, this) && rightClassTable.sanitize (c, this) &&
hb_barrier () &&
c->check_range (this, array))); c->check_range (this, array)));
} }
@ -509,6 +513,7 @@ struct KerxSubTableFormat4
double the ankrActionIndex to get the correct offset here. */ double the ankrActionIndex to get the correct offset here. */
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2]; const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
if (!c->sanitizer.check_array (data, 2)) return; if (!c->sanitizer.check_array (data, 2)) return;
hb_barrier ();
unsigned int markControlPoint = *data++; unsigned int markControlPoint = *data++;
unsigned int currControlPoint = *data++; unsigned int currControlPoint = *data++;
hb_position_t markX = 0; hb_position_t markX = 0;
@ -537,6 +542,7 @@ struct KerxSubTableFormat4
double the ankrActionIndex to get the correct offset here. */ double the ankrActionIndex to get the correct offset here. */
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2]; const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
if (!c->sanitizer.check_array (data, 2)) return; if (!c->sanitizer.check_array (data, 2)) return;
hb_barrier ();
unsigned int markAnchorPoint = *data++; unsigned int markAnchorPoint = *data++;
unsigned int currAnchorPoint = *data++; unsigned int currAnchorPoint = *data++;
const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint, const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
@ -557,6 +563,7 @@ struct KerxSubTableFormat4
by 4 to get the correct offset for the given action. */ by 4 to get the correct offset for the given action. */
const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4]; const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
if (!c->sanitizer.check_array (data, 4)) return; if (!c->sanitizer.check_array (data, 4)) return;
hb_barrier ();
int markX = *data++; int markX = *data++;
int markY = *data++; int markY = *data++;
int currX = *data++; int currX = *data++;
@ -639,6 +646,7 @@ struct KerxSubTableFormat6
if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0; if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32)); const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
if (unlikely (!v->sanitize (&c->sanitizer))) return 0; if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
hb_barrier ();
return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
} }
else else
@ -649,6 +657,7 @@ struct KerxSubTableFormat6
unsigned int offset = l + r; unsigned int offset = l + r;
const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD)); const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD));
if (unlikely (!v->sanitize (&c->sanitizer))) return 0; if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
hb_barrier ();
return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
} }
} }
@ -674,6 +683,7 @@ struct KerxSubTableFormat6
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
(is_long () ? (is_long () ?
( (
u.l.rowIndexTable.sanitize (c, this) && u.l.rowIndexTable.sanitize (c, this) &&
@ -787,9 +797,10 @@ struct KerxSubTable
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.header.sanitize (c) || if (!(u.header.sanitize (c) &&
u.header.length <= u.header.static_size || hb_barrier () &&
!c->check_range (this, u.header.length)) u.header.length >= u.header.static_size &&
c->check_range (this, u.header.length)))
return_trace (false); return_trace (false);
return_trace (dispatch (c)); return_trace (dispatch (c));
@ -936,9 +947,10 @@ struct KerxTable
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!thiz()->version.sanitize (c) || if (unlikely (!(thiz()->version.sanitize (c) &&
(unsigned) thiz()->version < (unsigned) T::minVersion || hb_barrier () &&
!thiz()->tableCount.sanitize (c))) (unsigned) thiz()->version >= (unsigned) T::minVersion &&
thiz()->tableCount.sanitize (c))))
return_trace (false); return_trace (false);
typedef typename T::SubTable SubTable; typedef typename T::SubTable SubTable;
@ -949,6 +961,7 @@ struct KerxTable
{ {
if (unlikely (!st->u.header.sanitize (c))) if (unlikely (!st->u.header.sanitize (c)))
return_trace (false); return_trace (false);
hb_barrier ();
/* OpenType kern table has 2-byte subtable lengths. That's limiting. /* OpenType kern table has 2-byte subtable lengths. That's limiting.
* MS implementation also only supports one subtable, of format 0, * MS implementation also only supports one subtable, of format 0,
* anyway. Certain versions of some fonts, like Calibry, contain * anyway. Certain versions of some fonts, like Calibry, contain

View File

@ -259,7 +259,9 @@ struct ContextualSubtable
unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint; unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs; const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
if (!replacement->sanitize (&c->sanitizer) || !*replacement) if (!(replacement->sanitize (&c->sanitizer) &&
hb_barrier () &&
*replacement))
replacement = nullptr; replacement = nullptr;
} }
if (replacement) if (replacement)
@ -287,7 +289,9 @@ struct ContextualSubtable
unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint; unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs; const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
if (!replacement->sanitize (&c->sanitizer) || !*replacement) if (!(replacement->sanitize (&c->sanitizer) &&
hb_barrier () &&
*replacement))
replacement = nullptr; replacement = nullptr;
} }
if (replacement) if (replacement)
@ -315,7 +319,7 @@ struct ContextualSubtable
bool has_glyph_classes; bool has_glyph_classes;
unsigned int mark; unsigned int mark;
const ContextualSubtable *table; const ContextualSubtable *table;
const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false> &subs; const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
}; };
bool apply (hb_aat_apply_context_t *c) const bool apply (hb_aat_apply_context_t *c) const
@ -336,6 +340,7 @@ struct ContextualSubtable
unsigned int num_entries = 0; unsigned int num_entries = 0;
if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false); if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
hb_barrier ();
if (!Types::extended) if (!Types::extended)
return_trace (substitutionTables.sanitize (c, this, 0)); return_trace (substitutionTables.sanitize (c, this, 0));
@ -359,7 +364,7 @@ struct ContextualSubtable
protected: protected:
StateTable<Types, EntryData> StateTable<Types, EntryData>
machine; machine;
NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false>, HBUINT> NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
substitutionTables; substitutionTables;
public: public:
DEFINE_SIZE_STATIC (20); DEFINE_SIZE_STATIC (20);
@ -513,6 +518,7 @@ struct LigatureSubtable
if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return; if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
if (unlikely (!actionData->sanitize (&c->sanitizer))) break; if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
hb_barrier ();
action = *actionData; action = *actionData;
uint32_t uoffset = action & LigActionOffset; uint32_t uoffset = action & LigActionOffset;
@ -523,6 +529,7 @@ struct LigatureSubtable
component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ); component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
const HBUINT16 &componentData = component[component_idx]; const HBUINT16 &componentData = component[component_idx];
if (unlikely (!componentData.sanitize (&c->sanitizer))) break; if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
hb_barrier ();
ligature_idx += componentData; ligature_idx += componentData;
DEBUG_MSG (APPLY, nullptr, "Action store %d last %d", DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
@ -533,6 +540,7 @@ struct LigatureSubtable
ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ); ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
const HBGlyphID16 &ligatureData = ligature[ligature_idx]; const HBGlyphID16 &ligatureData = ligature[ligature_idx];
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break; if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
hb_barrier ();
hb_codepoint_t lig = ligatureData; hb_codepoint_t lig = ligatureData;
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig); DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
@ -544,6 +552,7 @@ struct LigatureSubtable
{ {
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return; if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE;
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return; if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
} }
@ -587,6 +596,7 @@ struct LigatureSubtable
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
/* The rest of array sanitizations are done at run-time. */ /* The rest of array sanitizations are done at run-time. */
return_trace (c->check_struct (this) && machine.sanitize (c) && return_trace (c->check_struct (this) && machine.sanitize (c) &&
hb_barrier () &&
ligAction && component && ligature); ligAction && component && ligature);
} }
@ -765,6 +775,7 @@ struct InsertionSubtable
unsigned int start = entry.data.markedInsertIndex; unsigned int start = entry.data.markedInsertIndex;
const HBGlyphID16 *glyphs = &insertionAction[start]; const HBGlyphID16 *glyphs = &insertionAction[start];
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
hb_barrier ();
bool before = flags & MarkedInsertBefore; bool before = flags & MarkedInsertBefore;
@ -793,6 +804,7 @@ struct InsertionSubtable
unsigned int start = entry.data.currentInsertIndex; unsigned int start = entry.data.currentInsertIndex;
const HBGlyphID16 *glyphs = &insertionAction[start]; const HBGlyphID16 *glyphs = &insertionAction[start];
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
hb_barrier ();
bool before = flags & CurrentInsertBefore; bool before = flags & CurrentInsertBefore;
@ -849,6 +861,7 @@ struct InsertionSubtable
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
/* The rest of array sanitizations are done at run-time. */ /* The rest of array sanitizations are done at run-time. */
return_trace (c->check_struct (this) && machine.sanitize (c) && return_trace (c->check_struct (this) && machine.sanitize (c) &&
hb_barrier () &&
insertionAction); insertionAction);
} }
@ -944,9 +957,10 @@ struct ChainSubtable
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!length.sanitize (c) || if (!(length.sanitize (c) &&
length <= min_size || hb_barrier () &&
!c->check_range (this, length)) length >= min_size &&
c->check_range (this, length)))
return_trace (false); return_trace (false);
hb_sanitize_with_object_t with (c, this); hb_sanitize_with_object_t with (c, this);
@ -1089,9 +1103,10 @@ struct Chain
bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!length.sanitize (c) || if (!(length.sanitize (c) &&
length < min_size || hb_barrier () &&
!c->check_range (this, length)) length >= min_size &&
c->check_range (this, length)))
return_trace (false); return_trace (false);
if (!c->check_array (featureZ.arrayZ, featureCount)) if (!c->check_array (featureZ.arrayZ, featureCount))
@ -1103,6 +1118,7 @@ struct Chain
{ {
if (!subtable->sanitize (c)) if (!subtable->sanitize (c))
return_trace (false); return_trace (false);
hb_barrier ();
subtable = &StructAfter<ChainSubtable<Types>> (*subtable); subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
} }
@ -1173,7 +1189,10 @@ struct mortmorx
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!version.sanitize (c) || !version || !chainCount.sanitize (c)) if (!(version.sanitize (c) &&
hb_barrier () &&
version &&
chainCount.sanitize (c)))
return_trace (false); return_trace (false);
const Chain<Types> *chain = &firstChain; const Chain<Types> *chain = &firstChain;
@ -1182,6 +1201,7 @@ struct mortmorx
{ {
if (!chain->sanitize (c, version)) if (!chain->sanitize (c, version))
return_trace (false); return_trace (false);
hb_barrier ();
chain = &StructAfter<Chain<Types>> (*chain); chain = &StructAfter<Chain<Types>> (*chain);
} }

View File

@ -144,6 +144,7 @@ struct opbd
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this) || version.major != 1)) if (unlikely (!c->check_struct (this) || version.major != 1))
return_trace (false); return_trace (false);
hb_barrier ();
switch (format) switch (format)
{ {

View File

@ -134,6 +134,7 @@ struct TrackData
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
sizeTable.sanitize (c, base, nSizes) && sizeTable.sanitize (c, base, nSizes) &&
trackTable.sanitize (c, nTracks, base, nSizes))); trackTable.sanitize (c, nTracks, base, nSizes)));
} }
@ -203,6 +204,7 @@ struct trak
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
version.major == 1 && version.major == 1 &&
horizData.sanitize (c, this, this) && horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this))); vertData.sanitize (c, this, this)));

View File

@ -40,7 +40,7 @@ HB_BEGIN_DECLS
* @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type * @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type
* @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0) * @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0)
* @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1) * @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1)
* @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2) * @HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2)
* @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3) * @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3)
* @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4) * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4)
* @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5) * @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5)
@ -88,7 +88,7 @@ typedef enum
HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0, HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0,
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1, HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1,
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2, HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION = 2,
HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3, HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3,
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4, HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4,
HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5, HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5,

View File

@ -46,7 +46,9 @@ struct FTStringRange
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && (base+tag).sanitize (c, length)); return_trace (c->check_struct (this) &&
hb_barrier () &&
(base+tag).sanitize (c, length));
} }
protected: protected:
@ -73,6 +75,7 @@ struct ltag
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
version >= 1 && version >= 1 &&
tagRanges.sanitize (c, this))); tagRanges.sanitize (c, this)));
} }

View File

@ -671,7 +671,7 @@ struct hb_pair_t
return 0; return 0;
} }
friend void swap (hb_pair_t& a, hb_pair_t& b) friend void swap (hb_pair_t& a, hb_pair_t& b) noexcept
{ {
hb_swap (a.first, b.first); hb_swap (a.first, b.first);
hb_swap (a.second, b.second); hb_swap (a.second, b.second);
@ -1053,6 +1053,18 @@ _hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
return val.cmp (key, ds...); return val.cmp (key, ds...);
} }
template <typename K, typename V>
static int
_hb_cmp_operator (const void *pkey, const void *pval)
{
const K& key = * (const K*) pkey;
const V& val = * (const V*) pval;
if (key < val) return -1;
if (key > val) return 1;
return 0;
}
template <typename V, typename K, typename ...Ts> template <typename V, typename K, typename ...Ts>
static inline bool static inline bool
hb_bsearch_impl (unsigned *pos, /* Out */ hb_bsearch_impl (unsigned *pos, /* Out */

View File

@ -47,6 +47,8 @@ enum hb_not_found_t
template <typename Type> template <typename Type>
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&> struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
{ {
static constexpr bool realloc_move = true;
/* /*
* Constructors. * Constructors.
*/ */

View File

@ -118,12 +118,12 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
*/ */
#ifndef _hb_compiler_memory_r_barrier #ifndef _hb_compiler_memory_r_barrier
#if defined(__ATOMIC_ACQUIRE) // gcc-like #if defined(__ATOMIC_ACQUIRE) // gcc-like
#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory") static inline void _hb_compiler_memory_r_barrier () { asm volatile("": : :"memory"); }
#elif !defined(_MSC_VER) #elif !defined(_MSC_VER)
#include <atomic> #include <atomic>
#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire) #define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
#else #else
#define _hb_compiler_memory_r_barrier() do {} while (0) static inline void _hb_compiler_memory_r_barrier () {}
#endif #endif
#endif #endif
@ -218,5 +218,11 @@ struct hb_atomic_ptr_t
T *v = nullptr; T *v = nullptr;
}; };
static inline bool hb_barrier ()
{
_hb_compiler_memory_r_barrier ();
return true;
}
#endif /* HB_ATOMIC_HH */ #endif /* HB_ATOMIC_HH */

View File

@ -39,10 +39,10 @@ struct hb_bit_set_invertible_t
hb_bit_set_invertible_t () = default; hb_bit_set_invertible_t () = default;
hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default; hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default;
hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); } hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) noexcept : hb_bit_set_invertible_t () { hb_swap (*this, other); }
hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default; hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default;
hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; } hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) noexcept { hb_swap (*this, other); return *this; }
friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) noexcept
{ {
if (likely (!a.s.successful || !b.s.successful)) if (likely (!a.s.successful || !b.s.successful))
return; return;
@ -359,8 +359,8 @@ struct hb_bit_set_invertible_t
typedef hb_codepoint_t __item_t__; typedef hb_codepoint_t __item_t__;
hb_codepoint_t __item__ () const { return v; } hb_codepoint_t __item__ () const { return v; }
bool __more__ () const { return v != INVALID; } bool __more__ () const { return v != INVALID; }
void __next__ () { s->next (&v); if (l) l--; } void __next__ () { s->next (&v); if (likely (l)) l--; }
void __prev__ () { s->previous (&v); } void __prev__ () { s->previous (&v); l++; }
unsigned __len__ () const { return l; } unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); } iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const bool operator != (const iter_t& o) const

View File

@ -38,10 +38,10 @@ struct hb_bit_set_t
~hb_bit_set_t () = default; ~hb_bit_set_t () = default;
hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); } hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); } hb_bit_set_t ( hb_bit_set_t&& other) noexcept : hb_bit_set_t () { hb_swap (*this, other); }
hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; } hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; } hb_bit_set_t& operator= (hb_bit_set_t&& other) noexcept { hb_swap (*this, other); return *this; }
friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) noexcept
{ {
if (likely (!a.successful || !b.successful)) if (likely (!a.successful || !b.successful))
return; return;

View File

@ -598,6 +598,11 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
* Creates a new blob containing the data from the * Creates a new blob containing the data from the
* specified binary font file. * specified binary font file.
* *
* The filename is passed directly to the system on all platforms,
* except on Windows, where the filename is interpreted as UTF-8.
* Only if the filename is not valid UTF-8, it will be interpreted
* according to the system codepage.
*
* Returns: An #hb_blob_t pointer with the content of the file, * Returns: An #hb_blob_t pointer with the content of the file,
* or hb_blob_get_empty() if failed. * or hb_blob_get_empty() if failed.
* *
@ -617,6 +622,11 @@ hb_blob_create_from_file (const char *file_name)
* Creates a new blob containing the data from the * Creates a new blob containing the data from the
* specified binary font file. * specified binary font file.
* *
* The filename is passed directly to the system on all platforms,
* except on Windows, where the filename is interpreted as UTF-8.
* Only if the filename is not valid UTF-8, it will be interpreted
* according to the system codepage.
*
* Returns: An #hb_blob_t pointer with the content of the file, * Returns: An #hb_blob_t pointer with the content of the file,
* or `NULL` if failed. * or `NULL` if failed.
* *
@ -672,10 +682,19 @@ fail_without_close:
if (unlikely (!file)) return nullptr; if (unlikely (!file)) return nullptr;
HANDLE fd; HANDLE fd;
int conversion;
unsigned int size = strlen (file_name) + 1; unsigned int size = strlen (file_name) + 1;
wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
if (unlikely (!wchar_file_name)) goto fail_without_close; if (unlikely (!wchar_file_name)) goto fail_without_close;
mbstowcs (wchar_file_name, file_name, size);
/* Assume file name is given in UTF-8 encoding */
conversion = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size);
if (conversion <= 0)
{
/* Conversion failed due to invalid UTF-8 characters,
Repeat conversion based on system code page */
mbstowcs(wchar_file_name, file_name, size);
}
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
{ {
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };

View File

@ -149,7 +149,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
} }
assert (text_start < text_end); assert (text_start < text_end);
if (0) if (false)
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
hb_buffer_clear_contents (fragment); hb_buffer_clear_contents (fragment);
@ -288,7 +288,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
} }
assert (text_start < text_end); assert (text_start < text_end);
if (0) if (false)
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
#if 0 #if 0

View File

@ -309,6 +309,7 @@ hb_buffer_t::clear ()
deallocate_var_all (); deallocate_var_all ();
serial = 0; serial = 0;
random_state = 1;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
} }
@ -1359,6 +1360,49 @@ hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
return buffer->not_found; return buffer->not_found;
} }
/**
* hb_buffer_set_random_state:
* @buffer: An #hb_buffer_t
* @state: the new random state
*
* Sets the random state of the buffer. The state changes
* every time a glyph uses randomness (eg. the `rand`
* OpenType feature). This function together with
* hb_buffer_get_random_state() allow for transferring
* the current random state to a subsequent buffer, to
* get better randomness distribution.
*
* Defaults to 1 and when buffer contents are cleared.
* A value of 0 disables randomness during shaping.
*
* Since: 8.4.0
**/
void
hb_buffer_set_random_state (hb_buffer_t *buffer,
unsigned state)
{
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->random_state = state;
}
/**
* hb_buffer_get_random_state:
* @buffer: An #hb_buffer_t
*
* See hb_buffer_set_random_state().
*
* Return value:
* The @buffer random state
*
* Since: 8.4.0
**/
unsigned
hb_buffer_get_random_state (const hb_buffer_t *buffer)
{
return buffer->random_state;
}
/** /**
* hb_buffer_clear_contents: * hb_buffer_clear_contents:

View File

@ -487,6 +487,12 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
HB_EXTERN hb_codepoint_t HB_EXTERN hb_codepoint_t
hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer); hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_random_state (hb_buffer_t *buffer,
unsigned state);
HB_EXTERN unsigned
hb_buffer_get_random_state (const hb_buffer_t *buffer);
/* /*
* Content API. * Content API.

View File

@ -116,6 +116,7 @@ struct hb_buffer_t
uint8_t allocated_var_bits; uint8_t allocated_var_bits;
uint8_t serial; uint8_t serial;
uint32_t random_state;
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */ unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */ int max_ops; /* Maximum allowed operations. */

View File

@ -54,8 +54,8 @@ struct top_dict_values_t : dict_values_t<OPSTR>
} }
void fini () { dict_values_t<OPSTR>::fini (); } void fini () { dict_values_t<OPSTR>::fini (); }
unsigned int charStringsOffset; int charStringsOffset;
unsigned int FDArrayOffset; int FDArrayOffset;
}; };
struct dict_opset_t : opset_t<number_t> struct dict_opset_t : opset_t<number_t>
@ -157,11 +157,11 @@ struct top_dict_opset_t : dict_opset_t
{ {
switch (op) { switch (op) {
case OpCode_CharStrings: case OpCode_CharStrings:
dictval.charStringsOffset = env.argStack.pop_uint (); dictval.charStringsOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
case OpCode_FDArray: case OpCode_FDArray:
dictval.FDArrayOffset = env.argStack.pop_uint (); dictval.FDArrayOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
case OpCode_FontMatrix: case OpCode_FontMatrix:

View File

@ -168,7 +168,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
protected: protected:
const int *coords; const int *coords;
unsigned int num_coords; unsigned int num_coords;
const CFF2VariationStore *varStore; const CFF2ItemVariationStore *varStore;
unsigned int region_count; unsigned int region_count;
unsigned int ivs; unsigned int ivs;
hb_vector_t<float> scalars; hb_vector_t<float> scalars;

View File

@ -996,7 +996,7 @@ hb_feature_to_string (hb_feature_t *feature,
if (feature->value > 1) if (feature->value > 1)
{ {
s[len++] = '='; s[len++] = '=';
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value)); len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32, feature->value));
} }
assert (len < ARRAY_LENGTH (s)); assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1); len = hb_min (len, size - 1);

View File

@ -47,14 +47,10 @@
# endif /* !__cplusplus */ # endif /* !__cplusplus */
#endif #endif
#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \ #if defined (_AIX)
defined (_sgi) || defined (__sun) || defined (sun) || \
defined (__digital__) || defined (__HP_cc)
# include <inttypes.h>
#elif defined (_AIX)
# include <sys/inttypes.h> # include <sys/inttypes.h>
#elif defined (_MSC_VER) && _MSC_VER < 1600 #elif defined (_MSC_VER) && _MSC_VER < 1600
/* VS 2010 (_MSC_VER 1600) has stdint.h */ /* VS 2010 (_MSC_VER 1600) has stdint.h */
typedef __int8 int8_t; typedef __int8 int8_t;
typedef unsigned __int8 uint8_t; typedef unsigned __int8 uint8_t;
typedef __int16 int16_t; typedef __int16 int16_t;
@ -63,10 +59,11 @@ typedef __int32 int32_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
typedef __int64 int64_t; typedef __int64 int64_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
#elif defined (__KERNEL__) #elif defined (_MSC_VER) && _MSC_VER < 1800
# include <linux/types.h> /* VS 2013 (_MSC_VER 1800) has inttypes.h */
#else
# include <stdint.h> # include <stdint.h>
#else
# include <inttypes.h>
#endif #endif
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) #if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))

View File

@ -56,15 +56,15 @@ struct shared_ptr
explicit shared_ptr (T *p = nullptr) : p (p) {} explicit shared_ptr (T *p = nullptr) : p (p) {}
shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {} shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {}
shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; } shared_ptr (shared_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; } shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; }
shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; } shared_ptr& operator = (shared_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
~shared_ptr () { v::destroy (p); p = nullptr; } ~shared_ptr () { v::destroy (p); p = nullptr; }
T* get() const { return p; } T* get() const { return p; }
void swap (shared_ptr &o) { std::swap (p, o.p); } void swap (shared_ptr &o) noexcept { std::swap (p, o.p); }
friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); } friend void swap (shared_ptr &a, shared_ptr &b) noexcept { std::swap (a.p, b.p); }
operator T * () const { return p; } operator T * () const { return p; }
T& operator * () const { return *get (); } T& operator * () const { return *get (); }
@ -98,16 +98,16 @@ struct unique_ptr
explicit unique_ptr (T *p = nullptr) : p (p) {} explicit unique_ptr (T *p = nullptr) : p (p) {}
unique_ptr (const unique_ptr &o) = delete; unique_ptr (const unique_ptr &o) = delete;
unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; } unique_ptr (unique_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
unique_ptr& operator = (const unique_ptr &o) = delete; unique_ptr& operator = (const unique_ptr &o) = delete;
unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; } unique_ptr& operator = (unique_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
~unique_ptr () { v::destroy (p); p = nullptr; } ~unique_ptr () { v::destroy (p); p = nullptr; }
T* get() const { return p; } T* get() const { return p; }
T* release () { T* v = p; p = nullptr; return v; } T* release () { T* v = p; p = nullptr; return v; }
void swap (unique_ptr &o) { std::swap (p, o.p); } void swap (unique_ptr &o) noexcept { std::swap (p, o.p); }
friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); } friend void swap (unique_ptr &a, unique_ptr &b) noexcept { std::swap (a.p, b.p); }
operator T * () const { return p; } operator T * () const { return p; }
T& operator * () const { return *get (); } T& operator * () const { return *get (); }

View File

@ -56,7 +56,7 @@ HB_BEGIN_DECLS
/** /**
* HB_SCRIPT_CANADIAN_ABORIGINAL: * HB_SCRIPT_CANADIAN_ABORIGINAL:
* *
* Use #HB_SCRIPT_CANADIAN_SYLLABICS instead: * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead.
* *
* Deprecated: 0.9.20 * Deprecated: 0.9.20
*/ */
@ -301,6 +301,15 @@ hb_font_get_glyph_shape (hb_font_t *font,
hb_draw_funcs_t *dfuncs, void *draw_data); hb_draw_funcs_t *dfuncs, void *draw_data);
/**
* HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION:
*
* Use #HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION instead.
*
* Deprecated: 8.3.0
*/
#define HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
#endif #endif

View File

@ -173,7 +173,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
t_DWriteCreateFactory p_DWriteCreateFactory; t_DWriteCreateFactory p_DWriteCreateFactory;
#if defined(__GNUC__) #if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type" #pragma GCC diagnostic ignored "-Wcast-function-type"
#endif #endif
@ -181,7 +181,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
p_DWriteCreateFactory = (t_DWriteCreateFactory) p_DWriteCreateFactory = (t_DWriteCreateFactory)
GetProcAddress (data->dwrite_dll, "DWriteCreateFactory"); GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
#if defined(__GNUC__) #if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif

View File

@ -0,0 +1,119 @@
/*
* Copyright © 2022 Red Hat, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_FEATURES_H
#define HB_FEATURES_H
HB_BEGIN_DECLS
/**
* SECTION: hb-features
* @title: hb-features
* @short_description: Feature detection
* @include: hb-features.h
*
* Macros for detecting optional HarfBuzz features at build time.
**/
/**
* HB_HAS_CAIRO:
*
* Defined if Harfbuzz has been built with cairo support.
*/
#
/**
* HB_HAS_CORETEXT:
*
* Defined if Harfbuzz has been built with CoreText support.
*/
#undef HB_HAS_CORETEXT
/**
* HB_HAS_DIRECTWRITE:
*
* Defined if Harfbuzz has been built with DirectWrite support.
*/
#undef HB_HAS_DIRECTWRITE
/**
* HB_HAS_FREETYPE:
*
* Defined if Harfbuzz has been built with Freetype support.
*/
#define HB_HAS_FREETYPE 1
/**
* HB_HAS_GDI:
*
* Defined if Harfbuzz has been built with GDI support.
*/
#undef HB_HAS_GDI
/**
* HB_HAS_GLIB:
*
* Defined if Harfbuzz has been built with GLib support.
*/
#define HB_HAS_GLIB 1
/**
* HB_HAS_GOBJECT:
*
* Defined if Harfbuzz has been built with GObject support.
*/
#undef HB_HAS_GOBJECT
/**
* HB_HAS_GRAPHITE:
*
* Defined if Harfbuzz has been built with Graphite support.
*/
#undef HB_HAS_GRAPHITE
/**
* HB_HAS_ICU:
*
* Defined if Harfbuzz has been built with ICU support.
*/
#undef HB_HAS_ICU
/**
* HB_HAS_UNISCRIBE:
*
* Defined if Harfbuzz has been built with Uniscribe support.
*/
#undef HB_HAS_UNISCRIBE
/**
* HB_HAS_WASM:
*
* Defined if Harfbuzz has been built with WebAssembly support.
*/
#undef HB_HAS_WASM
HB_END_DECLS
#endif /* HB_FEATURES_H */

View File

@ -651,7 +651,7 @@ struct hb_font_t
{ {
if (get_glyph_name (glyph, s, size)) return; if (get_glyph_name (glyph, s, size)) return;
if (size && snprintf (s, size, "gid%u", glyph) < 0) if (size && snprintf (s, size, "gid%" PRIu32, glyph) < 0)
*s = '\0'; *s = '\0';
} }

View File

@ -224,8 +224,8 @@ _hb_ft_hb_font_check_changed (hb_font_t *font,
* *
* Sets the FT_Load_Glyph load flags for the specified #hb_font_t. * Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
* *
* For more information, see * For more information, see
* https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
* *
* This function works with #hb_font_t objects created by * This function works with #hb_font_t objects created by
* hb_ft_font_create() or hb_ft_font_create_referenced(). * hb_ft_font_create() or hb_ft_font_create_referenced().
@ -252,8 +252,8 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
* *
* Fetches the FT_Load_Glyph load flags of the specified #hb_font_t. * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
* *
* For more information, see * For more information, see
* https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
* *
* This function works with #hb_font_t objects created by * This function works with #hb_font_t objects created by
* hb_ft_font_create() or hb_ft_font_create_referenced(). * hb_ft_font_create() or hb_ft_font_create_referenced().
@ -1118,10 +1118,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
* This variant of the function does not provide any life-cycle management. * This variant of the function does not provide any life-cycle management.
* *
* Most client programs should use hb_ft_face_create_referenced() * Most client programs should use hb_ft_face_create_referenced()
* (or, perhaps, hb_ft_face_create_cached()) instead. * (or, perhaps, hb_ft_face_create_cached()) instead.
* *
* If you know you have valid reasons not to use hb_ft_face_create_referenced(), * If you know you have valid reasons not to use hb_ft_face_create_referenced(),
* then it is the client program's responsibility to destroy @ft_face * then it is the client program's responsibility to destroy @ft_face
* after the #hb_face_t face object has been destroyed. * after the #hb_face_t face object has been destroyed.
* *
* Return value: (transfer full): the new #hb_face_t face object * Return value: (transfer full): the new #hb_face_t face object
@ -1215,7 +1215,7 @@ hb_ft_face_finalize (void *arg)
hb_face_t * hb_face_t *
hb_ft_face_create_cached (FT_Face ft_face) hb_ft_face_create_cached (FT_Face ft_face)
{ {
if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize)) if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize))
{ {
if (ft_face->generic.finalizer) if (ft_face->generic.finalizer)
ft_face->generic.finalizer (ft_face); ft_face->generic.finalizer (ft_face);
@ -1241,13 +1241,13 @@ hb_ft_face_create_cached (FT_Face ft_face)
* This variant of the function does not provide any life-cycle management. * This variant of the function does not provide any life-cycle management.
* *
* Most client programs should use hb_ft_font_create_referenced() * Most client programs should use hb_ft_font_create_referenced()
* instead. * instead.
* *
* If you know you have valid reasons not to use hb_ft_font_create_referenced(), * If you know you have valid reasons not to use hb_ft_font_create_referenced(),
* then it is the client program's responsibility to destroy @ft_face * then it is the client program's responsibility to destroy @ft_face
* after the #hb_font_t font object has been destroyed. * after the #hb_font_t font object has been destroyed.
* *
* HarfBuzz will use the @destroy callback on the #hb_font_t font object * HarfBuzz will use the @destroy callback on the #hb_font_t font object
* if it is supplied when you use this function. However, even if @destroy * if it is supplied when you use this function. However, even if @destroy
* is provided, it is the client program's responsibility to destroy @ft_face, * is provided, it is the client program's responsibility to destroy @ft_face,
* and it is the client program's responsibility to ensure that @ft_face is * and it is the client program's responsibility to ensure that @ft_face is

View File

@ -93,15 +93,16 @@ hb_icu_script_to_script (UScriptCode script)
UScriptCode UScriptCode
hb_icu_script_from_script (hb_script_t script) hb_icu_script_from_script (hb_script_t script)
{ {
UScriptCode out = USCRIPT_INVALID_CODE;
if (unlikely (script == HB_SCRIPT_INVALID)) if (unlikely (script == HB_SCRIPT_INVALID))
return USCRIPT_INVALID_CODE; return out;
unsigned int numScriptCode = 1 + u_getIntPropertyMaxValue (UCHAR_SCRIPT); UErrorCode icu_err = U_ZERO_ERROR;
for (unsigned int i = 0; i < numScriptCode; i++) const unsigned char buf[5] = {HB_UNTAG (script), 0};
if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script)) uscript_getCode ((const char *) buf, &out, 1, &icu_err);
return (UScriptCode) i;
return USCRIPT_UNKNOWN; return out;
} }

View File

@ -106,7 +106,7 @@
#endif #endif
#ifndef HB_COLRV1_MAX_EDGE_COUNT #ifndef HB_COLRV1_MAX_EDGE_COUNT
#define HB_COLRV1_MAX_EDGE_COUNT 65536 #define HB_COLRV1_MAX_EDGE_COUNT 2048
#endif #endif

View File

@ -42,13 +42,37 @@ template <typename K, typename V,
bool minus_one = false> bool minus_one = false>
struct hb_hashmap_t struct hb_hashmap_t
{ {
static constexpr bool realloc_move = true;
hb_hashmap_t () { init (); } hb_hashmap_t () { init (); }
~hb_hashmap_t () { fini (); } ~hb_hashmap_t () { fini (); }
hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { alloc (o.population); hb_copy (o, *this); } hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t ()
hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); } {
if (unlikely (!o.mask)) return;
if (item_t::is_trivial)
{
items = (item_t *) hb_malloc (sizeof (item_t) * (o.mask + 1));
if (unlikely (!items))
{
successful = false;
return;
}
population = o.population;
occupancy = o.occupancy;
mask = o.mask;
prime = o.prime;
max_chain_length = o.max_chain_length;
memcpy (items, o.items, sizeof (item_t) * (mask + 1));
return;
}
alloc (o.population); hb_copy (o, *this);
}
hb_hashmap_t (hb_hashmap_t&& o) noexcept : hb_hashmap_t () { hb_swap (*this, o); }
hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; } hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; } hb_hashmap_t& operator= (hb_hashmap_t&& o) noexcept { hb_swap (*this, o); return *this; }
hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t () hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
{ {
@ -113,26 +137,23 @@ struct hb_hashmap_t
}; };
hb_object_header_t header; hb_object_header_t header;
unsigned int successful : 1; /* Allocations successful */ bool successful; /* Allocations successful */
unsigned int population : 31; /* Not including tombstones. */ unsigned short max_chain_length;
unsigned int population; /* Not including tombstones. */
unsigned int occupancy; /* Including tombstones. */ unsigned int occupancy; /* Including tombstones. */
unsigned int mask; unsigned int mask;
unsigned int prime; unsigned int prime;
unsigned int max_chain_length;
item_t *items; item_t *items;
friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) noexcept
{ {
if (unlikely (!a.successful || !b.successful)) if (unlikely (!a.successful || !b.successful))
return; return;
unsigned tmp = a.population; hb_swap (a.max_chain_length, b.max_chain_length);
a.population = b.population; hb_swap (a.population, b.population);
b.population = tmp;
//hb_swap (a.population, b.population);
hb_swap (a.occupancy, b.occupancy); hb_swap (a.occupancy, b.occupancy);
hb_swap (a.mask, b.mask); hb_swap (a.mask, b.mask);
hb_swap (a.prime, b.prime); hb_swap (a.prime, b.prime);
hb_swap (a.max_chain_length, b.max_chain_length);
hb_swap (a.items, b.items); hb_swap (a.items, b.items);
} }
void init () void init ()
@ -140,10 +161,10 @@ struct hb_hashmap_t
hb_object_init (this); hb_object_init (this);
successful = true; successful = true;
max_chain_length = 0;
population = occupancy = 0; population = occupancy = 0;
mask = 0; mask = 0;
prime = 0; prime = 0;
max_chain_length = 0;
items = nullptr; items = nullptr;
} }
void fini () void fini ()
@ -209,9 +230,10 @@ struct hb_hashmap_t
old_items[i].hash, old_items[i].hash,
std::move (old_items[i].value)); std::move (old_items[i].value));
} }
if (!item_t::is_trivial)
old_items[i].~item_t ();
} }
if (!item_t::is_trivial)
for (unsigned int i = 0; i < old_size; i++)
old_items[i].~item_t ();
hb_free (old_items); hb_free (old_items);
@ -533,7 +555,7 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
~hb_map_t () = default; ~hb_map_t () = default;
hb_map_t () : hashmap () {} hb_map_t () : hashmap () {}
hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {} hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {}
hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {} hb_map_t (hb_map_t &&o) noexcept : hashmap (std::move ((hashmap &) o)) {}
hb_map_t& operator= (const hb_map_t&) = default; hb_map_t& operator= (const hb_map_t&) = default;
hb_map_t& operator= (hb_map_t&&) = default; hb_map_t& operator= (hb_map_t&&) = default;
hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {} hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {}

View File

@ -325,7 +325,7 @@ retry:
hb_user_data_array_t *user_data = obj->header.user_data.get_acquire (); hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (unlikely (!user_data)) if (unlikely (!user_data))
{ {
user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1); user_data = (hb_user_data_array_t *) hb_calloc (1, sizeof (hb_user_data_array_t));
if (unlikely (!user_data)) if (unlikely (!user_data))
return false; return false;
user_data->init (); user_data->init ();

View File

@ -267,6 +267,7 @@ struct TTCHeader
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!u.header.version.sanitize (c))) return_trace (false); if (unlikely (!u.header.version.sanitize (c))) return_trace (false);
hb_barrier ();
switch (u.header.version.major) { switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */ case 2: /* version 2 is compatible with version 1 */
case 1: return_trace (u.version1.sanitize (c)); case 1: return_trace (u.version1.sanitize (c));
@ -302,6 +303,7 @@ struct ResourceRecord
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
offset.sanitize (c, data_base) && offset.sanitize (c, data_base) &&
hb_barrier () &&
get_face (data_base).sanitize (c)); get_face (data_base).sanitize (c));
} }
@ -337,6 +339,7 @@ struct ResourceTypeRecord
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
resourcesZ.sanitize (c, type_base, resourcesZ.sanitize (c, type_base,
get_resource_count (), get_resource_count (),
data_base)); data_base));
@ -385,6 +388,7 @@ struct ResourceMap
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
typeList.sanitize (c, this, typeList.sanitize (c, this,
&(this+typeList), &(this+typeList),
data_base)); data_base));
@ -428,6 +432,7 @@ struct ResourceForkHeader
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
data.sanitize (c, this, dataLen) && data.sanitize (c, this, dataLen) &&
map.sanitize (c, this, &(this+data))); map.sanitize (c, this, &(this+data)));
} }
@ -508,6 +513,7 @@ struct OpenTypeFontFile
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!u.tag.sanitize (c))) return_trace (false); if (unlikely (!u.tag.sanitize (c))) return_trace (false);
hb_barrier ();
switch (u.tag) { switch (u.tag) {
case CFFTag: /* All the non-collection tags */ case CFFTag: /* All the non-collection tags */
case TrueTag: case TrueTag:

View File

@ -309,7 +309,7 @@ struct _hb_has_null<Type, true>
static Type *get_crap () { return &Crap (Type); } static Type *get_crap () { return &Crap (Type); }
}; };
template <typename Type, typename OffsetType, bool has_null=true> template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
struct OffsetTo : Offset<OffsetType, has_null> struct OffsetTo : Offset<OffsetType, has_null>
{ {
using target_t = Type; using target_t = Type;
@ -335,22 +335,22 @@ struct OffsetTo : Offset<OffsetType, has_null>
} }
template <typename Base, template <typename Base,
hb_enable_if (hb_is_convertible (const Base, const void *))> hb_enable_if (hb_is_convertible (const Base, const BaseType *))>
friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
template <typename Base, template <typename Base,
hb_enable_if (hb_is_convertible (const Base, const void *))> hb_enable_if (hb_is_convertible (const Base, const BaseType *))>
friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
template <typename Base, template <typename Base,
hb_enable_if (hb_is_convertible (Base, void *))> hb_enable_if (hb_is_convertible (Base, BaseType *))>
friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
template <typename Base, template <typename Base,
hb_enable_if (hb_is_convertible (Base, void *))> hb_enable_if (hb_is_convertible (Base, BaseType *))>
friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
template <typename ...Ts> template <typename Base, typename ...Ts>
bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
const void *src_base, Ts&&... ds) const Base *src_base, Ts&&... ds)
{ {
*this = 0; *this = 0;
if (src.is_null ()) if (src.is_null ())
@ -414,10 +414,11 @@ struct OffsetTo : Offset<OffsetType, has_null>
const void *src_base, unsigned dst_bias = 0) const void *src_base, unsigned dst_bias = 0)
{ return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); }
bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const bool sanitize_shallow (hb_sanitize_context_t *c, const BaseType *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false); if (unlikely (!c->check_struct (this))) return_trace (false);
hb_barrier ();
//if (unlikely (this->is_null ())) return_trace (true); //if (unlikely (this->is_null ())) return_trace (true);
if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
return_trace (true); return_trace (true);
@ -427,10 +428,11 @@ struct OffsetTo : Offset<OffsetType, has_null>
#ifndef HB_OPTIMIZE_SIZE #ifndef HB_OPTIMIZE_SIZE
HB_ALWAYS_INLINE HB_ALWAYS_INLINE
#endif #endif
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const bool sanitize (hb_sanitize_context_t *c, const BaseType *base, Ts&&... ds) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (sanitize_shallow (c, base) && return_trace (sanitize_shallow (c, base) &&
hb_barrier () &&
(this->is_null () || (this->is_null () ||
c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) || c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) ||
neuter (c))); neuter (c)));
@ -445,14 +447,14 @@ struct OffsetTo : Offset<OffsetType, has_null>
DEFINE_SIZE_STATIC (sizeof (OffsetType)); DEFINE_SIZE_STATIC (sizeof (OffsetType));
}; };
/* Partial specializations. */ /* Partial specializations. */
template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>; template <typename Type, typename BaseType=void, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, BaseType, has_null>;
template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>; template <typename Type, typename BaseType=void, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, BaseType, has_null>;
template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>; template <typename Type, typename BaseType=void, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, BaseType, has_null>;
template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>; template <typename Type, typename OffsetType, typename BaseType=void> using NNOffsetTo = OffsetTo<Type, OffsetType, BaseType, false>;
template <typename Type> using NNOffset16To = Offset16To<Type, false>; template <typename Type, typename BaseType=void> using NNOffset16To = Offset16To<Type, BaseType, false>;
template <typename Type> using NNOffset24To = Offset24To<Type, false>; template <typename Type, typename BaseType=void> using NNOffset24To = Offset24To<Type, BaseType, false>;
template <typename Type> using NNOffset32To = Offset32To<Type, false>; template <typename Type, typename BaseType=void> using NNOffset32To = Offset32To<Type, BaseType, false>;
/* /*
@ -536,6 +538,7 @@ struct UnsizedArrayOf
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c, count))) return_trace (false); if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
hb_barrier ();
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
return_trace (false); return_trace (false);
@ -555,17 +558,17 @@ struct UnsizedArrayOf
}; };
/* Unsized array of offset's */ /* Unsized array of offset's */
template <typename Type, typename OffsetType, bool has_null=true> template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>; using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, BaseType, has_null>>;
/* Unsized array of offsets relative to the beginning of the array itself. */ /* Unsized array of offsets relative to the beginning of the array itself. */
template <typename Type, typename OffsetType, bool has_null=true> template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, BaseType, has_null>
{ {
const Type& operator [] (int i_) const const Type& operator [] (int i_) const
{ {
unsigned int i = (unsigned int) i_; unsigned int i = (unsigned int) i_;
const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i];
if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */ if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
_hb_compiler_memory_r_barrier (); _hb_compiler_memory_r_barrier ();
return this+*p; return this+*p;
@ -573,7 +576,7 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_
Type& operator [] (int i_) Type& operator [] (int i_)
{ {
unsigned int i = (unsigned int) i_; unsigned int i = (unsigned int) i_;
const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i];
if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */ if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
_hb_compiler_memory_r_barrier (); _hb_compiler_memory_r_barrier ();
return this+*p; return this+*p;
@ -583,7 +586,7 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, BaseType, has_null>
::sanitize (c, count, this, std::forward<Ts> (ds)...))); ::sanitize (c, count, this, std::forward<Ts> (ds)...)));
} }
}; };
@ -725,6 +728,7 @@ struct ArrayOf
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false); if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
hb_barrier ();
unsigned int count = len; unsigned int count = len;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@ -735,7 +739,9 @@ struct ArrayOf
bool sanitize_shallow (hb_sanitize_context_t *c) const bool sanitize_shallow (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (len.sanitize (c) && c->check_array_sized (arrayZ, len, sizeof (LenType))); return_trace (len.sanitize (c) &&
hb_barrier () &&
c->check_array_sized (arrayZ, len, sizeof (LenType)));
} }
public: public:
@ -866,6 +872,7 @@ struct HeadlessArrayOf
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false); if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
hb_barrier ();
unsigned int count = get_length (); unsigned int count = get_length ();
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@ -878,6 +885,7 @@ struct HeadlessArrayOf
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (lenP1.sanitize (c) && return_trace (lenP1.sanitize (c) &&
hb_barrier () &&
(!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType)))); (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType))));
} }
@ -919,6 +927,7 @@ struct ArrayOfM1
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false); if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
hb_barrier ();
unsigned int count = lenM1 + 1; unsigned int count = lenM1 + 1;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@ -931,6 +940,7 @@ struct ArrayOfM1
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (lenM1.sanitize (c) && return_trace (lenM1.sanitize (c) &&
hb_barrier () &&
(c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType)))); (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType))));
} }
@ -975,6 +985,13 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
return_trace (ret); return_trace (ret);
} }
SortedArrayOf* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
SortedArrayOf* out = reinterpret_cast<SortedArrayOf *> (ArrayOf<Type, LenType>::copy (c));
return_trace (out);
}
template <typename T> template <typename T>
Type &bsearch (const T &x, Type &not_found = Crap (Type)) Type &bsearch (const T &x, Type &not_found = Crap (Type))
{ return *as_array ().bsearch (x, &not_found); } { return *as_array ().bsearch (x, &not_found); }
@ -1104,6 +1121,7 @@ struct VarSizedBinSearchArrayOf
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false); if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
hb_barrier ();
unsigned int count = get_length (); unsigned int count = get_length ();
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...))) if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...)))
@ -1130,6 +1148,7 @@ struct VarSizedBinSearchArrayOf
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (header.sanitize (c) && return_trace (header.sanitize (c) &&
hb_barrier () &&
Type::static_size <= header.unitSize && Type::static_size <= header.unitSize &&
c->check_range (bytesZ.arrayZ, c->check_range (bytesZ.arrayZ,
header.nUnits, header.nUnits,

View File

@ -41,10 +41,21 @@ using namespace OT;
using objidx_t = hb_serialize_context_t::objidx_t; using objidx_t = hb_serialize_context_t::objidx_t;
using whence_t = hb_serialize_context_t::whence_t; using whence_t = hb_serialize_context_t::whence_t;
/* utility macro */ /* CFF offsets can technically be negative */
template<typename Type> template<typename Type, typename ...Ts>
static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) static inline const Type& StructAtOffsetOrNull (const void *P, int offset, hb_sanitize_context_t &sc, Ts&&... ds)
{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); } {
if (!offset) return Null (Type);
const char *p = (const char *) P + offset;
if (!sc.check_point (p)) return Null (Type);
const Type &obj = *reinterpret_cast<const Type *> (p);
if (!obj.sanitize (&sc, std::forward<Ts> (ds)...)) return Null (Type);
return obj;
}
struct code_pair_t struct code_pair_t
{ {
@ -78,7 +89,8 @@ struct CFFIndex
hb_requires (hb_is_iterable (Iterable))> hb_requires (hb_is_iterable (Iterable))>
bool serialize (hb_serialize_context_t *c, bool serialize (hb_serialize_context_t *c,
const Iterable &iterable, const Iterable &iterable,
const unsigned *p_data_size = nullptr) const unsigned *p_data_size = nullptr,
unsigned min_off_size = 0)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
unsigned data_size; unsigned data_size;
@ -88,7 +100,7 @@ struct CFFIndex
total_size (iterable, &data_size); total_size (iterable, &data_size);
auto it = hb_iter (iterable); auto it = hb_iter (iterable);
if (unlikely (!serialize_header (c, +it, data_size))) return_trace (false); if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false);
unsigned char *ret = c->allocate_size<unsigned char> (data_size, false); unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
if (unlikely (!ret)) return_trace (false); if (unlikely (!ret)) return_trace (false);
for (const auto &_ : +it) for (const auto &_ : +it)
@ -111,11 +123,13 @@ struct CFFIndex
hb_requires (hb_is_iterator (Iterator))> hb_requires (hb_is_iterator (Iterator))>
bool serialize_header (hb_serialize_context_t *c, bool serialize_header (hb_serialize_context_t *c,
Iterator it, Iterator it,
unsigned data_size) unsigned data_size,
unsigned min_off_size = 0)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8; unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
off_size = hb_max(min_off_size, off_size);
/* serialize CFFIndex header */ /* serialize CFFIndex header */
if (unlikely (!c->extend_min (this))) return_trace (false); if (unlikely (!c->extend_min (this))) return_trace (false);
@ -195,7 +209,7 @@ struct CFFIndex
template <typename Iterable, template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))> hb_requires (hb_is_iterable (Iterable))>
static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr) static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0)
{ {
auto it = + hb_iter (iterable); auto it = + hb_iter (iterable);
if (!it) if (!it)
@ -211,6 +225,7 @@ struct CFFIndex
if (data_size) *data_size = total; if (data_size) *data_size = total;
unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
off_size = hb_max(min_off_size, off_size);
return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total; return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
} }
@ -274,8 +289,10 @@ struct CFFIndex
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
(count == 0 || /* empty INDEX */ (count == 0 || /* empty INDEX */
(count < count + 1u && (count < count + 1u &&
hb_barrier () &&
c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 && c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1u) && c->check_array (offsets, offSize, count + 1u) &&
c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count)))))); c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count))))));
@ -412,6 +429,7 @@ struct FDSelect0 {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this)))) if (unlikely (!(c->check_struct (this))))
return_trace (false); return_trace (false);
hb_barrier ();
if (unlikely (!c->check_array (fds, c->get_num_glyphs ()))) if (unlikely (!c->check_array (fds, c->get_num_glyphs ())))
return_trace (false); return_trace (false);
@ -438,7 +456,9 @@ struct FDSelect3_4_Range
bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (first < c->get_num_glyphs () && (fd < fdcount)); return_trace (c->check_struct (this) &&
hb_barrier () &&
first < c->get_num_glyphs () && (fd < fdcount));
} }
GID_TYPE first; GID_TYPE first;
@ -456,15 +476,20 @@ struct FDSelect3_4
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) || if (unlikely (!(c->check_struct (this) &&
(nRanges () == 0) || ranges[0].first != 0)) ranges.sanitize (c, nullptr, fdcount) &&
hb_barrier () &&
(nRanges () != 0) &&
ranges[0].first == 0)))
return_trace (false); return_trace (false);
for (unsigned int i = 1; i < nRanges (); i++) for (unsigned int i = 1; i < nRanges (); i++)
if (unlikely (ranges[i - 1].first >= ranges[i].first)) if (unlikely (ranges[i - 1].first >= ranges[i].first))
return_trace (false); return_trace (false);
if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ()))) if (unlikely (!(sentinel().sanitize (c) &&
hb_barrier () &&
(sentinel() == c->get_num_glyphs ()))))
return_trace (false); return_trace (false);
return_trace (true); return_trace (true);
@ -559,6 +584,7 @@ struct FDSelect
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
switch (format) switch (format)
{ {

View File

@ -275,6 +275,7 @@ struct Encoding
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
switch (table_format ()) switch (table_format ())
{ {
@ -376,13 +377,13 @@ struct Charset1_2 {
bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
num_glyphs--; num_glyphs--;
unsigned i; unsigned i;
for (i = 0; num_glyphs > 0; i++) for (i = 0; num_glyphs > 0; i++)
{ {
if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1))) if (unlikely (!(ranges[i].sanitize (c) &&
hb_barrier () &&
(num_glyphs >= ranges[i].nLeft + 1))))
return_trace (false); return_trace (false);
num_glyphs -= (ranges[i].nLeft + 1); num_glyphs -= (ranges[i].nLeft + 1);
} }
@ -615,6 +616,7 @@ struct Charset
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
switch (format) switch (format)
{ {
@ -761,9 +763,9 @@ struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t>
unsigned int ros_supplement; unsigned int ros_supplement;
unsigned int cidCount; unsigned int cidCount;
unsigned int EncodingOffset; int EncodingOffset;
unsigned int CharsetOffset; int CharsetOffset;
unsigned int FDSelectOffset; int FDSelectOffset;
table_info_t privateDictInfo; table_info_t privateDictInfo;
}; };
@ -819,24 +821,24 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
break; break;
case OpCode_Encoding: case OpCode_Encoding:
dictval.EncodingOffset = env.argStack.pop_uint (); dictval.EncodingOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
if (unlikely (dictval.EncodingOffset == 0)) return; if (unlikely (dictval.EncodingOffset == 0)) return;
break; break;
case OpCode_charset: case OpCode_charset:
dictval.CharsetOffset = env.argStack.pop_uint (); dictval.CharsetOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
if (unlikely (dictval.CharsetOffset == 0)) return; if (unlikely (dictval.CharsetOffset == 0)) return;
break; break;
case OpCode_FDSelect: case OpCode_FDSelect:
dictval.FDSelectOffset = env.argStack.pop_uint (); dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
case OpCode_Private: case OpCode_Private:
dictval.privateDictInfo.offset = env.argStack.pop_uint (); dictval.privateDictInfo.offset = env.argStack.pop_int ();
dictval.privateDictInfo.size = env.argStack.pop_uint (); dictval.privateDictInfo.size = env.argStack.pop_uint ();
env.clear_args (); env.clear_args ();
break; break;
@ -911,7 +913,7 @@ struct cff1_private_dict_values_base_t : dict_values_t<VAL>
} }
void fini () { dict_values_t<VAL>::fini (); } void fini () { dict_values_t<VAL>::fini (); }
unsigned int subrsOffset; int subrsOffset;
const CFF1Subrs *localSubrs; const CFF1Subrs *localSubrs;
}; };
@ -946,7 +948,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
env.clear_args (); env.clear_args ();
break; break;
case OpCode_Subrs: case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint (); dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
@ -988,7 +990,7 @@ struct cff1_private_dict_opset_subset_t : dict_opset_t
break; break;
case OpCode_Subrs: case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint (); dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
@ -1055,6 +1057,7 @@ struct cff1
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
likely (version.major == 1)); likely (version.major == 1));
} }
@ -1085,14 +1088,17 @@ struct cff1
nameIndex = &cff->nameIndex (cff); nameIndex = &cff->nameIndex (cff);
if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc)) if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
goto fail; goto fail;
hb_barrier ();
topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ()); topDictIndex = &StructAtOffsetOrNull<CFF1TopDictIndex> (nameIndex, nameIndex->get_size (), sc);
if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0)) if (topDictIndex == &Null (CFF1TopDictIndex) || (topDictIndex->count == 0))
goto fail; goto fail;
hb_barrier ();
{ /* parse top dict */ { /* parse top dict */
const hb_ubytes_t topDictStr = (*topDictIndex)[0]; const hb_ubytes_t topDictStr = (*topDictIndex)[0];
if (unlikely (!topDictStr.sanitize (&sc))) goto fail; if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
hb_barrier ();
cff1_top_dict_interp_env_t env (topDictStr); cff1_top_dict_interp_env_t env (topDictStr);
cff1_top_dict_interpreter_t top_interp (env); cff1_top_dict_interpreter_t top_interp (env);
if (unlikely (!top_interp.interpret (topDict))) goto fail; if (unlikely (!top_interp.interpret (topDict))) goto fail;
@ -1102,17 +1108,17 @@ struct cff1
charset = &Null (Charset); charset = &Null (Charset);
else else
{ {
charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset); charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset, sc, &num_charset_entries);
if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc, &num_charset_entries))) goto fail; if (unlikely (charset == &Null (Charset))) goto fail;
} }
fdCount = 1; fdCount = 1;
if (is_CID ()) if (is_CID ())
{ {
fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset); fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset, sc);
fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset); fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset, sc, fdArray->count);
if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) || if (unlikely (fdArray == &Null (CFF1FDArray) ||
(fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) fdSelect == &Null (CFF1FDSelect)))
goto fail; goto fail;
fdCount = fdArray->count; fdCount = fdArray->count;
@ -1132,22 +1138,18 @@ struct cff1
{ {
if (!is_predef_encoding ()) if (!is_predef_encoding ())
{ {
encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset); encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset, sc);
if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) goto fail; if (unlikely (encoding == &Null (Encoding))) goto fail;
} }
} }
stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ()); stringIndex = &StructAtOffsetOrNull<CFF1StringIndex> (topDictIndex, topDictIndex->get_size (), sc);
if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc)) if (stringIndex == &Null (CFF1StringIndex))
goto fail; goto fail;
globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ()); globalSubrs = &StructAtOffsetOrNull<CFF1Subrs> (stringIndex, stringIndex->get_size (), sc);
if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc)) charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset, sc);
goto fail; if (charStrings == &Null (CFF1CharStrings))
charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
goto fail; goto fail;
num_glyphs = charStrings->count; num_glyphs = charStrings->count;
@ -1166,6 +1168,7 @@ struct cff1
{ {
hb_ubytes_t fontDictStr = (*fdArray)[i]; hb_ubytes_t fontDictStr = (*fdArray)[i];
if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
hb_barrier ();
cff1_font_dict_values_t *font; cff1_font_dict_values_t *font;
cff1_top_dict_interp_env_t env (fontDictStr); cff1_top_dict_interp_env_t env (fontDictStr);
cff1_font_dict_interpreter_t font_interp (env); cff1_font_dict_interpreter_t font_interp (env);
@ -1175,17 +1178,13 @@ struct cff1
font->init (); font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail; if (unlikely (!font_interp.interpret (*font))) goto fail;
PRIVDICTVAL *priv = &privateDicts[i]; PRIVDICTVAL *priv = &privateDicts[i];
const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
num_interp_env_t env2 (privDictStr); num_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2); dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
priv->init (); priv->init ();
if (unlikely (!priv_interp.interpret (*priv))) goto fail; if (unlikely (!priv_interp.interpret (*priv))) goto fail;
priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
if (priv->localSubrs != &Null (CFF1Subrs) &&
unlikely (!priv->localSubrs->sanitize (&sc)))
goto fail;
} }
} }
else /* non-CID */ else /* non-CID */
@ -1193,17 +1192,14 @@ struct cff1
cff1_top_dict_values_t *font = &topDict; cff1_top_dict_values_t *font = &topDict;
PRIVDICTVAL *priv = &privateDicts[0]; PRIVDICTVAL *priv = &privateDicts[0];
const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
num_interp_env_t env (privDictStr); num_interp_env_t env (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env); dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
priv->init (); priv->init ();
if (unlikely (!priv_interp.interpret (*priv))) goto fail; if (unlikely (!priv_interp.interpret (*priv))) goto fail;
priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
if (priv->localSubrs != &Null (CFF1Subrs) && hb_barrier ();
unlikely (!priv->localSubrs->sanitize (&sc)))
goto fail;
} }
return; return;
@ -1420,7 +1416,7 @@ struct cff1
hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire (); hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire ();
if (unlikely (!names)) if (unlikely (!names))
{ {
names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1); names = (hb_sorted_vector_t<gname_t> *) hb_calloc (1, sizeof (hb_sorted_vector_t<gname_t>));
if (likely (names)) if (likely (names))
{ {
names->init (); names->init ();

View File

@ -90,6 +90,7 @@ struct CFF2FDSelect
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
switch (format) switch (format)
{ {
@ -110,19 +111,22 @@ struct CFF2FDSelect
DEFINE_SIZE_MIN (2); DEFINE_SIZE_MIN (2);
}; };
struct CFF2VariationStore struct CFF2ItemVariationStore
{ {
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)) && c->check_range (&varStore, size) && varStore.sanitize (c)); return_trace (c->check_struct (this) &&
hb_barrier () &&
c->check_range (&varStore, size) &&
varStore.sanitize (c));
} }
bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore) bool serialize (hb_serialize_context_t *c, const CFF2ItemVariationStore *varStore)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
unsigned int size_ = varStore->get_size (); unsigned int size_ = varStore->get_size ();
CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_); CFF2ItemVariationStore *dest = c->allocate_size<CFF2ItemVariationStore> (size_);
if (unlikely (!dest)) return_trace (false); if (unlikely (!dest)) return_trace (false);
hb_memcpy (dest, varStore, size_); hb_memcpy (dest, varStore, size_);
return_trace (true); return_trace (true);
@ -131,9 +135,9 @@ struct CFF2VariationStore
unsigned int get_size () const { return HBUINT16::static_size + size; } unsigned int get_size () const { return HBUINT16::static_size + size; }
HBUINT16 size; HBUINT16 size;
VariationStore varStore; ItemVariationStore varStore;
DEFINE_SIZE_MIN (2 + VariationStore::min_size); DEFINE_SIZE_MIN (2 + ItemVariationStore::min_size);
}; };
struct cff2_top_dict_values_t : top_dict_values_t<> struct cff2_top_dict_values_t : top_dict_values_t<>
@ -146,8 +150,8 @@ struct cff2_top_dict_values_t : top_dict_values_t<>
} }
void fini () { top_dict_values_t<>::fini (); } void fini () { top_dict_values_t<>::fini (); }
unsigned int vstoreOffset; int vstoreOffset;
unsigned int FDSelectOffset; int FDSelectOffset;
}; };
struct cff2_top_dict_opset_t : top_dict_opset_t<> struct cff2_top_dict_opset_t : top_dict_opset_t<>
@ -165,11 +169,11 @@ struct cff2_top_dict_opset_t : top_dict_opset_t<>
break; break;
case OpCode_vstore: case OpCode_vstore:
dictval.vstoreOffset = env.argStack.pop_uint (); dictval.vstoreOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
case OpCode_FDSelect: case OpCode_FDSelect:
dictval.FDSelectOffset = env.argStack.pop_uint (); dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
@ -237,7 +241,7 @@ struct cff2_private_dict_values_base_t : dict_values_t<VAL>
} }
void fini () { dict_values_t<VAL>::fini (); } void fini () { dict_values_t<VAL>::fini (); }
unsigned int subrsOffset; int subrsOffset;
const CFF2Subrs *localSubrs; const CFF2Subrs *localSubrs;
unsigned int ivs; unsigned int ivs;
}; };
@ -291,7 +295,7 @@ struct cff2_private_dict_opset_t : dict_opset_t
env.clear_args (); env.clear_args ();
break; break;
case OpCode_Subrs: case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint (); dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
case OpCode_vsindexdict: case OpCode_vsindexdict:
@ -340,7 +344,7 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t
return; return;
case OpCode_Subrs: case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint (); dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args (); env.clear_args ();
break; break;
@ -384,6 +388,7 @@ struct cff2
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
likely (version.major == 2)); likely (version.major == 2));
} }
@ -414,23 +419,22 @@ struct cff2
{ /* parse top dict */ { /* parse top dict */
hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize); hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
if (unlikely (!topDictStr.sanitize (&sc))) goto fail; if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
hb_barrier ();
num_interp_env_t env (topDictStr); num_interp_env_t env (topDictStr);
cff2_top_dict_interpreter_t top_interp (env); cff2_top_dict_interpreter_t top_interp (env);
topDict.init (); topDict.init ();
if (unlikely (!top_interp.interpret (topDict))) goto fail; if (unlikely (!top_interp.interpret (topDict))) goto fail;
} }
globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize); globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc);
varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset); varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc);
charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset); charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc);
fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset); fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc);
fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset); fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc, fdArray->count);
if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) || if (charStrings == &Null (CFF2CharStrings) ||
(charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) || globalSubrs == &Null (CFF2Subrs) ||
(globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || fdArray == &Null (CFF2FDArray))
(fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
(((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
goto fail; goto fail;
num_glyphs = charStrings->count; num_glyphs = charStrings->count;
@ -446,6 +450,7 @@ struct cff2
{ {
const hb_ubytes_t fontDictStr = (*fdArray)[i]; const hb_ubytes_t fontDictStr = (*fdArray)[i];
if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
hb_barrier ();
cff2_font_dict_values_t *font; cff2_font_dict_values_t *font;
num_interp_env_t env (fontDictStr); num_interp_env_t env (fontDictStr);
cff2_font_dict_interpreter_t font_interp (env); cff2_font_dict_interpreter_t font_interp (env);
@ -454,17 +459,13 @@ struct cff2
font->init (); font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail; if (unlikely (!font_interp.interpret (*font))) goto fail;
const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
cff2_priv_dict_interp_env_t env2 (privDictStr); cff2_priv_dict_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2); dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
privateDicts[i].init (); privateDicts[i].init ();
if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail; if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset); privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc);
if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
goto fail;
} }
return; return;
@ -499,7 +500,7 @@ struct cff2
hb_blob_t *blob = nullptr; hb_blob_t *blob = nullptr;
cff2_top_dict_values_t topDict; cff2_top_dict_values_t topDict;
const CFF2Subrs *globalSubrs = nullptr; const CFF2Subrs *globalSubrs = nullptr;
const CFF2VariationStore *varStore = nullptr; const CFF2ItemVariationStore *varStore = nullptr;
const CFF2CharStrings *charStrings = nullptr; const CFF2CharStrings *charStrings = nullptr;
const CFF2FDArray *fdArray = nullptr; const CFF2FDArray *fdArray = nullptr;
const CFF2FDSelect *fdSelect = nullptr; const CFF2FDSelect *fdSelect = nullptr;

View File

@ -41,6 +41,30 @@
namespace OT { namespace OT {
static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
{
uint16_t mapping[] = {
0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
};
uint16_t *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
_hb_cmp_operator<uint16_t, uint16_t>);
return c ? (c - mapping) + 0x7F : 0;
}
struct CmapSubtableFormat0 struct CmapSubtableFormat0
{ {
@ -556,6 +580,7 @@ struct CmapSubtableFormat4
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
if (unlikely (!c->check_range (this, length))) if (unlikely (!c->check_range (this, length)))
{ {
@ -742,10 +767,11 @@ struct CmapSubtableLongSegmented
unsigned num_glyphs) const unsigned num_glyphs) const
{ {
hb_codepoint_t last_end = 0; hb_codepoint_t last_end = 0;
for (unsigned i = 0; i < this->groups.len; i++) unsigned count = this->groups.len;
for (unsigned i = 0; i < count; i++)
{ {
hb_codepoint_t start = this->groups[i].startCharCode; hb_codepoint_t start = this->groups.arrayZ[i].startCharCode;
hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups.arrayZ[i].endCharCode,
(hb_codepoint_t) HB_UNICODE_MAX); (hb_codepoint_t) HB_UNICODE_MAX);
if (unlikely (start > end || start < last_end)) { if (unlikely (start > end || start < last_end)) {
// Range is not in order and is invalid, skip it. // Range is not in order and is invalid, skip it.
@ -754,7 +780,7 @@ struct CmapSubtableLongSegmented
last_end = end; last_end = end;
hb_codepoint_t gid = this->groups[i].glyphID; hb_codepoint_t gid = this->groups.arrayZ[i].glyphID;
if (!gid) if (!gid)
{ {
if (T::formatNumber == 13) continue; if (T::formatNumber == 13) continue;
@ -767,9 +793,9 @@ struct CmapSubtableLongSegmented
mapping->alloc (mapping->get_population () + end - start + 1); mapping->alloc (mapping->get_population () + end - start + 1);
unicodes->add_range (start, end);
for (unsigned cp = start; cp <= end; cp++) for (unsigned cp = start; cp <= end; cp++)
{ {
unicodes->add (cp);
mapping->set (cp, gid); mapping->set (cp, gid);
gid += T::increment; gid += T::increment;
} }
@ -1427,6 +1453,7 @@ struct CmapSubtable
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 0: return_trace (u.format0 .sanitize (c)); case 0: return_trace (u.format0 .sanitize (c));
case 4: return_trace (u.format4 .sanitize (c)); case 4: return_trace (u.format4 .sanitize (c));
@ -1462,8 +1489,11 @@ struct EncodingRecord
int ret; int ret;
ret = platformID.cmp (other.platformID); ret = platformID.cmp (other.platformID);
if (ret) return ret; if (ret) return ret;
ret = encodingID.cmp (other.encodingID); if (other.encodingID != 0xFFFF)
if (ret) return ret; {
ret = encodingID.cmp (other.encodingID);
if (ret) return ret;
}
return 0; return 0;
} }
@ -1811,9 +1841,13 @@ struct cmap
c->plan)); c->plan));
} }
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const const CmapSubtable *find_best_subtable (bool *symbol = nullptr,
bool *mac = nullptr,
bool *macroman = nullptr) const
{ {
if (symbol) *symbol = false; if (symbol) *symbol = false;
if (mac) *mac = false;
if (macroman) *macroman = false;
const CmapSubtable *subtable; const CmapSubtable *subtable;
@ -1838,6 +1872,20 @@ struct cmap
if ((subtable = this->find_subtable (0, 1))) return subtable; if ((subtable = this->find_subtable (0, 1))) return subtable;
if ((subtable = this->find_subtable (0, 0))) return subtable; if ((subtable = this->find_subtable (0, 0))) return subtable;
/* MacRoman subtable. */
if ((subtable = this->find_subtable (1, 0)))
{
if (mac) *mac = true;
if (macroman) *macroman = true;
return subtable;
}
/* Any other Mac subtable; we just map ASCII for these. */
if ((subtable = this->find_subtable (1, 0xFFFF)))
{
if (mac) *mac = true;
return subtable;
}
/* Meh. */ /* Meh. */
return &Null (CmapSubtable); return &Null (CmapSubtable);
} }
@ -1849,8 +1897,8 @@ struct cmap
accelerator_t (hb_face_t *face) accelerator_t (hb_face_t *face)
{ {
this->table = hb_sanitize_context_t ().reference_table<cmap> (face); this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
bool symbol; bool symbol, mac, macroman;
this->subtable = table->find_best_subtable (&symbol); this->subtable = table->find_best_subtable (&symbol, &mac, &macroman);
this->subtable_uvs = &Null (CmapSubtableFormat14); this->subtable_uvs = &Null (CmapSubtableFormat14);
{ {
const CmapSubtable *st = table->find_subtable (0, 5); const CmapSubtable *st = table->find_subtable (0, 5);
@ -1859,6 +1907,7 @@ struct cmap
} }
this->get_glyph_data = subtable; this->get_glyph_data = subtable;
#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
if (unlikely (symbol)) if (unlikely (symbol))
{ {
switch ((unsigned) face->table.OS2->get_font_page ()) { switch ((unsigned) face->table.OS2->get_font_page ()) {
@ -1878,7 +1927,16 @@ struct cmap
break; break;
} }
} }
else if (unlikely (macroman))
{
this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
}
else if (unlikely (mac))
{
this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
}
else else
#endif
{ {
switch (subtable->u.format) { switch (subtable->u.format) {
/* Accelerate format 4 and format 12. */ /* Accelerate format 4 and format 12. */
@ -1921,7 +1979,7 @@ struct cmap
hb_codepoint_t *glyph, hb_codepoint_t *glyph,
cache_t *cache = nullptr) const cache_t *cache = nullptr) const
{ {
if (unlikely (!this->get_glyph_funcZ)) return 0; if (unlikely (!this->get_glyph_funcZ)) return false;
return _cached_get (unicode, glyph, cache); return _cached_get (unicode, glyph, cache);
} }
@ -2003,6 +2061,28 @@ struct cmap
return false; return false;
} }
template <typename Type>
HB_INTERNAL static bool get_glyph_from_ascii (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph)
{
const Type *typed_obj = (const Type *) obj;
return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph);
}
template <typename Type>
HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph)
{
if (get_glyph_from_ascii<Type> (obj, codepoint, glyph))
return true;
const Type *typed_obj = (const Type *) obj;
unsigned c = unicode_to_macroman (codepoint);
return c && typed_obj->get_glyph (c, glyph);
}
private: private:
hb_nonnull_ptr_t<const CmapSubtable> subtable; hb_nonnull_ptr_t<const CmapSubtable> subtable;
hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs; hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
@ -2032,34 +2112,13 @@ struct cmap
return &(this+result.subtable); return &(this+result.subtable);
} }
const EncodingRecord *find_encodingrec (unsigned int platform_id,
unsigned int encoding_id) const
{
EncodingRecord key;
key.platformID = platform_id;
key.encodingID = encoding_id;
return encodingRecord.as_array ().bsearch (key);
}
bool find_subtable (unsigned format) const
{
auto it =
+ hb_iter (encodingRecord)
| hb_map (&EncodingRecord::subtable)
| hb_map (hb_add (this))
| hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
;
return it.len ();
}
public: public:
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
likely (version == 0) && likely (version == 0) &&
encodingRecord.sanitize (c, this)); encodingRecord.sanitize (c, this));
} }

View File

@ -208,12 +208,12 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::HVAR &HVAR = *hmtx.var_table; const OT::HVAR &HVAR = *hmtx.var_table;
const OT::VariationStore &varStore = &HVAR + HVAR.varStore; const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore;
OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr; OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
bool use_cache = font->num_coords; bool use_cache = font->num_coords;
#else #else
OT::VariationStore::cache_t *varStore_cache = nullptr; OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
bool use_cache = false; bool use_cache = false;
#endif #endif
@ -277,7 +277,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
} }
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
OT::VariationStore::destroy_cache (varStore_cache); OT::ItemVariationStore::destroy_cache (varStore_cache);
#endif #endif
if (font->x_strength && !font->embolden_in_place) if (font->x_strength && !font->embolden_in_place)
@ -313,10 +313,10 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
{ {
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::VVAR &VVAR = *vmtx.var_table; const OT::VVAR &VVAR = *vmtx.var_table;
const OT::VariationStore &varStore = &VVAR + VVAR.varStore; const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore;
OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr; OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
#else #else
OT::VariationStore::cache_t *varStore_cache = nullptr; OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
#endif #endif
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
@ -327,7 +327,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
} }
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) #if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
OT::VariationStore::destroy_cache (varStore_cache); OT::ItemVariationStore::destroy_cache (varStore_cache);
#endif #endif
} }
else else

View File

@ -71,6 +71,7 @@ struct DeviceRecord
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
c->check_range (this, sizeDeviceRecord))); c->check_range (this, sizeDeviceRecord)));
} }
@ -152,6 +153,7 @@ struct hdmx
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
!hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) && !hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) &&
min_size + numRecords * sizeDeviceRecord > numRecords * sizeDeviceRecord && min_size + numRecords * sizeDeviceRecord > numRecords * sizeDeviceRecord &&
sizeDeviceRecord >= DeviceRecord::min_size && sizeDeviceRecord >= DeviceRecord::min_size &&

View File

@ -103,6 +103,7 @@ struct head
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
version.major == 1 && version.major == 1 &&
magicNumber == 0x5F0F3CF5u); magicNumber == 0x5F0F3CF5u);
} }

View File

@ -50,7 +50,9 @@ struct _hea
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && likely (version.major == 1)); return_trace (c->check_struct (this) &&
hb_barrier () &&
likely (version.major == 1));
} }
public: public:

View File

@ -145,6 +145,29 @@ struct hmtxvmtx
table->minTrailingBearing = min_rsb; table->minTrailingBearing = min_rsb;
table->maxExtent = max_extent; table->maxExtent = max_extent;
} }
if (T::is_horizontal)
{
const auto &OS2 = *c->plan->source->table.OS2;
if (OS2.has_data () &&
table->ascender == OS2.sTypoAscender &&
table->descender == OS2.sTypoDescender &&
table->lineGap == OS2.sTypoLineGap)
{
table->ascender = static_cast<int> (roundf (OS2.sTypoAscender +
MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
c->plan->normalized_coords.arrayZ,
c->plan->normalized_coords.length)));
table->descender = static_cast<int> (roundf (OS2.sTypoDescender +
MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,
c->plan->normalized_coords.arrayZ,
c->plan->normalized_coords.length)));
table->lineGap = static_cast<int> (roundf (OS2.sTypoLineGap +
MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,
c->plan->normalized_coords.arrayZ,
c->plan->normalized_coords.length)));
}
}
} }
#endif #endif
@ -374,7 +397,7 @@ struct hmtxvmtx
unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph,
hb_font_t *font, hb_font_t *font,
VariationStore::cache_t *store_cache = nullptr) const ItemVariationStore::cache_t *store_cache = nullptr) const
{ {
unsigned int advance = get_advance_without_var_unscaled (glyph); unsigned int advance = get_advance_without_var_unscaled (glyph);

View File

@ -79,6 +79,7 @@ struct KernSubTableFormat3
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
c->check_range (kernValueZ, c->check_range (kernValueZ,
kernValueCount * sizeof (FWORD) + kernValueCount * sizeof (FWORD) +
glyphCount * 2 + glyphCount * 2 +
@ -147,9 +148,10 @@ struct KernSubTable
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!u.header.sanitize (c) || if (unlikely (!(u.header.sanitize (c) &&
u.header.length < u.header.min_size || hb_barrier () &&
!c->check_range (this, u.header.length))) return_trace (false); u.header.length >= u.header.min_size &&
c->check_range (this, u.header.length)))) return_trace (false);
return_trace (dispatch (c)); return_trace (dispatch (c));
} }
@ -337,6 +339,7 @@ struct kern
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.version32.sanitize (c)) return_trace (false); if (!u.version32.sanitize (c)) return_trace (false);
hb_barrier ();
return_trace (dispatch (c)); return_trace (dispatch (c));
} }

View File

@ -46,6 +46,12 @@ struct BaseCoordFormat1
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate); return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
} }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
return_trace ((bool) c->serializer->embed (*this));
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -67,6 +73,17 @@ struct BaseCoordFormat2
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate); return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
} }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->referenceGlyph,
c->plan->glyph_map->get (referenceGlyph),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -86,7 +103,7 @@ struct BaseCoordFormat2
struct BaseCoordFormat3 struct BaseCoordFormat3
{ {
hb_position_t get_coord (hb_font_t *font, hb_position_t get_coord (hb_font_t *font,
const VariationStore &var_store, const ItemVariationStore &var_store,
hb_direction_t direction) const hb_direction_t direction) const
{ {
const Device &device = this+deviceTable; const Device &device = this+deviceTable;
@ -96,6 +113,23 @@ struct BaseCoordFormat3
: font->em_scale_x (coordinate) + device.get_x_delta (font, var_store); : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
} }
void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
{
unsigned varidx = (this+deviceTable).get_variation_index ();
varidx_set.add (varidx);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable,
this, 0,
hb_serialize_context_t::Head,
&c->plan->base_variation_idx_map));
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
@ -120,7 +154,7 @@ struct BaseCoord
bool has_data () const { return u.format; } bool has_data () const { return u.format; }
hb_position_t get_coord (hb_font_t *font, hb_position_t get_coord (hb_font_t *font,
const VariationStore &var_store, const ItemVariationStore &var_store,
hb_direction_t direction) const hb_direction_t direction) const
{ {
switch (u.format) { switch (u.format) {
@ -131,10 +165,32 @@ struct BaseCoord
} }
} }
void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
{
switch (u.format) {
case 3: u.format3.collect_variation_indices (varidx_set);
default:return;
}
}
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!u.format.sanitize (c))) return_trace (false); if (unlikely (!u.format.sanitize (c))) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 1: return_trace (u.format1.sanitize (c)); case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c)); case 2: return_trace (u.format2.sanitize (c));
@ -160,12 +216,37 @@ struct FeatMinMaxRecord
bool has_data () const { return tag; } bool has_data () const { return tag; }
hb_tag_t get_feature_tag () const { return tag; }
void get_min_max (const BaseCoord **min, const BaseCoord **max) const void get_min_max (const BaseCoord **min, const BaseCoord **max) const
{ {
if (likely (min)) *min = &(this+minCoord); if (likely (min)) *min = &(this+minCoord);
if (likely (max)) *max = &(this+maxCoord); if (likely (max)) *max = &(this+maxCoord);
} }
void collect_variation_indices (const hb_subset_plan_t* plan,
const void *base,
hb_set_t& varidx_set /* OUT */) const
{
if (!plan->layout_features.has (tag))
return;
(base+minCoord).collect_variation_indices (varidx_set);
(base+maxCoord).collect_variation_indices (varidx_set);
}
bool subset (hb_subset_context_t *c,
const void *base) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
if (!(out->minCoord.serialize_subset (c, minCoord, base)))
return_trace (false);
return_trace (out->maxCoord.serialize_subset (c, maxCoord, base));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -205,6 +286,39 @@ struct MinMax
} }
} }
void collect_variation_indices (const hb_subset_plan_t* plan,
hb_set_t& varidx_set /* OUT */) const
{
(this+minCoord).collect_variation_indices (varidx_set);
(this+maxCoord).collect_variation_indices (varidx_set);
for (const FeatMinMaxRecord& record : featMinMaxRecords)
record.collect_variation_indices (plan, this, varidx_set);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
if (!(out->minCoord.serialize_subset (c, minCoord, this)) ||
!(out->maxCoord.serialize_subset (c, maxCoord, this)))
return_trace (false);
unsigned len = 0;
for (const FeatMinMaxRecord& _ : featMinMaxRecords)
{
hb_tag_t feature_tag = _.get_feature_tag ();
if (!c->plan->layout_features.has (feature_tag))
continue;
if (!_.subset (c, this)) return false;
len++;
}
return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len,
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -239,6 +353,26 @@ struct BaseValues
return this+baseCoords[baseline_tag_index]; return this+baseCoords[baseline_tag_index];
} }
void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
{
for (const auto& _ : baseCoords)
(this+_).collect_variation_indices (varidx_set);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
out->defaultIndex = defaultIndex;
for (const auto& _ : baseCoords)
if (!subset_offset_array (c, out->baseCoords, this) (_))
return_trace (false);
return_trace (bool (out->baseCoords));
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -269,6 +403,20 @@ struct BaseLangSysRecord
const MinMax &get_min_max () const { return this+minMax; } const MinMax &get_min_max () const { return this+minMax; }
void collect_variation_indices (const hb_subset_plan_t* plan,
hb_set_t& varidx_set /* OUT */) const
{ (this+minMax).collect_variation_indices (plan, varidx_set); }
bool subset (hb_subset_context_t *c,
const void *base) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (out->minMax.serialize_subset (c, minMax, base));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -299,6 +447,35 @@ struct BaseScript
bool has_values () const { return baseValues; } bool has_values () const { return baseValues; }
bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ } bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
void collect_variation_indices (const hb_subset_plan_t* plan,
hb_set_t& varidx_set /* OUT */) const
{
(this+baseValues).collect_variation_indices (varidx_set);
(this+defaultMinMax).collect_variation_indices (plan, varidx_set);
for (const BaseLangSysRecord& _ : baseLangSysRecords)
_.collect_variation_indices (plan, varidx_set);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this))
return_trace (false);
if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this))
return_trace (false);
for (const auto& _ : baseLangSysRecords)
if (!_.subset (c, this)) return_trace (false);
return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len,
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -331,9 +508,31 @@ struct BaseScriptRecord
bool has_data () const { return baseScriptTag; } bool has_data () const { return baseScriptTag; }
hb_tag_t get_script_tag () const { return baseScriptTag; }
const BaseScript &get_base_script (const BaseScriptList *list) const const BaseScript &get_base_script (const BaseScriptList *list) const
{ return list+baseScript; } { return list+baseScript; }
void collect_variation_indices (const hb_subset_plan_t* plan,
const void* list,
hb_set_t& varidx_set /* OUT */) const
{
if (!plan->layout_scripts.has (baseScriptTag))
return;
(list+baseScript).collect_variation_indices (plan, varidx_set);
}
bool subset (hb_subset_context_t *c,
const void *base) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (out->baseScript.serialize_subset (c, baseScript, base));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -360,6 +559,33 @@ struct BaseScriptList
return record->has_data () ? record->get_base_script (this) : Null (BaseScript); return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
} }
void collect_variation_indices (const hb_subset_plan_t* plan,
hb_set_t& varidx_set /* OUT */) const
{
for (const BaseScriptRecord& _ : baseScriptRecords)
_.collect_variation_indices (plan, this, varidx_set);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
unsigned len = 0;
for (const BaseScriptRecord& _ : baseScriptRecords)
{
hb_tag_t script_tag = _.get_script_tag ();
if (!c->plan->layout_scripts.has (script_tag))
continue;
if (!_.subset (c, this)) return false;
len++;
}
return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len,
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -421,6 +647,20 @@ struct Axis
return true; return true;
} }
void collect_variation_indices (const hb_subset_plan_t* plan,
hb_set_t& varidx_set /* OUT */) const
{ (this+baseScriptList).collect_variation_indices (plan, varidx_set); }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
out->baseTagList.serialize_copy (c->serializer, baseTagList, this);
return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this));
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -452,8 +692,41 @@ struct BASE
const Axis &get_axis (hb_direction_t direction) const const Axis &get_axis (hb_direction_t direction) const
{ return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; } { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
const VariationStore &get_var_store () const bool has_var_store () const
{ return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; } { return version.to_int () >= 0x00010001u && varStore != 0; }
const ItemVariationStore &get_var_store () const
{ return version.to_int () < 0x00010001u ? Null (ItemVariationStore) : this+varStore; }
void collect_variation_indices (const hb_subset_plan_t* plan,
hb_set_t& varidx_set /* OUT */) const
{
(this+hAxis).collect_variation_indices (plan, varidx_set);
(this+vAxis).collect_variation_indices (plan, varidx_set);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
out->version = version;
if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this))
return_trace (false);
if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this))
return_trace (false);
if (has_var_store ())
{
if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size))
return_trace (false);
return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ()));
}
return_trace (true);
}
bool get_baseline (hb_font_t *font, bool get_baseline (hb_font_t *font,
hb_tag_t baseline_tag, hb_tag_t baseline_tag,
@ -486,7 +759,7 @@ struct BASE
&min_coord, &max_coord)) &min_coord, &max_coord))
return false; return false;
const VariationStore &var_store = get_var_store (); const ItemVariationStore &var_store = get_var_store ();
if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction); if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction); if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
return true; return true;
@ -496,6 +769,7 @@ struct BASE
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
likely (version.major == 1) && likely (version.major == 1) &&
hAxis.sanitize (c, this) && hAxis.sanitize (c, this) &&
vAxis.sanitize (c, this) && vAxis.sanitize (c, this) &&
@ -508,7 +782,7 @@ struct BASE
* of BASE table (may be NULL) */ * of BASE table (may be NULL) */
Offset16To<Axis>vAxis; /* Offset to vertical Axis table, from beginning Offset16To<Axis>vAxis; /* Offset to vertical Axis table, from beginning
* of BASE table (may be NULL) */ * of BASE table (may be NULL) */
Offset32To<VariationStore> Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation varStore; /* Offset to the table of Item Variation
* Store--from beginning of BASE * Store--from beginning of BASE
* header (may be NULL). Introduced * header (may be NULL). Introduced

View File

@ -64,7 +64,7 @@ struct hb_collect_feature_substitutes_with_var_context_t
const hb_hashmap_t<hb_tag_t, Triple> *axes_location; const hb_hashmap_t<hb_tag_t, Triple> *axes_location;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map; hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map; hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
bool& insert_catch_all_feature_variation_record; hb_set_t& catch_all_record_feature_idxes;
// not stored in subset_plan // not stored in subset_plan
hb_set_t *feature_indices; hb_set_t *feature_indices;
@ -142,6 +142,8 @@ struct hb_subset_layout_context_t :
const hb_map_t *feature_index_map; const hb_map_t *feature_index_map;
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map; const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map; hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
const hb_set_t *catch_all_record_feature_idxes;
const hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>> *feature_idx_tag_map;
unsigned cur_script_index; unsigned cur_script_index;
unsigned cur_feature_var_record_idx; unsigned cur_feature_var_record_idx;
@ -164,6 +166,8 @@ struct hb_subset_layout_context_t :
feature_index_map = &c_->plan->gsub_features; feature_index_map = &c_->plan->gsub_features;
feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map; feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map;
feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map; feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map;
catch_all_record_feature_idxes = &c_->plan->gsub_old_features;
feature_idx_tag_map = &c_->plan->gsub_old_feature_idx_tag_map;
} }
else else
{ {
@ -172,6 +176,8 @@ struct hb_subset_layout_context_t :
feature_index_map = &c_->plan->gpos_features; feature_index_map = &c_->plan->gpos_features;
feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map; feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map;
feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map; feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map;
catch_all_record_feature_idxes = &c_->plan->gpos_old_features;
feature_idx_tag_map = &c_->plan->gpos_old_feature_idx_tag_map;
} }
} }
@ -182,7 +188,7 @@ struct hb_subset_layout_context_t :
unsigned lookup_index_count; unsigned lookup_index_count;
}; };
struct VariationStore; struct ItemVariationStore;
struct hb_collect_variation_indices_context_t : struct hb_collect_variation_indices_context_t :
hb_dispatch_context_t<hb_collect_variation_indices_context_t> hb_dispatch_context_t<hb_collect_variation_indices_context_t>
{ {
@ -454,6 +460,7 @@ struct FeatureParamsSize
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false); if (unlikely (!c->check_struct (this))) return_trace (false);
hb_barrier ();
/* This subtable has some "history", if you will. Some earlier versions of /* This subtable has some "history", if you will. Some earlier versions of
* Adobe tools calculated the offset of the FeatureParams subtable from the * Adobe tools calculated the offset of the FeatureParams subtable from the
@ -820,6 +827,7 @@ struct Feature
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
return_trace (false); return_trace (false);
hb_barrier ();
/* Some earlier versions of Adobe tools calculated the offset of the /* Some earlier versions of Adobe tools calculated the offset of the
* FeatureParams subtable from the beginning of the FeatureList table! * FeatureParams subtable from the beginning of the FeatureList table!
@ -838,6 +846,7 @@ struct Feature
unsigned int orig_offset = featureParams; unsigned int orig_offset = featureParams;
if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
return_trace (false); return_trace (false);
hb_barrier ();
if (featureParams == 0 && closure && if (featureParams == 0 && closure &&
closure->tag == HB_TAG ('s','i','z','e') && closure->tag == HB_TAG ('s','i','z','e') &&
@ -900,7 +909,8 @@ struct Record
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
const Record_sanitize_closure_t closure = {tag, base}; const Record_sanitize_closure_t closure = {tag, base};
return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); return_trace (c->check_struct (this) &&
offset.sanitize (c, base, &closure));
} }
Tag tag; /* 4-byte Tag identifier */ Tag tag; /* 4-byte Tag identifier */
@ -1371,10 +1381,20 @@ struct Lookup
if (lookupFlag & LookupFlag::UseMarkFilteringSet) if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{ {
if (unlikely (!c->serializer->extend (out))) return_trace (false);
const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable); const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable); hb_codepoint_t *idx;
outMarkFilteringSet = markFilteringSet; if (!c->plan->used_mark_sets_map.has (markFilteringSet, &idx))
{
unsigned new_flag = lookupFlag;
new_flag &= ~LookupFlag::UseMarkFilteringSet;
out->lookupFlag = new_flag;
}
else
{
if (unlikely (!c->serializer->extend (out))) return_trace (false);
HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable);
outMarkFilteringSet = *idx;
}
} }
// Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup // Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup
@ -1391,6 +1411,7 @@ struct Lookup
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false); if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
hb_barrier ();
unsigned subtables = get_subtable_count (); unsigned subtables = get_subtable_count ();
if (unlikely (!c->visit_subtables (subtables))) return_trace (false); if (unlikely (!c->visit_subtables (subtables))) return_trace (false);
@ -1406,6 +1427,8 @@ struct Lookup
if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ())) if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
{ {
hb_barrier ();
/* The spec says all subtables of an Extension lookup should /* The spec says all subtables of an Extension lookup should
* have the same type, which shall not be the Extension type * have the same type, which shall not be the Extension type
* itself (but we already checked for that). * itself (but we already checked for that).
@ -2156,6 +2179,7 @@ struct ClassDef
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 1: return_trace (u.format1.sanitize (c)); case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c)); case 2: return_trace (u.format2.sanitize (c));
@ -2534,7 +2558,9 @@ struct VarRegionList
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount)); return_trace (c->check_struct (this) &&
hb_barrier () &&
axesZ.sanitize (c, axisCount * regionCount));
} }
bool serialize (hb_serialize_context_t *c, bool serialize (hb_serialize_context_t *c,
@ -2728,6 +2754,7 @@ struct VarData
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
regionIndices.sanitize (c) && regionIndices.sanitize (c) &&
hb_barrier () &&
wordCount () <= regionIndices.len && wordCount () <= regionIndices.len &&
c->check_range (get_delta_bytes (), c->check_range (get_delta_bytes (),
itemCount, itemCount,
@ -3009,7 +3036,7 @@ struct VarData
DEFINE_SIZE_ARRAY (6, regionIndices); DEFINE_SIZE_ARRAY (6, regionIndices);
}; };
struct VariationStore struct ItemVariationStore
{ {
friend struct item_variations_t; friend struct item_variations_t;
using cache_t = VarRegionList::cache_t; using cache_t = VarRegionList::cache_t;
@ -3077,6 +3104,7 @@ struct VariationStore
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
format == 1 && format == 1 &&
regions.sanitize (c, this) && regions.sanitize (c, this) &&
dataSets.sanitize (c, this)); dataSets.sanitize (c, this));
@ -3113,7 +3141,7 @@ struct VariationStore
} }
bool serialize (hb_serialize_context_t *c, bool serialize (hb_serialize_context_t *c,
const VariationStore *src, const ItemVariationStore *src,
const hb_array_t <const hb_inc_bimap_t> &inner_maps) const hb_array_t <const hb_inc_bimap_t> &inner_maps)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
@ -3169,7 +3197,7 @@ struct VariationStore
return_trace (true); return_trace (true);
} }
VariationStore *copy (hb_serialize_context_t *c) const ItemVariationStore *copy (hb_serialize_context_t *c) const
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
auto *out = c->start_embed (this); auto *out = c->start_embed (this);
@ -3199,7 +3227,7 @@ struct VariationStore
return_trace (false); return_trace (false);
#endif #endif
VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> (); ItemVariationStore *varstore_prime = c->serializer->start_embed<ItemVariationStore> ();
if (unlikely (!varstore_prime)) return_trace (false); if (unlikely (!varstore_prime)) return_trace (false);
varstore_prime->serialize (c->serializer, this, inner_maps); varstore_prime->serialize (c->serializer, this, inner_maps);
@ -3330,8 +3358,12 @@ struct ConditionFormat1
Triple axis_range (-1.f, 0.f, 1.f); Triple axis_range (-1.f, 0.f, 1.f);
Triple *axis_limit; Triple *axis_limit;
bool axis_set_by_user = false;
if (c->axes_location->has (axis_tag, &axis_limit)) if (c->axes_location->has (axis_tag, &axis_limit))
{
axis_range = *axis_limit; axis_range = *axis_limit;
axis_set_by_user = true;
}
float axis_min_val = axis_range.minimum; float axis_min_val = axis_range.minimum;
float axis_default_val = axis_range.middle; float axis_default_val = axis_range.middle;
@ -3350,8 +3382,7 @@ struct ConditionFormat1
return DROP_RECORD_WITH_VAR; return DROP_RECORD_WITH_VAR;
//condition met and axis pinned, drop the condition //condition met and axis pinned, drop the condition
if (c->axes_location->has (axis_tag) && if (axis_set_by_user && axis_range.is_point ())
c->axes_location->get (axis_tag).is_point ())
return DROP_COND_WITH_VAR; return DROP_COND_WITH_VAR;
if (filter_max_val != axis_max_val || filter_min_val != axis_min_val) if (filter_max_val != axis_max_val || filter_min_val != axis_min_val)
@ -3365,7 +3396,6 @@ struct ConditionFormat1
condition_map->set (axisIndex, val); condition_map->set (axisIndex, val);
return KEEP_COND_WITH_VAR; return KEEP_COND_WITH_VAR;
} }
return KEEP_RECORD_WITH_VAR; return KEEP_RECORD_WITH_VAR;
} }
@ -3424,6 +3454,7 @@ struct Condition
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) { switch (u.format) {
case 1: return_trace (u.format1.sanitize (c)); case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true); default:return_trace (true);
@ -3497,12 +3528,15 @@ struct ConditionSet
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const hb_subset_layout_context_t *l,
bool insert_catch_all) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
if (insert_catch_all) return_trace (true);
hb_set_t *retained_cond_set = nullptr; hb_set_t *retained_cond_set = nullptr;
if (l->feature_record_cond_idx_map != nullptr) if (l->feature_record_cond_idx_map != nullptr)
retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx); retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
@ -3548,27 +3582,51 @@ struct FeatureTableSubstitutionRecord
} }
void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t& catch_all_record_feature_idxes,
const hb_set_t *feature_indices, const hb_set_t *feature_indices,
const void *base) const const void *base) const
{ {
if (feature_indices->has (featureIndex)) if (feature_indices->has (featureIndex))
{
feature_substitutes_map->set (featureIndex, &(base+feature)); feature_substitutes_map->set (featureIndex, &(base+feature));
catch_all_record_feature_idxes.add (featureIndex);
}
}
bool serialize (hb_subset_layout_context_t *c,
unsigned feature_index,
const Feature *f, const Tag *tag)
{
TRACE_SERIALIZE (this);
hb_serialize_context_t *s = c->subset_context->serializer;
if (unlikely (!s->extend_min (this))) return_trace (false);
uint32_t *new_feature_idx;
if (!c->feature_index_map->has (feature_index, &new_feature_idx))
return_trace (false);
if (!s->check_assign (featureIndex, *new_feature_idx, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
s->push ();
bool ret = f->subset (c->subset_context, c, tag);
if (ret) s->add_link (feature, s->pop_pack ());
else s->pop_discard ();
return_trace (ret);
} }
bool subset (hb_subset_layout_context_t *c, const void *base) const bool subset (hb_subset_layout_context_t *c, const void *base) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
if (!c->feature_index_map->has (featureIndex) || uint32_t *new_feature_index;
c->feature_substitutes_map->has (featureIndex)) { if (!c->feature_index_map->has (featureIndex, &new_feature_index))
// Feature that is being substituted is not being retained, so we don't
// need this.
return_trace (false); return_trace (false);
}
auto *out = c->subset_context->serializer->embed (this); auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
out->featureIndex = c->feature_index_map->get (featureIndex); out->featureIndex = *new_feature_index;
return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c)); return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c));
} }
@ -3600,16 +3658,10 @@ struct FeatureTableSubstitution
} }
void collect_lookups (const hb_set_t *feature_indexes, void collect_lookups (const hb_set_t *feature_indexes,
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const hb_set_t *lookup_indexes /* OUT */) const
{ {
+ hb_iter (substitutions) + hb_iter (substitutions)
| hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex) | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
| hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
{
if (feature_substitutes_map == nullptr) return true;
return !feature_substitutes_map->has (record.featureIndex);
})
| hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r) | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
{ r.collect_lookups (this, lookup_indexes); }) { r.collect_lookups (this, lookup_indexes); })
; ;
@ -3634,11 +3686,14 @@ struct FeatureTableSubstitution
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
{ {
for (const FeatureTableSubstitutionRecord& record : substitutions) for (const FeatureTableSubstitutionRecord& record : substitutions)
record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this); record.collect_feature_substitutes_with_variations (c->feature_substitutes_map,
c->catch_all_record_feature_idxes,
c->feature_indices, this);
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const hb_subset_layout_context_t *l,
bool insert_catch_all) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -3647,6 +3702,22 @@ struct FeatureTableSubstitution
out->version.major = version.major; out->version.major = version.major;
out->version.minor = version.minor; out->version.minor = version.minor;
if (insert_catch_all)
{
for (unsigned feature_index : *(l->catch_all_record_feature_idxes))
{
hb_pair_t<const void*, const void*> *p;
if (!l->feature_idx_tag_map->has (feature_index, &p))
return_trace (false);
auto *o = out->substitutions.serialize_append (c->serializer);
if (!o->serialize (l, feature_index,
reinterpret_cast<const Feature*> (p->first),
reinterpret_cast<const Tag*> (p->second)))
return_trace (false);
}
return_trace (true);
}
+ substitutions.iter () + substitutions.iter ()
| hb_apply (subset_record_array (l, &(out->substitutions), this)) | hb_apply (subset_record_array (l, &(out->substitutions), this))
; ;
@ -3658,6 +3729,7 @@ struct FeatureTableSubstitution
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (version.sanitize (c) && return_trace (version.sanitize (c) &&
hb_barrier () &&
likely (version.major == 1) && likely (version.major == 1) &&
substitutions.sanitize (c, this)); substitutions.sanitize (c, this));
} }
@ -3676,10 +3748,9 @@ struct FeatureVariationRecord
void collect_lookups (const void *base, void collect_lookups (const void *base,
const hb_set_t *feature_indexes, const hb_set_t *feature_indexes,
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const hb_set_t *lookup_indexes /* OUT */) const
{ {
return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes); return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
} }
void closure_features (const void *base, void closure_features (const void *base,
@ -3705,14 +3776,15 @@ struct FeatureVariationRecord
} }
} }
bool subset (hb_subset_layout_context_t *c, const void *base) const bool subset (hb_subset_layout_context_t *c, const void *base,
bool insert_catch_all = false) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->subset_context->serializer->embed (this); auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
out->conditions.serialize_subset (c->subset_context, conditions, base, c); out->conditions.serialize_subset (c->subset_context, conditions, base, c, insert_catch_all);
out->substitutions.serialize_subset (c->subset_context, substitutions, base, c); out->substitutions.serialize_subset (c->subset_context, substitutions, base, c, insert_catch_all);
return_trace (true); return_trace (true);
} }
@ -3771,9 +3843,8 @@ struct FeatureVariations
if (c->universal) if (c->universal)
break; break;
} }
if (c->variation_applied && !c->universal && if (c->universal || c->record_cond_idx_map->is_empty ())
!c->record_cond_idx_map->is_empty ()) c->catch_all_record_feature_idxes.reset ();
c->insert_catch_all_feature_variation_record = true;
} }
FeatureVariations* copy (hb_serialize_context_t *c) const FeatureVariations* copy (hb_serialize_context_t *c) const
@ -3783,11 +3854,17 @@ struct FeatureVariations
} }
void collect_lookups (const hb_set_t *feature_indexes, void collect_lookups (const hb_set_t *feature_indexes,
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
hb_set_t *lookup_indexes /* OUT */) const hb_set_t *lookup_indexes /* OUT */) const
{ {
for (const FeatureVariationRecord& r : varRecords) unsigned count = varRecords.len;
r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes); for (unsigned int i = 0; i < count; i++)
{
if (feature_record_cond_idx_map &&
!feature_record_cond_idx_map->has (i))
continue;
varRecords[i].collect_lookups (this, feature_indexes, lookup_indexes);
}
} }
void closure_features (const hb_map_t *lookup_indexes, void closure_features (const hb_map_t *lookup_indexes,
@ -3832,6 +3909,13 @@ struct FeatureVariations
l->cur_feature_var_record_idx = i; l->cur_feature_var_record_idx = i;
subset_record_array (l, &(out->varRecords), this) (varRecords[i]); subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
} }
if (out->varRecords.len && !l->catch_all_record_feature_idxes->is_empty ())
{
bool insert_catch_all_record = true;
subset_record_array (l, &(out->varRecords), this, insert_catch_all_record) (varRecords[0]);
}
return_trace (bool (out->varRecords)); return_trace (bool (out->varRecords));
} }
@ -3839,6 +3923,7 @@ struct FeatureVariations
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (version.sanitize (c) && return_trace (version.sanitize (c) &&
hb_barrier () &&
likely (version.major == 1) && likely (version.major == 1) &&
varRecords.sanitize (c, this)); varRecords.sanitize (c, this));
} }
@ -3945,13 +4030,13 @@ struct VariationDevice
private: private:
hb_position_t get_x_delta (hb_font_t *font, hb_position_t get_x_delta (hb_font_t *font,
const VariationStore &store, const ItemVariationStore &store,
VariationStore::cache_t *store_cache = nullptr) const ItemVariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_x (get_delta (font, store, store_cache)); } { return font->em_scalef_x (get_delta (font, store, store_cache)); }
hb_position_t get_y_delta (hb_font_t *font, hb_position_t get_y_delta (hb_font_t *font,
const VariationStore &store, const ItemVariationStore &store,
VariationStore::cache_t *store_cache = nullptr) const ItemVariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_y (get_delta (font, store, store_cache)); } { return font->em_scalef_y (get_delta (font, store, store_cache)); }
VariationDevice* copy (hb_serialize_context_t *c, VariationDevice* copy (hb_serialize_context_t *c,
@ -3985,10 +4070,10 @@ struct VariationDevice
private: private:
float get_delta (hb_font_t *font, float get_delta (hb_font_t *font,
const VariationStore &store, const ItemVariationStore &store,
VariationStore::cache_t *store_cache = nullptr) const ItemVariationStore::cache_t *store_cache = nullptr) const
{ {
return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache); return store.get_delta (varIdx, font->coords, font->num_coords, (ItemVariationStore::cache_t *) store_cache);
} }
protected: protected:
@ -4012,8 +4097,8 @@ struct DeviceHeader
struct Device struct Device
{ {
hb_position_t get_x_delta (hb_font_t *font, hb_position_t get_x_delta (hb_font_t *font,
const VariationStore &store=Null (VariationStore), const ItemVariationStore &store=Null (ItemVariationStore),
VariationStore::cache_t *store_cache = nullptr) const ItemVariationStore::cache_t *store_cache = nullptr) const
{ {
switch (u.b.format) switch (u.b.format)
{ {
@ -4030,8 +4115,8 @@ struct Device
} }
} }
hb_position_t get_y_delta (hb_font_t *font, hb_position_t get_y_delta (hb_font_t *font,
const VariationStore &store=Null (VariationStore), const ItemVariationStore &store=Null (ItemVariationStore),
VariationStore::cache_t *store_cache = nullptr) const ItemVariationStore::cache_t *store_cache = nullptr) const
{ {
switch (u.b.format) switch (u.b.format)
{ {

View File

@ -708,8 +708,8 @@ struct hb_ot_apply_context_t :
recurse_func_t recurse_func = nullptr; recurse_func_t recurse_func = nullptr;
const GDEF &gdef; const GDEF &gdef;
const GDEF::accelerator_t &gdef_accel; const GDEF::accelerator_t &gdef_accel;
const VariationStore &var_store; const ItemVariationStore &var_store;
VariationStore::cache_t *var_store_cache; ItemVariationStore::cache_t *var_store_cache;
hb_set_digest_t digest; hb_set_digest_t digest;
hb_direction_t direction; hb_direction_t direction;
@ -723,7 +723,6 @@ struct hb_ot_apply_context_t :
bool auto_zwj = true; bool auto_zwj = true;
bool per_syllable = false; bool per_syllable = false;
bool random = false; bool random = false;
uint32_t random_state = 1;
unsigned new_syllables = (unsigned) -1; unsigned new_syllables = (unsigned) -1;
signed last_base = -1; // GPOS uses signed last_base = -1; // GPOS uses
@ -766,7 +765,7 @@ struct hb_ot_apply_context_t :
~hb_ot_apply_context_t () ~hb_ot_apply_context_t ()
{ {
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
VariationStore::destroy_cache (var_store_cache); ItemVariationStore::destroy_cache (var_store_cache);
#endif #endif
} }
@ -788,8 +787,8 @@ struct hb_ot_apply_context_t :
uint32_t random_number () uint32_t random_number ()
{ {
/* http://www.cplusplus.com/reference/random/minstd_rand/ */ /* http://www.cplusplus.com/reference/random/minstd_rand/ */
random_state = random_state * 48271 % 2147483647; buffer->random_state = buffer->random_state * 48271 % 2147483647;
return random_state; return buffer->random_state;
} }
bool match_properties_mark (hb_codepoint_t glyph, bool match_properties_mark (hb_codepoint_t glyph,
@ -2051,6 +2050,7 @@ struct Rule
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
c->check_range (inputZ.arrayZ, c->check_range (inputZ.arrayZ,
inputZ.item_size * (inputCount ? inputCount - 1 : 0) + inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
LookupRecord::static_size * lookupCount)); LookupRecord::static_size * lookupCount));
@ -2826,6 +2826,7 @@ struct ContextFormat3
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false); if (unlikely (!c->check_struct (this))) return_trace (false);
hb_barrier ();
unsigned int count = glyphCount; unsigned int count = glyphCount;
if (unlikely (!count)) return_trace (false); /* We want to access coverageZ[0] freely. */ if (unlikely (!count)) return_trace (false); /* We want to access coverageZ[0] freely. */
if (unlikely (!c->check_array (coverageZ.arrayZ, count))) return_trace (false); if (unlikely (!c->check_array (coverageZ.arrayZ, count))) return_trace (false);
@ -3219,10 +3220,13 @@ struct ChainRule
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
/* Hyper-optimized sanitized because this is really hot. */ /* Hyper-optimized sanitized because this is really hot. */
if (unlikely (!backtrack.len.sanitize (c))) return_trace (false); if (unlikely (!backtrack.len.sanitize (c))) return_trace (false);
hb_barrier ();
const auto &input = StructAfter<decltype (inputX)> (backtrack); const auto &input = StructAfter<decltype (inputX)> (backtrack);
if (unlikely (!input.lenP1.sanitize (c))) return_trace (false); if (unlikely (!input.lenP1.sanitize (c))) return_trace (false);
hb_barrier ();
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input); const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
if (unlikely (!lookahead.len.sanitize (c))) return_trace (false); if (unlikely (!lookahead.len.sanitize (c))) return_trace (false);
hb_barrier ();
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead); const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
return_trace (likely (lookup.sanitize (c))); return_trace (likely (lookup.sanitize (c)));
} }
@ -4121,11 +4125,14 @@ struct ChainContextFormat3
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!backtrack.sanitize (c, this))) return_trace (false); if (unlikely (!backtrack.sanitize (c, this))) return_trace (false);
hb_barrier ();
const auto &input = StructAfter<decltype (inputX)> (backtrack); const auto &input = StructAfter<decltype (inputX)> (backtrack);
if (unlikely (!input.sanitize (c, this))) return_trace (false); if (unlikely (!input.sanitize (c, this))) return_trace (false);
hb_barrier ();
if (unlikely (!input.len)) return_trace (false); /* To be consistent with Context. */ if (unlikely (!input.len)) return_trace (false); /* To be consistent with Context. */
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input); const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
if (unlikely (!lookahead.sanitize (c, this))) return_trace (false); if (unlikely (!lookahead.sanitize (c, this))) return_trace (false);
hb_barrier ();
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead); const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
return_trace (likely (lookup.sanitize (c))); return_trace (likely (lookup.sanitize (c)));
} }
@ -4209,6 +4216,7 @@ struct ExtensionFormat1
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
extensionLookupType != T::SubTable::Extension); extensionLookupType != T::SubTable::Extension);
} }
@ -4472,13 +4480,6 @@ struct GSUBGPOSVersion1_2
if (!c->subset_context->serializer->extend_min (&out->featureVars)) if (!c->subset_context->serializer->extend_min (&out->featureVars))
return_trace (false); return_trace (false);
// TODO(qxliu76): the current implementation doesn't correctly handle feature variations
// that are dropped by instancing when the associated conditions don't trigger.
// Since partial instancing isn't yet supported this isn't an issue yet but will
// need to be fixed for partial instancing.
// if all axes are pinned all feature vars are dropped. // if all axes are pinned all feature vars are dropped.
bool ret = !c->subset_context->plan->all_axes_pinned bool ret = !c->subset_context->plan->all_axes_pinned
&& out->featureVars.serialize_subset (c->subset_context, featureVars, this, c); && out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
@ -4513,6 +4514,7 @@ struct GSUBGPOS
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!u.version.sanitize (c))) return_trace (false); if (unlikely (!u.version.sanitize (c))) return_trace (false);
hb_barrier ();
switch (u.version.major) { switch (u.version.major) {
case 1: return_trace (u.version1.sanitize<TLookup> (c)); case 1: return_trace (u.version1.sanitize<TLookup> (c));
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K
@ -4638,11 +4640,11 @@ struct GSUBGPOS
} }
void feature_variation_collect_lookups (const hb_set_t *feature_indexes, void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
hb_set_t *lookup_indexes /* OUT */) const hb_set_t *lookup_indexes /* OUT */) const
{ {
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes); get_feature_variations ().collect_lookups (feature_indexes, feature_record_cond_idx_map, lookup_indexes);
#endif #endif
} }

View File

@ -214,6 +214,7 @@ struct JSTF
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (version.sanitize (c) && return_trace (version.sanitize (c) &&
hb_barrier () &&
likely (version.major == 1) && likely (version.major == 1) &&
scriptList.sanitize (c, this)); scriptList.sanitize (c, this));
} }

View File

@ -2127,7 +2127,7 @@ hb_ot_layout_get_font_extents (hb_font_t *font,
hb_tag_t language_tag, hb_tag_t language_tag,
hb_font_extents_t *extents) hb_font_extents_t *extents)
{ {
hb_position_t min, max; hb_position_t min = 0, max = 0;
if (font->face->table.BASE->get_min_max (font, direction, script_tag, language_tag, HB_TAG_NONE, if (font->face->table.BASE->get_min_max (font, direction, script_tag, language_tag, HB_TAG_NONE,
&min, &max)) &min, &max))
{ {

View File

@ -333,6 +333,7 @@ struct MathKern
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
sanitize_math_value_records (c)); sanitize_math_value_records (c));
} }
@ -343,27 +344,20 @@ struct MathKern
const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
int sign = font->y_scale < 0 ? -1 : +1; int sign = font->y_scale < 0 ? -1 : +1;
/* The description of the MathKern table is a ambiguous, but interpreting /* According to OpenType spec (v1.9), except for the boundary cases, the index
* "between the two heights found at those indexes" for 0 < i < len as * chosen for kern value should be i such that
* * correctionHeight[i-1] <= correction_height < correctionHeight[i]
* correctionHeight[i-1] < correction_height <= correctionHeight[i] * We can use the binary search algorithm of std::upper_bound(). Or, we can
* * use the internal hb_bsearch_impl.
* makes the result consistent with the limit cases and we can just use the
* binary search algorithm of std::upper_bound:
*/ */
unsigned int i = 0; unsigned int pos;
unsigned int count = heightCount; auto cmp = +[](const void* key, const void* p,
while (count > 0) int sign, hb_font_t* font, const MathKern* mathKern) -> int {
{ return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern);
unsigned int half = count / 2; };
hb_position_t height = correctionHeight[i + half].get_y_value (font, this); unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight,
if (sign * height < sign * correction_height) heightCount, MathValueRecord::static_size,
{ cmp, sign, font, this) ? pos + 1 : pos;
i += half + 1;
count -= half + 1;
} else
count = half;
}
return kernValue[i].get_x_value (font, this); return kernValue[i].get_x_value (font, this);
} }
@ -984,6 +978,7 @@ struct MathVariants
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
vertGlyphCoverage.sanitize (c, this) && vertGlyphCoverage.sanitize (c, this) &&
horizGlyphCoverage.sanitize (c, this) && horizGlyphCoverage.sanitize (c, this) &&
hb_barrier () &&
c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
sanitize_offsets (c)); sanitize_offsets (c));
} }
@ -1103,6 +1098,7 @@ struct MATH
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (version.sanitize (c) && return_trace (version.sanitize (c) &&
likely (version.major == 1) && likely (version.major == 1) &&
hb_barrier () &&
mathConstants.sanitize (c, this) && mathConstants.sanitize (c, this) &&
mathGlyphInfo.sanitize (c, this) && mathGlyphInfo.sanitize (c, this) &&
mathVariants.sanitize (c, this)); mathVariants.sanitize (c, this));

View File

@ -85,7 +85,7 @@ struct maxp
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
if (version.major == 1) if (version.major == 1)
{ {
const maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*this); const maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*this);
@ -103,6 +103,7 @@ struct maxp
maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu); maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu);
if (maxp_prime->version.major == 1) if (maxp_prime->version.major == 1)
{ {
hb_barrier ();
const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this); const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1); maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
if (unlikely (!dest_v1)) return_trace (false); if (unlikely (!dest_v1)) return_trace (false);

View File

@ -51,6 +51,7 @@ struct DataMap
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
dataZ.sanitize (c, base, dataLength))); dataZ.sanitize (c, base, dataLength)));
} }
@ -101,6 +102,7 @@ struct meta
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
version == 1 && version == 1 &&
dataMaps.sanitize (c, this))); dataMaps.sanitize (c, this)));
} }

View File

@ -209,6 +209,23 @@ struct OS2
return ret; return ret;
} }
static unsigned calc_avg_char_width (const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>>& hmtx_map)
{
unsigned num = 0;
unsigned total_width = 0;
for (const auto& _ : hmtx_map.values_ref ())
{
unsigned width = _.first;
if (width)
{
total_width += width;
num++;
}
}
return num ? (unsigned) roundf ((double) total_width / (double) num) : 0;
}
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
@ -239,10 +256,16 @@ struct OS2
if (os2_prime->version >= 2) if (os2_prime->version >= 2)
{ {
hb_barrier ();
auto *table = & const_cast<OS2V2Tail &> (os2_prime->v2 ()); auto *table = & const_cast<OS2V2Tail &> (os2_prime->v2 ());
HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_X_HEIGHT, sxHeight); HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_X_HEIGHT, sxHeight);
HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_CAP_HEIGHT, sCapHeight); HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_CAP_HEIGHT, sCapHeight);
} }
unsigned avg_char_width = calc_avg_char_width (c->plan->hmtx_map);
if (!c->serializer->check_assign (os2_prime->xAvgCharWidth, avg_char_width,
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
} }
#endif #endif
@ -261,12 +284,12 @@ struct OS2
os2_prime->usWidthClass = width_class; os2_prime->usWidthClass = width_class;
} }
if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
return_trace (true);
os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ()); os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
os2_prime->usLastCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_max ()); os2_prime->usLastCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
return_trace (true);
_update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange); _update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
return_trace (true); return_trace (true);
@ -334,6 +357,7 @@ struct OS2
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false); if (unlikely (!c->check_struct (this))) return_trace (false);
hb_barrier ();
if (unlikely (version >= 1 && !v1X.sanitize (c))) return_trace (false); if (unlikely (version >= 1 && !v1X.sanitize (c))) return_trace (false);
if (unlikely (version >= 2 && !v2X.sanitize (c))) return_trace (false); if (unlikely (version >= 2 && !v2X.sanitize (c))) return_trace (false);
if (unlikely (version >= 5 && !v5X.sanitize (c))) return_trace (false); if (unlikely (version >= 5 && !v5X.sanitize (c))) return_trace (false);

View File

@ -122,7 +122,10 @@ struct post
} }
if (glyph_names && version.major == 2) if (glyph_names && version.major == 2)
{
hb_barrier ();
return_trace (v2X.subset (c)); return_trace (v2X.subset (c));
}
return_trace (true); return_trace (true);
} }
@ -138,6 +141,7 @@ struct post
version = table->version.to_int (); version = table->version.to_int ();
if (version != 0x00020000) return; if (version != 0x00020000) return;
hb_barrier ();
const postV2Tail &v2 = table->v2X; const postV2Tail &v2 = table->v2X;
@ -217,10 +221,16 @@ struct post
unsigned int get_glyph_count () const unsigned int get_glyph_count () const
{ {
if (version == 0x00010000) if (version == 0x00010000)
{
hb_barrier ();
return format1_names_length; return format1_names_length;
}
if (version == 0x00020000) if (version == 0x00020000)
{
hb_barrier ();
return glyphNameIndex->len; return glyphNameIndex->len;
}
return 0; return 0;
} }
@ -245,13 +255,18 @@ struct post
{ {
if (version == 0x00010000) if (version == 0x00010000)
{ {
hb_barrier ();
if (glyph >= format1_names_length) if (glyph >= format1_names_length)
return hb_bytes_t (); return hb_bytes_t ();
return format1_names (glyph); return format1_names (glyph);
} }
if (version != 0x00020000 || glyph >= glyphNameIndex->len) if (version != 0x00020000)
return hb_bytes_t ();
hb_barrier ();
if (glyph >= glyphNameIndex->len)
return hb_bytes_t (); return hb_bytes_t ();
unsigned int index = glyphNameIndex->arrayZ[glyph]; unsigned int index = glyphNameIndex->arrayZ[glyph];
@ -284,6 +299,7 @@ struct post
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
hb_barrier () &&
(version.to_int () == 0x00010000 || (version.to_int () == 0x00010000 ||
(version.to_int () == 0x00020000 && v2X.sanitize (c)) || (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
version.to_int () == 0x00030000)); version.to_int () == 0x00030000));

View File

@ -155,7 +155,7 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
#endif #endif
bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face); bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
if (false) if (false)
; {}
#ifndef HB_NO_AAT_SHAPE #ifndef HB_NO_AAT_SHAPE
/* Prefer GPOS over kerx if GSUB is present; /* Prefer GPOS over kerx if GSUB is present;
* https://github.com/harfbuzz/harfbuzz/issues/3008 */ * https://github.com/harfbuzz/harfbuzz/issues/3008 */
@ -167,15 +167,16 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos)) if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
{ {
if (false) {}
#ifndef HB_NO_AAT_SHAPE #ifndef HB_NO_AAT_SHAPE
if (has_kerx) else if (has_kerx)
plan.apply_kerx = true; plan.apply_kerx = true;
else
#endif #endif
#ifndef HB_NO_OT_KERN #ifndef HB_NO_OT_KERN
if (hb_ot_layout_has_kerning (face)) else if (hb_ot_layout_has_kerning (face))
plan.apply_kern = true; plan.apply_kern = true;
#endif #endif
else {}
} }
plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern); plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);

View File

@ -560,9 +560,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%u,%u,%u)", DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%u,%u,%u)",
step == MEASURE ? "measuring" : "cutting", context, start, end); step == MEASURE ? "measuring" : "cutting", context, start, end);
DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%u width %d", start - context, w_total); DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%u width %" PRId32, start - context, w_total);
DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%d", n_fixed, w_fixed); DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%" PRId32, n_fixed, w_fixed);
DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating); DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%" PRId32, n_repeating, w_repeating);
/* Number of additional times to repeat each repeating tile. */ /* Number of additional times to repeat each repeating tile. */
int n_copies = 0; int n_copies = 0;
@ -602,7 +602,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (info[k - 1].arabic_shaping_action() == STCH_REPEATING) if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
repeat += n_copies; repeat += n_copies;
DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %u; j=%u", DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %" PRIu32 "; j=%u",
repeat, info[k - 1].codepoint, j); repeat, info[k - 1].codepoint, j);
pos[k - 1].x_advance = 0; pos[k - 1].x_advance = 0;
for (unsigned int n = 0; n < repeat; n++) for (unsigned int n = 0; n < repeat; n++)

View File

@ -327,6 +327,7 @@ struct AxisValueFormat4
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
axisValues.sanitize (c, axisCount))); axisValues.sanitize (c, axisCount)));
} }
@ -348,7 +349,7 @@ struct AxisValueFormat4
struct AxisValue struct AxisValue
{ {
bool get_value (unsigned int axis_index) const float get_value (unsigned int axis_index) const
{ {
switch (u.format) switch (u.format)
{ {
@ -356,7 +357,7 @@ struct AxisValue
case 2: return u.format2.get_value (); case 2: return u.format2.get_value ();
case 3: return u.format3.get_value (); case 3: return u.format3.get_value ();
case 4: return u.format4.get_axis_record (axis_index).get_value (); case 4: return u.format4.get_axis_record (axis_index).get_value ();
default:return 0; default:return 0.f;
} }
} }
@ -416,6 +417,7 @@ struct AxisValue
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
hb_barrier ();
switch (u.format) switch (u.format)
{ {
@ -483,7 +485,7 @@ struct STAT
hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets (); hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
for (unsigned int i = 0; i < axis_values.length; i++) for (unsigned int i = 0; i < axis_values.length; i++)
{ {
const AxisValue& axis_value = this+axis_values[i]; const AxisValue& axis_value = this+offsetToAxisValueOffsets+axis_values[i];
if (axis_value.get_axis_index () == axis_index) if (axis_value.get_axis_index () == axis_index)
{ {
if (value) if (value)
@ -560,6 +562,7 @@ struct STAT
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
version.major == 1 && version.major == 1 &&
version.minor > 0 && version.minor > 0 &&
designAxesOffset.sanitize (c, this, designAxisCount) && designAxesOffset.sanitize (c, this, designAxisCount) &&

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