Merge branch 'master' into cff-subset
This commit is contained in:
commit
ce6639cd27
|
@ -45,32 +45,47 @@ struct Anchor
|
||||||
return_trace (c->check_struct (this));
|
return_trace (c->check_struct (this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
FWORD xCoordinate;
|
FWORD xCoordinate;
|
||||||
FWORD yCoordinate;
|
FWORD yCoordinate;
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (4);
|
DEFINE_SIZE_STATIC (4);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef LArrayOf<Anchor> GlyphAnchors;
|
||||||
|
|
||||||
struct ankr
|
struct ankr
|
||||||
{
|
{
|
||||||
static const hb_tag_t tableTag = HB_AAT_TAG_ankr;
|
static const hb_tag_t tableTag = HB_AAT_TAG_ankr;
|
||||||
|
|
||||||
|
inline const Anchor &get_anchor (hb_codepoint_t glyph_id,
|
||||||
|
unsigned int i,
|
||||||
|
unsigned int num_glyphs,
|
||||||
|
const char *end) const
|
||||||
|
{
|
||||||
|
unsigned int offset = (this+lookupTable).get_value_or_null (glyph_id, num_glyphs);
|
||||||
|
const GlyphAnchors &anchors = StructAtOffset<GlyphAnchors> (&(this+anchorData), offset);
|
||||||
|
/* TODO Use sanitizer; to avoid overflows and more. */
|
||||||
|
if (unlikely ((const char *) &anchors + anchors.get_size () > end))
|
||||||
|
return Null(Anchor);
|
||||||
|
return anchors[i];
|
||||||
|
}
|
||||||
|
|
||||||
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 (likely (c->check_struct (this) &&
|
return_trace (likely (c->check_struct (this) &&
|
||||||
version == 0 &&
|
version == 0 &&
|
||||||
lookupTable.sanitize (c, this) &&
|
lookupTable.sanitize (c, this)));
|
||||||
anchors.sanitize (c, this)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HBUINT16 version; /* Version number (set to zero) */
|
HBUINT16 version; /* Version number (set to zero) */
|
||||||
HBUINT16 flags; /* Flags (currently unused; set to zero) */
|
HBUINT16 flags; /* Flags (currently unused; set to zero) */
|
||||||
LOffsetTo<Lookup<HBUINT16> >
|
LOffsetTo<Lookup<Offset<HBUINT16, false> > >
|
||||||
lookupTable; /* Offset to the table's lookup table */
|
lookupTable; /* Offset to the table's lookup table */
|
||||||
LOffsetTo<LArrayOf<Anchor> >
|
LOffsetTo<HBUINT8>
|
||||||
anchors; /* Offset to the glyph data table */
|
anchorData; /* Offset to the glyph data table */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (12);
|
DEFINE_SIZE_STATIC (12);
|
||||||
|
|
|
@ -514,6 +514,7 @@ struct StateTableDriver
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ankr;
|
||||||
|
|
||||||
struct hb_aat_apply_context_t :
|
struct hb_aat_apply_context_t :
|
||||||
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
|
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
|
||||||
|
@ -529,6 +530,8 @@ struct hb_aat_apply_context_t :
|
||||||
hb_face_t *face;
|
hb_face_t *face;
|
||||||
hb_buffer_t *buffer;
|
hb_buffer_t *buffer;
|
||||||
hb_sanitize_context_t sanitizer;
|
hb_sanitize_context_t sanitizer;
|
||||||
|
const ankr &ankr_table;
|
||||||
|
const char *ankr_end;
|
||||||
|
|
||||||
/* Unused. For debug tracing only. */
|
/* Unused. For debug tracing only. */
|
||||||
unsigned int lookup_index;
|
unsigned int lookup_index;
|
||||||
|
@ -537,11 +540,15 @@ struct hb_aat_apply_context_t :
|
||||||
inline hb_aat_apply_context_t (hb_ot_shape_plan_t *plan_,
|
inline hb_aat_apply_context_t (hb_ot_shape_plan_t *plan_,
|
||||||
hb_font_t *font_,
|
hb_font_t *font_,
|
||||||
hb_buffer_t *buffer_,
|
hb_buffer_t *buffer_,
|
||||||
hb_blob_t *table) :
|
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)),
|
||||||
|
const ankr &ankr_table_ = Null(ankr),
|
||||||
|
const char *ankr_end_ = nullptr) :
|
||||||
plan (plan_), font (font_), face (font->face), buffer (buffer_),
|
plan (plan_), font (font_), face (font->face), buffer (buffer_),
|
||||||
sanitizer (), lookup_index (0), debug_depth (0)
|
sanitizer (),
|
||||||
|
ankr_table (ankr_table_), ankr_end (ankr_end_),
|
||||||
|
lookup_index (0), debug_depth (0)
|
||||||
{
|
{
|
||||||
sanitizer.init (table);
|
sanitizer.init (blob);
|
||||||
sanitizer.set_num_glyphs (face->get_num_glyphs ());
|
sanitizer.set_num_glyphs (face->get_num_glyphs ());
|
||||||
sanitizer.start_processing ();
|
sanitizer.start_processing ();
|
||||||
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
|
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "hb-open-type.hh"
|
#include "hb-open-type.hh"
|
||||||
#include "hb-aat-layout-common.hh"
|
#include "hb-aat-layout-common.hh"
|
||||||
|
#include "hb-ot-layout-gpos-table.hh"
|
||||||
#include "hb-ot-kern-table.hh"
|
#include "hb-ot-kern-table.hh"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -99,6 +100,100 @@ struct KerxSubTableFormat0
|
||||||
|
|
||||||
struct KerxSubTableFormat1
|
struct KerxSubTableFormat1
|
||||||
{
|
{
|
||||||
|
struct EntryData
|
||||||
|
{
|
||||||
|
HBUINT16 kernActionIndex;/* Index into the kerning value array. If
|
||||||
|
* this index is 0xFFFF, then no kerning
|
||||||
|
* is to be performed. */
|
||||||
|
public:
|
||||||
|
DEFINE_SIZE_STATIC (2);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct driver_context_t
|
||||||
|
{
|
||||||
|
static const bool in_place = true;
|
||||||
|
enum Flags
|
||||||
|
{
|
||||||
|
Push = 0x8000, /* If set, push this glyph on the kerning stack. */
|
||||||
|
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
|
||||||
|
* before going to the new state. */
|
||||||
|
Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */
|
||||||
|
Reserved = 0x1FFF, /* Not used; set to 0. */
|
||||||
|
};
|
||||||
|
|
||||||
|
inline driver_context_t (const KerxSubTableFormat1 *table,
|
||||||
|
hb_aat_apply_context_t *c_) :
|
||||||
|
c (c_),
|
||||||
|
/* Apparently the offset kernAction is from the beginning of the state-machine,
|
||||||
|
* similar to offsets in morx table, NOT from beginning of this table, like
|
||||||
|
* other subtables in kerx. Discovered via testing. */
|
||||||
|
kernAction (&table->machine + table->kernAction),
|
||||||
|
depth (0) {}
|
||||||
|
|
||||||
|
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||||
|
const Entry<EntryData> *entry)
|
||||||
|
{
|
||||||
|
return entry->data.kernActionIndex != 0xFFFF;
|
||||||
|
}
|
||||||
|
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||||
|
const Entry<EntryData> *entry)
|
||||||
|
{
|
||||||
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
|
unsigned int flags = entry->flags;
|
||||||
|
|
||||||
|
if (flags & Reset)
|
||||||
|
{
|
||||||
|
depth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & Push)
|
||||||
|
{
|
||||||
|
if (likely (depth < ARRAY_LENGTH (stack)))
|
||||||
|
stack[depth++] = buffer->idx;
|
||||||
|
else
|
||||||
|
depth = 0; /* Probably not what CoreText does, but better? */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->data.kernActionIndex != 0xFFFF)
|
||||||
|
{
|
||||||
|
const FWORD *actions = &kernAction[entry->data.kernActionIndex];
|
||||||
|
if (!c->sanitizer.check_array (actions, depth))
|
||||||
|
{
|
||||||
|
depth = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hb_mask_t kern_mask = c->plan->kern_mask;
|
||||||
|
for (unsigned int i = 0; i < depth; i++)
|
||||||
|
{
|
||||||
|
/* Apparently, when spec says "Each pops one glyph from the kerning stack
|
||||||
|
* and applies the kerning value to it.", it doesn't mean it in that order.
|
||||||
|
* The deepest item in the stack corresponds to the first item in the action
|
||||||
|
* list. Discovered by testing. */
|
||||||
|
unsigned int idx = stack[i];
|
||||||
|
int v = *actions++;
|
||||||
|
if (buffer->info[idx].mask & kern_mask)
|
||||||
|
{
|
||||||
|
/* XXX Non-forward direction... */
|
||||||
|
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||||
|
buffer->pos[idx].x_advance += c->font->em_scale_x (v);
|
||||||
|
else
|
||||||
|
buffer->pos[idx].y_advance += c->font->em_scale_y (v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
depth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
hb_aat_apply_context_t *c;
|
||||||
|
const UnsizedArrayOf<FWORD> &kernAction;
|
||||||
|
unsigned int stack[8];
|
||||||
|
unsigned int depth;
|
||||||
|
};
|
||||||
|
|
||||||
inline bool apply (hb_aat_apply_context_t *c) const
|
inline bool apply (hb_aat_apply_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_APPLY (this);
|
TRACE_APPLY (this);
|
||||||
|
@ -106,7 +201,10 @@ struct KerxSubTableFormat1
|
||||||
if (!c->plan->requested_kerning)
|
if (!c->plan->requested_kerning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* TODO */
|
driver_context_t dc (this, c);
|
||||||
|
|
||||||
|
StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
|
||||||
|
driver.drive (&dc);
|
||||||
|
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
@ -114,14 +212,13 @@ struct KerxSubTableFormat1
|
||||||
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 (likely (c->check_struct (this) &&
|
return_trace (likely (machine.sanitize (c)));
|
||||||
stateHeader.sanitize (c)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
KerxSubTableHeader header;
|
KerxSubTableHeader header;
|
||||||
StateTable<HBUINT16> stateHeader;
|
StateTable<EntryData> machine;
|
||||||
LOffsetTo<ArrayOf<HBUINT16> > valueTable;
|
LOffsetTo<UnsizedArrayOf<FWORD>, false> kernAction;
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (32);
|
DEFINE_SIZE_STATIC (32);
|
||||||
};
|
};
|
||||||
|
@ -136,7 +233,7 @@ struct KerxSubTableFormat2
|
||||||
unsigned int offset = l + r;
|
unsigned int offset = l + r;
|
||||||
const FWORD *v = &StructAtOffset<FWORD> (&(this+array), offset);
|
const FWORD *v = &StructAtOffset<FWORD> (&(this+array), offset);
|
||||||
if (unlikely ((const char *) v < (const char *) &array ||
|
if (unlikely ((const char *) v < (const char *) &array ||
|
||||||
(const char *) v + v->static_size - (const char *) this <= header.length))
|
(const char *) v + v->static_size - (const char *) this > header.length))
|
||||||
return 0;
|
return 0;
|
||||||
return *v;
|
return *v;
|
||||||
}
|
}
|
||||||
|
@ -159,11 +256,9 @@ struct KerxSubTableFormat2
|
||||||
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 (likely (c->check_struct (this) &&
|
return_trace (likely (rowWidth.sanitize (c) &&
|
||||||
rowWidth.sanitize (c) &&
|
|
||||||
leftClassTable.sanitize (c, this) &&
|
leftClassTable.sanitize (c, this) &&
|
||||||
rightClassTable.sanitize (c, this) &&
|
rightClassTable.sanitize (c, this)));
|
||||||
array.sanitize (c, this)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct accelerator_t
|
struct accelerator_t
|
||||||
|
@ -190,7 +285,8 @@ struct KerxSubTableFormat2
|
||||||
LOffsetTo<Lookup<HBUINT16> >
|
LOffsetTo<Lookup<HBUINT16> >
|
||||||
rightClassTable;/* Offset from beginning of this subtable to
|
rightClassTable;/* Offset from beginning of this subtable to
|
||||||
* right-hand class table. */
|
* right-hand class table. */
|
||||||
LOffsetTo<FWORD> array; /* Offset from beginning of this subtable to
|
LOffsetTo<UnsizedArrayOf<FWORD>, false>
|
||||||
|
array; /* Offset from beginning of this subtable to
|
||||||
* the start of the kerning array. */
|
* the start of the kerning array. */
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (28);
|
DEFINE_SIZE_STATIC (28);
|
||||||
|
@ -198,11 +294,152 @@ struct KerxSubTableFormat2
|
||||||
|
|
||||||
struct KerxSubTableFormat4
|
struct KerxSubTableFormat4
|
||||||
{
|
{
|
||||||
|
struct EntryData
|
||||||
|
{
|
||||||
|
HBUINT16 ankrActionIndex;/* Either 0xFFFF (for no action) or the index of
|
||||||
|
* the action to perform. */
|
||||||
|
public:
|
||||||
|
DEFINE_SIZE_STATIC (2);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct driver_context_t
|
||||||
|
{
|
||||||
|
static const bool in_place = true;
|
||||||
|
enum Flags
|
||||||
|
{
|
||||||
|
Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
|
||||||
|
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
|
||||||
|
* going to the new state. */
|
||||||
|
Reserved = 0x3FFF, /* Not used; set to 0. */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SubTableFlags
|
||||||
|
{
|
||||||
|
ActionType = 0xC0000000, /* A two-bit field containing the action type. */
|
||||||
|
Unused = 0x3F000000, /* Unused - must be zero. */
|
||||||
|
Offset = 0x00FFFFFF, /* Masks the offset in bytes from the beginning
|
||||||
|
* of the subtable to the beginning of the control
|
||||||
|
* point table. */
|
||||||
|
};
|
||||||
|
|
||||||
|
inline driver_context_t (const KerxSubTableFormat4 *table,
|
||||||
|
hb_aat_apply_context_t *c_) :
|
||||||
|
c (c_),
|
||||||
|
action_type ((table->flags & ActionType) >> 30),
|
||||||
|
ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
|
||||||
|
mark_set (false),
|
||||||
|
mark (0) {}
|
||||||
|
|
||||||
|
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||||
|
const Entry<EntryData> *entry)
|
||||||
|
{
|
||||||
|
return entry->data.ankrActionIndex != 0xFFFF;
|
||||||
|
}
|
||||||
|
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||||
|
const Entry<EntryData> *entry)
|
||||||
|
{
|
||||||
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
|
unsigned int flags = entry->flags;
|
||||||
|
|
||||||
|
if (mark_set && entry->data.ankrActionIndex != 0xFFFF)
|
||||||
|
{
|
||||||
|
hb_glyph_position_t &o = buffer->cur_pos();
|
||||||
|
switch (action_type)
|
||||||
|
{
|
||||||
|
case 0: /* Control Point Actions.*/
|
||||||
|
{
|
||||||
|
/* indexed into glyph outline. */
|
||||||
|
const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
|
||||||
|
if (!c->sanitizer.check_array (data, 2))
|
||||||
|
return false;
|
||||||
|
HB_UNUSED unsigned int markControlPoint = *data++;
|
||||||
|
HB_UNUSED unsigned int currControlPoint = *data++;
|
||||||
|
hb_position_t markX = 0;
|
||||||
|
hb_position_t markY = 0;
|
||||||
|
hb_position_t currX = 0;
|
||||||
|
hb_position_t currY = 0;
|
||||||
|
if (!c->font->get_glyph_contour_point_for_origin (c->buffer->info[mark].codepoint,
|
||||||
|
markControlPoint,
|
||||||
|
HB_DIRECTION_LTR /*XXX*/,
|
||||||
|
&markX, &markY) ||
|
||||||
|
!c->font->get_glyph_contour_point_for_origin (c->buffer->cur ().codepoint,
|
||||||
|
currControlPoint,
|
||||||
|
HB_DIRECTION_LTR /*XXX*/,
|
||||||
|
&currX, &currY))
|
||||||
|
return true; /* True, such that the machine continues. */
|
||||||
|
|
||||||
|
o.x_offset = markX - currX;
|
||||||
|
o.y_offset = markY - currY;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /* Anchor Point Actions. */
|
||||||
|
{
|
||||||
|
/* Indexed into 'ankr' table. */
|
||||||
|
const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
|
||||||
|
if (!c->sanitizer.check_array (data, 2))
|
||||||
|
return false;
|
||||||
|
unsigned int markAnchorPoint = *data++;
|
||||||
|
unsigned int currAnchorPoint = *data++;
|
||||||
|
const Anchor markAnchor = c->ankr_table.get_anchor (c->buffer->info[mark].codepoint,
|
||||||
|
markAnchorPoint,
|
||||||
|
c->face->get_num_glyphs (),
|
||||||
|
c->ankr_end);
|
||||||
|
const Anchor currAnchor = c->ankr_table.get_anchor (c->buffer->cur ().codepoint,
|
||||||
|
currAnchorPoint,
|
||||||
|
c->face->get_num_glyphs (),
|
||||||
|
c->ankr_end);
|
||||||
|
|
||||||
|
o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate);
|
||||||
|
o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* Control Point Coordinate Actions. */
|
||||||
|
{
|
||||||
|
const FWORD *data = (const FWORD *) &ankrData[entry->data.ankrActionIndex];
|
||||||
|
if (!c->sanitizer.check_array (data, 4))
|
||||||
|
return false;
|
||||||
|
int markX = *data++;
|
||||||
|
int markY = *data++;
|
||||||
|
int currX = *data++;
|
||||||
|
int currY = *data++;
|
||||||
|
|
||||||
|
o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX);
|
||||||
|
o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
o.attach_type() = ATTACH_TYPE_MARK;
|
||||||
|
o.attach_chain() = (int) mark - (int) buffer->idx;
|
||||||
|
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & Mark)
|
||||||
|
{
|
||||||
|
mark_set = true;
|
||||||
|
mark = buffer->idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
hb_aat_apply_context_t *c;
|
||||||
|
unsigned int action_type;
|
||||||
|
const HBUINT16 *ankrData;
|
||||||
|
bool mark_set;
|
||||||
|
unsigned int mark;
|
||||||
|
};
|
||||||
|
|
||||||
inline bool apply (hb_aat_apply_context_t *c) const
|
inline bool apply (hb_aat_apply_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_APPLY (this);
|
TRACE_APPLY (this);
|
||||||
|
|
||||||
/* TODO */
|
driver_context_t dc (this, c);
|
||||||
|
|
||||||
|
StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
|
||||||
|
driver.drive (&dc);
|
||||||
|
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
@ -211,14 +448,18 @@ struct KerxSubTableFormat4
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
|
||||||
/* TODO */
|
/* The rest of array sanitizations are done at run-time. */
|
||||||
return_trace (likely (c->check_struct (this)));
|
return_trace (c->check_struct (this) &&
|
||||||
|
machine.sanitize (c) &&
|
||||||
|
flags.sanitize (c));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
KerxSubTableHeader header;
|
KerxSubTableHeader header;
|
||||||
|
StateTable<EntryData> machine;
|
||||||
|
HBUINT32 flags;
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (12);
|
DEFINE_SIZE_STATIC (32);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KerxSubTableFormat6
|
struct KerxSubTableFormat6
|
||||||
|
@ -241,7 +482,7 @@ struct KerxSubTableFormat6
|
||||||
unsigned int offset = l + r;
|
unsigned int offset = l + r;
|
||||||
const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
|
const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
|
||||||
if (unlikely ((const char *) v < (const char *) &t.array ||
|
if (unlikely ((const char *) v < (const char *) &t.array ||
|
||||||
(const char *) v + v->static_size - (const char *) this <= header.length))
|
(const char *) v + v->static_size - (const char *) this > header.length))
|
||||||
return 0;
|
return 0;
|
||||||
return *v;
|
return *v;
|
||||||
}
|
}
|
||||||
|
@ -253,7 +494,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 ((const char *) v < (const char *) &t.array ||
|
if (unlikely ((const char *) v < (const char *) &t.array ||
|
||||||
(const char *) v + v->static_size - (const char *) this <= header.length))
|
(const char *) v + v->static_size - (const char *) this > header.length))
|
||||||
return 0;
|
return 0;
|
||||||
return *v;
|
return *v;
|
||||||
}
|
}
|
||||||
|
@ -281,12 +522,10 @@ struct KerxSubTableFormat6
|
||||||
is_long () ?
|
is_long () ?
|
||||||
(
|
(
|
||||||
u.l.rowIndexTable.sanitize (c, this) &&
|
u.l.rowIndexTable.sanitize (c, this) &&
|
||||||
u.l.columnIndexTable.sanitize (c, this) &&
|
u.l.columnIndexTable.sanitize (c, this)
|
||||||
u.l.array.sanitize (c, this)
|
|
||||||
) : (
|
) : (
|
||||||
u.s.rowIndexTable.sanitize (c, this) &&
|
u.s.rowIndexTable.sanitize (c, this) &&
|
||||||
u.s.columnIndexTable.sanitize (c, this) &&
|
u.s.columnIndexTable.sanitize (c, this)
|
||||||
u.s.array.sanitize (c, this)
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,13 +555,15 @@ struct KerxSubTableFormat6
|
||||||
{
|
{
|
||||||
LOffsetTo<Lookup<HBUINT32> > rowIndexTable;
|
LOffsetTo<Lookup<HBUINT32> > rowIndexTable;
|
||||||
LOffsetTo<Lookup<HBUINT32> > columnIndexTable;
|
LOffsetTo<Lookup<HBUINT32> > columnIndexTable;
|
||||||
LOffsetTo<FWORD32> array;
|
LOffsetTo<UnsizedArrayOf<FWORD32>, false>
|
||||||
|
array;
|
||||||
} l;
|
} l;
|
||||||
struct Short
|
struct Short
|
||||||
{
|
{
|
||||||
LOffsetTo<Lookup<HBUINT16> > rowIndexTable;
|
LOffsetTo<Lookup<HBUINT16> > rowIndexTable;
|
||||||
LOffsetTo<Lookup<HBUINT16> > columnIndexTable;
|
LOffsetTo<Lookup<HBUINT16> > columnIndexTable;
|
||||||
LOffsetTo<FWORD> array;
|
LOffsetTo<UnsizedArrayOf<FWORD>, false>
|
||||||
|
array;
|
||||||
} s;
|
} s;
|
||||||
} u;
|
} u;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -164,7 +164,7 @@ struct RearrangementSubtable
|
||||||
|
|
||||||
driver_context_t dc (this);
|
driver_context_t dc (this);
|
||||||
|
|
||||||
StateTableDriver<void> driver (machine, c->buffer, c->face);
|
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
|
||||||
driver.drive (&dc);
|
driver.drive (&dc);
|
||||||
|
|
||||||
return_trace (dc.ret);
|
return_trace (dc.ret);
|
||||||
|
@ -365,7 +365,7 @@ struct LigatureSubtable
|
||||||
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> *entry)
|
||||||
{
|
{
|
||||||
return !!(entry->flags & PerformAction);
|
return entry->flags & PerformAction;
|
||||||
}
|
}
|
||||||
inline bool transition (StateTableDriver<EntryData> *driver,
|
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> *entry)
|
||||||
|
|
|
@ -46,28 +46,32 @@ struct TrackTableEntry
|
||||||
{
|
{
|
||||||
friend struct TrackData;
|
friend struct TrackData;
|
||||||
|
|
||||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base,
|
|
||||||
unsigned int size) const
|
|
||||||
{
|
|
||||||
TRACE_SANITIZE (this);
|
|
||||||
return_trace (likely (c->check_struct (this) &&
|
|
||||||
(valuesZ.sanitize (c, base, size))));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
inline float get_track_value () const
|
inline float get_track_value () const
|
||||||
{
|
{
|
||||||
return track.to_float ();
|
return track.to_float ();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int get_value (const void *base, unsigned int index) const
|
inline int get_value (const void *base,
|
||||||
|
unsigned int index,
|
||||||
|
unsigned int nSizes) const
|
||||||
{
|
{
|
||||||
return (base+valuesZ)[index];
|
return hb_array_t<FWORD> ((base+valuesZ).arrayZ, nSizes)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline bool sanitize (hb_sanitize_context_t *c, const void *base,
|
||||||
|
unsigned int nSizes) const
|
||||||
|
{
|
||||||
|
TRACE_SANITIZE (this);
|
||||||
|
return_trace (likely (c->check_struct (this) &&
|
||||||
|
(valuesZ.sanitize (c, base, nSizes))));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Fixed track; /* Track value for this record. */
|
Fixed track; /* Track value for this record. */
|
||||||
NameID trackNameID; /* The 'name' table index for this track */
|
NameID trackNameID; /* The 'name' table index for this track.
|
||||||
|
* (a short word or phrase like "loose"
|
||||||
|
* or "very tight") */
|
||||||
OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false>
|
OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false>
|
||||||
valuesZ; /* Offset from start of tracking table to
|
valuesZ; /* Offset from start of tracking table to
|
||||||
* per-size tracking values for this track. */
|
* per-size tracking values for this track. */
|
||||||
|
@ -78,12 +82,20 @@ struct TrackTableEntry
|
||||||
|
|
||||||
struct TrackData
|
struct TrackData
|
||||||
{
|
{
|
||||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
inline float interpolate_at (unsigned int idx,
|
||||||
|
float target_size,
|
||||||
|
const TrackTableEntry &trackTableEntry,
|
||||||
|
const void *base) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
unsigned int sizes = nSizes;
|
||||||
return_trace (c->check_struct (this) &&
|
hb_array_t<Fixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||||
sizeTable.sanitize (c, base, nSizes) &&
|
|
||||||
trackTable.sanitize (c, nTracks, base, nSizes));
|
float s0 = size_table[idx].to_float ();
|
||||||
|
float s1 = size_table[idx + 1].to_float ();
|
||||||
|
float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
|
||||||
|
return (float) t * trackTableEntry.get_value (base, idx + 1, sizes) +
|
||||||
|
((float) 1.0 - t) * trackTableEntry.get_value (base, idx, sizes);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float get_tracking (const void *base, float ptem) const
|
inline float get_tracking (const void *base, float ptem) const
|
||||||
|
@ -94,48 +106,59 @@ struct TrackData
|
||||||
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
|
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
|
||||||
*/
|
*/
|
||||||
float csspx = ptem * 96.f / 72.f;
|
float csspx = ptem * 96.f / 72.f;
|
||||||
Fixed fixed_size;
|
|
||||||
fixed_size.set_float (csspx);
|
|
||||||
|
|
||||||
/* XXX Clean this up. Make it work with nSizes==1 and 0. */
|
|
||||||
|
|
||||||
unsigned int sizes = nSizes;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Choose track.
|
||||||
|
*/
|
||||||
const TrackTableEntry *trackTableEntry = nullptr;
|
const TrackTableEntry *trackTableEntry = nullptr;
|
||||||
for (unsigned int i = 0; i < sizes; ++i)
|
unsigned int count = nTracks;
|
||||||
// For now we only seek for track entries with zero tracking value
|
for (unsigned int i = 0; i < count; i++)
|
||||||
if (trackTable[i].get_track_value () == 0.f)
|
{
|
||||||
trackTableEntry = &trackTable[0];
|
/* Note: Seems like the track entries are sorted by values. But the
|
||||||
|
* spec doesn't explicitly say that. It just mentions it in the example. */
|
||||||
|
|
||||||
// We couldn't match any, exit
|
/* For now we only seek for track entries with zero tracking value */
|
||||||
|
|
||||||
|
if (trackTable[i].get_track_value () == 0.f)
|
||||||
|
{
|
||||||
|
trackTableEntry = &trackTable[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!trackTableEntry) return 0.;
|
if (!trackTableEntry) return 0.;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Choose size.
|
||||||
|
*/
|
||||||
|
unsigned int sizes = nSizes;
|
||||||
|
if (!sizes) return 0.;
|
||||||
|
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
|
||||||
|
|
||||||
/* TODO bfind() */
|
/* TODO bfind() */
|
||||||
|
hb_array_t<Fixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||||
unsigned int size_index;
|
unsigned int size_index;
|
||||||
UnsizedArrayOf<Fixed> size_table = base+sizeTable;
|
for (size_index = 0; size_index < sizes; size_index++)
|
||||||
for (size_index = 0; size_index < sizes; ++size_index)
|
if (size_table[size_index].to_float () >= csspx)
|
||||||
if (size_table[size_index] >= fixed_size)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO(ebraminio): We don't attempt to extrapolate to larger or
|
return interpolate_at (size_index ? size_index - 1 : 0, csspx,
|
||||||
// smaller values for now but we should do, per spec
|
*trackTableEntry, base);
|
||||||
if (size_index == sizes)
|
}
|
||||||
return trackTableEntry->get_value (base, sizes - 1);
|
|
||||||
if (size_index == 0 || size_table[size_index] == fixed_size)
|
|
||||||
return trackTableEntry->get_value (base, size_index);
|
|
||||||
|
|
||||||
float s0 = size_table[size_index - 1].to_float ();
|
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||||
float s1 = size_table[size_index].to_float ();
|
{
|
||||||
float t = (csspx - s0) / (s1 - s0);
|
TRACE_SANITIZE (this);
|
||||||
return (float) t * trackTableEntry->get_value (base, size_index) +
|
return_trace (c->check_struct (this) &&
|
||||||
((float) 1.0 - t) * trackTableEntry->get_value (base, size_index - 1);
|
sizeTable.sanitize (c, base, nSizes) &&
|
||||||
|
trackTable.sanitize (c, nTracks, base, nSizes));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
|
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
|
||||||
HBUINT16 nSizes; /* Number of point sizes included in this table. */
|
HBUINT16 nSizes; /* Number of point sizes included in this table. */
|
||||||
LOffsetTo<UnsizedArrayOf<Fixed>, false>
|
LOffsetTo<UnsizedArrayOf<Fixed>, false>
|
||||||
sizeTable; /* Offset to array[nSizes] of size values. */
|
sizeTable; /* Offset from start of the tracking table to
|
||||||
|
* Array[nSizes] of size values.. */
|
||||||
UnsizedArrayOf<TrackTableEntry>
|
UnsizedArrayOf<TrackTableEntry>
|
||||||
trackTable; /* Array[nTracks] of TrackTableEntry records. */
|
trackTable; /* Array[nTracks] of TrackTableEntry records. */
|
||||||
|
|
||||||
|
@ -147,6 +170,8 @@ struct trak
|
||||||
{
|
{
|
||||||
static const hb_tag_t tableTag = HB_AAT_TAG_trak;
|
static const hb_tag_t tableTag = HB_AAT_TAG_trak;
|
||||||
|
|
||||||
|
inline bool has_data (void) const { return version.to_int () != 0; }
|
||||||
|
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -169,24 +194,24 @@ struct trak
|
||||||
{
|
{
|
||||||
const TrackData &trackData = this+horizData;
|
const TrackData &trackData = this+horizData;
|
||||||
float tracking = trackData.get_tracking (this, ptem);
|
float tracking = trackData.get_tracking (this, ptem);
|
||||||
hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2);
|
hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
|
||||||
|
hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
|
||||||
foreach_grapheme (buffer, start, end)
|
foreach_grapheme (buffer, start, end)
|
||||||
{
|
{
|
||||||
buffer->pos[start].x_offset += advance_to_add;
|
|
||||||
buffer->pos[start].x_advance += advance_to_add;
|
buffer->pos[start].x_advance += advance_to_add;
|
||||||
buffer->pos[end].x_advance += advance_to_add;
|
buffer->pos[start].x_offset += offset_to_add;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const TrackData &trackData = this+vertData;
|
const TrackData &trackData = this+vertData;
|
||||||
float tracking = trackData.get_tracking (this, ptem);
|
float tracking = trackData.get_tracking (this, ptem);
|
||||||
hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2);
|
hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
|
||||||
|
hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
|
||||||
foreach_grapheme (buffer, start, end)
|
foreach_grapheme (buffer, start, end)
|
||||||
{
|
{
|
||||||
buffer->pos[start].y_offset += advance_to_add;
|
|
||||||
buffer->pos[start].y_advance += advance_to_add;
|
buffer->pos[start].y_advance += advance_to_add;
|
||||||
buffer->pos[end].y_advance += advance_to_add;
|
buffer->pos[start].y_offset += offset_to_add;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,15 +219,17 @@ struct trak
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FixedVersion<> version; /* Version of the tracking table--currently
|
FixedVersion<> version; /* Version of the tracking table
|
||||||
* 0x00010000u for version 1.0. */
|
* (0x00010000u for version 1.0). */
|
||||||
HBUINT16 format; /* Format of the tracking table */
|
HBUINT16 format; /* Format of the tracking table (set to 0). */
|
||||||
OffsetTo<TrackData> horizData; /* TrackData for horizontal text */
|
OffsetTo<TrackData> horizData; /* Offset from start of tracking table to TrackData
|
||||||
OffsetTo<TrackData> vertData; /* TrackData for vertical text */
|
* for horizontal text (or 0 if none). */
|
||||||
|
OffsetTo<TrackData> vertData; /* Offset from start of tracking table to TrackData
|
||||||
|
* for vertical text (or 0 if none). */
|
||||||
HBUINT16 reserved; /* Reserved. Set to 0. */
|
HBUINT16 reserved; /* Reserved. Set to 0. */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_MIN (12);
|
DEFINE_SIZE_STATIC (12);
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace AAT */
|
} /* namespace AAT */
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise.
|
#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* morx/kerx/trak/ankr
|
* morx/kerx/trak
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline const AAT::morx&
|
static inline const AAT::morx&
|
||||||
|
@ -68,6 +68,26 @@ _get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr)
|
||||||
*blob = hb_ot_face_data (face)->kerx.get_blob ();
|
*blob = hb_ot_face_data (face)->kerx.get_blob ();
|
||||||
return kerx;
|
return kerx;
|
||||||
}
|
}
|
||||||
|
static inline const AAT::ankr&
|
||||||
|
_get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr)
|
||||||
|
{
|
||||||
|
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
|
||||||
|
{
|
||||||
|
if (blob)
|
||||||
|
*blob = hb_blob_get_empty ();
|
||||||
|
return Null(AAT::ankr);
|
||||||
|
}
|
||||||
|
const AAT::ankr& ankr = *(hb_ot_face_data (face)->ankr.get ());
|
||||||
|
if (blob)
|
||||||
|
*blob = hb_ot_face_data (face)->ankr.get_blob ();
|
||||||
|
return ankr;
|
||||||
|
}
|
||||||
|
static inline const AAT::trak&
|
||||||
|
_get_trak (hb_face_t *face)
|
||||||
|
{
|
||||||
|
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(AAT::trak);
|
||||||
|
return *(hb_ot_face_data (face)->trak.get ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
hb_bool_t
|
hb_bool_t
|
||||||
|
@ -103,6 +123,27 @@ hb_aat_layout_position (hb_ot_shape_plan_t *plan,
|
||||||
hb_blob_t *blob;
|
hb_blob_t *blob;
|
||||||
const AAT::kerx& kerx = _get_kerx (font->face, &blob);
|
const AAT::kerx& kerx = _get_kerx (font->face, &blob);
|
||||||
|
|
||||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
|
hb_blob_t *ankr_blob;
|
||||||
|
const AAT::ankr& ankr = _get_ankr (font->face, &ankr_blob);
|
||||||
|
|
||||||
|
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob,
|
||||||
|
ankr, ankr_blob->data + ankr_blob->length);
|
||||||
kerx.apply (&c);
|
kerx.apply (&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hb_bool_t
|
||||||
|
hb_aat_layout_has_tracking (hb_face_t *face)
|
||||||
|
{
|
||||||
|
return _get_trak (face).has_data ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hb_aat_layout_track (hb_ot_shape_plan_t *plan,
|
||||||
|
hb_font_t *font,
|
||||||
|
hb_buffer_t *buffer)
|
||||||
|
{
|
||||||
|
const AAT::trak& trak = _get_trak (font->face);
|
||||||
|
|
||||||
|
AAT::hb_aat_apply_context_t c (plan, font, buffer);
|
||||||
|
trak.apply (&c);
|
||||||
|
}
|
||||||
|
|
|
@ -47,4 +47,12 @@ hb_aat_layout_position (hb_ot_shape_plan_t *plan,
|
||||||
hb_font_t *font,
|
hb_font_t *font,
|
||||||
hb_buffer_t *buffer);
|
hb_buffer_t *buffer);
|
||||||
|
|
||||||
|
HB_INTERNAL hb_bool_t
|
||||||
|
hb_aat_layout_has_tracking (hb_face_t *face);
|
||||||
|
|
||||||
|
HB_INTERNAL void
|
||||||
|
hb_aat_layout_track (hb_ot_shape_plan_t *plan,
|
||||||
|
hb_font_t *font,
|
||||||
|
hb_buffer_t *buffer);
|
||||||
|
|
||||||
#endif /* HB_AAT_LAYOUT_HH */
|
#endif /* HB_AAT_LAYOUT_HH */
|
||||||
|
|
|
@ -1755,10 +1755,6 @@ template <typename context_t>
|
||||||
struct GPOS_accelerator_t : GPOS::accelerator_t {};
|
struct GPOS_accelerator_t : GPOS::accelerator_t {};
|
||||||
|
|
||||||
|
|
||||||
#undef attach_chain
|
|
||||||
#undef attach_type
|
|
||||||
|
|
||||||
|
|
||||||
} /* namespace OT */
|
} /* namespace OT */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -100,22 +100,23 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
|
||||||
else if (hb_aat_layout_has_positioning (face))
|
else if (hb_aat_layout_has_positioning (face))
|
||||||
plan.apply_kerx = true;
|
plan.apply_kerx = true;
|
||||||
|
|
||||||
if (plan.requested_kerning)
|
if (plan.requested_kerning && !plan.apply_kerx && !has_gpos_kern)
|
||||||
{
|
{
|
||||||
if (plan.apply_kerx)
|
/* Apparently Apple applies kerx if GPOS kern was not applied. */
|
||||||
;/* kerx supercedes kern. */
|
if (hb_aat_layout_has_positioning (face))
|
||||||
else if (!has_gpos_kern)
|
plan.apply_kerx = true;
|
||||||
{
|
if (hb_ot_layout_has_kerning (face))
|
||||||
if (hb_ot_layout_has_kerning (face))
|
plan.apply_kern = true;
|
||||||
plan.apply_kern = true;
|
else
|
||||||
else
|
plan.fallback_kerning = true;
|
||||||
plan.fallback_kerning = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
|
plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
|
||||||
if (!plan.apply_gpos)
|
if (!plan.apply_gpos && !plan.apply_kerx)
|
||||||
plan.fallback_mark_positioning = true;
|
plan.fallback_mark_positioning = true;
|
||||||
|
|
||||||
|
/* Currently we always apply trak. */
|
||||||
|
plan.apply_trak = hb_aat_layout_has_tracking (face);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -820,34 +821,39 @@ hb_ot_position_complex (const hb_ot_shape_context_t *c)
|
||||||
|
|
||||||
hb_ot_layout_position_start (c->font, c->buffer);
|
hb_ot_layout_position_start (c->font, c->buffer);
|
||||||
|
|
||||||
switch (c->plan->shaper->zero_width_marks)
|
if (!c->plan->apply_kerx)
|
||||||
{
|
switch (c->plan->shaper->zero_width_marks)
|
||||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
|
{
|
||||||
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
|
||||||
break;
|
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
|
||||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->plan->apply_gpos)
|
if (c->plan->apply_gpos)
|
||||||
c->plan->position (c->font, c->buffer);
|
c->plan->position (c->font, c->buffer);
|
||||||
else if (c->plan->apply_kerx)
|
else if (c->plan->apply_kerx)
|
||||||
hb_aat_layout_position (c->plan, c->font, c->buffer);
|
hb_aat_layout_position (c->plan, c->font, c->buffer);
|
||||||
|
|
||||||
switch (c->plan->shaper->zero_width_marks)
|
if (c->plan->apply_trak)
|
||||||
{
|
hb_aat_layout_track (c->plan, c->font, c->buffer);
|
||||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
|
|
||||||
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
if (!c->plan->apply_kerx)
|
||||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
|
switch (c->plan->shaper->zero_width_marks)
|
||||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
|
{
|
||||||
break;
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
|
||||||
}
|
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
|
||||||
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Finishing off GPOS has to follow a certain order. */
|
/* Finishing off GPOS has to follow a certain order. */
|
||||||
hb_ot_layout_position_finish_advances (c->font, c->buffer);
|
hb_ot_layout_position_finish_advances (c->font, c->buffer);
|
||||||
|
|
|
@ -50,10 +50,11 @@ struct hb_ot_shape_plan_t
|
||||||
bool fallback_kerning : 1;
|
bool fallback_kerning : 1;
|
||||||
bool fallback_mark_positioning : 1;
|
bool fallback_mark_positioning : 1;
|
||||||
|
|
||||||
bool apply_morx : 1;
|
bool apply_gpos : 1;
|
||||||
bool apply_kerx : 1;
|
bool apply_kerx : 1;
|
||||||
bool apply_kern : 1;
|
bool apply_kern : 1;
|
||||||
bool apply_gpos : 1;
|
bool apply_morx : 1;
|
||||||
|
bool apply_trak : 1;
|
||||||
|
|
||||||
|
|
||||||
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
|
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
TESTS = \
|
TESTS = \
|
||||||
|
tests/aat-trak.tests \
|
||||||
tests/arabic-fallback-shaping.tests \
|
tests/arabic-fallback-shaping.tests \
|
||||||
tests/arabic-feature-order.tests \
|
tests/arabic-feature-order.tests \
|
||||||
tests/arabic-like-joining.tests \
|
tests/arabic-like-joining.tests \
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,8 @@
|
||||||
|
../fonts/TestTRAK.ttf::U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
|
||||||
|
../fonts/TestTRAK.ttf:--font-ptem=.5:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
|
||||||
|
../fonts/TestTRAK.ttf:--font-ptem=1:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
|
||||||
|
../fonts/TestTRAK.ttf:--font-ptem=2:U+0041,U+0042,U+0043:[A.alt=0@93,0+1187|B=1@93,0+1187|C.alt=2@93,0+1187]
|
||||||
|
../fonts/TestTRAK.ttf:--font-ptem=9:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
|
||||||
|
../fonts/TestTRAK.ttf:--font-ptem=24:U+0041,U+0042,U+0043:[A.alt=0@-12,0+976|B=1@-12,0+976|C.alt=2@-12,0+976]
|
||||||
|
../fonts/TestTRAK.ttf:--font-ptem=72:U+0041,U+0042,U+0043:[A.alt=0@-50,0+900|B=1@-50,0+900|C.alt=2@-50,0+900]
|
||||||
|
../fonts/TestTRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-100,0+800|B=1@-100,0+800|C.alt=2@-100,0+800]
|
Loading…
Reference in New Issue