[BASE] Improvements (#1347)

This commit is contained in:
Ebrahim Byagowi 2018-11-03 22:28:30 +03:30 committed by GitHub
parent c560ca9251
commit b8a78ce201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 391 additions and 381 deletions

View File

@ -1,6 +1,7 @@
/* /*
* Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu> * Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu>
* Copyright © 2018 Google, Inc. * Copyright © 2018 Google, Inc.
* Copyright © 2018 Ebrahim Byagowi
* *
* This is part of HarfBuzz, a text shaping library. * This is part of HarfBuzz, a text shaping library.
* *
@ -31,6 +32,9 @@
#include "hb-open-type.hh" #include "hb-open-type.hh"
#include "hb-ot-layout-common.hh" #include "hb-ot-layout-common.hh"
/* To be removed */
typedef hb_tag_t hb_ot_layout_baseline_t;
namespace OT { namespace OT {
/* /*
@ -38,19 +42,14 @@ namespace OT {
* https://docs.microsoft.com/en-us/typography/opentype/spec/base * https://docs.microsoft.com/en-us/typography/opentype/spec/base
*/ */
/* XXX Review this. */
#define NOT_INDEXED ((unsigned int) -1)
struct BaseCoordFormat1 struct BaseCoordFormat1
{ {
inline int get_coord (void) const { return coordinate; } inline hb_position_t get_coord () const { return coordinate; }
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this)); return_trace (likely (c->check_struct (this)));
} }
protected: protected:
@ -62,7 +61,7 @@ struct BaseCoordFormat1
struct BaseCoordFormat2 struct BaseCoordFormat2
{ {
inline int get_coord (void) const inline hb_position_t get_coord () const
{ {
/* TODO */ /* TODO */
return coordinate; return coordinate;
@ -86,37 +85,45 @@ struct BaseCoordFormat2
struct BaseCoordFormat3 struct BaseCoordFormat3
{ {
inline int get_coord (void) const inline hb_position_t get_coord (hb_font_t *font,
const VariationStore &var_store,
hb_direction_t direction) const
{ {
/* TODO */ const Device &device = this+deviceTable;
return coordinate; return coordinate + (HB_DIRECTION_IS_VERTICAL (direction) ?
device.get_y_delta (font, var_store) :
device.get_x_delta (font, var_store));
} }
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); return_trace (likely (c->check_struct (this) &&
deviceTable.sanitize (c, this)));
} }
protected: protected:
HBUINT16 format; /* Format identifier--format = 3 */ HBUINT16 format; /* Format identifier--format = 3 */
FWORD coordinate; /* X or Y value, in design units */ FWORD coordinate; /* X or Y value, in design units */
OffsetTo<Device> deviceTable; /* Offset to Device table for X or OffsetTo<Device>
* Y value, from beginning of deviceTable; /* Offset to Device table for X or
* BaseCoord table (may be NULL). */ * Y value, from beginning of
* BaseCoord table (may be NULL). */
public: public:
DEFINE_SIZE_STATIC (6); DEFINE_SIZE_STATIC (6);
}; };
struct BaseCoord struct BaseCoord
{ {
inline int get_coord (void) const inline hb_position_t get_coord (hb_font_t *font,
const VariationStore &var_store,
hb_direction_t direction) const
{ {
/* XXX wire up direction and font. */
switch (u.format) { switch (u.format) {
case 1: return u.format1.get_coord (); case 1: return u.format1.get_coord ();
case 2: return u.format2.get_coord (); case 2: return u.format2.get_coord ();
case 3: return u.format3.get_coord (); case 3: return u.format3.get_coord (font, var_store, direction);
default:return 0; default:return 0;
} }
} }
@ -124,7 +131,7 @@ struct BaseCoord
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false); if (unlikely (!u.format.sanitize (c))) return_trace (false);
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));
@ -146,28 +153,40 @@ struct BaseCoord
struct FeatMinMaxRecord struct FeatMinMaxRecord
{ {
inline int get_min_value (void) const { return (this+minCoord).get_coord(); } static int cmp (const void *key_, const void *entry_)
inline int get_max_value (void) const { return (this+maxCoord).get_coord(); } {
hb_tag_t key = * (hb_tag_t *) key_;
const FeatMinMaxRecord &entry = * (const FeatMinMaxRecord *) entry_;
return key < (unsigned int) entry.tag ? -1 :
key > (unsigned int) entry.tag ? 1 :
0;
}
inline const Tag& get_tag () const { return tag; } inline void get_min_max (const BaseCoord **min, const BaseCoord **max) const
{
if (likely (min)) *min = &(this+minCoord);
if (likely (max)) *max = &(this+maxCoord);
}
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
minCoord.sanitize (c, base) && minCoord.sanitize (c, this) &&
maxCoord.sanitize (c, base)); maxCoord.sanitize (c, this)));
} }
protected: protected:
Tag tag; /* 4-byte feature identification tag--must Tag tag; /* 4-byte feature identification tag--must
* match feature tag in FeatureList */ * match feature tag in FeatureList */
OffsetTo<BaseCoord> minCoord; /* Offset to BaseCoord table that defines OffsetTo<BaseCoord>
* the minimum extent value, from beginning minCoord; /* Offset to BaseCoord table that defines
* of MinMax table (may be NULL) */ * the minimum extent value, from beginning
OffsetTo<BaseCoord> maxCoord; /* Offset to BaseCoord table that defines * of MinMax table (may be NULL) */
* the maximum extent value, from beginning OffsetTo<BaseCoord>
* of MinMax table (may be NULL) */ maxCoord; /* Offset to BaseCoord table that defines
* the maximum extent value, from beginning
* of MinMax table (may be NULL) */
public: public:
DEFINE_SIZE_STATIC (8); DEFINE_SIZE_STATIC (8);
@ -175,257 +194,202 @@ struct FeatMinMaxRecord
struct MinMax struct MinMax
{ {
inline unsigned int get_feature_tag_index (Tag featureTableTag) const inline void get_min_max (hb_tag_t feature_tag,
const BaseCoord **min,
const BaseCoord **max) const
{ {
/* TODO bsearch */ const FeatMinMaxRecord *minMaxCoord = (const FeatMinMaxRecord *)
unsigned int count = featMinMaxRecords.len; hb_bsearch (&feature_tag, featMinMaxRecords.arrayZ,
for (unsigned int i = 0; i < count; i++) featMinMaxRecords.len,
FeatMinMaxRecord::static_size,
FeatMinMaxRecord::cmp);
if (minMaxCoord)
minMaxCoord->get_min_max (min, max);
else
{ {
Tag tag = featMinMaxRecords[i].get_tag (); if (likely (min)) *min = &(this+minCoord);
int cmp = tag.cmp(featureTableTag); if (likely (max)) *max = &(this+maxCoord);
if (cmp == 0) return i;
if (cmp > 0) return NOT_INDEXED;
} }
return NOT_INDEXED;
}
inline int get_min_value (unsigned int featureTableTagIndex) const
{
if (featureTableTagIndex == NOT_INDEXED)
return (this+minCoord).get_coord();
return featMinMaxRecords[featureTableTagIndex].get_min_value();
}
inline int get_max_value (unsigned int featureTableTagIndex) const
{
if (featureTableTagIndex == NOT_INDEXED)
return (this+maxCoord).get_coord();
return featMinMaxRecords[featureTableTagIndex].get_max_value();
} }
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
minCoord.sanitize (c, this) && minCoord.sanitize (c, this) &&
maxCoord.sanitize (c, this) && maxCoord.sanitize (c, this) &&
featMinMaxRecords.sanitize (c, this)); featMinMaxRecords.sanitize (c, this)));
} }
protected: protected:
OffsetTo<BaseCoord> minCoord; /* Offset to BaseCoord table that defines OffsetTo<BaseCoord>
* minimum extent value, from the beginning minCoord; /* Offset to BaseCoord table that defines
* of MinMax table (may be NULL) */ * minimum extent value, from the beginning
OffsetTo<BaseCoord> maxCoord; /* Offset to BaseCoord table that defines * of MinMax table (may be NULL) */
* maximum extent value, from the beginning OffsetTo<BaseCoord>
* of MinMax table (may be NULL) */ maxCoord; /* Offset to BaseCoord table that defines
* maximum extent value, from the beginning
* of MinMax table (may be NULL) */
ArrayOf<FeatMinMaxRecord> ArrayOf<FeatMinMaxRecord>
featMinMaxRecords; /* Array of FeatMinMaxRecords, in alphabetical featMinMaxRecords;
* order by featureTableTag */ /* Array of FeatMinMaxRecords, in alphabetical
* order by featureTableTag */
public: public:
DEFINE_SIZE_ARRAY (6, featMinMaxRecords); DEFINE_SIZE_ARRAY (6, featMinMaxRecords);
}; };
/* TODO... */
struct BaseLangSysRecord
{
inline const Tag& get_tag(void) const
{ return baseLangSysTag; }
inline unsigned int get_feature_tag_index (Tag featureTableTag) const
{ return (this+minMax).get_feature_tag_index( featureTableTag); }
inline int get_min_value (unsigned int featureTableTagIndex) const
{ return (this+minMax).get_min_value( featureTableTagIndex); }
inline int get_max_value (unsigned int featureTableTagIndex) const
{ return (this+minMax).get_max_value (featureTableTagIndex); }
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
minMax.sanitize (c, base));
}
protected:
Tag baseLangSysTag;
OffsetTo<MinMax> minMax;
public:
DEFINE_SIZE_STATIC (6);
};
struct BaseValues struct BaseValues
{ {
inline unsigned int get_default_base_tag_index (void) const inline const BaseCoord &get_base_coord (int baseline_tag_index) const
{ return defaultIndex; }
inline int get_base_coord (unsigned int baselineTagIndex) const
{ {
return (this+baseCoords[baselineTagIndex]).get_coord (); if (baseline_tag_index == -1) baseline_tag_index = defaultIndex;
return this+baseCoords[baseline_tag_index];
} }
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
baseCoords.sanitize (c, this)); baseCoords.sanitize (c, this)));
} }
protected: protected:
Index defaultIndex; Index defaultIndex; /* Index number of default baseline for this
OffsetArrayOf<BaseCoord> baseCoords; * script equals index position of baseline tag
* in baselineTags array of the BaseTagList */
OffsetArrayOf<BaseCoord>
baseCoords; /* Number of BaseCoord tables defined — should equal
* baseTagCount in the BaseTagList
*
* Array of offsets to BaseCoord tables, from beginning of
* BaseValues table order matches baselineTags array in
* the BaseTagList */
public: public:
DEFINE_SIZE_ARRAY (4, baseCoords); DEFINE_SIZE_ARRAY (4, baseCoords);
}; };
struct BaseScript { struct BaseLangSysRecord
{
inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const static int cmp (const void *key_, const void *entry_)
{ {
/* XXX bsearch */ hb_tag_t key = * (hb_tag_t *) key_;
Tag tag; const BaseLangSysRecord &entry = * (const BaseLangSysRecord *) entry_;
int cmp; return key < (unsigned int) entry.baseLangSysTag ? -1 :
unsigned int count = baseLangSysRecords.len; key > (unsigned int) entry.baseLangSysTag ? 1 :
for (unsigned int i = 0; i < count; i++) 0;
{
tag = baseLangSysRecords[i].get_tag ();
// taking advantage of alphabetical order
cmp = tag.cmp(baseLangSysTag);
if (cmp == 0) return i;
if (cmp > 0) return NOT_INDEXED;
}
return NOT_INDEXED;
} }
inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const inline const MinMax &get_min_max () const
{ { return this+minMax; }
if (baseLangSysIndex == NOT_INDEXED)
{
if (unlikely(defaultMinMax)) return NOT_INDEXED;
return (this+defaultMinMax).get_feature_tag_index (featureTableTag);
}
return baseLangSysRecords[baseLangSysIndex].get_feature_tag_index (featureTableTag);
}
inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{
if (baseLangSysIndex == NOT_INDEXED)
return (this+defaultMinMax).get_min_value (featureTableTagIndex);
return baseLangSysRecords[baseLangSysIndex].get_max_value (featureTableTagIndex);
}
inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{
if (baseLangSysIndex == NOT_INDEXED)
return (this+defaultMinMax).get_min_value (featureTableTagIndex);
return baseLangSysRecords[baseLangSysIndex].get_max_value (featureTableTagIndex);
}
inline unsigned int get_default_base_tag_index (void) const
{ return (this+baseValues).get_default_base_tag_index (); }
inline int get_base_coord (unsigned int baselineTagIndex) const
{ return (this+baseValues).get_base_coord (baselineTagIndex); }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
baseValues.sanitize (c, this) &&
defaultMinMax.sanitize (c, this) &&
baseLangSysRecords.sanitize (c, this));
}
protected:
OffsetTo<BaseValues> baseValues;
OffsetTo<MinMax> defaultMinMax;
ArrayOf<BaseLangSysRecord> baseLangSysRecords;
public:
DEFINE_SIZE_ARRAY (6, baseLangSysRecords);
};
struct BaseScriptRecord {
inline const Tag& get_tag (void) const
{ return baseScriptTag; }
inline unsigned int get_default_base_tag_index(void) const
{ return (this+baseScript).get_default_base_tag_index (); }
inline int get_base_coord(unsigned int baselineTagIndex) const
{ return (this+baseScript).get_base_coord (baselineTagIndex); }
inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const
{ return (this+baseScript).get_lang_tag_index (baseLangSysTag); }
inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const
{ return (this+baseScript).get_feature_tag_index (baseLangSysIndex, featureTableTag); }
inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{ return (this+baseScript).get_max_value (baseLangSysIndex, featureTableTagIndex); }
inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{ return (this+baseScript).get_min_value (baseLangSysIndex, featureTableTagIndex); }
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
baseScript.sanitize (c, base)); minMax.sanitize (c, this)));
} }
protected: protected:
Tag baseScriptTag; Tag baseLangSysTag; /* 4-byte language system identification tag */
OffsetTo<BaseScript> baseScript; OffsetTo<MinMax>
minMax; /* Offset to MinMax table, from beginning
* of BaseScript table */
public: public:
DEFINE_SIZE_STATIC (6); DEFINE_SIZE_STATIC (6);
}; };
struct BaseScriptList { struct BaseScript
{
inline unsigned int get_base_script_index (Tag baseScriptTag) const inline const MinMax &get_min_max (hb_tag_t language_tag) const
{ {
/* XXX bsearch? */ const BaseLangSysRecord* record = (const BaseLangSysRecord *)
unsigned int count = baseScriptRecords.len; hb_bsearch (&language_tag, baseLangSysRecords.arrayZ,
for (unsigned int i = 0; i < count; i++) baseLangSysRecords.len,
if (baseScriptRecords[i].get_tag() == baseScriptTag) BaseLangSysRecord::static_size,
return i; BaseLangSysRecord::cmp);
return NOT_INDEXED; return record ? record->get_min_max () : this+defaultMinMax;
} }
inline unsigned int get_default_base_tag_index (unsigned int baseScriptIndex) const inline const BaseCoord &get_base_coord (int baseline_tag_index) const
{ return (this+baseValues).get_base_coord (baseline_tag_index); }
inline bool is_empty () const
{ return !baseValues; }
inline bool sanitize (hb_sanitize_context_t *c) const
{ {
return baseScriptRecords[baseScriptIndex].get_default_base_tag_index(); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
baseValues.sanitize (c, this) &&
defaultMinMax.sanitize (c, this) &&
baseLangSysRecords.sanitize (c, this)));
} }
inline int get_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const protected:
OffsetTo<BaseValues>
baseValues; /* Offset to BaseValues table, from beginning
* of BaseScript table (may be NULL) */
OffsetTo<MinMax>
defaultMinMax; /* Offset to MinMax table, from beginning of
* BaseScript table (may be NULL) */
ArrayOf<BaseLangSysRecord>
baseLangSysRecords;
/* Number of BaseLangSysRecords
* defined may be zero (0) */
public:
DEFINE_SIZE_ARRAY (6, baseLangSysRecords);
};
struct BaseScriptList;
struct BaseScriptRecord
{
static int cmp (const void *key_, const void *entry_)
{ {
return baseScriptRecords[baseScriptIndex].get_base_coord(baselineTagIndex); hb_tag_t key = * (hb_tag_t *) key_;
const BaseScriptRecord &entry = * (const BaseScriptRecord *) entry_;
return key < (unsigned int) entry.baseScriptTag ? -1 :
key > (unsigned int) entry.baseScriptTag ? 1 :
0;
} }
inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const inline const BaseScript &get_base_script (const BaseScriptList *list) const
{ return list+baseScript; }
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
return baseScriptRecords[baseScriptIndex].get_lang_tag_index(baseLangSysTag); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
baseScript.sanitize (c, base)));
} }
inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const protected:
Tag baseScriptTag; /* 4-byte script identification tag */
OffsetTo<BaseScript>
baseScript; /* Offset to BaseScript table, from beginning
* of BaseScriptList */
public:
DEFINE_SIZE_STATIC (6);
};
struct BaseScriptList
{
inline const BaseScriptRecord *find_record (hb_tag_t script) const
{ {
return baseScriptRecords[baseScriptIndex].get_feature_tag_index(baseLangSysIndex, featureTableTag); return (const BaseScriptRecord *) hb_bsearch (&script, baseScriptRecords.arrayZ,
baseScriptRecords.len,
BaseScriptRecord::static_size,
BaseScriptRecord::cmp);
} }
inline int get_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const /* TODO: Or client should handle fallback? */
inline const BaseScript &get_base_script (hb_tag_t script) const
{ {
return baseScriptRecords[baseScriptIndex].get_max_value(baseLangSysIndex, featureTableTagIndex); const BaseScriptRecord *record = find_record (script);
} if (!record) record = find_record ((hb_script_t) HB_TAG ('D','F','L','T'));
inline int get_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const return record ? record->get_base_script (this) : Null (BaseScript);
{
return baseScriptRecords[baseScriptIndex].get_min_value(baseLangSysIndex, featureTableTagIndex);
} }
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
@ -436,86 +400,61 @@ struct BaseScriptList {
} }
protected: protected:
ArrayOf<BaseScriptRecord> baseScriptRecords; ArrayOf<BaseScriptRecord>
baseScriptRecords;
public: public:
DEFINE_SIZE_ARRAY (2, baseScriptRecords); DEFINE_SIZE_ARRAY (2, baseScriptRecords);
}; };
struct BaseTagList
{
inline unsigned int get_tag_index (Tag baselineTag) const
{
/* TODO bsearch? */
unsigned int count = baselineTags.len;
for (unsigned int i = 0; i < count; i++)
if (baselineTags[i] == baselineTag)
return i;
return NOT_INDEXED;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
SortedArrayOf<Tag> baselineTags;
public:
DEFINE_SIZE_ARRAY (2, baselineTags);
};
struct Axis struct Axis
{ {
inline bool get_baseline (hb_ot_layout_baseline_t baseline,
inline unsigned int get_base_tag_index (Tag baselineTag) const hb_tag_t script_tag,
hb_tag_t language_tag,
const BaseCoord **coord) const
{ {
return (this+baseTagList).get_tag_index(baselineTag); const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
if (base_script.is_empty ()) return false;
if (likely (coord)) *coord = &base_script.get_base_coord ((this+baseTagList).bsearch (baseline));
return true;
} }
inline unsigned int get_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const inline bool get_min_max (hb_tag_t script_tag,
hb_tag_t language_tag,
hb_tag_t feature_tag,
const BaseCoord **min_coord,
const BaseCoord **max_coord) const
{ {
return (this+baseScriptList).get_default_base_tag_index(baseScriptIndex); const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
} if (base_script.is_empty ()) return false;
inline int get_base_coord (unsigned int baseScriptIndex, unsigned int baselineTagIndex) const base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
{
return (this+baseScriptList).get_base_coord(baseScriptIndex, baselineTagIndex);
}
inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const return true;
{
return (this+baseScriptList).get_lang_tag_index(baseScriptIndex, baseLangSysTag);
}
inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
{
return (this+baseScriptList).get_feature_tag_index(baseScriptIndex, baseLangSysIndex, featureTableTag);
}
inline int get_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{
return (this+baseScriptList).get_max_value(baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
}
inline int get_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{
return (this+baseScriptList).get_min_value(baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
} }
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
baseTagList.sanitize (c, this) && (this+baseTagList).sanitize (c) &&
baseScriptList.sanitize (c, this)); (this+baseScriptList).sanitize (c)));
} }
protected: protected:
OffsetTo<BaseTagList> baseTagList; OffsetTo<SortedArrayOf<Tag> >
OffsetTo<BaseScriptList> baseScriptList; baseTagList; /* Offset to BaseTagList table, from beginning
* of Axis table (may be NULL)
* Array of 4-byte baseline identification tags must
* be in alphabetical order */
OffsetTo<BaseScriptList>
baseScriptList; /* Offset to BaseScriptList table, from beginning
* of Axis table
* Array of BaseScriptRecords, in alphabetical order
* by baseScriptTag */
public: public:
DEFINE_SIZE_STATIC (4); DEFINE_SIZE_STATIC (4);
@ -525,99 +464,70 @@ struct BASE
{ {
static const hb_tag_t tableTag = HB_OT_TAG_BASE; static const hb_tag_t tableTag = HB_OT_TAG_BASE;
inline bool has_v_axis(void) { return vAxis != 0; } inline const Axis &get_axis (hb_direction_t direction) const
{ return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
inline bool has_h_axis(void) { return hAxis != 0; } inline const VariationStore &get_var_store () const
{ return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
inline unsigned int get_h_base_tag_index (Tag baselineTag) const inline bool get_baseline (hb_font_t *font,
hb_ot_layout_baseline_t baseline,
hb_direction_t direction,
hb_tag_t script_tag,
hb_tag_t language_tag,
hb_position_t *base) const
{ {
return (this+hAxis).get_base_tag_index(baselineTag); const BaseCoord *base_coord;
if (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord))
return false;
if (likely (base && base_coord)) *base = base_coord->get_coord (font,
get_var_store (),
direction);
return true;
} }
inline unsigned int get_h_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const /* TODO: Expose this separately sometime? */
inline bool get_min_max (hb_font_t *font,
hb_direction_t direction,
hb_tag_t script_tag,
hb_tag_t language_tag,
hb_tag_t feature_tag,
hb_position_t *min,
hb_position_t *max)
{ {
return (this+hAxis).get_default_base_tag_index_for_script_index(baseScriptIndex); const BaseCoord *min_coord, *max_coord;
} if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
&min_coord, &max_coord))
return false;
inline int get_h_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const const VariationStore &var_store = get_var_store ();
{ if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
return (this+hAxis).get_base_coord(baseScriptIndex, baselineTagIndex); if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
} return true;
inline unsigned int get_v_base_tag_index(Tag baselineTag) const
{
return (this+vAxis).get_base_tag_index(baselineTag);
}
inline unsigned int get_v_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
{
return (this+vAxis).get_default_base_tag_index_for_script_index(baseScriptIndex);
}
inline int get_v_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
{
return (this+vAxis).get_base_coord(baseScriptIndex, baselineTagIndex);
}
inline unsigned int get_h_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
{
return (this+hAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag);
}
inline unsigned int get_h_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
{
return (this+hAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag);
}
inline int get_h_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{
return (this+hAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
}
inline int get_h_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{
return (this+hAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
}
inline unsigned int get_v_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
{
return (this+vAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag);
}
inline unsigned int get_v_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
{
return (this+vAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag);
}
inline int get_v_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{
return (this+vAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
}
inline int get_v_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
{
return (this+vAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
} }
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (likely (c->check_struct (this) &&
likely (version.major == 1) && likely (version.major == 1) &&
hAxis.sanitize (c, this) && hAxis.sanitize (c, this) &&
vAxis.sanitize (c, this) && vAxis.sanitize (c, this) &&
(version.to_int () < 0x00010001u || varStore.sanitize (c, this))); (version.to_int () < 0x00010001u || varStore.sanitize (c, this))));
} }
protected: protected:
FixedVersion<> version; FixedVersion<>version; /* Version of the BASE table */
OffsetTo<Axis> hAxis; OffsetTo<Axis>hAxis; /* Offset to horizontal Axis table, from beginning
OffsetTo<Axis> vAxis; * of BASE table (may be NULL) */
OffsetTo<Axis>vAxis; /* Offset to vertical Axis table, from beginning
* of BASE table (may be NULL) */
LOffsetTo<VariationStore> LOffsetTo<VariationStore>
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
* in version 0x00010001. */ * in version 0x00010001. */
public: public:
DEFINE_SIZE_MIN (8); DEFINE_SIZE_MIN (8);
}; };

