[PATCH 1/4] d2d1/effect: Initial implementation of subproperties.

Nikolay Sivov wine at gitlab.winehq.org
Thu Jun 30 03:23:39 CDT 2022


From: Nikolay Sivov <nsivov at codeweavers.com>

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/d2d1/d2d1_private.h |   8 +
 dlls/d2d1/effect.c       | 359 +++++++++++++++++++++++++++++++--------
 dlls/d2d1/factory.c      |  51 +++++-
 dlls/d2d1/tests/d2d1.c   |  61 ++++++-
 4 files changed, 409 insertions(+), 70 deletions(-)

diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index 7e74f5dd959..db6787c2f86 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -617,10 +617,14 @@ struct d2d_effect_property
     UINT32 size;
     PD2D1_PROPERTY_SET_FUNCTION set_function;
     PD2D1_PROPERTY_GET_FUNCTION get_function;
+    struct d2d_effect_properties *subproperties;
 };
 
 struct d2d_effect_properties
 {
+    ID2D1Properties ID2D1Properties_iface;
+    struct d2d_effect *effect;
+
     struct d2d_effect_property *properties;
     size_t offset;
     size_t size;
@@ -673,6 +677,10 @@ HRESULT d2d_effect_create(struct d2d_device_context *context, const CLSID *effec
         ID2D1Effect **effect) DECLSPEC_HIDDEN;
 HRESULT d2d_effect_properties_add(struct d2d_effect_properties *props, const WCHAR *name,
         UINT32 index, D2D1_PROPERTY_TYPE type, const WCHAR *value) DECLSPEC_HIDDEN;
+HRESULT d2d_effect_subproperties_add(struct d2d_effect_properties *props, const WCHAR *name,
+        UINT32 index, D2D1_PROPERTY_TYPE type, const WCHAR *value) DECLSPEC_HIDDEN;
+struct d2d_effect_property * d2d_effect_properties_get_property_by_name(
+        const struct d2d_effect_properties *properties, const WCHAR *name) DECLSPEC_HIDDEN;
 void d2d_effect_properties_cleanup(struct d2d_effect_properties *props) DECLSPEC_HIDDEN;
 
 static inline BOOL d2d_array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c
index 7abee71e6d9..5daf16fd838 100644
--- a/dlls/d2d1/effect.c
+++ b/dlls/d2d1/effect.c
@@ -229,8 +229,8 @@ static const struct d2d_effect_info builtin_effects[] =
     {&CLSID_D2D1Grayscale,              1, 1, 1},
 };
 
