[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