From: Ziqing Hui zhui@codeweavers.com
--- dlls/d2d1/d2d1_private.h | 14 ++++- dlls/d2d1/effect.c | 133 ++++++++++++++++++++++++++++++++++----- 2 files changed, 131 insertions(+), 16 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 8de2f6de79f..8970a4b7f28 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -676,7 +676,16 @@ void d2d_factory_register_effect(struct d2d_factory *factory,
struct d2d_transform_node { - ID2D1TransformNode *node; + BOOL effect_input; + union + { + ID2D1TransformNode *transform; + ID2D1Bitmap *bitmap; + } u; + struct d2d_transform_node **inputs; + UINT32 input_count; + struct d2d_transform_node *output; + UINT32 output_to_index; struct list entry; };
@@ -684,6 +693,9 @@ struct d2d_transform_graph { ID2D1TransformGraph ID2D1TransformGraph_iface; LONG refcount; + struct d2d_transform_node *input_nodes; + UINT32 input_count; + struct d2d_transform_node *output_node; struct list nodes; };
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 0ac2d4b3ade..cdae0455755 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -27,7 +27,7 @@ static struct d2d_transform_node *d2d_transform_graph_find_node(const struct d2d
LIST_FOR_EACH_ENTRY_REV(entry, &graph->nodes, struct d2d_transform_node, entry) { - if (entry->node == node) + if (entry->u.transform == node) return entry; } return NULL; @@ -35,8 +35,26 @@ static struct d2d_transform_node *d2d_transform_graph_find_node(const struct d2d
static void d2d_transform_graph_remove_node(struct d2d_transform_graph *graph, struct d2d_transform_node *node) { + UINT32 i; + + for (i = 0; i < graph->input_count; ++i) + { + if (graph->input_nodes[i].output == node) + graph->input_nodes[i].output = NULL; + } + if (graph->output_node == node) + graph->output_node = NULL; + for (i = 0; i < node->input_count; ++i) + { + if (node->inputs[i]) + node->inputs[i]->output = NULL; + } + if (node->output) + node->output->inputs[node->output_to_index] = NULL; list_remove(&node->entry); - ID2D1TransformNode_Release(node->node); + + ID2D1TransformNode_Release(node->u.transform); + free(node->inputs); free(node); }
@@ -75,12 +93,19 @@ static ULONG STDMETHODCALLTYPE d2d_transform_graph_Release(ID2D1TransformGraph * { struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); ULONG refcount = InterlockedDecrement(&graph->refcount); + UINT32 i;
TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
if (!refcount) { ID2D1TransformGraph_Clear(iface); + for (i = 0; i < graph->input_count; ++i) + { + if (graph->input_nodes[i].u.bitmap) + ID2D1Bitmap_Release(graph->input_nodes[i].u.bitmap); + } + free(graph->input_nodes); free(graph); }
@@ -89,17 +114,39 @@ static ULONG STDMETHODCALLTYPE d2d_transform_graph_Release(ID2D1TransformGraph *
static UINT32 STDMETHODCALLTYPE d2d_transform_graph_GetInputCount(ID2D1TransformGraph *iface) { - FIXME("iface %p stub!\n", iface); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
- return 0; + TRACE("iface %p\n", iface); + + return graph->input_count; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetSingleTransformNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) { - FIXME("iface %p, node %p stub!\n", iface, node); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + UINT32 input_count, i; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, node %p.\n", iface, node); + + input_count = ID2D1TransformNode_GetInputCount(node); + if (input_count != graph->input_count) + return E_INVALIDARG; + + ID2D1TransformGraph_Clear(iface); + + if (FAILED(hr = ID2D1TransformGraph_AddNode(iface, node))) + return hr; + if (FAILED(hr = ID2D1TransformGraph_SetOutputNode(iface, node))) + return hr; + for (i = 0; i < input_count; ++i) + { + if (FAILED(hr = ID2D1TransformGraph_ConnectToEffectInput(iface, i, node, i))) + return hr; + } + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_AddNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) @@ -115,7 +162,13 @@ static HRESULT STDMETHODCALLTYPE d2d_transform_graph_AddNode(ID2D1TransformGraph if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY;
- ID2D1TransformNode_AddRef(entry->node = node); + entry->input_count = ID2D1TransformNode_GetInputCount(node); + if (!(entry->inputs = calloc(entry->input_count, sizeof(*entry->inputs)))) + { + free(entry); + return E_OUTOFMEMORY; + } + ID2D1TransformNode_AddRef(entry->u.transform = node); list_add_tail(&graph->nodes, &entry->entry);
return S_OK; @@ -137,25 +190,58 @@ static HRESULT STDMETHODCALLTYPE d2d_transform_graph_RemoveNode(ID2D1TransformGr
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetOutputNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) { - FIXME("iface %p, node %p stub!\n", iface, node); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *entry;
- return E_NOTIMPL; + TRACE("iface %p, node %p.\n", iface, node); + + if (!(entry = d2d_transform_graph_find_node(graph, node))) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + + graph->output_node = entry; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_ConnectNode(ID2D1TransformGraph *iface, ID2D1TransformNode *from_node, ID2D1TransformNode *to_node, UINT32 index) { - FIXME("iface %p, from_node %p, to_node %p, index %u stub!\n", iface, from_node, to_node, index); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *from, *to;
- return E_NOTIMPL; + TRACE("iface %p, from_node %p, to_node %p, index %u.\n", iface, from_node, to_node, index); + + if (!(from = d2d_transform_graph_find_node(graph, from_node)) + || !(to = d2d_transform_graph_find_node(graph, to_node))) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + if (index >= to->input_count) + return E_INVALIDARG; + + from->output = to; + from->output_to_index = index; + to->inputs[index] = from; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_ConnectToEffectInput(ID2D1TransformGraph *iface, UINT32 input_index, ID2D1TransformNode *node, UINT32 node_index) { - FIXME("iface %p, input_index %u, node %p, node_index %u stub!\n", iface, input_index, node, node_index); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *entry;
- return E_NOTIMPL; + TRACE("iface %p, input_index %u, node %p, node_index %u.\n", iface, input_index, node, node_index); + + if (!(entry = d2d_transform_graph_find_node(graph, node))) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + if (input_index >= graph->input_count || node_index >= entry->input_count) + return E_INVALIDARG; + + graph->input_nodes[input_index].output = entry; + graph->input_nodes[input_index].output_to_index = node_index; + entry->inputs[node_index] = &graph->input_nodes[input_index]; + + return S_OK; }
static void STDMETHODCALLTYPE d2d_transform_graph_Clear(ID2D1TransformGraph *iface) @@ -194,11 +280,23 @@ static const ID2D1TransformGraphVtbl d2d_transform_graph_vtbl = d2d_transform_graph_SetPassthroughGraph, };
-static void d2d_transform_graph_init(struct d2d_transform_graph *graph) +static HRESULT d2d_transform_graph_init(struct d2d_transform_graph *graph, UINT32 input_count) { + UINT32 i; + graph->ID2D1TransformGraph_iface.lpVtbl = &d2d_transform_graph_vtbl; graph->refcount = 1; + + if (!(graph->input_nodes = calloc(input_count, sizeof(*graph->input_nodes)))) + return E_OUTOFMEMORY; + for (i = 0; i < input_count; ++i) + { + graph->input_nodes[i].effect_input = TRUE; + } + graph->input_count = input_count; + list_init(&graph->nodes); + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_effect_impl_QueryInterface(ID2D1EffectImpl *iface, REFIID iid, void **out) @@ -1639,7 +1737,12 @@ HRESULT d2d_effect_create(struct d2d_device_context *context, const CLSID *effec ID2D1EffectContext_Release(&effect_context->ID2D1EffectContext_iface); return E_OUTOFMEMORY; } - d2d_transform_graph_init(graph); + if (FAILED(hr = d2d_transform_graph_init(graph, reg->default_input_count))) + { + free(graph); + ID2D1EffectContext_Release(&effect_context->ID2D1EffectContext_iface); + return hr; + }
if (!(object = calloc(1, sizeof(*object)))) {