[PATCH v3 3/5] d2d1: Implement property parsing for RegisterEffectFromStream().

Ziqing Hui zhui at codeweavers.com
Mon Jun 13 23:08:54 CDT 2022


Signed-off-by: Ziqing Hui <zhui at codeweavers.com>
---

v3: Don't check EndElement name.
    Check required system property after XML parsing is done.

 dlls/d2d1/d2d1_private.h |  25 +++++
 dlls/d2d1/factory.c      | 211 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 234 insertions(+), 2 deletions(-)

diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index efc9247a822..b57c971a2ce 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -603,6 +603,15 @@ struct d2d_effect_context
 void d2d_effect_context_init(struct d2d_effect_context *effect_context,
         struct d2d_device_context *device_context) DECLSPEC_HIDDEN;
 
+struct d2d_effect_property
+{
+    WCHAR *name;
+    D2D1_PROPERTY_TYPE type;
+    BYTE *value;
+    PD2D1_PROPERTY_SET_FUNCTION set_function;
+    PD2D1_PROPERTY_GET_FUNCTION get_function;
+};
+
 struct d2d_effect_info
 {
     const CLSID *clsid;
@@ -768,4 +777,20 @@ static inline const char *debug_d2d_ellipse(const D2D1_ELLIPSE *ellipse)
             ellipse->point.x, ellipse->point.y, ellipse->radiusX, ellipse->radiusY);
 }
 
+static inline WCHAR *heap_strdupW(const WCHAR *str)
+{
+    WCHAR *ret = NULL;
+    size_t size;
+
+    if(!str)
+        return ret;
+
+    size = (wcslen(str) + 1) * sizeof(*str);
+    if(!(ret = heap_alloc(size)))
+        return ret;
+    memcpy(ret, str, size);
+
+    return ret;
+}
+
 #endif /* __WINE_D2D1_PRIVATE_H */
diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c
index 273b699ef8d..3f48557ca37 100644
--- a/dlls/d2d1/factory.c
+++ b/dlls/d2d1/factory.c
@@ -37,6 +37,10 @@ struct d2d_effect_reg
 
     UINT32 input_count;
 
+    struct d2d_effect_property *properties;
+    size_t property_size;
+    size_t property_count;
+
     struct list entry;
 };
 
@@ -68,9 +72,18 @@ static inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *i
 
 static void d2d_effect_reg_cleanup(struct d2d_effect_reg *reg)
 {
+    size_t i;
+
     if (!reg)
         return;
 
+    for (i = 0; i < reg->property_count; ++i)
+    {
+        heap_free(reg->properties[i].name);
+        heap_free(reg->properties[i].value);
+    }
+    heap_free(reg->properties);
+
     heap_free(reg);
 }
 
@@ -603,10 +616,155 @@ static BOOL next_xml_node(IXmlReader *xml_reader, XmlNodeType *node_type, const
     return S_FALSE;
 }
 
