From: Nikolay Sivov Subject: [PATCH v3 1/4] d2d1/effect: Initial implementation of subproperties. Message-Id: Date: Thu, 30 Jun 2022 21:34:12 +0000 In-Reply-To: References: From: Nikolay Sivov Signed-off-by: Nikolay Sivov --- dlls/d2d1/d2d1_private.h | 8 + dlls/d2d1/effect.c | 359 +++++++++++++++++++++++++++++++-------- dlls/d2d1/factory.c | 51 +++++- dlls/d2d1/tests/d2d1.c | 57 ++++++- 4 files changed, 405 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 960d4480747..332fd02a07f 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -10934,12 +10934,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; @@ -10984,6 +10987,58 @@ 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)); + + 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