View File

@ -37,10 +37,8 @@
#include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise
#include "hb-ot-layout-base-table.hh" // Just so we compile them; unused otherwise #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise
#include "hb-ot-layout-jstf-table.hh" // Just so we compile them; unused otherwise
#include "hb-ot-kern-table.hh" #include "hb-ot-kern-table.hh"
#include "hb-ot-name-table.hh" #include "hb-ot-name-table.hh"
@ -1425,3 +1423,62 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
{ {
apply_string<GSUBProxy> (c, lookup, accel); apply_string<GSUBProxy> (c, lookup, accel);
} }
#if 0
static const OT::BASE& _get_base (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::BASE);
return *hb_ot_face_data (face)->BASE;
}
hb_bool_t
hb_ot_layout_get_baseline (hb_font_t *font,
hb_ot_layout_baseline_t baseline,
hb_direction_t direction,
hb_tag_t script_tag,
hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */)
{
const OT::BASE &base = _get_base (font->face);
bool result = base.get_baseline (font, baseline, direction, script_tag,
language_tag, coord);
/* TODO: Simulate https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags#ideographic-em-box */
if (!result && coord) *coord = 0;
if (coord) *coord = font->em_scale_dir (*coord, direction);
return result;
}
/* To be moved to public header */
/*
* BASE
*/
/**
* hb_ot_layout_baseline_t:
*
* https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
*
* Since: DONTREPLACEME
*/
typedef enum {
HB_OT_LAYOUT_BASELINE_HANG = HB_TAG('h','a','n','g'),
HB_OT_LAYOUT_BASELINE_ICFB = HB_TAG('i','c','f','b'),
HB_OT_LAYOUT_BASELINE_ICFT = HB_TAG('i','c','f','t'),
HB_OT_LAYOUT_BASELINE_IDEO = HB_TAG('i','d','e','o'),
HB_OT_LAYOUT_BASELINE_IDTB = HB_TAG('i','d','t','b'),
HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'),
HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n')
} hb_ot_layout_baseline_t;
HB_EXTERN hb_bool_t
hb_ot_layout_get_baseline (hb_font_t *font,
hb_ot_layout_baseline_t baseline,
hb_direction_t direction,
hb_tag_t script_tag,
hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */);
#endif

