dwrite: Implement HasVerticalGlyphVariants().
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
90bcff0eae
commit
e30607fdb0
|
@ -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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue