Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/tests/d2d1.c | 120 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 8 deletions(-)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index bc662b4f8ae..970706bc569 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -99,6 +99,17 @@ L"<?xml version='1.0'?> \ </Effect> \ ";
+static const WCHAR *effect_xml_inputs_attribute = +L"<?xml version='1.0'?> \ + <Effect> \ + <Property name='DisplayName' type='string'/> \ + <Property name='Author' type='string'/> \ + <Property name='Category' type='string'/> \ + <Property name='Description' type='string'/> \ + <Inputs min='1' max='10' deadbeef='abcdef'/> \ + </Effect> \ +"; + static const WCHAR *effect_xml_without_version = L"<Effect> \ <Property name='DisplayName' type='string'/> \ @@ -170,6 +181,90 @@ L"<?xml version='1.0'?> \ </Effect> \ ";
+static const WCHAR *effect_xml_wrong_type = +L"<?xml version='1.0'?> \ + <Effect> \ + <Property name='DisplayName' type='string' value='TestEffect'/> \ + <Property name='Author' type='uint32' value='32'/> \ + <Property name='Category' type='string' value='Test'/> \ + <Property name='Description' type='string' value='Test effect.'/> \ + <Inputs/> \ + </Effect> \ +"; + +static const WCHAR *effect_xml_duplicate_property = +L"<?xml version='1.0'?> \ + <Effect> \ + <Property name='DisplayName' type='string'/> \ + <Property name='Author' type='string'/> \ + <Property name='Category' type='string'/> \ + <Property name='Description' type='string'/> \ + <Property name='Description' type='string'/> \ + <Inputs/> \ + </Effect> \ +"; + +static const WCHAR *effect_xml_lower_case_effect = +L"<?xml version='1.0'?> \ + <effect> \ + <Property name='DisplayName' type='string'/> \ + <Property name='Author' type='string'/> \ + <Property name='Category' type='string'/> \ + <Property name='Description' type='string'/> \ + <Inputs/> \ + </effect> \ +"; + +static const WCHAR *effect_xml_lower_case_property = +L"<?xml version='1.0'?> \ + <Effect> \ + <property name='DisplayName' type='string'/> \ + <property name='Author' type='string'/> \ + <property name='Category' type='string'/> \ + <property name='Description' type='string'/> \ + <Inputs/> \ + </Effect> \ +"; + +static const WCHAR *effect_xml_lower_case_inputs = +L"<?xml version='1.0'?> \ + <Effect> \ + <Property name='DisplayName' type='string'/> \ + <Property name='Author' type='string'/> \ + <Property name='Category' type='string'/> \ + <Property name='Description' type='string'/> \ + <inputs/> \ + </Effect> \ +"; + +static const WCHAR *effect_xml_min_max_inputs_a = +L"<?xml version='1.0'?> \ + <Effect> \ + <Property name='DisplayName' type='string'/> \ + <Property name='Author' type='string'/> \ + <Property name='Category' type='string'/> \ + <Property name='Description' type='string'/> \ + <Property name='MinInputs' type='uint32' value='1'/> \ + <Property name='MaxInputs' type='uint32' value='2'/> \ + <Inputs/> \ + </Effect> \ +"; + +static const WCHAR *effect_xml_min_max_inputs_b = +L"<?xml version='1.0'?> \ + <Effect> \ + <Property name='DisplayName' type='string'/> \ + <Property name='Author' type='string'/> \ + <Property name='Category' type='string'/> \ + <Property name='Description' type='string'/> \ + <Inputs> \ + <Property name='Min' type='uint32' value='1'/> \ + <Property name='Max' type='uint32' value='2'/> \ + </Inputs> \ + </Effect> \ +"; + + static const DWORD test_vs[] = { #if 0 @@ -10604,10 +10699,11 @@ static void test_effect_register(BOOL d3d11) } xml_tests[] = { - {effect_xml_a, S_OK}, - {effect_xml_b, S_OK}, - {effect_xml_c, S_OK}, - {effect_xml_minimum, S_OK}, + {effect_xml_a, S_OK}, + {effect_xml_b, S_OK}, + {effect_xml_c, S_OK}, + {effect_xml_minimum, S_OK}, + {effect_xml_inputs_attribute, S_OK}, {effect_xml_without_version, HRESULT_FROM_WIN32(ERROR_NOT_FOUND)}, {effect_xml_without_inputs, E_INVALIDARG}, {effect_xml_without_name, E_INVALIDARG}, @@ -10615,6 +10711,13 @@ static void test_effect_register(BOOL d3d11) {effect_xml_without_category, E_INVALIDARG}, {effect_xml_without_description, E_INVALIDARG}, {effect_xml_without_type, E_INVALIDARG}, + {effect_xml_wrong_type, E_INVALIDARG}, + {effect_xml_duplicate_property, E_INVALIDARG}, + {effect_xml_lower_case_effect, HRESULT_FROM_WIN32(ERROR_NOT_FOUND)}, + {effect_xml_lower_case_property, HRESULT_FROM_WIN32(ERROR_NOT_FOUND)}, + {effect_xml_lower_case_inputs, HRESULT_FROM_WIN32(ERROR_NOT_FOUND)}, + {effect_xml_min_max_inputs_a, E_INVALIDARG}, + {effect_xml_min_max_inputs_b, HRESULT_FROM_WIN32(ERROR_NOT_FOUND)}, };
const D2D1_PROPERTY_BINDING binding[] = @@ -10926,10 +11029,11 @@ static void test_effect_properties(BOOL d3d11) } system_property_tests[] = { - {effect_xml_a, L"TestEffectA", effect_author, effect_category, effect_description, 1, 1}, - {effect_xml_b, L"TestEffectB", effect_author, effect_category, effect_description, 1, 1}, - {effect_xml_c, L"TestEffectC", effect_author, effect_category, effect_description, 1, 1}, - {effect_xml_minimum, L"", L"" ,L"", L"", 0, 0}, + {effect_xml_a, L"TestEffectA", effect_author, effect_category, effect_description, 1, 1}, + {effect_xml_b, L"TestEffectB", effect_author, effect_category, effect_description, 1, 1}, + {effect_xml_c, L"TestEffectC", effect_author, effect_category, effect_description, 1, 1}, + {effect_xml_minimum, L"", L"" ,L"", L"", 0, 0}, + {effect_xml_inputs_attribute, L"", L"" ,L"", L"", 0, 0}, };
if (!init_test_context(&ctx, d3d11))
Signed-off-by: Ziqing Hui zhui@codeweavers.com ---
v3: Remove goto. Don't check EndElement name.
dlls/d2d1/Makefile.in | 2 +- dlls/d2d1/factory.c | 158 +++++++++++++++++++++++++++++++++++++++++- system_property_count | 0 3 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 system_property_count
diff --git a/dlls/d2d1/Makefile.in b/dlls/d2d1/Makefile.in index 413571338ba..2456c63c336 100644 --- a/dlls/d2d1/Makefile.in +++ b/dlls/d2d1/Makefile.in @@ -1,6 +1,6 @@ MODULE = d2d1.dll IMPORTLIB = d2d1 -IMPORTS = d3d10_1 dxguid uuid gdi32 user32 advapi32 +IMPORTS = d3d10_1 dxguid uuid gdi32 user32 advapi32 ole32 xmllite DELAYIMPORTS = dwrite
C_SRCS = \ diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index 01dac8051c0..273b699ef8d 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -18,6 +18,8 @@
#define D2D1_INIT_GUID #include "d2d1_private.h" +#include "xmllite.h" +#include "wine/list.h"
WINE_DECLARE_DEBUG_CHANNEL(winediag); WINE_DEFAULT_DEBUG_CHANNEL(d2d); @@ -27,6 +29,17 @@ struct d2d_settings d2d_settings = ~0u, /* No ID2D1Factory version limit by default. */ };
+struct d2d_effect_reg +{ + CLSID id; + PD2D1_EFFECT_FACTORY factory; + UINT32 count; + + UINT32 input_count; + + struct list entry; +}; + struct d2d_factory { ID2D1Factory3 ID2D1Factory3_iface; @@ -39,6 +52,8 @@ struct d2d_factory float dpi_y;
CRITICAL_SECTION cs; + + struct list effect_regs; };
static inline struct d2d_factory *impl_from_ID2D1Factory3(ID2D1Factory3 *iface) @@ -51,6 +66,14 @@ static inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *i return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Multithread_iface); }
+static void d2d_effect_reg_cleanup(struct d2d_effect_reg *reg) +{ + if (!reg) + return; + + heap_free(reg); +} + static HRESULT d2d_factory_reload_sysmetrics(struct d2d_factory *factory) { HDC hdc; @@ -112,6 +135,7 @@ static ULONG STDMETHODCALLTYPE d2d_factory_Release(ID2D1Factory3 *iface) { struct d2d_factory *factory = impl_from_ID2D1Factory3(iface); ULONG refcount = InterlockedDecrement(&factory->refcount); + struct d2d_effect_reg *iter, *iter2;
TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
@@ -120,6 +144,8 @@ static ULONG STDMETHODCALLTYPE d2d_factory_Release(ID2D1Factory3 *iface) if (factory->device) ID3D10Device1_Release(factory->device); DeleteCriticalSection(&factory->cs); + LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &factory->effect_regs, struct d2d_effect_reg, entry) + d2d_effect_reg_cleanup(iter); heap_free(factory); }
@@ -564,14 +590,141 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_CreateGdiMetafile(ID2D1Factory3 *if return E_NOTIMPL; }
+static BOOL next_xml_node(IXmlReader *xml_reader, XmlNodeType *node_type, const WCHAR **node_name) +{ + while (IXmlReader_Read(xml_reader, node_type) == S_OK) + { + if (*node_type == XmlNodeType_Whitespace) + continue; + if (FAILED(IXmlReader_GetLocalName(xml_reader, node_name, NULL))) + return E_INVALIDARG; + return S_OK; + } + return S_FALSE; +} + +static HRESULT parse_property(IXmlReader *xml_reader, struct d2d_effect_reg *reg) +{ + /* FIXME: Property parsing is not implemented. */ + return S_OK; +} + +static HRESULT parse_inputs(IXmlReader *xml_reader, struct d2d_effect_reg *reg) +{ + const WCHAR *node_name; + XmlNodeType node_type; + + if (IXmlReader_IsEmptyElement(xml_reader)) + return S_OK; + + while (next_xml_node(xml_reader, &node_type, &node_name) == S_OK) + { + if (node_type == XmlNodeType_Element && !wcscmp(node_name, L"Input")) + { + ++reg->input_count; + /* FIXME: Name attribute of input is ignored. */ + } + else if (node_type == XmlNodeType_EndElement) + { + return S_OK; + } + } + + return E_INVALIDARG; +} + +static HRESULT parse_effect_xml(IStream *property_xml, struct d2d_effect_reg *reg) +{ + IXmlReader *xml_reader; + const WCHAR *node_name; + XmlNodeType node_type; + HRESULT hr; + + if (FAILED(hr = CreateXmlReader(&IID_IXmlReader, (void **)&xml_reader, NULL))) + return hr; + if (FAILED(hr = IXmlReader_SetInput(xml_reader, (IUnknown *)property_xml))) + { + IXmlReader_Release(xml_reader); + return hr; + } + + /* Read version node */ + if (next_xml_node(xml_reader, &node_type, &node_name) != S_OK || node_type != XmlNodeType_XmlDeclaration) + { + IXmlReader_Release(xml_reader); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + + /* Read effect node */ + if (next_xml_node(xml_reader, &node_type, &node_name) != S_OK + || node_type != XmlNodeType_Element || wcscmp(node_name, L"Effect") != 0) + { + IXmlReader_Release(xml_reader); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + + /* Loop inside effect node */ + while (next_xml_node(xml_reader, &node_type, &node_name) == S_OK) + { + if (node_type == XmlNodeType_Element) + { + if (!wcscmp(node_name, L"Property")) + hr = parse_property(xml_reader, reg); + else if (!wcscmp(node_name, L"Inputs")) + hr = parse_inputs(xml_reader, reg); + + if (FAILED(hr)) + { + IXmlReader_Release(xml_reader); + return hr; + } + } + else if (node_type == XmlNodeType_EndElement) + { + IXmlReader_Release(xml_reader); + return S_OK; + } + } + + IXmlReader_Release(xml_reader); + return E_INVALIDARG; +} + static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromStream(ID2D1Factory3 *iface, REFCLSID effect_id, IStream *property_xml, const D2D1_PROPERTY_BINDING *bindings, UINT32 binding_count, PD2D1_EFFECT_FACTORY effect_factory) { - FIXME("iface %p, effect_id %s, property_xml %p, bindings %p, binding_count %u, effect_factory %p stub!\n", + struct d2d_factory *factory = impl_from_ID2D1Factory3(iface); + struct d2d_effect_reg *iter, *entry = NULL; + HRESULT hr; + + TRACE("iface %p, effect_id %s, property_xml %p, bindings %p, binding_count %u, effect_factory %p.\n", iface, debugstr_guid(effect_id), property_xml, bindings, binding_count, effect_factory);
- return E_NOTIMPL; + LIST_FOR_EACH_ENTRY(iter, &factory->effect_regs, struct d2d_effect_reg, entry) + { + if (IsEqualGUID(effect_id, &iter->id)) + { + ++iter->count; + return S_OK; + } + } + + if (!(entry = heap_alloc_zero(sizeof(*entry)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = parse_effect_xml(property_xml, entry))) + { + d2d_effect_reg_cleanup(entry); + return hr; + } + + entry->count = 1; + entry->id = *effect_id; + entry->factory = effect_factory; + list_add_tail(&factory->effect_regs, &entry->entry); + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromString(ID2D1Factory3 *iface, @@ -743,6 +896,7 @@ static void d2d_factory_init(struct d2d_factory *factory, D2D1_FACTORY_TYPE fact factory->refcount = 1; d2d_factory_reload_sysmetrics(factory); InitializeCriticalSection(&factory->cs); + list_init(&factory->effect_regs); }
HRESULT WINAPI D2D1CreateFactory(D2D1_FACTORY_TYPE factory_type, REFIID iid, diff --git a/system_property_count b/system_property_count new file mode 100644 index 00000000000..e69de29bb2d
On 6/14/22 07:08, Ziqing Hui wrote:
- /* Loop inside effect node */
- while (next_xml_node(xml_reader, &node_type, &node_name) == S_OK)
- {
if (node_type == XmlNodeType_Element)
{
if (!wcscmp(node_name, L"Property"))
hr = parse_property(xml_reader, reg);
else if (!wcscmp(node_name, L"Inputs"))
hr = parse_inputs(xml_reader, reg);
if (FAILED(hr))
{
IXmlReader_Release(xml_reader);
return hr;
}
}
else if (node_type == XmlNodeType_EndElement)
{
IXmlReader_Release(xml_reader);
return S_OK;
}
- }
This should properly skip EndElement of Property and Inputs, so explicit check for EndElement here belongs to "Effect" and not some nested node. Easier way would be to error out on unrecognized element names, and like I said before, returning from parse_property or parse_inputs should already skip nested EndElement.
Regarding error handling, you might as well create xml_reader at the caller of this helper, so you don't have to release it all the time.
Note that return type of next_xml_node() is incorrect.
This patch also has some stray file attached to it.
@@ -1,6 +1,6 @@ MODULE = d2d1.dll IMPORTLIB = d2d1 -IMPORTS = d3d10_1 dxguid uuid gdi32 user32 advapi32 +IMPORTS = d3d10_1 dxguid uuid gdi32 user32 advapi32 ole32 xmllite DELAYIMPORTS = dwrite
New imports might as well go to DELAYIMPORTS, I don't think we necessarily will have to go through xml parsing for builtin effects.
On 6/14/22 10:18 PM, Nikolay Sivov wrote:
On 6/14/22 07:08, Ziqing Hui wrote:
+ /* Loop inside effect node */ + while (next_xml_node(xml_reader, &node_type, &node_name) == S_OK) + { + if (node_type == XmlNodeType_Element) + { + if (!wcscmp(node_name, L"Property")) + hr = parse_property(xml_reader, reg); + else if (!wcscmp(node_name, L"Inputs")) + hr = parse_inputs(xml_reader, reg);
+ if (FAILED(hr)) + { + IXmlReader_Release(xml_reader); + return hr; + } + } + else if (node_type == XmlNodeType_EndElement) + { + IXmlReader_Release(xml_reader); + return S_OK; + } + }
This should properly skip EndElement of Property and Inputs, so explicit check for EndElement here belongs to "Effect" and not some nested node. Easier way would be to error out on unrecognized element names, and like I said before, returning from parse_property or parse_inputs should already skip nested EndElement.
Sorry for my poor understanding... I'm kind of confused by what "skip" means here. So let us make it more clearly.
I use a while loop like this to iterate through XML elements:
while (next_xml_node(xml_reader, &node_type, &node_name) == S_OK) { ... }
This loop exists in parse_effect_xml, parse_property and parse_inputs.
Does "skip" means something like this? :
while (next_xml_node(xml_reader, &node_type, &node_name) == S_OK) { ... if (node_type == EndElement) return break; }
Does "skip" means that we should not check whether last node type is EndElement after loop is end. (And do that check in parent level?)
Regarding error handling, you might as well create xml_reader at the caller of this helper, so you don't have to release it all the time.
Note that return type of next_xml_node() is incorrect.
This patch also has some stray file attached to it.
@@ -1,6 +1,6 @@ MODULE = d2d1.dll IMPORTLIB = d2d1 -IMPORTS = d3d10_1 dxguid uuid gdi32 user32 advapi32 +IMPORTS = d3d10_1 dxguid uuid gdi32 user32 advapi32 ole32 xmllite DELAYIMPORTS = dwrite
New imports might as well go to DELAYIMPORTS, I don't think we necessarily will have to go through xml parsing for builtin effects.
Signed-off-by: Ziqing Hui zhui@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 **)®->properties, ®->property_size, reg->property_count + 1, sizeof(*reg->properties))) + { + ERR("Failed to resize properties array.\n"); + return E_OUTOFMEMORY; + } + + entry = ®->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;
Signed-off-by: Ziqing Hui zhui@codeweavers.com ---
v3: Remove goto.
dlls/d2d1/factory.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index 3f48557ca37..e5a82f7ffdb 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -938,10 +938,33 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromString(ID2D1Facto REFCLSID effect_id, const WCHAR *property_xml, const D2D1_PROPERTY_BINDING *bindings, UINT32 binding_count, PD2D1_EFFECT_FACTORY effect_factory) { - FIXME("iface %p, effect_id %s, property_xml %s, bindings %p, binding_count %u, effect_factory %p stub!\n", - iface, debugstr_guid(effect_id), debugstr_w(property_xml), bindings, binding_count, effect_factory); + static const LARGE_INTEGER zero; + IStream *stream; + ULONG size; + HRESULT hr;
- return S_OK; + TRACE("iface %p, effect_id %s, property_xml %s, bindings %p, binding_count %u, effect_factory %p.\n", + iface, debugstr_guid(effect_id), debugstr_w(property_xml), bindings, binding_count, effect_factory); + + if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &stream))) + return hr; + + size = sizeof(*property_xml) * (wcslen(property_xml) + 1); + if (FAILED(hr = IStream_Write(stream, property_xml, size, NULL))) + { + IStream_Release(stream); + return hr; + } + if (FAILED(hr = IStream_Seek(stream, zero, SEEK_SET, NULL))) + { + IStream_Release(stream); + return hr; + } + + hr = ID2D1Factory3_RegisterEffectFromStream(iface, effect_id, stream, bindings, binding_count, effect_factory); + + IStream_Release(stream); + return hr; }
static HRESULT STDMETHODCALLTYPE d2d_factory_UnregisterEffect(ID2D1Factory3 *iface, REFCLSID effect_id)
Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/factory.c | 21 +++++++++++++++++++-- dlls/d2d1/tests/d2d1.c | 32 +++++++++++++++++--------------- 2 files changed, 36 insertions(+), 17 deletions(-)
diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index e5a82f7ffdb..ae0fb51bde8 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -969,9 +969,26 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromString(ID2D1Facto
static HRESULT STDMETHODCALLTYPE d2d_factory_UnregisterEffect(ID2D1Factory3 *iface, REFCLSID effect_id) { - FIXME("iface %p, effect_id %s stub!\n", iface, debugstr_guid(effect_id)); + struct d2d_factory *factory = impl_from_ID2D1Factory3(iface); + struct d2d_effect_reg *iter, *iter2;
- return E_NOTIMPL; + TRACE("iface %p, effect_id %s.\n", iface, debugstr_guid(effect_id)); + + LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &factory->effect_regs, struct d2d_effect_reg, entry) + { + if (IsEqualGUID(effect_id, &iter->id)) + { + --iter->count; + if (!iter->count) + { + list_remove(&iter->entry); + d2d_effect_reg_cleanup(iter); + } + return S_OK; + } + } + + return D2DERR_EFFECT_IS_NOT_REGISTERED; }
static HRESULT STDMETHODCALLTYPE d2d_factory_GetRegisteredEffects(ID2D1Factory3 *iface, diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 970706bc569..7d60d3c52a2 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -10772,7 +10772,11 @@ static void test_effect_register(BOOL d3d11) winetest_push_context("Test %u", i);
hr = ID2D1Factory1_RegisterEffectFromString(factory, &CLSID_TestEffect, test->xml, NULL, 0, effect_impl_create); - todo_wine_if(test->hr != S_OK) + todo_wine_if(test->xml == effect_xml_without_inputs + || test->xml == effect_xml_lower_case_property + || test->xml == effect_xml_lower_case_inputs + || test->xml == effect_xml_min_max_inputs_a + || test->xml == effect_xml_min_max_inputs_b) ok(hr == test->hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, test->hr); if (hr == S_OK) { @@ -10780,9 +10784,9 @@ static void test_effect_register(BOOL d3d11) hr = ID2D1DeviceContext_CreateEffect(device_context, &CLSID_TestEffect, &effect); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == D2DERR_EFFECT_IS_NOT_REGISTERED, "Got unexpected hr %#lx.\n", hr); + ok(hr == D2DERR_EFFECT_IS_NOT_REGISTERED, "Got unexpected hr %#lx.\n", hr); if (effect) ID2D1Effect_Release(effect); } @@ -10805,11 +10809,11 @@ static void test_effect_register(BOOL d3d11) hr = ID2D1Factory1_RegisterEffectFromString(factory, &CLSID_TestEffect, test->xml, NULL, 0, effect_impl_create); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == D2DERR_EFFECT_IS_NOT_REGISTERED, "Got unexpected hr %#lx.\n", hr); + ok(hr == D2DERR_EFFECT_IS_NOT_REGISTERED, "Got unexpected hr %#lx.\n", hr);
winetest_pop_context(); } @@ -10844,9 +10848,9 @@ static void test_effect_register(BOOL d3d11) }
hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
/* Register effect with property binding */ for (i = 0; i < ARRAY_SIZE(binding_tests); ++i) @@ -10856,7 +10860,6 @@ static void test_effect_register(BOOL d3d11)
hr = ID2D1Factory1_RegisterEffectFromString(factory, &CLSID_TestEffect, test->effect_xml, test->binding, test->binding_count, effect_impl_create); - todo_wine_if(test->hr != S_OK) ok(hr == test->hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, test->hr); ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect);
@@ -10905,13 +10908,13 @@ static void test_effect_register(BOOL d3d11) }
hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
/* Unregister builtin effect */ hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_D2D1Composite); - todo_wine ok(hr == D2DERR_EFFECT_IS_NOT_REGISTERED, "Got unexpected hr %#lx.\n", hr); + ok(hr == D2DERR_EFFECT_IS_NOT_REGISTERED, "Got unexpected hr %#lx.\n", hr);
release_test_context(&ctx); } @@ -10989,7 +10992,6 @@ done: if (effect) ID2D1Effect_Release(effect); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); release_test_context(&ctx); } @@ -11147,7 +11149,7 @@ static void test_effect_properties(BOOL d3d11) if (effect) ID2D1Effect_Release(effect); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); winetest_pop_context(); }
@@ -11240,7 +11242,7 @@ done: if (effect) ID2D1Effect_Release(effect); hr = ID2D1Factory1_UnregisterEffect(factory, &CLSID_TestEffect); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
release_test_context(&ctx); }