+static HRESULT heap_get_attr(IXmlReader *xml_reader, const WCHAR *name, WCHAR **ptr)
+{
+    const WCHAR *attr_value;
+
+    *ptr = NULL;
+
+    if (IXmlReader_MoveToAttributeByName(xml_reader, name, NULL) != S_OK)
+        return E_INVALIDARG;
+    if (IXmlReader_GetValue(xml_reader, &attr_value, NULL) != S_OK)
+        return E_INVALIDARG;
+    if (!(*ptr = heap_strdupW(attr_value)))
+        return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT get_property_type(IXmlReader *xml_reader, D2D1_PROPERTY_TYPE *type)
+{
+    const WCHAR *str;
+    unsigned int i;
+
+    static const WCHAR *type_str[] =
+    {
+        L"",             /* D2D1_PROPERTY_TYPE_UNKNOWN */
+        L"string",       /* D2D1_PROPERTY_TYPE_STRING */
+        L"bool",         /* D2D1_PROPERTY_TYPE_BOOL */
+        L"uint32",       /* D2D1_PROPERTY_TYPE_UINT32 */
+        L"int32",        /* D2D1_PROPERTY_TYPE_INT32 */
+        L"float",        /* D2D1_PROPERTY_TYPE_FLOAT */
+        L"vector2",      /* D2D1_PROPERTY_TYPE_VECTOR2 */
+        L"vector3",      /* D2D1_PROPERTY_TYPE_VECTOR3 */
+        L"vector4",      /* D2D1_PROPERTY_TYPE_VECTOR4 */
+        L"blob",         /* D2D1_PROPERTY_TYPE_BLOB */
+        L"iunknown",     /* D2D1_PROPERTY_TYPE_IUNKNOWN */
+        L"enum",         /* D2D1_PROPERTY_TYPE_ENUM */
+        L"array",        /* D2D1_PROPERTY_TYPE_ARRAY */
+        L"clsid",        /* D2D1_PROPERTY_TYPE_CLSID */
+        L"matrix3x2",    /* D2D1_PROPERTY_TYPE_MATRIX_3X2 */
+        L"matrix4x3",    /* D2D1_PROPERTY_TYPE_MATRIX_4X3 */
+        L"matrix4x4",    /* D2D1_PROPERTY_TYPE_MATRIX_4X4 */
+        L"matrix5x4",    /* D2D1_PROPERTY_TYPE_MATRIX_5X4 */
+        L"colorcontext", /* D2D1_PROPERTY_TYPE_COLOR_CONTEXT */
+    };
+
+    if (IXmlReader_MoveToAttributeByName(xml_reader, L"type", NULL) != S_OK)
+        return E_INVALIDARG;
+    if (IXmlReader_GetValue(xml_reader, &str, NULL) != S_OK)
+        return E_INVALIDARG;
+
+    for (i = 0; i < ARRAY_SIZE(type_str); ++i)
+    {
+        if (!wcscmp(str, type_str[i]))
+        {
+            *type = i;
+            return S_OK;
+        }
+    }
+
+    return E_INVALIDARG;
+}
+
+static HRESULT add_property(struct d2d_effect_reg *reg, WCHAR *name, D2D1_PROPERTY_TYPE type, BYTE *value)
+{
+    struct d2d_effect_property *entry;
+
+    if (!d2d_array_reserve((void **)&reg->properties, &reg->property_size, reg->property_count + 1, sizeof(*reg->properties)))
+    {
+        ERR("Failed to resize properties array.\n");
+        return E_OUTOFMEMORY;
+    }
+
+    entry = &reg->properties[reg->property_count++];
+    entry->name = name;
+    entry->type = type;
+    entry->value = value;
+    entry->set_function = NULL;
+    entry->get_function = NULL;
+
+    return S_OK;
+}
+
+static HRESULT parse_sub_property(IXmlReader *xml_reader, struct d2d_effect_reg *reg)
+{
+    /* FIXME: Sub property is ignored. */
+    return S_OK;
+}
+
 static HRESULT parse_property(IXmlReader *xml_reader, struct d2d_effect_reg *reg)
 {
-    /* FIXME: Property parsing is not implemented. */
-    return S_OK;
+    WCHAR *name = NULL, *value = NULL;
+    D2D1_PROPERTY_TYPE type;
+    const WCHAR *node_name;
+    XmlNodeType node_type;
+    unsigned int i;
+    HRESULT hr;
+
+    /* Get property name, type, value */
+    if (FAILED(hr = heap_get_attr(xml_reader, L"name", &name)))
+        return hr;
+    if (FAILED(hr = get_property_type(xml_reader, &type)))
+        goto done;
+    heap_get_attr(xml_reader, L"value", &value);
+
+    /* Check if property is already set */
+    for (i = 0; i < reg->property_count; ++i)
+    {
+        if (!wcscmp(name, reg->properties[i].name))
+        {
+            hr = E_INVALIDARG;
+            goto done;
+        }
+    }
+
+    /* Parse sub properties */
+    if (FAILED(hr = IXmlReader_MoveToElement(xml_reader)))
+        goto done;
+    if (!IXmlReader_IsEmptyElement(xml_reader))
+    {
+        while ((hr = next_xml_node(xml_reader, &node_type, &node_name)) == S_OK)
+        {
+            if (node_type == XmlNodeType_Element && !wcscmp(node_name, L"Property"))
+            {
+                if (FAILED(hr = parse_sub_property(xml_reader, reg)))
+                    goto done;
+            }
+            else if (node_type == XmlNodeType_EndElement)
+            {
+                break;
+            }
+        }
+
+        if (FAILED(hr) || node_type != XmlNodeType_EndElement)
+        {
+            hr = E_INVALIDARG;
+            goto done;
+        }
+    }
+
+    /* Add property to array */
+    hr = add_property(reg, name, type, (BYTE *)value);
+
+done:
+    if (hr != S_OK)
+    {
+        heap_free(value);
+        heap_free(name);
+    }
+
+    return hr;
 }
 
 static HRESULT parse_inputs(IXmlReader *xml_reader, struct d2d_effect_reg *reg)
@@ -694,8 +852,10 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromStream(ID2D1Facto
         REFCLSID effect_id, IStream *property_xml, const D2D1_PROPERTY_BINDING *bindings,
         UINT32 binding_count, PD2D1_EFFECT_FACTORY effect_factory)
 {
+    BOOL display_name = FALSE, author = FALSE, category = FALSE, description = FALSE, wrong_type = FALSE, system_property;
     struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
     struct d2d_effect_reg *iter, *entry = NULL;
+    unsigned int i, j;
     HRESULT hr;
 
     TRACE("iface %p, effect_id %s, property_xml %p, bindings %p, binding_count %u, effect_factory %p.\n",
@@ -719,6 +879,53 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromStream(ID2D1Facto
         return hr;
     }
 
+    /* Check system properties */
+    for (i = 0; i < entry->property_count; ++i)
+    {
+        system_property = TRUE;
+
+        if (!wcscmp(entry->properties[i].name, L"DisplayName"))
+            display_name = TRUE;
+        else if (!wcscmp(entry->properties[i].name, L"Author"))
+            author = TRUE;
+        else if (!wcscmp(entry->properties[i].name, L"Category"))
+            category = TRUE;
+        else if (!wcscmp(entry->properties[i].name, L"Description"))
+            description = TRUE;
+        else
+            system_property = FALSE;
+
+        if (system_property && entry->properties[i].type != D2D1_PROPERTY_TYPE_STRING)
+        {
+            wrong_type = TRUE;
+            break;
+        }
+    }
+    if (!display_name || !author || !category || !description || wrong_type)
+    {
+        d2d_effect_reg_cleanup(entry);
+        return E_INVALIDARG;
+    }
+
+    /* bind getter and setter to properties */
+    for (i = 0; i < binding_count; ++i)
+    {
+        for (j = 0; j < entry->property_count; ++j)
+        {
+            if (!wcscmp(bindings[i].propertyName, entry->properties[j].name))
+            {
+                entry->properties[j].get_function = bindings[i].getFunction;
+                entry->properties[j].set_function = bindings[i].setFunction;
+                break;
+            }
+        }
+        if (j == entry->property_count)
+        {
+            d2d_effect_reg_cleanup(entry);
+            return D2DERR_INVALID_PROPERTY;
+        }
+    }
+
     entry->count = 1;
     entry->id = *effect_id;
     entry->factory = effect_factory;
-- 
2.25.1




More information about the wine-devel mailing list