dwrite: Add a helper to apply positional lookup.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b57db6f8fe
commit
b2d6fbe100
|
@ -424,6 +424,19 @@ struct gpos_gsub_header
|
||||||
WORD lookup_list;
|
WORD lookup_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum gpos_lookup_type
|
||||||
|
{
|
||||||
|
GPOS_LOOKUP_SINGLE_ADJUSTMENT = 1,
|
||||||
|
GPOS_LOOKUP_PAIR_ADJUSTMENT = 2,
|
||||||
|
GPOS_LOOKUP_CURSIVE_ATTACHMENT = 3,
|
||||||
|
GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT = 4,
|
||||||
|
GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT = 5,
|
||||||
|
GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT = 6,
|
||||||
|
GPOS_LOOKUP_CONTEXTUAL_POSITION = 7,
|
||||||
|
GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION = 8,
|
||||||
|
GPOS_LOOKUP_EXTENSION_POSITION = 9,
|
||||||
|
};
|
||||||
|
|
||||||
enum OPENTYPE_PLATFORM_ID
|
enum OPENTYPE_PLATFORM_ID
|
||||||
{
|
{
|
||||||
OPENTYPE_PLATFORM_UNICODE = 0,
|
OPENTYPE_PLATFORM_UNICODE = 0,
|
||||||
|
@ -433,6 +446,13 @@ enum OPENTYPE_PLATFORM_ID
|
||||||
OPENTYPE_PLATFORM_CUSTOM
|
OPENTYPE_PLATFORM_CUSTOM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ot_gpos_extensionpos_format1
|
||||||
|
{
|
||||||
|
WORD format;
|
||||||
|
WORD lookup_type;
|
||||||
|
DWORD extension_offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct ot_feature
|
struct ot_feature
|
||||||
{
|
{
|
||||||
WORD feature_params;
|
WORD feature_params;
|
||||||
|
@ -440,17 +460,19 @@ struct ot_feature
|
||||||
WORD lookuplist_index[1];
|
WORD lookuplist_index[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
struct ot_lookup_list
|
||||||
WORD LookupCount;
|
{
|
||||||
WORD Lookup[1];
|
WORD lookup_count;
|
||||||
} OT_LookupList;
|
WORD lookup[1];
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
struct ot_lookup_table
|
||||||
WORD LookupType;
|
{
|
||||||
WORD LookupFlag;
|
WORD lookup_type;
|
||||||
WORD SubTableCount;
|
WORD flags;
|
||||||
WORD SubTable[1];
|
WORD subtable_count;
|
||||||
} OT_LookupTable;
|
WORD subtable[1];
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
WORD SubstFormat;
|
WORD SubstFormat;
|
||||||
|
@ -2166,7 +2188,7 @@ BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
|
||||||
{
|
{
|
||||||
const struct gpos_gsub_header *header;
|
const struct gpos_gsub_header *header;
|
||||||
const struct ot_feature_list *featurelist;
|
const struct ot_feature_list *featurelist;
|
||||||
const OT_LookupList *lookup_list;
|
const struct ot_lookup_list *lookup_list;
|
||||||
BOOL exists = FALSE, ret = FALSE;
|
BOOL exists = FALSE, ret = FALSE;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
const void *data;
|
const void *data;
|
||||||
|
@ -2180,14 +2202,14 @@ BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
|
||||||
|
|
||||||
header = data;
|
header = data;
|
||||||
featurelist = (struct ot_feature_list *)((BYTE*)header + GET_BE_WORD(header->feature_list));
|
featurelist = (struct ot_feature_list *)((BYTE*)header + GET_BE_WORD(header->feature_list));
|
||||||
lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->lookup_list));
|
lookup_list = (const struct ot_lookup_list *)((BYTE*)header + GET_BE_WORD(header->lookup_list));
|
||||||
|
|
||||||
for (i = 0; i < GET_BE_WORD(featurelist->feature_count); i++) {
|
for (i = 0; i < GET_BE_WORD(featurelist->feature_count); i++) {
|
||||||
if (featurelist->features[i].tag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
|
if (featurelist->features[i].tag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
|
||||||
const struct ot_feature *feature = (const struct ot_feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->features[i].offset));
|
const struct ot_feature *feature = (const struct ot_feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->features[i].offset));
|
||||||
UINT16 lookup_count = GET_BE_WORD(feature->lookup_count), index, count, type;
|
UINT16 lookup_count = GET_BE_WORD(feature->lookup_count), index, count, type;
|
||||||
const GSUB_SingleSubstFormat2 *subst2;
|
const GSUB_SingleSubstFormat2 *subst2;
|
||||||
const OT_LookupTable *lookup_table;
|
const struct ot_lookup_table *lookup_table;
|
||||||
UINT32 offset;
|
UINT32 offset;
|
||||||
|
|
||||||
if (lookup_count == 0)
|
if (lookup_count == 0)
|
||||||
|
@ -2196,17 +2218,17 @@ BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
|
||||||
for (j = 0; j < lookup_count; ++j) {
|
for (j = 0; j < lookup_count; ++j) {
|
||||||
/* check if lookup is empty */
|
/* check if lookup is empty */
|
||||||
index = GET_BE_WORD(feature->lookuplist_index[j]);
|
index = GET_BE_WORD(feature->lookuplist_index[j]);
|
||||||
lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
|
lookup_table = (const struct ot_lookup_table *)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->lookup[index]));
|
||||||
|
|
||||||
type = GET_BE_WORD(lookup_table->LookupType);
|
type = GET_BE_WORD(lookup_table->lookup_type);
|
||||||
if (type != GSUB_LOOKUP_SINGLE_SUBST && type != GSUB_LOOKUP_EXTENSION_SUBST)
|
if (type != GSUB_LOOKUP_SINGLE_SUBST && type != GSUB_LOOKUP_EXTENSION_SUBST)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
count = GET_BE_WORD(lookup_table->SubTableCount);
|
count = GET_BE_WORD(lookup_table->subtable_count);
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
offset = GET_BE_WORD(lookup_table->SubTable[0]);
|
offset = GET_BE_WORD(lookup_table->subtable[0]);
|
||||||
if (type == GSUB_LOOKUP_EXTENSION_SUBST) {
|
if (type == GSUB_LOOKUP_EXTENSION_SUBST) {
|
||||||
const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
|
const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
|
||||||
if (GET_BE_WORD(ext->SubstFormat) == 1)
|
if (GET_BE_WORD(ext->SubstFormat) == 1)
|
||||||
|
@ -2497,9 +2519,178 @@ DWORD opentype_layout_find_language(const struct scriptshaping_cache *cache, DWO
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct lookup
|
||||||
|
{
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int subtable_count;
|
||||||
|
unsigned int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct glyph_iterator
|
||||||
|
{
|
||||||
|
const struct scriptshaping_context *context;
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int pos;
|
||||||
|
unsigned int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void glyph_iterator_init(const struct scriptshaping_context *context, unsigned int flags, unsigned int pos,
|
||||||
|
unsigned int len, struct glyph_iterator *iter)
|
||||||
|
{
|
||||||
|
iter->context = context;
|
||||||
|
iter->flags = flags;
|
||||||
|
iter->pos = pos;
|
||||||
|
iter->len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL glyph_iterator_match(const struct glyph_iterator *iter)
|
||||||
|
{
|
||||||
|
/* FIXME: implement class matching */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_context *context,
|
||||||
|
struct glyph_iterator *iter, const struct lookup *lookup)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_context *context,
|
||||||
|
struct glyph_iterator *iter, const struct lookup *lookup)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_context *context,
|
||||||
|
struct glyph_iterator *iter, const struct lookup *lookup)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(const struct scriptshaping_context *context,
|
||||||
|
struct glyph_iterator *iter, const struct lookup *lookup)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(const struct scriptshaping_context *context,
|
||||||
|
struct glyph_iterator *iter, const struct lookup *lookup)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(const struct scriptshaping_context *context,
|
||||||
|
struct glyph_iterator *iter, const struct lookup *lookup)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL opentype_layout_apply_gpos_contextual_positioning(const struct scriptshaping_context *context,
|
||||||
|
struct glyph_iterator *iter, const struct lookup *lookup)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL opentype_layout_apply_gpos_chaining_contextual_positioning(const struct scriptshaping_context *context,
|
||||||
|
struct glyph_iterator *iter, const struct lookup *lookup)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *context, int lookup_index)
|
static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *context, int lookup_index)
|
||||||
{
|
{
|
||||||
/* FIXME: stub */
|
struct scriptshaping_cache *cache = context->cache;
|
||||||
|
const struct ot_lookup_table *lookup_table;
|
||||||
|
struct glyph_iterator iter;
|
||||||
|
struct lookup lookup;
|
||||||
|
WORD lookup_type;
|
||||||
|
|
||||||
|
lookup.offset = table_read_be_word(&cache->gpos.table, cache->gpos.lookup_list +
|
||||||
|
FIELD_OFFSET(struct ot_lookup_list, lookup[lookup_index]));
|
||||||
|
if (!lookup.offset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lookup.offset += cache->gpos.lookup_list;
|
||||||
|
|
||||||
|
if (!(lookup_table = table_read_ensure(&cache->gpos.table, lookup.offset, sizeof(*lookup_table))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lookup.subtable_count = GET_BE_WORD(lookup_table->subtable_count);
|
||||||
|
if (!lookup.subtable_count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lookup_type = GET_BE_WORD(lookup_table->lookup_type);
|
||||||
|
if (lookup_type == GPOS_LOOKUP_EXTENSION_POSITION)
|
||||||
|
{
|
||||||
|
const struct ot_gpos_extensionpos_format1 *extension = table_read_ensure(&cache->gpos.table,
|
||||||
|
lookup.offset + GET_BE_WORD(lookup_table->subtable[0]), sizeof(*extension));
|
||||||
|
WORD format;
|
||||||
|
|
||||||
|
if (!extension)
|
||||||
|
return;
|
||||||
|
|
||||||
|
format = GET_BE_WORD(extension->format);
|
||||||
|
if (format != 1)
|
||||||
|
{
|
||||||
|
WARN("Unexpected extension table format %u.\n", format);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup_type = GET_BE_WORD(extension->lookup_type);
|
||||||
|
}
|
||||||
|
lookup.flags = GET_BE_WORD(lookup_table->flags);
|
||||||
|
|
||||||
|
glyph_iterator_init(context, lookup.flags, 0, context->glyph_count, &iter);
|
||||||
|
|
||||||
|
while (iter.pos < context->glyph_count)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
if (!glyph_iterator_match(&iter))
|
||||||
|
{
|
||||||
|
++iter.pos;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (lookup_type)
|
||||||
|
{
|
||||||
|
case GPOS_LOOKUP_SINGLE_ADJUSTMENT:
|
||||||
|
ret = opentype_layout_apply_gpos_single_adjustment(context, &iter, &lookup);
|
||||||
|
break;
|
||||||
|
case GPOS_LOOKUP_PAIR_ADJUSTMENT:
|
||||||
|
ret = opentype_layout_apply_gpos_pair_adjustment(context, &iter, &lookup);
|
||||||
|
break;
|
||||||
|
case GPOS_LOOKUP_CURSIVE_ATTACHMENT:
|
||||||
|
ret = opentype_layout_apply_gpos_cursive_attachment(context, &iter, &lookup);
|
||||||
|
break;
|
||||||
|
case GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT:
|
||||||
|
ret = opentype_layout_apply_gpos_mark_to_base_attachment(context, &iter, &lookup);
|
||||||
|
break;
|
||||||
|
case GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT:
|
||||||
|
ret = opentype_layout_apply_gpos_mark_to_lig_attachment(context, &iter, &lookup);
|
||||||
|
break;
|
||||||
|
case GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT:
|
||||||
|
ret = opentype_layout_apply_gpos_mark_to_mark_attachment(context, &iter, &lookup);
|
||||||
|
break;
|
||||||
|
case GPOS_LOOKUP_CONTEXTUAL_POSITION:
|
||||||
|
ret = opentype_layout_apply_gpos_contextual_positioning(context, &iter, &lookup);
|
||||||
|
break;
|
||||||
|
case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION:
|
||||||
|
ret = opentype_layout_apply_gpos_chaining_contextual_positioning(context, &iter, &lookup);
|
||||||
|
break;
|
||||||
|
case GPOS_LOOKUP_EXTENSION_POSITION:
|
||||||
|
WARN("Recursive extension lookup.\n");
|
||||||
|
ret = FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN("Unknown lookup type %u.\n", lookup_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some lookups update position after making changes. */
|
||||||
|
if (!ret)
|
||||||
|
++iter.pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lookups
|
struct lookups
|
||||||
|
|
Loading…
Reference in New Issue