dwrite: Implement HasVerticalGlyphVariants().

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2016-07-05 12:55:54 +03:00 committed by Alexandre Julliard
parent 90bcff0eae
commit e30607fdb0
4 changed files with 346 additions and 12 deletions

View file

@ -229,6 +229,7 @@ extern UINT32 opentype_get_cpal_palettecount(const void*) DECLSPEC_HIDDEN;
extern UINT32 opentype_get_cpal_paletteentrycount(const void*) DECLSPEC_HIDDEN;
extern HRESULT opentype_get_cpal_entries(const void*,UINT32,UINT32,UINT32,DWRITE_COLOR_F*) DECLSPEC_HIDDEN;
extern HRESULT opentype_get_font_signature(struct file_stream_desc*,FONTSIGNATURE*) DECLSPEC_HIDDEN;
extern BOOL opentype_has_vertical_variants(IDWriteFontFace3*) DECLSPEC_HIDDEN;
struct dwrite_colorglyph {
USHORT layer; /* [0, num_layers) index indicating current layer */

View file

@ -205,6 +205,13 @@ struct dwrite_colorglyphenum {
#define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
#define GLYPH_MAX 65536
enum fontface_flags {
FONTFACE_IS_SYMBOL = 1 << 0,
FONTFACE_IS_MONOSPACED = 1 << 1,
FONTFACE_HAS_KERN_PAIRS = 1 << 2,
FONTFACE_HAS_VERTICAL_VARIANTS = 1 << 3
};
struct dwrite_fontface {
IDWriteFontFace3 IDWriteFontFace3_iface;
LONG ref;
@ -219,9 +226,7 @@ struct dwrite_fontface {
DWRITE_FONT_METRICS1 metrics;
DWRITE_CARET_METRICS caret;
INT charmap;
BOOL is_symbol;
BOOL has_kerning_pairs : 1;
BOOL is_monospaced : 1;
UINT16 flags;
struct dwrite_fonttable cmap;
struct dwrite_fonttable vdmx;
@ -545,7 +550,7 @@ static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace3 *iface)
{
struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
TRACE("(%p)\n", This);
return This->is_symbol;
return !!(This->flags & FONTFACE_IS_SYMBOL);
}
static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS *metrics)
@ -859,7 +864,7 @@ static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace3 *iface)
{
struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
TRACE("(%p)\n", This);
return This->is_monospaced;
return !!(This->flags & FONTFACE_IS_MONOSPACED);
}
static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace3 *iface,
@ -929,7 +934,7 @@ static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace3
return E_INVALIDARG;
}
if (!This->has_kerning_pairs) {
if (This->flags & FONTFACE_HAS_KERN_PAIRS) {
memset(adjustments, 0, count*sizeof(INT32));
return S_OK;
}
@ -945,7 +950,7 @@ static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace3 *iface)
{
struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
TRACE("(%p)\n", This);
return This->has_kerning_pairs;
return !!(This->flags & FONTFACE_HAS_KERN_PAIRS);
}
static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace3 *iface,
@ -968,8 +973,8 @@ static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace3
static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace3 *iface)
{
struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
FIXME("(%p): stub\n", This);
return FALSE;
TRACE("(%p)\n", This);
return !!(This->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
}
static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace3 *iface)
@ -4130,6 +4135,7 @@ HRESULT create_fontface(const struct fontface_desc *desc, IDWriteFontFace3 **ret
struct file_stream_desc stream_desc;
struct dwrite_fontface *fontface;
HRESULT hr = S_OK;
BOOL is_symbol;
int i;
*ret = NULL;
@ -4188,9 +4194,17 @@ HRESULT create_fontface(const struct fontface_desc *desc, IDWriteFontFace3 **ret
fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
}
}
fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace3_iface, &fontface->is_symbol);
fontface->has_kerning_pairs = freetype_has_kerning_pairs(&fontface->IDWriteFontFace3_iface);
fontface->is_monospaced = freetype_is_monospaced(&fontface->IDWriteFontFace3_iface);
fontface->flags = 0;
fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace3_iface, &is_symbol);
if (is_symbol)
fontface->flags |= FONTFACE_IS_SYMBOL;
if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace3_iface))
fontface->flags |= FONTFACE_HAS_KERN_PAIRS;
if (freetype_is_monospaced(&fontface->IDWriteFontFace3_iface))
fontface->flags |= FONTFACE_IS_MONOSPACED;
if (opentype_has_vertical_variants(&fontface->IDWriteFontFace3_iface))
fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
/* Font properties are reused from font object when 'normal' face creation path is used:
collection -> family -> matching font -> fontface.

View file

@ -334,6 +334,49 @@ enum OPENTYPE_PLATFORM_ID
OPENTYPE_PLATFORM_CUSTOM
};
typedef struct {
WORD FeatureParams;
WORD LookupCount;
WORD LookupListIndex[1];
} OT_Feature;
typedef struct {
WORD LookupCount;
WORD Lookup[1];
} OT_LookupList;
typedef struct {
WORD LookupType;
WORD LookupFlag;
WORD SubTableCount;
WORD SubTable[1];
} OT_LookupTable;
typedef struct {
WORD SubstFormat;
WORD Coverage;
WORD DeltaGlyphID;
} GSUB_SingleSubstFormat1;
typedef struct {
WORD SubstFormat;
WORD Coverage;
WORD GlyphCount;
WORD Substitute[1];
} GSUB_SingleSubstFormat2;
typedef struct {
WORD SubstFormat;
WORD ExtensionLookupType;
DWORD ExtensionOffset;
} GSUB_ExtensionPosFormat1;
enum OPENTYPE_GPOS_LOOKUPS
{
OPENTYPE_GPOS_SINGLE_SUBST = 1,
OPENTYPE_GPOS_EXTENSION_SUBST = 7
};
enum TT_NAME_WINDOWS_ENCODING_ID
{
TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
@ -1887,3 +1930,76 @@ HRESULT opentype_get_font_signature(struct file_stream_desc *stream_desc, FONTSI
return hr;
}
BOOL opentype_has_vertical_variants(IDWriteFontFace3 *fontface)
{
const OT_FeatureList *featurelist;
const OT_LookupList *lookup_list;
BOOL exists = FALSE, ret = FALSE;
const GPOS_GSUB_Header *header;
const void *data;
void *context;
UINT32 size;
HRESULT hr;
UINT16 i;
hr = IDWriteFontFace3_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
if (FAILED(hr) || !exists)
return FALSE;
header = data;
featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), index, count, type;
const GSUB_SingleSubstFormat2 *subst2;
const OT_LookupTable *lookup_table;
UINT32 offset;
if (lookup_count == 0)
continue;
/* check if lookup is empty */
index = GET_BE_WORD(feature->LookupListIndex[0]);
lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
type = GET_BE_WORD(lookup_table->LookupType);
if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
continue;
count = GET_BE_WORD(lookup_table->SubTableCount);
if (count == 0)
continue;
offset = GET_BE_WORD(lookup_table->SubTable[0]);
if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
if (GET_BE_WORD(ext->SubstFormat) == 1)
offset += GET_BE_DWORD(ext->ExtensionOffset);
else
FIXME("Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
}
subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
index = GET_BE_WORD(subst2->SubstFormat);
if (index == 1)
FIXME("Validate Single Substitution Format 1\n");
else if (index == 2) {
/* SimSun-ExtB has 0 glyph count for this substitution */
if (GET_BE_WORD(subst2->GlyphCount) > 0) {
ret = TRUE;
break;
}
}
else
WARN("Unknown Single Substitution Format, %u\n", index);
}
}
IDWriteFontFace3_ReleaseFontTable(fontface, context);
return ret;
}

