Signed-off-by: Ziqing Hui zhui@codeweavers.com ---
v2: Rework.
dlls/d2d1/d2d1_private.h | 25 +++++ dlls/d2d1/factory.c | 203 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 226 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 38b5c59e879..0bffae15ff6 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -37,6 +37,11 @@ struct d2d_effect_reg
UINT32 input_count;
+ struct d2d_effect_property *properties; + size_t property_size; + size_t property_count; + size_t system_property_count; + struct list entry; };
@@ -68,9 +73,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 +617,168 @@ 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; + } + + if (!wcscmp(name, L"DisplayName") + || !wcscmp(name, L"Author") + || !wcscmp(name, L"Category") + || !wcscmp(name, L"Description")) + { + if (type != D2D1_PROPERTY_TYPE_STRING) + return E_INVALIDARG; + ++reg->system_property_count; + } + + 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; + BOOL end_node_found; + 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)) + { + end_node_found = FALSE; + 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 && !wcscmp(node_name, L"Property")) + { + end_node_found = TRUE; + break; + } + } + + if (FAILED(hr) || !end_node_found) + { + 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) @@ -700,6 +872,7 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromStream(ID2D1Facto { 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", @@ -723,6 +896,32 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromStream(ID2D1Facto if (FAILED(hr = parse_effect_xml(property_xml, entry))) goto done;
+ /* System properties: DisplayName, Author, Category, Description are required */ + if (entry->system_property_count != 4) + { + hr = E_INVALIDARG; + goto done; + } + + /* 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) + { + hr = D2DERR_INVALID_PROPERTY; + goto done; + } + } + entry->count = 1; entry->id = *effect_id; entry->factory = effect_factory;