[GX] Implement Feature Variations

Not hooked up to shaper yet.
This commit is contained in:
Behdad Esfahbod 2016-09-10 01:24:28 -07:00
parent 85ec494434
commit 59055b5494
5 changed files with 180 additions and 8 deletions

View File

@ -507,7 +507,7 @@ struct Feature
{ return this+featureParams; }
inline bool sanitize (hb_sanitize_context_t *c,
const Record<Feature>::sanitize_closure_t *closure) const
const Record<Feature>::sanitize_closure_t *closure = NULL) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
@ -1333,6 +1333,172 @@ struct VariationStore
DEFINE_SIZE_ARRAY (8, dataSets);
};
/*
* Feature Variations
*/
struct ConditionFormat1
{
friend struct Condition;
private:
inline bool evaluate (int *coords, unsigned int coord_len) const
{
int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
USHORT format; /* Format identifier--format = 1 */
USHORT axisIndex;
F2DOT14 filterRangeMinValue;
F2DOT14 filterRangeMaxValue;
public:
DEFINE_SIZE_STATIC (8);
};
struct Condition
{
inline bool evaluate (int *coords, unsigned int coord_len) const
{
switch (u.format) {
case 1: return u.format1.evaluate (coords, coord_len);
default:return false;
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
USHORT format; /* Format identifier */
ConditionFormat1 format1;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
struct ConditionSet
{
inline bool evaluate (int *coords, unsigned int coord_len) const
{
unsigned int count = conditions.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+conditions.array[i]).evaluate (coords, coord_len))
return false;
return true;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (conditions.sanitize (c, this));
}
protected:
OffsetArrayOf<Condition, ULONG> conditions;
public:
DEFINE_SIZE_ARRAY (2, conditions);
};
struct FeatureTableSubstitutionRecord
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && feature.sanitize (c, this));
}
protected:
USHORT featureIndex;
OffsetTo<Feature, ULONG> feature;
public:
DEFINE_SIZE_STATIC (6);
};
struct FeatureTableSubstitution
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
substitutions.sanitize (c, this));
}
protected:
FixedVersion<> version; /* Version--0x00010000u */
OffsetArrayOf<FeatureTableSubstitutionRecord, ULONG>
substitutions;
public:
DEFINE_SIZE_ARRAY (6, substitutions);
};
struct FeatureVariationRecord
{
friend struct FeatureVariations;
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (conditions.sanitize (c, base) &&
substitutions.sanitize (c, base));
}
protected:
OffsetTo<ConditionSet, ULONG>
conditions;
OffsetTo<FeatureTableSubstitution, ULONG>
substitutions;
public:
DEFINE_SIZE_STATIC (8);
};
struct FeatureVariations
{
inline const FeatureTableSubstitution &
get_substitutions (int *coords, unsigned int coord_len) const
{
unsigned int count = varRecords.len;
for (unsigned int i = 0; i < count; i++)
{
const FeatureVariationRecord &record = varRecords.array[i];
if ((this+record.conditions).evaluate (coords, coord_len))
return (this+record.substitutions);
}
return Null(FeatureTableSubstitution);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
varRecords.sanitize (c, this));
}
protected:
FixedVersion<> version; /* Version--0x00010000u */
ArrayOf<FeatureVariationRecord, ULONG>
varRecords;
public:
DEFINE_SIZE_ARRAY (8, varRecords);
};
/*
* Device Tables

View File

@ -397,7 +397,6 @@ struct GDEF
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */

View File

@ -1518,8 +1518,6 @@ struct GPOS : GSUBGPOS
const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
return_trace (list.sanitize (c, this));
}
public:
DEFINE_SIZE_STATIC (10);
};

View File

@ -1273,8 +1273,6 @@ struct GSUB : GSUBGPOS
const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
return_trace (list.sanitize (c, this));
}
public:
DEFINE_SIZE_STATIC (10);
};

View File

@ -2271,6 +2271,11 @@ struct GSUBGPOS
inline const Lookup& get_lookup (unsigned int i) const
{ return (this+lookupList)[i]; }
inline const FeatureTableSubstitution &
get_feature_substitutions (int *coords, unsigned int coord_len) const
{ return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
.get_substitutions (coords, coord_len); }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -2278,7 +2283,8 @@ struct GSUBGPOS
likely (version.major == 1) &&
scriptList.sanitize (c, this) &&
featureList.sanitize (c, this) &&
lookupList.sanitize (c, this));
lookupList.sanitize (c, this) &&
(version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
}
protected:
@ -2290,8 +2296,13 @@ struct GSUBGPOS
featureList; /* FeatureList table */
OffsetTo<LookupList>
lookupList; /* LookupList table */
OffsetTo<FeatureVariations, ULONG>
featureVars; /* Offset to Feature Variations
table--from beginning of table
* (may be NULL). Introduced
* in version 0x00010001. */
public:
DEFINE_SIZE_STATIC (10);
DEFINE_SIZE_MIN (10);
};