View File

@ -391,22 +391,6 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
unsigned int *char_count /* IN/OUT. May be NULL */, unsigned int *char_count /* IN/OUT. May be NULL */,
hb_codepoint_t *characters /* OUT. May be NULL */); hb_codepoint_t *characters /* OUT. May be NULL */);
/*
* BASE
*/
#if 0
#define HB_OT_TAG_BASE_HANG HB_TAG('h','a','n','g')
#define HB_OT_TAG_BASE_ICFB HB_TAG('i','c','f','b')
#define HB_OT_TAG_BASE_ICFT HB_TAG('i','c','f','t')
#define HB_OT_TAG_BASE_IDEO HB_TAG('i','d','e','o')
#define HB_OT_TAG_BASE_IDTB HB_TAG('i','d','t','b')
#define HB_OT_TAG_BASE_MATH HB_TAG('m','a','t','h')
#define HB_OT_TAG_BASE_ROMN HB_TAG('r','o','m','n')
#endif
HB_END_DECLS HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */ #endif /* HB_OT_LAYOUT_H */

View File

@ -28,6 +28,7 @@ check_PROGRAMS = $(TEST_PROGS)
noinst_PROGRAMS = $(TEST_PROGS) noinst_PROGRAMS = $(TEST_PROGS)
TEST_PROGS = \ TEST_PROGS = \
test-baseline \
test-blob \ test-blob \
test-buffer \ test-buffer \
test-collect-unicodes \ test-collect-unicodes \

BIN
test/api/fonts/base.ttf Normal file

Binary file not shown.

58
test/api/test-baseline.c Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* 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.
*/
#include "hb-test.h"
#include <hb-ot.h>
/* Unit tests for hb-ot-layout.h baseline */
static void
test_ot_layout_base (void)
{
hb_face_t *face = hb_test_open_font_file ("fonts/base.ttf");
hb_font_t *font = hb_font_create (face);
#if 0
hb_position_t position;
g_assert (hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_ICFB, HB_DIRECTION_TTB,
HB_TAG ('h','a','n','i'),
HB_TAG ('E','N','G',' '),
&position));
g_assert_cmpint (46, ==, position);
#endif
hb_font_destroy (font);
hb_face_destroy (face);
}
int
main (int argc, char **argv)
{
hb_test_init (&argc, &argv);
hb_test_add (test_ot_layout_base);
return hb_test_run();
}