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:
Nikolay Sivov 2019-01-31 11:35:29 +03:00 committed by Alexandre Julliard
parent b57db6f8fe
commit b2d6fbe100
1 changed files with 209 additions and 18 deletions

View File

@ -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