-HRESULT d2d_effect_properties_add(struct d2d_effect_properties *props, const WCHAR *name,
-        UINT32 index, D2D1_PROPERTY_TYPE type, const WCHAR *value)
+static HRESULT d2d_effect_properties_internal_add(struct d2d_effect_properties *props,
+        const WCHAR *name, UINT32 index, BOOL subprop, D2D1_PROPERTY_TYPE type, const WCHAR *value)
 {
     static const UINT32 sizes[] =
     {
@@ -246,7 +246,7 @@ HRESULT d2d_effect_properties_add(struct d2d_effect_properties *props, const WCH
         0,                   /* FIXME: D2D1_PROPERTY_TYPE_BLOB */
         sizeof(void *),      /* D2D1_PROPERTY_TYPE_IUNKNOWN */
         sizeof(UINT32),      /* D2D1_PROPERTY_TYPE_ENUM */
-        0,                   /* FIXME: D2D1_PROPERTY_TYPE_ARRAY */
+        sizeof(UINT32),      /* D2D1_PROPERTY_TYPE_ARRAY */
         sizeof(CLSID),       /* D2D1_PROPERTY_TYPE_CLSID */
         6 * sizeof(float),   /* D2D1_PROPERTY_TYPE_MATRIX_3X2 */
         12 * sizeof(float),  /* D2D1_PROPERTY_TYPE_MATRIX_4X3 */
@@ -258,7 +258,7 @@ HRESULT d2d_effect_properties_add(struct d2d_effect_properties *props, const WCH
 
     assert(type >= D2D1_PROPERTY_TYPE_STRING && type <= D2D1_PROPERTY_TYPE_COLOR_CONTEXT);
 
-    if (type == D2D1_PROPERTY_TYPE_BLOB || type == D2D1_PROPERTY_TYPE_ARRAY)
+    if (type == D2D1_PROPERTY_TYPE_BLOB)
     {
         FIXME("Ignoring property %s of type %u.\n", wine_dbgstr_w(name), type);
         return S_OK;
@@ -279,21 +279,24 @@ HRESULT d2d_effect_properties_add(struct d2d_effect_properties *props, const WCH
     props->data.count += sizes[type];
 
     p = &props->properties[props->count++];
+    memset(p, 0, sizeof(*p));
     p->index = index;
     if (p->index < 0x80000000)
     {
         props->custom_count++;
-        /* FIXME: this should probably be controller by subproperty */
+        /* FIXME: this should probably be controlled by subproperty */
         p->readonly = FALSE;
     }
+    else if (subprop)
+        p->readonly = TRUE;
     else
         p->readonly = index != D2D1_PROPERTY_CACHED && index != D2D1_PROPERTY_PRECISION;
     p->name = wcsdup(name);
     p->type = type;
-    if (p->type == D2D1_PROPERTY_TYPE_STRING)
+    if (p->type == D2D1_PROPERTY_TYPE_STRING && value)
     {
-        p->data.ptr = value ? wcsdup(value) : NULL;
-        p->size = value ? (wcslen(value) + 1) * sizeof(WCHAR) : 0;
+        p->data.ptr = wcsdup(value);
+        p->size = (wcslen(value) + 1) * sizeof(WCHAR);
     }
     else
     {
@@ -337,15 +340,26 @@ HRESULT d2d_effect_properties_add(struct d2d_effect_properties *props, const WCH
         else if (p->size)
             memset(props->data.ptr + p->data.offset, 0, p->size);
     }
-    p->set_function = NULL;
-    p->get_function = NULL;
 
     return S_OK;
 }
 
+HRESULT d2d_effect_properties_add(struct d2d_effect_properties *props, const WCHAR *name,
+        UINT32 index, D2D1_PROPERTY_TYPE type, const WCHAR *value)
+{
+    return d2d_effect_properties_internal_add(props, name, index, FALSE, type, value);
+}
+
+HRESULT d2d_effect_subproperties_add(struct d2d_effect_properties *props, const WCHAR *name,
+        UINT32 index, D2D1_PROPERTY_TYPE type, const WCHAR *value)
+{
+    return d2d_effect_properties_internal_add(props, name, index, TRUE, type, value);
+}
+
 static HRESULT d2d_effect_duplicate_properties(struct d2d_effect_properties *dst,
         const struct d2d_effect_properties *src)
 {
+    HRESULT hr;
     size_t i;
 
     memset(dst, 0, sizeof(*dst));
@@ -372,6 +386,14 @@ static HRESULT d2d_effect_duplicate_properties(struct d2d_effect_properties *dst
         d->name = wcsdup(s->name);
         if (d->type == D2D1_PROPERTY_TYPE_STRING)
             d->data.ptr = wcsdup((WCHAR *)s->data.ptr);
+
+        if (s->subproperties)
+        {
+            if (!(d->subproperties = calloc(1, sizeof(*d->subproperties))))
+                return E_OUTOFMEMORY;
+            if (FAILED(hr = d2d_effect_duplicate_properties(d->subproperties, s->subproperties)))
+                return hr;
+        }
     }
 
     return S_OK;
@@ -391,7 +413,7 @@ static struct d2d_effect_property * d2d_effect_properties_get_property_by_index(
     return NULL;
 }
 
-static struct d2d_effect_property * d2d_effect_properties_get_property_by_name(
+struct d2d_effect_property * d2d_effect_properties_get_property_by_name(
         const struct d2d_effect_properties *properties, const WCHAR *name)
 {
     unsigned int i;
@@ -405,9 +427,10 @@ static struct d2d_effect_property * d2d_effect_properties_get_property_by_name(
     return NULL;
 }
 
-static UINT32 d2d_effect_properties_get_value_size(const struct d2d_effect *effect,
-        const struct d2d_effect_properties *properties, UINT32 index)
+static UINT32 d2d_effect_properties_get_value_size(const struct d2d_effect_properties *properties,
+        UINT32 index)
 {
+    struct d2d_effect *effect = properties->effect;
     struct d2d_effect_property *prop;
     UINT32 size;
 
@@ -432,10 +455,10 @@ static HRESULT d2d_effect_return_string(const WCHAR *str, WCHAR *buffer, UINT32
     return S_OK;
 }
 
-static HRESULT d2d_effect_property_get_value(const struct d2d_effect *effect,
-        const struct d2d_effect_properties *properties, const struct d2d_effect_property *prop,
-        D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 size)
+static HRESULT d2d_effect_property_get_value(const struct d2d_effect_properties *properties,
+        const struct d2d_effect_property *prop, D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 size)
 {
+    struct d2d_effect *effect = properties->effect;
     UINT32 actual_size;
 
     if (type != D2D1_PROPERTY_TYPE_UNKNOWN && prop->type != type) return E_INVALIDARG;
@@ -446,7 +469,6 @@ static HRESULT d2d_effect_property_get_value(const struct d2d_effect *effect,
 
     switch (prop->type)
     {
-        case D2D1_PROPERTY_TYPE_ARRAY:
         case D2D1_PROPERTY_TYPE_BLOB:
             FIXME("Unimplemented for type %u.\n", prop->type);
             return E_NOTIMPL;
@@ -460,10 +482,10 @@ static HRESULT d2d_effect_property_get_value(const struct d2d_effect *effect,
     return S_OK;
 }
 
-static HRESULT d2d_effect_property_set_value(const struct d2d_effect *effect,
-        struct d2d_effect_properties *properties, struct d2d_effect_property *prop,
-        D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 size)
+static HRESULT d2d_effect_property_set_value(struct d2d_effect_properties *properties,
+        struct d2d_effect_property *prop, D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 size)
 {
+    struct d2d_effect *effect = properties->effect;
     if (prop->readonly) return E_INVALIDARG;
     if (type != D2D1_PROPERTY_TYPE_UNKNOWN && prop->type != type) return E_INVALIDARG;
     if (prop->get_function && !prop->set_function) return E_INVALIDARG;
@@ -499,6 +521,11 @@ void d2d_effect_properties_cleanup(struct d2d_effect_properties *props)
         free(p->name);
         if (p->type == D2D1_PROPERTY_TYPE_STRING)
             free(p->data.ptr);
+        if (p->subproperties)
+        {
+            d2d_effect_properties_cleanup(p->subproperties);
+            free(p->subproperties);
+        }
     }
     free(props->properties);
     free(props->data.ptr);
@@ -967,118 +994,91 @@ static UINT32 STDMETHODCALLTYPE d2d_effect_GetPropertyCount(ID2D1Effect *iface)
 
     TRACE("iface %p.\n", iface);
 
-    return effect->properties.custom_count;
+    return ID2D1Properties_GetPropertyCount(&effect->properties.ID2D1Properties_iface);
 }
 
 static HRESULT STDMETHODCALLTYPE d2d_effect_GetPropertyName(ID2D1Effect *iface, UINT32 index,
         WCHAR *name, UINT32 name_count)
 {
     struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
-    struct d2d_effect_property *prop;
 
     TRACE("iface %p, index %u, name %p, name_count %u.\n", iface, index, name, name_count);
 
-    if (!(prop = d2d_effect_properties_get_property_by_index(&effect->properties, index)))
-        return D2DERR_INVALID_PROPERTY;
-
-    return d2d_effect_return_string(prop->name, name, name_count);
+    return ID2D1Properties_GetPropertyName(&effect->properties.ID2D1Properties_iface,
+            index, name, name_count);
 }
 
 static UINT32 STDMETHODCALLTYPE d2d_effect_GetPropertyNameLength(ID2D1Effect *iface, UINT32 index)
 {
     struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
-    struct d2d_effect_property *prop;
 
     TRACE("iface %p, index %u.\n", iface, index);
 
-    if (!(prop = d2d_effect_properties_get_property_by_index(&effect->properties, index)))
-        return D2DERR_INVALID_PROPERTY;
-
-    return wcslen(prop->name) + 1;
+    return ID2D1Properties_GetPropertyNameLength(&effect->properties.ID2D1Properties_iface, index);
 }
 
 static D2D1_PROPERTY_TYPE STDMETHODCALLTYPE d2d_effect_GetType(ID2D1Effect *iface, UINT32 index)
 {
     struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
-    struct d2d_effect_property *prop;
 
     TRACE("iface %p, index %#x.\n", iface, index);
 
-    if (!(prop = d2d_effect_properties_get_property_by_index(&effect->properties, index)))
-        return D2D1_PROPERTY_TYPE_UNKNOWN;
-
-    return prop->type;
+    return ID2D1Properties_GetType(&effect->properties.ID2D1Properties_iface, index);
 }
 
 static UINT32 STDMETHODCALLTYPE d2d_effect_GetPropertyIndex(ID2D1Effect *iface, const WCHAR *name)
 {
     struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
-    struct d2d_effect_property *prop;
 
     TRACE("iface %p, name %s.\n", iface, debugstr_w(name));
 
-    if (!(prop = d2d_effect_properties_get_property_by_name(&effect->properties, name)))
-        return D2D1_INVALID_PROPERTY_INDEX;
-
-    return prop->index;
+    return ID2D1Properties_GetPropertyIndex(&effect->properties.ID2D1Properties_iface, name);
 }
 
 static HRESULT STDMETHODCALLTYPE d2d_effect_SetValueByName(ID2D1Effect *iface, const WCHAR *name,
         D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 value_size)
 {
     struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
-    struct d2d_effect_property *prop;
 
     TRACE("iface %p, name %s, type %u, value %p, value_size %u.\n", iface, debugstr_w(name),
             type, value, value_size);
 
-    if (!(prop = d2d_effect_properties_get_property_by_name(&effect->properties, name)))
-        return D2DERR_INVALID_PROPERTY;
-
-    return d2d_effect_property_set_value(effect, &effect->properties, prop, type, value, value_size);
+    return ID2D1Properties_SetValueByName(&effect->properties.ID2D1Properties_iface, name,
+            type, value, value_size);
 }
 
 static HRESULT STDMETHODCALLTYPE d2d_effect_SetValue(ID2D1Effect *iface, UINT32 index, D2D1_PROPERTY_TYPE type,
         const BYTE *value, UINT32 value_size)
 {
     struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
-    struct d2d_effect_property *prop;
 
     TRACE("iface %p, index %#x, type %u, value %p, value_size %u.\n", iface, index, type, value, value_size);
 
-    if (!(prop = d2d_effect_properties_get_property_by_index(&effect->properties, index)))
-        return D2DERR_INVALID_PROPERTY;
-
-    return d2d_effect_property_set_value(effect, &effect->properties, prop, type, value, value_size);
+    return ID2D1Properties_SetValue(&effect->properties.ID2D1Properties_iface, index, type,
+            value, value_size);
 }
 
 static HRESULT STDMETHODCALLTYPE d2d_effect_GetValueByName(ID2D1Effect *iface, const WCHAR *name,
         D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 value_size)
 {
     struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
-    struct d2d_effect_property *prop;
 
     TRACE("iface %p, name %s, type %#x, value %p, value_size %u.\n", iface, debugstr_w(name), type,
             value, value_size);
 
-    if (!(prop = d2d_effect_properties_get_property_by_name(&effect->properties, name)))
-        return D2DERR_INVALID_PROPERTY;
-
-    return d2d_effect_property_get_value(effect, &effect->properties, prop, type, value, value_size);
+    return ID2D1Properties_GetValueByName(&effect->properties.ID2D1Properties_iface, name, type,
+            value, value_size);
 }
 
 static HRESULT STDMETHODCALLTYPE d2d_effect_GetValue(ID2D1Effect *iface, UINT32 index, D2D1_PROPERTY_TYPE type,
         BYTE *value, UINT32 value_size)
 {
     struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
-    struct d2d_effect_property *prop;
 
     TRACE("iface %p, index %#x, type %u, value %p, value_size %u.\n", iface, index, type, value, value_size);
 
-    if (!(prop = d2d_effect_properties_get_property_by_index(&effect->properties, index)))
-        return D2DERR_INVALID_PROPERTY;
-
-    return d2d_effect_property_get_value(effect, &effect->properties, prop, type, value, value_size);
+    return ID2D1Properties_GetValue(&effect->properties.ID2D1Properties_iface, index, type,
+            value, value_size);
 }
 
 static UINT32 STDMETHODCALLTYPE d2d_effect_GetValueSize(ID2D1Effect *iface, UINT32 index)
@@ -1087,14 +1087,17 @@ static UINT32 STDMETHODCALLTYPE d2d_effect_GetValueSize(ID2D1Effect *iface, UINT
 
     TRACE("iface %p, index %#x.\n", iface, index);
 
-    return d2d_effect_properties_get_value_size(effect, &effect->properties, index);
+    return ID2D1Properties_GetValueSize(&effect->properties.ID2D1Properties_iface, index);
 }
 
-static HRESULT STDMETHODCALLTYPE d2d_effect_GetSubProperties(ID2D1Effect *iface, UINT32 index, ID2D1Properties **props)
+static HRESULT STDMETHODCALLTYPE d2d_effect_GetSubProperties(ID2D1Effect *iface, UINT32 index,
+        ID2D1Properties **props)
 {
-    FIXME("iface %p, index %u, props %p stub!\n", iface, index, props);
+    struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
 
-    return E_NOTIMPL;
+    TRACE("iface %p, index %u, props %p.\n", iface, index, props);
+
+    return ID2D1Properties_GetSubProperties(&effect->properties.ID2D1Properties_iface, index, props);
 }
 
 static void STDMETHODCALLTYPE d2d_effect_SetInput(ID2D1Effect *iface, UINT32 index, ID2D1Image *input, BOOL invalidate)
@@ -1255,17 +1258,234 @@ static const ID2D1ImageVtbl d2d_effect_image_vtbl =
     d2d_effect_image_GetFactory,
 };
 
+static inline struct d2d_effect_properties *impl_from_ID2D1Properties(ID2D1Properties *iface)
+{
+    return CONTAINING_RECORD(iface, struct d2d_effect_properties, ID2D1Properties_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_effect_properties_QueryInterface(ID2D1Properties *iface,
+        REFIID riid, void **obj)
+{
+    if (IsEqualGUID(riid, &IID_ID2D1Properties) ||
+            IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        ID2D1Properties_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE d2d_effect_properties_AddRef(ID2D1Properties *iface)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    return ID2D1Effect_AddRef(&properties->effect->ID2D1Effect_iface);
+}
+
+static ULONG STDMETHODCALLTYPE d2d_effect_properties_Release(ID2D1Properties *iface)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    return ID2D1Effect_Release(&properties->effect->ID2D1Effect_iface);
+}
+
+static UINT32 STDMETHODCALLTYPE d2d_effect_properties_GetPropertyCount(ID2D1Properties *iface)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return properties->custom_count;
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_effect_properties_GetPropertyName(ID2D1Properties *iface,
+        UINT32 index, WCHAR *name, UINT32 name_count)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, index %u, name %p, name_count %u.\n", iface, index, name, name_count);
+
+    if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
+        return D2DERR_INVALID_PROPERTY;
+
+    return d2d_effect_return_string(prop->name, name, name_count);
+}
+
+static UINT32 STDMETHODCALLTYPE d2d_effect_properties_GetPropertyNameLength(ID2D1Properties *iface,
+        UINT32 index)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, index %u.\n", iface, index);
+
+    if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
+        return D2DERR_INVALID_PROPERTY;
+
+    return wcslen(prop->name) + 1;
+}
+
+static D2D1_PROPERTY_TYPE STDMETHODCALLTYPE d2d_effect_properties_GetType(ID2D1Properties *iface,
+        UINT32 index)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, index %#x.\n", iface, index);
+
+    if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
+        return D2D1_PROPERTY_TYPE_UNKNOWN;
+
+    return prop->type;
+}
+
+static UINT32 STDMETHODCALLTYPE d2d_effect_properties_GetPropertyIndex(ID2D1Properties *iface,
+        const WCHAR *name)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_w(name));
+
+    if (!(prop = d2d_effect_properties_get_property_by_name(properties, name)))
+        return D2D1_INVALID_PROPERTY_INDEX;
+
+    return prop->index;
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_effect_properties_SetValueByName(ID2D1Properties *iface,
+        const WCHAR *name, D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 value_size)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, name %s, type %u, value %p, value_size %u.\n", iface, debugstr_w(name),
+            type, value, value_size);
+
+    if (!(prop = d2d_effect_properties_get_property_by_name(properties, name)))
+        return D2DERR_INVALID_PROPERTY;
+
+    return d2d_effect_property_set_value(properties, prop, type, value, value_size);
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_effect_properties_SetValue(ID2D1Properties *iface,
+        UINT32 index, D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 value_size)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, index %#x, type %u, value %p, value_size %u.\n", iface, index, type, value, value_size);
+
+    if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
+        return D2DERR_INVALID_PROPERTY;
+
+    return d2d_effect_property_set_value(properties, prop, type, value, value_size);
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_effect_properties_GetValueByName(ID2D1Properties *iface,
+        const WCHAR *name, D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 value_size)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, name %s, type %#x, value %p, value_size %u.\n", iface, debugstr_w(name), type,
+            value, value_size);
+
+    if (!(prop = d2d_effect_properties_get_property_by_name(properties, name)))
+        return D2DERR_INVALID_PROPERTY;
+
+    return d2d_effect_property_get_value(properties, prop, type, value, value_size);
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_effect_properties_GetValue(ID2D1Properties *iface,
+        UINT32 index, D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 value_size)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, index %#x, type %u, value %p, value_size %u.\n", iface, index, type, value, value_size);
+
+    if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
+        return D2DERR_INVALID_PROPERTY;
+
+    return d2d_effect_property_get_value(properties, prop, type, value, value_size);
+}
+
+static UINT32 STDMETHODCALLTYPE d2d_effect_properties_GetValueSize(ID2D1Properties *iface,
+        UINT32 index)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+
+    TRACE("iface %p, index %#x.\n", iface, index);
+
+    return d2d_effect_properties_get_value_size(properties, index);
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_effect_properties_GetSubProperties(ID2D1Properties *iface,
+        UINT32 index, ID2D1Properties **props)
+{
+    struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
+    struct d2d_effect_property *prop;
+
+    TRACE("iface %p, index %u, props %p.\n", iface, index, props);
+
+    if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
+        return D2DERR_INVALID_PROPERTY;
+
+    if (!prop->subproperties) return D2DERR_NO_SUBPROPERTIES;
+
+    *props = &prop->subproperties->ID2D1Properties_iface;
+    ID2D1Properties_AddRef(*props);
+    return S_OK;
+}
+
+static const ID2D1PropertiesVtbl d2d_effect_properties_vtbl =
+{
+    d2d_effect_properties_QueryInterface,
+    d2d_effect_properties_AddRef,
+    d2d_effect_properties_Release,
+    d2d_effect_properties_GetPropertyCount,
+    d2d_effect_properties_GetPropertyName,
+    d2d_effect_properties_GetPropertyNameLength,
+    d2d_effect_properties_GetType,
+    d2d_effect_properties_GetPropertyIndex,
+    d2d_effect_properties_SetValueByName,
+    d2d_effect_properties_SetValue,
+    d2d_effect_properties_GetValueByName,
+    d2d_effect_properties_GetValue,
+    d2d_effect_properties_GetValueSize,
+    d2d_effect_properties_GetSubProperties,
+};
+
+static void d2d_effect_init_properties_vtbls(struct d2d_effect *effect)
+{
+    unsigned int i;
+
+    effect->properties.ID2D1Properties_iface.lpVtbl = &d2d_effect_properties_vtbl;
+    effect->properties.effect = effect;
+
+    for (i = 0; i < effect->properties.count; ++i)
+    {
+        struct d2d_effect_property *prop = &effect->properties.properties[i];
+        if (!prop->subproperties) continue;
+        prop->subproperties->ID2D1Properties_iface.lpVtbl = &d2d_effect_properties_vtbl;
+        prop->subproperties->effect = effect;
+    }
+}
+
 HRESULT d2d_effect_create(struct d2d_device_context *context, const CLSID *effect_id,
         ID2D1Effect **effect)
 {
     const struct d2d_effect_info *builtin = NULL;
     struct d2d_effect_context *effect_context;
     const struct d2d_effect_registration *reg;
+    unsigned int i, default_input_count;
     struct d2d_transform_graph *graph;
     PD2D1_EFFECT_FACTORY factory;
     struct d2d_effect *object;
     WCHAR clsidW[39];
-    unsigned int i;
     HRESULT hr;
 
     if (!(reg = d2d_factory_get_registered_effect(context->factory, effect_id)))
@@ -1323,7 +1543,7 @@ HRESULT d2d_effect_create(struct d2d_device_context *context, const CLSID *effec
         d2d_effect_properties_add(&object->properties, L"MaxInputs", D2D1_PROPERTY_MAX_INPUTS,
                 D2D1_PROPERTY_TYPE_UINT32, max_inputs);
 
-        d2d_effect_SetInputCount(&object->ID2D1Effect_iface, builtin->default_input_count);
+        default_input_count = builtin->default_input_count;
 
         factory = builtin_factory_stub;
     }
@@ -1335,7 +1555,7 @@ HRESULT d2d_effect_create(struct d2d_device_context *context, const CLSID *effec
         d2d_effect_properties_add(&object->properties, L"MaxInputs", D2D1_PROPERTY_MAX_INPUTS,
                 D2D1_PROPERTY_TYPE_UINT32, L"1" /* FIXME */);
 
-        d2d_effect_SetInputCount(&object->ID2D1Effect_iface, 1);
+        default_input_count = 1;
 
         factory = reg->factory;
     }
@@ -1343,6 +1563,9 @@ HRESULT d2d_effect_create(struct d2d_device_context *context, const CLSID *effec
     d2d_effect_properties_add(&object->properties, L"CLSID", D2D1_PROPERTY_CLSID, D2D1_PROPERTY_TYPE_CLSID, clsidW);
     d2d_effect_properties_add(&object->properties, L"Cached", D2D1_PROPERTY_CACHED, D2D1_PROPERTY_TYPE_BOOL, L"false");
     d2d_effect_properties_add(&object->properties, L"Precision", D2D1_PROPERTY_PRECISION, D2D1_PROPERTY_TYPE_ENUM, L"0");
+    d2d_effect_init_properties_vtbls(object);
+
+    d2d_effect_SetInputCount(&object->ID2D1Effect_iface, default_input_count);
 
     if (FAILED(hr = factory((IUnknown **)&object->impl)))
     {
diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c
index 911d809b58b..699b8c05669 100644
--- a/dlls/d2d1/factory.c
+++ b/dlls/d2d1/factory.c
@@ -782,6 +782,55 @@ static HRESULT parse_effect_property(IXmlReader *reader, struct d2d_effect_regis
     return hr;
 }
 
+static HRESULT parse_effect_inputs(IXmlReader *reader, struct d2d_effect_registration *effect)
+{
+    struct d2d_effect_properties *subproperties;
+    unsigned int depth, input_count = 0;
+    struct d2d_effect_property *inputs;
+    XmlNodeType node_type;
+    WCHAR nameW[16];
+    WCHAR *name;
+    HRESULT hr;
+
+    if (FAILED(hr = d2d_effect_properties_add(&effect->properties, L"Inputs",
+            D2D1_PROPERTY_INPUTS, D2D1_PROPERTY_TYPE_ARRAY, NULL)))
+        return hr;
+
+    if (!(inputs = d2d_effect_properties_get_property_by_name(&effect->properties, L"Inputs")))
+        return E_FAIL;
+    if (!(inputs->subproperties = calloc(1, sizeof(*inputs->subproperties))))
+        return E_OUTOFMEMORY;
+    subproperties = inputs->subproperties;
+
+    d2d_effect_subproperties_add(subproperties, L"IsReadOnly", D2D1_SUBPROPERTY_ISREADONLY,
+            D2D1_PROPERTY_TYPE_BOOL, L"true");
+    d2d_effect_subproperties_add(subproperties, L"DisplayName", D2D1_SUBPROPERTY_DISPLAYNAME,
+            D2D1_PROPERTY_TYPE_STRING, L"Inputs");
+
+    if (IXmlReader_IsEmptyElement(reader)) return S_OK;
+
+    while (parse_effect_get_next_xml_node(reader, XmlNodeType_None, L"Input", &depth) == S_OK)
+    {
+        if (FAILED(hr = IXmlReader_GetNodeType(reader, &node_type))) return hr;
+        if (node_type == XmlNodeType_EndElement) continue;
+        if (node_type != XmlNodeType_Element) return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+
+        if (FAILED(hr = parse_effect_get_attribute(reader, L"name", &name))) return hr;
+
+        swprintf(nameW, ARRAY_SIZE(nameW), L"%lu", input_count);
+        d2d_effect_subproperties_add(subproperties, nameW, input_count, D2D1_PROPERTY_TYPE_STRING, name);
+        input_count++;
+
+        free(name);
+    }
+    *(UINT32 *)(effect->properties.data.ptr + inputs->data.offset) = input_count;
+
+    if (FAILED(hr = IXmlReader_GetNodeType(reader, &node_type))) return hr;
+    if (node_type != XmlNodeType_EndElement) return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+
+    return S_OK;
+}
+
 static HRESULT parse_effect_xml(IXmlReader *reader, struct d2d_effect_registration *effect)
 {
     const WCHAR *node_name;
@@ -808,7 +857,7 @@ static HRESULT parse_effect_xml(IXmlReader *reader, struct d2d_effect_registrati
         if (!wcscmp(node_name, L"Property"))
             hr = parse_effect_property(reader, effect);
         else if (!wcscmp(node_name, L"Inputs"))
-            hr = parse_effect_skip_element(reader, depth);
+            hr = parse_effect_inputs(reader, effect);
         else
         {
             WARN("Unexpected element %s.\n", debugstr_w(node_name));
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index 6ba4d8cec59..fe7bfa38753 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -10926,12 +10926,15 @@ static void test_effect_context(BOOL d3d11)
 
 static void test_effect_properties(BOOL d3d11)
 {
-    UINT32 i, min_inputs, max_inputs, integer, index;
+    UINT32 i, min_inputs, max_inputs, integer, index, size;
     ID2D1EffectContext *effect_context;
     D2D1_BUFFER_PRECISION precision;
+    ID2D1Properties *subproperties;
+    D2D1_PROPERTY_TYPE prop_type;
     struct d2d1_test_context ctx;
     ID2D1Factory1 *factory;
     ID2D1Effect *effect;
+    UINT32 count, data;
     WCHAR buffer[128];
     CLSID clsid;
     BOOL cached;
@@ -10976,6 +10979,62 @@ static void test_effect_properties(BOOL d3d11)
         return;
     }
 
+    /* Inputs array */
+    hr = ID2D1Factory1_RegisterEffectFromString(factory, &CLSID_TestEffect, effect_xml_a,
+            NULL, 0, effect_impl_create);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+
+    hr = ID2D1DeviceContext_CreateEffect(ctx.context, &CLSID_TestEffect, &effect);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+
+    size = ID2D1Effect_GetValueSize(effect, D2D1_PROPERTY_INPUTS);
+    ok(size == 4, "Unexpected size %u.\n", size);
+    prop_type = ID2D1Effect_GetType(effect, D2D1_PROPERTY_INPUTS);
+    ok(prop_type == D2D1_PROPERTY_TYPE_ARRAY, "Unexpected type %u.\n", prop_type);
+    hr = ID2D1Effect_GetPropertyName(effect, D2D1_PROPERTY_INPUTS, buffer, ARRAY_SIZE(buffer));
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(buffer, L"Inputs"), "Unexpected name %s.\n", wine_dbgstr_w(buffer));
+
+    /* Value is the number of elements. */
+    data = 123;
+    hr = ID2D1Effect_GetValue(effect, D2D1_PROPERTY_INPUTS, D2D1_PROPERTY_TYPE_ARRAY,
+            (BYTE *)&data, sizeof(data));
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(data == 1, "Unexpected data %u.\n", data);
+
+    hr = ID2D1Effect_GetSubProperties(effect, D2D1_PROPERTY_INPUTS, &subproperties);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+
+    count = ID2D1Properties_GetPropertyCount(subproperties);
+    ok(count == 1, "Unexpected count %u.\n", count);
+
+    hr = ID2D1Properties_GetPropertyName(subproperties, 0, buffer, ARRAY_SIZE(buffer));
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(buffer, L"0"), "Unexpected name %s.\n", wine_dbgstr_w(buffer));
+    hr = ID2D1Properties_GetValue(subproperties, 0, D2D1_PROPERTY_TYPE_STRING,
+            (BYTE *)buffer, sizeof(buffer));
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(buffer, L"Source"), "Unexpected value %s.\n", wine_dbgstr_w(buffer));
+
+    hr = ID2D1Properties_GetValue(subproperties, D2D1_SUBPROPERTY_ISREADONLY, D2D1_PROPERTY_TYPE_BOOL,
+            (BYTE *)&data, sizeof(data));
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(data == TRUE, "Unexpected value %u.\n", data);
+    hr = ID2D1Properties_GetPropertyName(subproperties, D2D1_SUBPROPERTY_ISREADONLY,
+            buffer, ARRAY_SIZE(buffer));
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(buffer, L"IsReadOnly"), "Unexpected name %s.\n", wine_dbgstr_w(buffer));
+    hr = ID2D1Properties_GetValue(subproperties, D2D1_SUBPROPERTY_DISPLAYNAME,
+            D2D1_PROPERTY_TYPE_STRING, (BYTE *)buffer, ARRAY_SIZE(buffer));
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(buffer, L"Inputs"), "Unexpected name %s.\n", wine_dbgstr_w(buffer));
+
+    ID2D1Properties_Release(subproperties);
+    ID2D1Effect_Release(effect);
+
+    hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+
     /* Test system properties */
 
     for (i = 0; i < ARRAY_SIZE(system_property_tests); ++i)
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/347



More information about the wine-devel mailing list