View file

@ -40,6 +40,7 @@
#define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
#define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
#define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
#define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
#ifdef WORDS_BIGENDIAN
#define GET_BE_WORD(x) (x)
@ -220,6 +221,60 @@ typedef struct {
USHORT numberOfHMetrics;
} TT_HHEA;
typedef struct {
DWORD version;
WORD ScriptList;
WORD FeatureList;
WORD LookupList;
} GSUB_Header;
typedef struct {
CHAR FeatureTag[4];
WORD Feature;
} OT_FeatureRecord;
typedef struct {
WORD FeatureCount;
OT_FeatureRecord FeatureRecord[1];
} OT_FeatureList;
typedef struct {
WORD FeatureParams;
WORD LookupCount;
WORD LookupListIndex[1];
} OT_Feature;
typedef struct {
WORD LookupCount;
WORD Lookup[1];
} OT_LookupList;
typedef struct {
WORD LookupType;
WORD LookupFlag;
WORD SubTableCount;
WORD SubTable[1];
} OT_LookupTable;
typedef struct {
WORD SubstFormat;
WORD Coverage;
WORD DeltaGlyphID;
} GSUB_SingleSubstFormat1;
typedef struct {
WORD SubstFormat;
WORD Coverage;
WORD GlyphCount;
WORD Substitute[1];
} GSUB_SingleSubstFormat2;
typedef struct {
WORD SubstFormat;
WORD ExtensionLookupType;
DWORD ExtensionOffset;
} GSUB_ExtensionPosFormat1;
#include "poppack.h"
static IDWriteFactory *create_factory(void)
@ -6300,6 +6355,153 @@ static void test_font_properties(void)
IDWriteFactory_Release(factory);
}
static BOOL has_vertical_glyph_variants(IDWriteFontFace1 *fontface)
{
const OT_FeatureList *featurelist;
const OT_LookupList *lookup_list;
BOOL exists = FALSE, ret = FALSE;
const GSUB_Header *header;
const void *data;
void *context;
UINT32 size;
HRESULT hr;
UINT16 i;
hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
ok(hr == S_OK, "got 0x%08x\n", hr);
if (!exists)
return FALSE;
header = data;
featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), index, count, type;
const GSUB_SingleSubstFormat2 *subst2;
const OT_LookupTable *lookup_table;
UINT32 offset;
if (lookup_count == 0)
continue;
ok(lookup_count == 1, "got lookup count %u\n", lookup_count);
/* check if lookup is empty */
index = GET_BE_WORD(feature->LookupListIndex[0]);
lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
type = GET_BE_WORD(lookup_table->LookupType);
ok(type == 1 || type == 7, "got unexpected lookup type %u\n", type);
count = GET_BE_WORD(lookup_table->SubTableCount);
if (count == 0)
continue;
ok(count > 0, "got unexpected subtable count %u\n", count);
offset = GET_BE_WORD(lookup_table->SubTable[0]);
if (type == 7) {
const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
if (GET_BE_WORD(ext->SubstFormat) == 1)
offset += GET_BE_DWORD(ext->ExtensionOffset);
else
ok(0, "Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
}
subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
index = GET_BE_WORD(subst2->SubstFormat);
if (index == 1)
ok(0, "validate Single Substitution Format 1\n");
else if (index == 2) {
/* SimSun-ExtB has 0 glyph count for this substitution */
if (GET_BE_WORD(subst2->GlyphCount) > 0) {
ret = TRUE;
break;
}
}
else
ok(0, "unknown Single Substitution Format, %u\n", index);
}
}
IDWriteFontFace1_ReleaseFontTable(fontface, context);
return ret;
}
static void test_HasVerticalGlyphVariants(void)
{
IDWriteFontCollection *syscollection;
IDWriteFontFace1 *fontface1;
IDWriteFontFace *fontface;
IDWriteFactory *factory;
UINT32 count, i;
HRESULT hr;
factory = create_factory();
fontface = create_fontface(factory);
hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
IDWriteFontFace_Release(fontface);
if (hr != S_OK) {
win_skip("HasVerticalGlyphVariants() is not supported.\n");
IDWriteFactory_Release(factory);
return;
}
IDWriteFontFace1_Release(fontface1);
hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
ok(hr == S_OK, "got 0x%08x\n", hr);
count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
for (i = 0; i < count; i++) {
IDWriteLocalizedStrings *names;
BOOL expected_vert, has_vert;
IDWriteFontFamily *family;
IDWriteFont *font;
WCHAR nameW[256];
hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
DWRITE_FONT_STYLE_NORMAL, &font);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IDWriteFont_CreateFontFace(font, &fontface);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IDWriteFontFamily_GetFamilyNames(family, &names);
ok(hr == S_OK, "got 0x%08x\n", hr);
get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
expected_vert = has_vertical_glyph_variants(fontface1);
has_vert = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
ok(expected_vert == has_vert, "%s: expected vertical feature %d, got %d\n",
wine_dbgstr_w(nameW), expected_vert, has_vert);
IDWriteLocalizedStrings_Release(names);
IDWriteFont_Release(font);
IDWriteFontFace1_Release(fontface1);
IDWriteFontFace_Release(fontface);
IDWriteFontFamily_Release(family);
}
IDWriteFontCollection_Release(syscollection);
IDWriteFactory_Release(factory);
}
START_TEST(font)
{
IDWriteFactory *factory;
@ -6357,6 +6559,7 @@ START_TEST(font)
test_CreateFontFaceReference();
test_GetFontSignature();
test_font_properties();
test_HasVerticalGlyphVariants();
IDWriteFactory_Release(factory);
}