[harfbuzz/GSUB] towards a partially working GSUB
This commit is contained in:
parent
30bd763fa2
commit
5a0b791184
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
/* Internal API */
|
/* Internal API */
|
||||||
|
|
||||||
static HB_Error
|
/*static XXX */ HB_Error
|
||||||
hb_buffer_ensure( HB_Buffer buffer,
|
hb_buffer_ensure( HB_Buffer buffer,
|
||||||
HB_UInt size )
|
HB_UInt size )
|
||||||
{
|
{
|
||||||
|
|
|
@ -78,7 +78,7 @@ HB_BEGIN_HEADER
|
||||||
|
|
||||||
|
|
||||||
#define ALLOC(_ptr,_size) \
|
#define ALLOC(_ptr,_size) \
|
||||||
( (_ptr) = _hb_alloc( _size, &error ), error != 0 )
|
( *(void**)&(_ptr) = _hb_alloc( _size, &error ), error != 0 )
|
||||||
|
|
||||||
#define REALLOC(_ptr,_newsz) \
|
#define REALLOC(_ptr,_newsz) \
|
||||||
( (_ptr) = _hb_realloc( (_ptr), (_newsz), &error ), error != 0 )
|
( (_ptr) = _hb_realloc( (_ptr), (_newsz), &error ), error != 0 )
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
#define HB_INTERNAL static
|
#define HB_INTERNAL static
|
||||||
#include "harfbuzz-buffer.c"
|
#include "harfbuzz-buffer.c"
|
||||||
#include "harfbuzz-gdef.c"
|
|
||||||
#include "harfbuzz-gsub.c"
|
#include "harfbuzz-gsub.c"
|
||||||
#include "harfbuzz-gpos.c"
|
#include "harfbuzz-gpos.c"
|
||||||
#include "harfbuzz-impl.c"
|
#include "harfbuzz-impl.c"
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#define DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP(Type, name) \
|
#define DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP(Type, name) \
|
||||||
inline const Type& name (hb_codepoint_t glyph) { \
|
inline const Type& name (hb_codepoint_t glyph) { \
|
||||||
const Coverage &c = get_coverage (); \
|
const Coverage &c = get_coverage (); \
|
||||||
hb_ot_layout_coverage_t c_index = c.get_coverage (glyph); \
|
unsigned int c_index = c.get_coverage (glyph); \
|
||||||
return (*this)[c_index]; \
|
return (*this)[c_index]; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ struct LigCaretList {
|
||||||
DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP (LigGlyph, get_lig_glyph);
|
DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP (LigGlyph, get_lig_glyph);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* AttachPoint tables, in Coverage Index order */
|
/* LigGlyph tables, in Coverage Index order */
|
||||||
DEFINE_OFFSET_ARRAY_TYPE (LigGlyph, ligGlyph, ligGlyphCount);
|
DEFINE_OFFSET_ARRAY_TYPE (LigGlyph, ligGlyph, ligGlyphCount);
|
||||||
DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
|
DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2007,2008 Red Hat, Inc.
|
* Copyright (C) 2007,2008,2009 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This is part of HarfBuzz, an OpenType Layout engine library.
|
* This is part of HarfBuzz, an OpenType Layout engine library.
|
||||||
*
|
*
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
#include "harfbuzz-buffer-private.h" /* XXX */
|
#include "harfbuzz-buffer-private.h" /* XXX */
|
||||||
|
|
||||||
#define DEFINE_GET_GLYPH_COVERAGE(name) \
|
#define DEFINE_GET_GLYPH_COVERAGE(name) \
|
||||||
inline hb_ot_layout_coverage_t get_##name (hb_codepoint_t glyph) const { \
|
inline unsigned int get_##name (hb_codepoint_t glyph) const { \
|
||||||
const Coverage &c = get_coverage (); \
|
const Coverage &c = get_coverage (); \
|
||||||
return c.get_coverage (glyph); \
|
return c.get_coverage (glyph); \
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,12 @@
|
||||||
unsigned int context_length, \
|
unsigned int context_length, \
|
||||||
unsigned int nesting_level_left, \
|
unsigned int nesting_level_left, \
|
||||||
unsigned int lookup_flag) const
|
unsigned int lookup_flag) const
|
||||||
|
#define SUBTABLE_SUBSTITUTE_CHAIN(obj) \
|
||||||
|
obj.substitute (layout, \
|
||||||
|
buffer, \
|
||||||
|
context_length, \
|
||||||
|
nesting_level_left, \
|
||||||
|
lookup_flag)
|
||||||
|
|
||||||
struct SingleSubstFormat1 {
|
struct SingleSubstFormat1 {
|
||||||
|
|
||||||
|
@ -55,9 +61,163 @@ struct SingleSubstFormat1 {
|
||||||
DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
|
DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
|
||||||
DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
|
DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
|
||||||
|
|
||||||
|
inline bool single_substitute (hb_codepoint_t &glyph_id) const {
|
||||||
|
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
index = get_glyph_coverage (glyph_id);
|
||||||
|
if (NOT_COVERED == index)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
glyph_id += deltaGlyphID;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if ( index >= ss->ssf.ssf2.GlyphCount )
|
||||||
|
return ERR(HB_Err_Invalid_SubTable);
|
||||||
|
value = ss->ssf.ssf2.Substitute[index];
|
||||||
|
if ( REPLACE_Glyph( buffer, value, nesting_level ) )
|
||||||
|
return error;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
USHORT substFormat; /* Format identifier--format = 1 */
|
||||||
|
Offset coverage; /* Offset to Coverage table--from
|
||||||
|
* beginning of Substitution table */
|
||||||
|
SHORT deltaGlyphID; /* Add to original GlyphID to get
|
||||||
|
* substitute GlyphID */
|
||||||
|
};
|
||||||
|
ASSERT_SIZE (SingleSubstFormat1, 6);
|
||||||
|
|
||||||
|
struct SingleSubstFormat2 {
|
||||||
|
|
||||||
|
friend struct SingleSubst;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
|
||||||
|
DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
|
||||||
|
|
||||||
|
inline bool single_substitute (hb_codepoint_t &glyph_id) const {
|
||||||
|
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
index = get_glyph_coverage (glyph_id);
|
||||||
|
|
||||||
|
if (index >= glyphCount)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
glyph_id = substitute[index];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
USHORT substFormat; /* Format identifier--format = 2 */
|
||||||
|
Offset coverage; /* Offset to Coverage table--from
|
||||||
|
* beginning of Substitution table */
|
||||||
|
USHORT glyphCount; /* Number of GlyphIDs in the Substitute
|
||||||
|
* array */
|
||||||
|
GlyphID substitute[]; /* Array of substitute
|
||||||
|
* GlyphIDs--ordered by Coverage Index */
|
||||||
|
};
|
||||||
|
ASSERT_SIZE (SingleSubstFormat2, 6);
|
||||||
|
|
||||||
|
struct SingleSubst {
|
||||||
|
|
||||||
|
friend struct SubstLookupSubTable;
|
||||||
|
|
||||||
|
unsigned int get_size (void) const {
|
||||||
|
switch (u.substFormat) {
|
||||||
|
case 1: return sizeof (u.format1);
|
||||||
|
case 2: return sizeof (u.format2);
|
||||||
|
default:return sizeof (u.substFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
inline SUBTABLE_SUBSTITUTE {
|
inline SUBTABLE_SUBSTITUTE {
|
||||||
|
|
||||||
hb_codepoint_t glyph_id;
|
hb_codepoint_t glyph_id;
|
||||||
hb_ot_layout_coverage_t index;
|
unsigned int property;
|
||||||
|
|
||||||
|
HB_UNUSED (nesting_level_left);
|
||||||
|
|
||||||
|
if (HB_UNLIKELY (context_length < 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
glyph_id = IN_CURGLYPH ();
|
||||||
|
|
||||||
|
switch (u.substFormat) {
|
||||||
|
case 1: if (!u.format1.single_substitute (glyph_id)) return false;
|
||||||
|
case 2: if (!u.format2.single_substitute (glyph_id)) return false;
|
||||||
|
default:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_hb_buffer_replace_output_glyph (buffer, glyph_id, context_length == NO_CONTEXT);
|
||||||
|
|
||||||
|
if ( _hb_ot_layout_has_new_glyph_classes (layout) )
|
||||||
|
{
|
||||||
|
/* we inherit the old glyph class to the substituted glyph */
|
||||||
|
_hb_ot_layout_set_glyph_property (layout, glyph_id, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union {
|
||||||
|
USHORT substFormat; /* Format identifier */
|
||||||
|
SingleSubstFormat1 format1;
|
||||||
|
SingleSubstFormat2 format2;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
DEFINE_NULL (SingleSubst, 2);
|
||||||
|
|
||||||
|
|
||||||
|
struct Sequence {
|
||||||
|
|
||||||
|
friend struct MultipleSubstFormat1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* GlyphID tables, in Coverage Index order */
|
||||||
|
DEFINE_OFFSET_ARRAY_TYPE (GlyphID, substitute, glyphCount);
|
||||||
|
|
||||||
|
inline void set_glyph_class (hb_ot_layout_t *layout, unsigned int property) const {
|
||||||
|
unsigned int n, count = glyphCount;
|
||||||
|
|
||||||
|
for (n = 0; n < count; n++)
|
||||||
|
_hb_ot_layout_set_glyph_property (layout, substitute[n], property);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
USHORT glyphCount; /* Number of GlyphIDs in the Substitute
|
||||||
|
* array. This should always be
|
||||||
|
* greater than 0. */
|
||||||
|
GlyphID substitute[]; /* String of GlyphIDs to substitute */
|
||||||
|
};
|
||||||
|
DEFINE_NULL_ASSERT_SIZE (Sequence, 2);
|
||||||
|
|
||||||
|
struct MultipleSubstFormat1 {
|
||||||
|
|
||||||
|
friend struct MultipleSubst;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* Sequence tables, in Coverage Index order */
|
||||||
|
DEFINE_OFFSET_ARRAY_TYPE (Sequence, sequence, sequenceCount);
|
||||||
|
DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
|
||||||
|
DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
|
||||||
|
|
||||||
|
inline SUBTABLE_SUBSTITUTE {
|
||||||
|
|
||||||
|
hb_codepoint_t glyph_id;
|
||||||
|
unsigned int index;
|
||||||
unsigned int property;
|
unsigned int property;
|
||||||
|
|
||||||
HB_UNUSED (nesting_level_left);
|
HB_UNUSED (nesting_level_left);
|
||||||
|
@ -71,77 +231,27 @@ struct SingleSubstFormat1 {
|
||||||
glyph_id = IN_CURGLYPH ();
|
glyph_id = IN_CURGLYPH ();
|
||||||
|
|
||||||
index = get_glyph_coverage (glyph_id);
|
index = get_glyph_coverage (glyph_id);
|
||||||
if (-1 == index)
|
if (index >= sequenceCount)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
glyph_id += deltaGlyphID;
|
const Sequence &seq = (*this)[index];
|
||||||
_hb_buffer_replace_output_glyph (buffer, glyph_id, context_length == NO_CONTEXT);
|
_hb_buffer_add_output_glyph_ids (buffer, 1,
|
||||||
|
seq.glyphCount, seq.substitute,
|
||||||
|
0xFFFF, 0xFFFF);
|
||||||
|
|
||||||
if ( _hb_ot_layout_has_new_glyph_classes (layout) )
|
if ( _hb_ot_layout_has_new_glyph_classes (layout) )
|
||||||
{
|
{
|
||||||
/* we inherit the old glyph class to the substituted glyph */
|
/* this is a guess only ... */
|
||||||
_hb_ot_layout_set_glyph_property (layout, glyph_id, property);
|
|
||||||
|
if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
|
||||||
|
property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
|
||||||
|
|
||||||
|
seq.set_glyph_class (layout, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
switch ( ss->SubstFormat )
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
value = (IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
|
|
||||||
if ( REPLACE_Glyph( buffer, value, nesting_level ) )
|
|
||||||
return error;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
if ( index >= ss->ssf.ssf2.GlyphCount )
|
|
||||||
return ERR(HB_Err_Invalid_SubTable);
|
|
||||||
value = ss->ssf.ssf2.Substitute[index];
|
|
||||||
if ( REPLACE_Glyph( buffer, value, nesting_level ) )
|
|
||||||
return error;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return ERR(HB_Err_Invalid_SubTable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _hb_ot_layout_has_new_glyph_classes (layout) )
|
|
||||||
{
|
|
||||||
/* we inherit the old glyph class to the substituted glyph */
|
|
||||||
|
|
||||||
hb_ot_layout_set_glyph_class (layout, value, properties);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
USHORT substFormat; /* Format identifier--format = 1 */
|
|
||||||
Offset coverage; /* Offset to Coverage table--from
|
|
||||||
* beginning of Substitution table */
|
|
||||||
SHORT deltaGlyphID; /* Add to original GlyphID to get
|
|
||||||
* substitute GlyphID */
|
|
||||||
};
|
|
||||||
ASSERT_SIZE (SingleSubstFormat1, 6);
|
|
||||||
|
|
||||||
struct SingleSubstFormat2 {
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
private:
|
|
||||||
USHORT substFormat; /* Format identifier--format = 2 */
|
|
||||||
Offset coverage; /* Offset to Coverage table--from
|
|
||||||
* beginning of Substitution table */
|
|
||||||
USHORT glyphCount; /* Number of GlyphIDs in the Substitute
|
|
||||||
* array */
|
|
||||||
GlyphID substitute[]; /* Array of substitute
|
|
||||||
* GlyphIDs--ordered by Coverage Index */
|
|
||||||
};
|
|
||||||
ASSERT_SIZE (SingleSubstFormat2, 6);
|
|
||||||
|
|
||||||
struct MultipleSubstFormat1 {
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USHORT substFormat; /* Format identifier--format = 1 */
|
USHORT substFormat; /* Format identifier--format = 1 */
|
||||||
Offset coverage; /* Offset to Coverage table--from
|
Offset coverage; /* Offset to Coverage table--from
|
||||||
|
@ -155,16 +265,42 @@ struct MultipleSubstFormat1 {
|
||||||
};
|
};
|
||||||
ASSERT_SIZE (MultipleSubstFormat1, 6);
|
ASSERT_SIZE (MultipleSubstFormat1, 6);
|
||||||
|
|
||||||
struct Sequence {
|
struct MultipleSubst {
|
||||||
|
|
||||||
|
unsigned int get_size (void) const {
|
||||||
|
switch (u.substFormat) {
|
||||||
|
case 1: return sizeof (u.format1);
|
||||||
|
default:return sizeof (u.substFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline SUBTABLE_SUBSTITUTE {
|
||||||
|
switch (u.substFormat) {
|
||||||
|
case 1: return SUBTABLE_SUBSTITUTE_CHAIN(u.format1);
|
||||||
|
default:return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union {
|
||||||
|
USHORT substFormat; /* Format identifier */
|
||||||
|
MultipleSubstFormat1 format1;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
DEFINE_NULL (MultipleSubst, 2);
|
||||||
|
|
||||||
|
|
||||||
|
struct AlternateSet {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USHORT glyphCount; /* Number of GlyphIDs in the Substitute
|
USHORT glyphCount; /* Number of GlyphIDs in the Alternate
|
||||||
* array. This should always be
|
* array */
|
||||||
* greater than 0. */
|
GlyphID alternate[]; /* Array of alternate GlyphIDs--in
|
||||||
GlyphID substitute[]; /* String of GlyphIDs to substitute */
|
* arbitrary order */
|
||||||
};
|
};
|
||||||
DEFINE_NULL_ASSERT_SIZE (Sequence, 2);
|
DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2);
|
||||||
|
|
||||||
struct AlternateSubstFormat1 {
|
struct AlternateSubstFormat1 {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
@ -181,16 +317,30 @@ struct AlternateSubstFormat1 {
|
||||||
};
|
};
|
||||||
ASSERT_SIZE (AlternateSubstFormat1, 6);
|
ASSERT_SIZE (AlternateSubstFormat1, 6);
|
||||||
|
|
||||||
struct AlternateSet {
|
|
||||||
|
struct Ligature {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USHORT glyphCount; /* Number of GlyphIDs in the Alternate
|
GlyphID ligGlyph; /* GlyphID of ligature to substitute */
|
||||||
* array */
|
USHORT compCount; /* Number of components in the ligature */
|
||||||
GlyphID alternate[]; /* Array of alternate GlyphIDs--in
|
GlyphID component[]; /* Array of component GlyphIDs--start
|
||||||
* arbitrary order */
|
* with the second component--ordered
|
||||||
|
* in writing direction */
|
||||||
};
|
};
|
||||||
DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2);
|
DEFINE_NULL_ASSERT_SIZE (Ligature, 4);
|
||||||
|
|
||||||
|
struct LigatureSet {
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
private:
|
||||||
|
USHORT ligatureCount; /* Number of Ligature tables */
|
||||||
|
Offset ligature[]; /* Array of offsets to Ligature
|
||||||
|
* tables--from beginning of
|
||||||
|
* LigatureSet table--ordered by
|
||||||
|
* preference */
|
||||||
|
};
|
||||||
|
DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2);
|
||||||
|
|
||||||
struct LigatureSubstFormat1 {
|
struct LigatureSubstFormat1 {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
@ -207,29 +357,6 @@ struct LigatureSubstFormat1 {
|
||||||
};
|
};
|
||||||
ASSERT_SIZE (LigatureSubstFormat1, 6);
|
ASSERT_SIZE (LigatureSubstFormat1, 6);
|
||||||
|
|
||||||
struct LigatureSet {
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
private:
|
|
||||||
USHORT ligatureCount; /* Number of Ligature tables */
|
|
||||||
Offset ligature[]; /* Array of offsets to Ligature
|
|
||||||
* tables--from beginning of
|
|
||||||
* LigatureSet table--ordered by
|
|
||||||
* preference */
|
|
||||||
};
|
|
||||||
DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2);
|
|
||||||
|
|
||||||
struct Ligature {
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
private:
|
|
||||||
GlyphID ligGlyph; /* GlyphID of ligature to substitute */
|
|
||||||
USHORT compCount; /* Number of components in the ligature */
|
|
||||||
GlyphID component[]; /* Array of component GlyphIDs--start
|
|
||||||
* with the second component--ordered
|
|
||||||
* in writing direction */
|
|
||||||
};
|
|
||||||
DEFINE_NULL_ASSERT_SIZE (Ligature, 4);
|
|
||||||
|
|
||||||
struct SubstLookupRecord {
|
struct SubstLookupRecord {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
@ -533,6 +660,17 @@ ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
|
||||||
* SubstLookup
|
* SubstLookup
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GSUB_Single = 1,
|
||||||
|
GSUB_Multiple = 2,
|
||||||
|
GSUB_Alternate = 3,
|
||||||
|
GSUB_Ligature = 4,
|
||||||
|
GSUB_Context = 5,
|
||||||
|
GSUB_ChainingContext = 6,
|
||||||
|
GSUB_Extension = 7,
|
||||||
|
GSUB_ReverseChainingContextSingle = 8,
|
||||||
|
};
|
||||||
|
|
||||||
struct SubstLookupSubTable {
|
struct SubstLookupSubTable {
|
||||||
DEFINE_NON_INSTANTIABLE(SubstLookupSubTable);
|
DEFINE_NON_INSTANTIABLE(SubstLookupSubTable);
|
||||||
|
|
||||||
|
@ -543,14 +681,14 @@ struct SubstLookupSubTable {
|
||||||
// case 1: return u.format1.get_size ();
|
// case 1: return u.format1.get_size ();
|
||||||
// case 2: return u.format2.get_size ();
|
// case 2: return u.format2.get_size ();
|
||||||
/*
|
/*
|
||||||
case Single:
|
case GSUB_Single:
|
||||||
case Multiple:
|
case GSUB_Multiple:
|
||||||
case Alternate:
|
case GSUB_Alternate:
|
||||||
case Ligature:
|
case GSUB_Ligature:
|
||||||
case Context:
|
case GSUB_Context:
|
||||||
case ChainingContext:
|
case GSUB_ChainingContext:
|
||||||
case Extension:
|
case GSUB_Extension:
|
||||||
case ReverseChainingContextSingle:
|
case GSUB_ReverseChainingContextSingle:
|
||||||
*/
|
*/
|
||||||
default:return sizeof (LookupSubTable);
|
default:return sizeof (LookupSubTable);
|
||||||
}
|
}
|
||||||
|
@ -562,13 +700,25 @@ struct SubstLookupSubTable {
|
||||||
unsigned int nesting_level_left,
|
unsigned int nesting_level_left,
|
||||||
unsigned int lookup_type,
|
unsigned int lookup_type,
|
||||||
unsigned int lookup_flag) const {
|
unsigned int lookup_flag) const {
|
||||||
|
switch (lookup_type) {
|
||||||
|
case GSUB_Single: return SUBTABLE_SUBSTITUTE_CHAIN (u.singleSubst);
|
||||||
|
/*
|
||||||
|
case GSUB_Multiple:
|
||||||
|
case GSUB_Alternate:
|
||||||
|
case GSUB_Ligature:
|
||||||
|
case GSUB_Context:
|
||||||
|
case GSUB_ChainingContext:
|
||||||
|
case GSUB_Extension:
|
||||||
|
case GSUB_ReverseChainingContextSingle:
|
||||||
|
*/
|
||||||
|
default:return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
union {
|
union {
|
||||||
USHORT substFormat;
|
USHORT substFormat;
|
||||||
CoverageFormat1 format1;
|
SingleSubst singleSubst;
|
||||||
CoverageFormat2 format2;
|
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -576,25 +726,16 @@ struct SubstLookup : Lookup {
|
||||||
|
|
||||||
DEFINE_NON_INSTANTIABLE(SubstLookup);
|
DEFINE_NON_INSTANTIABLE(SubstLookup);
|
||||||
|
|
||||||
static const unsigned int Single = 1;
|
|
||||||
static const unsigned int Multiple = 2;
|
|
||||||
static const unsigned int Alternate = 3;
|
|
||||||
static const unsigned int Ligature = 4;
|
|
||||||
static const unsigned int Context = 5;
|
|
||||||
static const unsigned int ChainingContext = 6;
|
|
||||||
static const unsigned int Extension = 7;
|
|
||||||
static const unsigned int ReverseChainingContextSingle = 8;
|
|
||||||
|
|
||||||
inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
|
inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
|
||||||
return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
|
return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Like get_type(), but looks through extension lookups.
|
/* Like get_type(), but looks through extension lookups.
|
||||||
* Never returns SubstLookup::Extension */
|
* Never returns Extension */
|
||||||
inline unsigned int get_effective_type (void) const {
|
inline unsigned int get_effective_type (void) const {
|
||||||
unsigned int type = get_type ();
|
unsigned int type = get_type ();
|
||||||
|
|
||||||
if (HB_UNLIKELY (type == Extension)) {
|
if (HB_UNLIKELY (type == GSUB_Extension)) {
|
||||||
/* Return lookup type of first extension subtable.
|
/* Return lookup type of first extension subtable.
|
||||||
* The spec says all of them should have the same type.
|
* The spec says all of them should have the same type.
|
||||||
* XXX check for that somehow */
|
* XXX check for that somehow */
|
||||||
|
@ -606,15 +747,16 @@ struct SubstLookup : Lookup {
|
||||||
|
|
||||||
inline bool is_reverse (void) const {
|
inline bool is_reverse (void) const {
|
||||||
switch (get_effective_type ()) {
|
switch (get_effective_type ()) {
|
||||||
case ReverseChainingContextSingle: return true;
|
case GSUB_ReverseChainingContextSingle: return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool substitute (hb_ot_layout_t *layout,
|
inline bool substitute_once (hb_ot_layout_t *layout,
|
||||||
hb_buffer_t *buffer,
|
hb_buffer_t *buffer,
|
||||||
unsigned int context_length,
|
unsigned int context_length,
|
||||||
unsigned int nesting_level_left) const {
|
unsigned int nesting_level_left) const {
|
||||||
|
|
||||||
unsigned int lookup_type = get_type ();
|
unsigned int lookup_type = get_type ();
|
||||||
unsigned int lookup_flag = get_flag ();
|
unsigned int lookup_flag = get_flag ();
|
||||||
|
|
||||||
|
@ -630,6 +772,47 @@ struct SubstLookup : Lookup {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool substitute_string (hb_ot_layout_t *layout,
|
||||||
|
hb_buffer_t *buffer,
|
||||||
|
hb_ot_layout_feature_mask_t mask) const {
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (!is_reverse ()) {
|
||||||
|
|
||||||
|
/* in/out forward substitution */
|
||||||
|
_hb_buffer_clear_output (buffer);
|
||||||
|
buffer->in_pos = 0;
|
||||||
|
while (buffer->in_pos < buffer->in_length) {
|
||||||
|
|
||||||
|
if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
|
||||||
|
substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
|
||||||
|
ret = true;
|
||||||
|
else
|
||||||
|
_hb_buffer_copy_output_glyph (buffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
_hb_buffer_swap (buffer);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* in-place backward substitution */
|
||||||
|
buffer->in_pos = buffer->in_length - 1;
|
||||||
|
do {
|
||||||
|
|
||||||
|
if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
|
||||||
|
substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
|
||||||
|
ret = true;
|
||||||
|
else
|
||||||
|
buffer->in_pos--;
|
||||||
|
|
||||||
|
} while (buffer->in_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
DEFINE_NULL_ALIAS (SubstLookup, Lookup);
|
DEFINE_NULL_ALIAS (SubstLookup, Lookup);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
|
|
||||||
#define NO_INDEX ((unsigned int) 0xFFFF)
|
#define NO_INDEX ((unsigned int) 0xFFFF)
|
||||||
#define NO_CONTEXT ((unsigned int) -1)
|
#define NO_CONTEXT ((unsigned int) -1)
|
||||||
|
#define NOT_COVERED ((unsigned int) -1)
|
||||||
|
#define MAX_NESTING_LEVEL 32
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Int types
|
* Int types
|
||||||
|
@ -717,16 +720,16 @@ struct CoverageFormat1 {
|
||||||
/* GlyphIDs, in sorted numerical order */
|
/* GlyphIDs, in sorted numerical order */
|
||||||
DEFINE_ARRAY_TYPE (GlyphID, glyphArray, glyphCount);
|
DEFINE_ARRAY_TYPE (GlyphID, glyphArray, glyphCount);
|
||||||
|
|
||||||
inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
|
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const {
|
||||||
GlyphID gid;
|
GlyphID gid;
|
||||||
if (HB_UNLIKELY (glyph_id > 65535))
|
if (HB_UNLIKELY (glyph_id > 65535))
|
||||||
return -1;
|
return NOT_COVERED;
|
||||||
gid = glyph_id;
|
gid = glyph_id;
|
||||||
// TODO: bsearch
|
// TODO: bsearch
|
||||||
for (unsigned int i = 0; i < glyphCount; i++)
|
for (unsigned int i = 0; i < glyphCount; i++)
|
||||||
if (gid == glyphArray[i])
|
if (gid == glyphArray[i])
|
||||||
return i;
|
return i;
|
||||||
return -1;
|
return NOT_COVERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -741,10 +744,10 @@ struct CoverageRangeRecord {
|
||||||
friend struct CoverageFormat2;
|
friend struct CoverageFormat2;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
|
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const {
|
||||||
if (glyph_id >= start && glyph_id <= end)
|
if (glyph_id >= start && glyph_id <= end)
|
||||||
return startCoverageIndex + (glyph_id - start);
|
return startCoverageIndex + (glyph_id - start);
|
||||||
return -1;
|
return NOT_COVERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -763,14 +766,14 @@ struct CoverageFormat2 {
|
||||||
/* CoverageRangeRecords, in sorted numerical start order */
|
/* CoverageRangeRecords, in sorted numerical start order */
|
||||||
DEFINE_ARRAY_TYPE (CoverageRangeRecord, rangeRecord, rangeCount);
|
DEFINE_ARRAY_TYPE (CoverageRangeRecord, rangeRecord, rangeCount);
|
||||||
|
|
||||||
inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
|
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const {
|
||||||
// TODO: bsearch
|
// TODO: bsearch
|
||||||
for (unsigned int i = 0; i < rangeCount; i++) {
|
for (unsigned int i = 0; i < rangeCount; i++) {
|
||||||
int coverage = rangeRecord[i].get_coverage (glyph_id);
|
int coverage = rangeRecord[i].get_coverage (glyph_id);
|
||||||
if (coverage >= 0)
|
if (coverage >= 0)
|
||||||
return coverage;
|
return coverage;
|
||||||
}
|
}
|
||||||
return -1;
|
return NOT_COVERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -793,11 +796,11 @@ struct Coverage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
|
unsigned int get_coverage (hb_codepoint_t glyph_id) const {
|
||||||
switch (u.coverageFormat) {
|
switch (u.coverageFormat) {
|
||||||
case 1: return u.format1.get_coverage(glyph_id);
|
case 1: return u.format1.get_coverage(glyph_id);
|
||||||
case 2: return u.format2.get_coverage(glyph_id);
|
case 2: return u.format2.get_coverage(glyph_id);
|
||||||
default:return -1;
|
default:return NOT_COVERED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,4 +993,14 @@ struct GSUBGPOS {
|
||||||
};
|
};
|
||||||
DEFINE_NULL_ASSERT_SIZE (GSUBGPOS, 10);
|
DEFINE_NULL_ASSERT_SIZE (GSUBGPOS, 10);
|
||||||
|
|
||||||
|
/* XXX */
|
||||||
|
#include "harfbuzz-impl.h"
|
||||||
|
HB_INTERNAL HB_Error
|
||||||
|
_hb_buffer_add_output_glyph_ids( HB_Buffer buffer,
|
||||||
|
HB_UShort num_in,
|
||||||
|
HB_UShort num_out,
|
||||||
|
const GlyphID *glyph_data,
|
||||||
|
HB_UShort component,
|
||||||
|
HB_UShort ligID );
|
||||||
|
|
||||||
#endif /* HB_OT_LAYOUT_OPEN_PRIVATE_H */
|
#endif /* HB_OT_LAYOUT_OPEN_PRIVATE_H */
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned int hb_ot_layout_class_t;
|
typedef unsigned int hb_ot_layout_class_t;
|
||||||
typedef int hb_ot_layout_coverage_t; /* -1 is not covered, >= 0 otherwise */
|
|
||||||
|
|
||||||
/* XXX #define HB_OT_LAYOUT_INTERNAL static */
|
/* XXX #define HB_OT_LAYOUT_INTERNAL static */
|
||||||
#define HB_OT_LAYOUT_INTERNAL
|
#define HB_OT_LAYOUT_INTERNAL
|
||||||
|
@ -64,6 +63,11 @@ _hb_ot_layout_check_glyph_property (hb_ot_layout_t *layout,
|
||||||
unsigned int lookup_flags,
|
unsigned int lookup_flags,
|
||||||
unsigned int *property);
|
unsigned int *property);
|
||||||
|
|
||||||
|
/* XXX */
|
||||||
|
HB_Error
|
||||||
|
hb_buffer_ensure( HB_Buffer buffer,
|
||||||
|
HB_UInt size );
|
||||||
|
|
||||||
HB_END_DECLS();
|
HB_END_DECLS();
|
||||||
|
|
||||||
#endif /* HB_OT_LAYOUT_PRIVATE_H */
|
#endif /* HB_OT_LAYOUT_PRIVATE_H */
|
||||||
|
|
|
@ -544,42 +544,82 @@ hb_ot_layout_substitute_lookup (hb_ot_layout_t *layout,
|
||||||
{
|
{
|
||||||
const GSUB &gsub = *(layout->gsub);
|
const GSUB &gsub = *(layout->gsub);
|
||||||
const SubstLookup &l = gsub.get_lookup (lookup_index);
|
const SubstLookup &l = gsub.get_lookup (lookup_index);
|
||||||
unsigned int lookup_type = l.get_type ();
|
|
||||||
unsigned int nesting_level_left = HB_OT_LAYOUT_MAX_NESTING_LEVEL;
|
|
||||||
unsigned int context_length = NO_CONTEXT;
|
|
||||||
bool handled, ret = false;
|
|
||||||
|
|
||||||
if (!l.is_reverse ()) {
|
return l.substitute_string (layout, buffer, mask);
|
||||||
|
|
||||||
/* in/out forward substitution */
|
|
||||||
_hb_buffer_clear_output (buffer);
|
|
||||||
buffer->in_pos = 0;
|
|
||||||
while (buffer->in_pos < buffer->in_length) {
|
|
||||||
|
|
||||||
if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
|
|
||||||
l.substitute (layout, buffer, context_length, nesting_level_left))
|
|
||||||
ret = true;
|
|
||||||
else
|
|
||||||
_hb_buffer_copy_output_glyph (buffer);
|
|
||||||
|
|
||||||
}
|
|
||||||
_hb_buffer_swap (buffer);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* in-place backward substitution */
|
|
||||||
buffer->in_pos = buffer->in_length - 1;
|
|
||||||
do {
|
|
||||||
|
|
||||||
if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
|
|
||||||
l.substitute (layout, buffer, context_length, nesting_level_left))
|
|
||||||
ret = true;
|
|
||||||
else
|
|
||||||
buffer->in_pos--;
|
|
||||||
|
|
||||||
} while (buffer->in_pos);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* XXX dupped, until he old code can be removed */
|
||||||
|
|
||||||
|
static HB_Error
|
||||||
|
hb_buffer_duplicate_out_buffer( HB_Buffer buffer )
|
||||||
|
{
|
||||||
|
if ( !buffer->alt_string )
|
||||||
|
{
|
||||||
|
HB_Error error;
|
||||||
|
|
||||||
|
if ( ALLOC_ARRAY( buffer->alt_string, buffer->allocated, HB_GlyphItemRec ) )
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->out_string = buffer->alt_string;
|
||||||
|
memcpy( buffer->out_string, buffer->in_string, buffer->out_length * sizeof (buffer->out_string[0]) );
|
||||||
|
buffer->separate_out = TRUE;
|
||||||
|
|
||||||
|
return HB_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HB_INTERNAL HB_Error
|
||||||
|
_hb_buffer_add_output_glyph_ids( HB_Buffer buffer,
|
||||||
|
HB_UShort num_in,
|
||||||
|
HB_UShort num_out,
|
||||||
|
const GlyphID *glyph_data,
|
||||||
|
HB_UShort component,
|
||||||
|
HB_UShort ligID )
|
||||||
|
{
|
||||||
|
HB_Error error;
|
||||||
|
HB_UShort i;
|
||||||
|
HB_UInt properties;
|
||||||
|
HB_UInt cluster;
|
||||||
|
|
||||||
|
error = hb_buffer_ensure( buffer, buffer->out_pos + num_out );
|
||||||
|
if ( error )
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if ( !buffer->separate_out )
|
||||||
|
{
|
||||||
|
error = hb_buffer_duplicate_out_buffer( buffer );
|
||||||
|
if ( error )
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties = buffer->in_string[buffer->in_pos].properties;
|
||||||
|
cluster = buffer->in_string[buffer->in_pos].cluster;
|
||||||
|
if ( component == 0xFFFF )
|
||||||
|
component = buffer->in_string[buffer->in_pos].component;
|
||||||
|
if ( ligID == 0xFFFF )
|
||||||
|
ligID = buffer->in_string[buffer->in_pos].ligID;
|
||||||
|
|
||||||
|
for ( i = 0; i < num_out; i++ )
|
||||||
|
{
|
||||||
|
HB_GlyphItem item = &buffer->out_string[buffer->out_pos + i];
|
||||||
|
|
||||||
|
item->gindex = glyph_data[i];
|
||||||
|
item->properties = properties;
|
||||||
|
item->cluster = cluster;
|
||||||
|
item->component = component;
|
||||||
|
item->ligID = ligID;
|
||||||
|
item->gproperty = HB_GLYPH_PROPERTY_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->in_pos += num_in;
|
||||||
|
buffer->out_pos += num_out;
|
||||||
|
|
||||||
|
buffer->out_length = buffer->out_pos;
|
||||||
|
|
||||||
|
return HB_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,8 +93,6 @@ typedef enum {
|
||||||
|
|
||||||
typedef uint32_t hb_ot_layout_feature_mask_t;
|
typedef uint32_t hb_ot_layout_feature_mask_t;
|
||||||
|
|
||||||
#define HB_OT_LAYOUT_MAX_NESTING_LEVEL 100
|
|
||||||
|
|
||||||
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX ((unsigned int) 0xFFFF)
|
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX ((unsigned int) 0xFFFF)
|
||||||
#define HB_OT_LAYOUT_NO_FEATURE_INDEX ((unsigned int) 0xFFFF)
|
#define HB_OT_LAYOUT_NO_FEATURE_INDEX ((unsigned int) 0xFFFF)
|
||||||
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX ((unsigned int) 0xFFFF)
|
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX ((unsigned int) 0xFFFF)
|
||||||
|
|
Loading…
Reference in New Issue