[PATCH 2/4] dwrite: Implement HasVerticalGlyphVariants()
Nikolay Sivov
nsivov at codeweavers.com
Tue Jul 5 04:55:54 CDT 2016
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/dwrite/dwrite_private.h | 1 +
dlls/dwrite/font.c | 38 +++++---
dlls/dwrite/opentype.c | 116 +++++++++++++++++++++++++
dlls/dwrite/tests/font.c | 203 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 346 insertions(+), 12 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 3309f3f..dfbeffe 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -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 */
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index c99c5c3..d635c15 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -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.
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 51a8dd8..19dc6dd 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -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;
+}
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index e211712..4fe494a 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -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);
}
--
2.8.1
More information about the wine-patches
mailing list