[PATCH v3 3/5] d2d1: Implement property parsing for RegisterEffectFromStream().
Ziqing Hui
zhui at codeweavers.com
Mon Jun 13 23:08:54 CDT 2022
Signed-off-by: Ziqing Hui <zhui at codeweavers.com>
---
v3: Don't check EndElement name.
Check required system property after XML parsing is done.
dlls/d2d1/d2d1_private.h | 25 +++++
dlls/d2d1/factory.c | 211 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 234 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index efc9247a822..b57c971a2ce 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -603,6 +603,15 @@ struct d2d_effect_context
void d2d_effect_context_init(struct d2d_effect_context *effect_context,
struct d2d_device_context *device_context) DECLSPEC_HIDDEN;
+struct d2d_effect_property
+{
+ WCHAR *name;
+ D2D1_PROPERTY_TYPE type;
+ BYTE *value;
+ PD2D1_PROPERTY_SET_FUNCTION set_function;
+ PD2D1_PROPERTY_GET_FUNCTION get_function;
+};
+
struct d2d_effect_info
{
const CLSID *clsid;
@@ -768,4 +777,20 @@ static inline const char *debug_d2d_ellipse(const D2D1_ELLIPSE *ellipse)
ellipse->point.x, ellipse->point.y, ellipse->radiusX, ellipse->radiusY);
}
+static inline WCHAR *heap_strdupW(const WCHAR *str)
+{
+ WCHAR *ret = NULL;
+ size_t size;
+
+ if(!str)
+ return ret;
+
+ size = (wcslen(str) + 1) * sizeof(*str);
+ if(!(ret = heap_alloc(size)))
+ return ret;
+ memcpy(ret, str, size);
+
+ return ret;
+}
+
#endif /* __WINE_D2D1_PRIVATE_H */
diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c
index 273b699ef8d..3f48557ca37 100644
--- a/dlls/d2d1/factory.c
+++ b/dlls/d2d1/factory.c
@@ -37,6 +37,10 @@ struct d2d_effect_reg
UINT32 input_count;
+ struct d2d_effect_property *properties;
+ size_t property_size;
+ size_t property_count;
+
struct list entry;
};
@@ -68,9 +72,18 @@ static inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *i
static void d2d_effect_reg_cleanup(struct d2d_effect_reg *reg)
{
+ size_t i;
+
if (!reg)
return;
+ for (i = 0; i < reg->property_count; ++i)
+ {
+ heap_free(reg->properties[i].name);
+ heap_free(reg->properties[i].value);
+ }
+ heap_free(reg->properties);
+
heap_free(reg);
}
@@ -603,10 +616,155 @@ static BOOL next_xml_node(IXmlReader *xml_reader, XmlNodeType *node_type, const
return S_FALSE;
}
+static HRESULT heap_get_attr(IXmlReader *xml_reader, const WCHAR *name, WCHAR **ptr)
+{
+ const WCHAR *attr_value;
+
+ *ptr = NULL;
+
+ if (IXmlReader_MoveToAttributeByName(xml_reader, name, NULL) != S_OK)
+ return E_INVALIDARG;
+ if (IXmlReader_GetValue(xml_reader, &attr_value, NULL) != S_OK)
+ return E_INVALIDARG;
+ if (!(*ptr = heap_strdupW(attr_value)))
+ return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+static HRESULT get_property_type(IXmlReader *xml_reader, D2D1_PROPERTY_TYPE *type)
+{
+ const WCHAR *str;
+ unsigned int i;
+
+ static const WCHAR *type_str[] =
+ {
+ L"", /* D2D1_PROPERTY_TYPE_UNKNOWN */
+ L"string", /* D2D1_PROPERTY_TYPE_STRING */
+ L"bool", /* D2D1_PROPERTY_TYPE_BOOL */
+ L"uint32", /* D2D1_PROPERTY_TYPE_UINT32 */
+ L"int32", /* D2D1_PROPERTY_TYPE_INT32 */
+ L"float", /* D2D1_PROPERTY_TYPE_FLOAT */
+ L"vector2", /* D2D1_PROPERTY_TYPE_VECTOR2 */
+ L"vector3", /* D2D1_PROPERTY_TYPE_VECTOR3 */
+ L"vector4", /* D2D1_PROPERTY_TYPE_VECTOR4 */
+ L"blob", /* D2D1_PROPERTY_TYPE_BLOB */
+ L"iunknown", /* D2D1_PROPERTY_TYPE_IUNKNOWN */
+ L"enum", /* D2D1_PROPERTY_TYPE_ENUM */
+ L"array", /* D2D1_PROPERTY_TYPE_ARRAY */
+ L"clsid", /* D2D1_PROPERTY_TYPE_CLSID */
+ L"matrix3x2", /* D2D1_PROPERTY_TYPE_MATRIX_3X2 */
+ L"matrix4x3", /* D2D1_PROPERTY_TYPE_MATRIX_4X3 */
+ L"matrix4x4", /* D2D1_PROPERTY_TYPE_MATRIX_4X4 */
+ L"matrix5x4", /* D2D1_PROPERTY_TYPE_MATRIX_5X4 */
+ L"colorcontext", /* D2D1_PROPERTY_TYPE_COLOR_CONTEXT */
+ };
+
+ if (IXmlReader_MoveToAttributeByName(xml_reader, L"type", NULL) != S_OK)
+ return E_INVALIDARG;
+ if (IXmlReader_GetValue(xml_reader, &str, NULL) != S_OK)
+ return E_INVALIDARG;
+
+ for (i = 0; i < ARRAY_SIZE(type_str); ++i)
+ {
+ if (!wcscmp(str, type_str[i]))
+ {
+ *type = i;
+ return S_OK;
+ }
+ }
+
+ return E_INVALIDARG;
+}
+
+static HRESULT add_property(struct d2d_effect_reg *reg, WCHAR *name, D2D1_PROPERTY_TYPE type, BYTE *value)
+{
+ struct d2d_effect_property *entry;
+
+ if (!d2d_array_reserve((void **)®->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;
--
2.25.1
More information about the wine-devel
mailing list