include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / d2d1 / effect.c
blobcebc492d895d5054a0300290b4be0b975d12409f
1 /*
2 * Copyright 2018 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "d2d1_private.h"
21 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
23 static inline struct d2d_transform *impl_from_ID2D1OffsetTransform(ID2D1OffsetTransform *iface)
25 return CONTAINING_RECORD(iface, struct d2d_transform, ID2D1TransformNode_iface);
28 static inline struct d2d_transform *impl_from_ID2D1BlendTransform(ID2D1BlendTransform *iface)
30 return CONTAINING_RECORD(iface, struct d2d_transform, ID2D1TransformNode_iface);
33 static inline struct d2d_transform *impl_from_ID2D1BorderTransform(ID2D1BorderTransform *iface)
35 return CONTAINING_RECORD(iface, struct d2d_transform, ID2D1TransformNode_iface);
38 static inline struct d2d_transform *impl_from_ID2D1BoundsAdjustmentTransform(
39 ID2D1BoundsAdjustmentTransform *iface)
41 return CONTAINING_RECORD(iface, struct d2d_transform, ID2D1TransformNode_iface);
44 static inline struct d2d_vertex_buffer *impl_from_ID2D1VertexBuffer(ID2D1VertexBuffer *iface)
46 return CONTAINING_RECORD(iface, struct d2d_vertex_buffer, ID2D1VertexBuffer_iface);
49 static HRESULT STDMETHODCALLTYPE d2d_vertex_buffer_QueryInterface(ID2D1VertexBuffer *iface,
50 REFIID iid, void **out)
52 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
54 if (IsEqualGUID(iid, &IID_ID2D1VertexBuffer)
55 || IsEqualGUID(iid, &IID_IUnknown))
57 *out = iface;
58 ID2D1VertexBuffer_AddRef(iface);
59 return S_OK;
62 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
63 *out = NULL;
64 return E_NOINTERFACE;
67 static ULONG STDMETHODCALLTYPE d2d_vertex_buffer_AddRef(ID2D1VertexBuffer *iface)
69 struct d2d_vertex_buffer *buffer = impl_from_ID2D1VertexBuffer(iface);
70 ULONG refcount = InterlockedIncrement(&buffer->refcount);
72 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
74 return refcount;
77 static ULONG STDMETHODCALLTYPE d2d_vertex_buffer_Release(ID2D1VertexBuffer *iface)
79 struct d2d_vertex_buffer *buffer = impl_from_ID2D1VertexBuffer(iface);
80 ULONG refcount = InterlockedDecrement(&buffer->refcount);
82 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
84 if (!refcount)
85 free(buffer);
87 return refcount;
90 static HRESULT STDMETHODCALLTYPE d2d_vertex_buffer_Map(ID2D1VertexBuffer *iface, BYTE **data, UINT32 size)
92 FIXME("iface %p, data %p, size %u.\n", iface, data, size);
94 return E_NOTIMPL;
97 static HRESULT STDMETHODCALLTYPE d2d_vertex_buffer_Unmap(ID2D1VertexBuffer *iface)
99 FIXME("iface %p.\n", iface);
101 return E_NOTIMPL;
104 static const ID2D1VertexBufferVtbl d2d_vertex_buffer_vtbl =
106 d2d_vertex_buffer_QueryInterface,
107 d2d_vertex_buffer_AddRef,
108 d2d_vertex_buffer_Release,
109 d2d_vertex_buffer_Map,
110 d2d_vertex_buffer_Unmap,
113 static HRESULT d2d_vertex_buffer_create(ID2D1VertexBuffer **buffer)
115 struct d2d_vertex_buffer *object;
117 if (!(object = calloc(1, sizeof(*object))))
118 return E_OUTOFMEMORY;
120 object->ID2D1VertexBuffer_iface.lpVtbl = &d2d_vertex_buffer_vtbl;
121 object->refcount = 1;
123 *buffer = &object->ID2D1VertexBuffer_iface;
125 return S_OK;
128 static HRESULT STDMETHODCALLTYPE d2d_offset_transform_QueryInterface(ID2D1OffsetTransform *iface,
129 REFIID iid, void **out)
131 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
133 if (IsEqualGUID(iid, &IID_ID2D1OffsetTransform)
134 || IsEqualGUID(iid, &IID_ID2D1TransformNode)
135 || IsEqualGUID(iid, &IID_IUnknown))
137 *out = iface;
138 ID2D1OffsetTransform_AddRef(iface);
139 return S_OK;
142 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
143 *out = NULL;
144 return E_NOINTERFACE;
147 static ULONG STDMETHODCALLTYPE d2d_offset_transform_AddRef(ID2D1OffsetTransform *iface)
149 struct d2d_transform *transform = impl_from_ID2D1OffsetTransform(iface);
150 ULONG refcount = InterlockedIncrement(&transform->refcount);
152 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
154 return refcount;
157 static ULONG STDMETHODCALLTYPE d2d_offset_transform_Release(ID2D1OffsetTransform *iface)
159 struct d2d_transform *transform = impl_from_ID2D1OffsetTransform(iface);
160 ULONG refcount = InterlockedDecrement(&transform->refcount);
162 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
164 if (!refcount)
165 free(transform);
167 return refcount;
170 static UINT32 STDMETHODCALLTYPE d2d_offset_transform_GetInputCount(ID2D1OffsetTransform *iface)
172 TRACE("iface %p.\n", iface);
174 return 1;
177 static void STDMETHODCALLTYPE d2d_offset_transform_SetOffset(ID2D1OffsetTransform *iface,
178 D2D1_POINT_2L offset)
180 struct d2d_transform *transform = impl_from_ID2D1OffsetTransform(iface);
182 TRACE("iface %p, offset %s.\n", iface, debug_d2d_point_2l(&offset));
184 transform->offset = offset;
187 static D2D1_POINT_2L * STDMETHODCALLTYPE d2d_offset_transform_GetOffset(ID2D1OffsetTransform *iface,
188 D2D1_POINT_2L *offset)
190 struct d2d_transform *transform = impl_from_ID2D1OffsetTransform(iface);
192 TRACE("iface %p.\n", iface);
194 *offset = transform->offset;
195 return offset;
198 static const ID2D1OffsetTransformVtbl d2d_offset_transform_vtbl =
200 d2d_offset_transform_QueryInterface,
201 d2d_offset_transform_AddRef,
202 d2d_offset_transform_Release,
203 d2d_offset_transform_GetInputCount,
204 d2d_offset_transform_SetOffset,
205 d2d_offset_transform_GetOffset,
208 static HRESULT d2d_offset_transform_create(D2D1_POINT_2L offset, ID2D1OffsetTransform **transform)
210 struct d2d_transform *object;
212 if (!(object = calloc(1, sizeof(*object))))
213 return E_OUTOFMEMORY;
215 object->ID2D1TransformNode_iface.lpVtbl = (ID2D1TransformNodeVtbl *)&d2d_offset_transform_vtbl;
216 object->refcount = 1;
217 object->offset = offset;
219 *transform = (ID2D1OffsetTransform *)&object->ID2D1TransformNode_iface;
221 return S_OK;
224 static HRESULT STDMETHODCALLTYPE d2d_blend_transform_QueryInterface(ID2D1BlendTransform *iface,
225 REFIID iid, void **out)
227 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
229 if (IsEqualGUID(iid, &IID_ID2D1BlendTransform)
230 || IsEqualGUID(iid, &IID_ID2D1ConcreteTransform)
231 || IsEqualGUID(iid, &IID_ID2D1TransformNode)
232 || IsEqualGUID(iid, &IID_IUnknown))
234 *out = iface;
235 ID2D1BlendTransform_AddRef(iface);
236 return S_OK;
239 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
240 *out = NULL;
241 return E_NOINTERFACE;
244 static ULONG STDMETHODCALLTYPE d2d_blend_transform_AddRef(ID2D1BlendTransform *iface)
246 struct d2d_transform *transform = impl_from_ID2D1BlendTransform(iface);
247 ULONG refcount = InterlockedIncrement(&transform->refcount);
249 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
251 return refcount;
254 static ULONG STDMETHODCALLTYPE d2d_blend_transform_Release(ID2D1BlendTransform *iface)
256 struct d2d_transform *transform = impl_from_ID2D1BlendTransform(iface);
257 ULONG refcount = InterlockedDecrement(&transform->refcount);
259 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
261 if (!refcount)
262 free(transform);
264 return refcount;
267 static UINT32 STDMETHODCALLTYPE d2d_blend_transform_GetInputCount(ID2D1BlendTransform *iface)
269 struct d2d_transform *transform = impl_from_ID2D1BlendTransform(iface);
271 TRACE("iface %p.\n", iface);
273 return transform->input_count;
276 static HRESULT STDMETHODCALLTYPE d2d_blend_transform_SetOutputBuffer(ID2D1BlendTransform *iface,
277 D2D1_BUFFER_PRECISION precision, D2D1_CHANNEL_DEPTH depth)
279 FIXME("iface %p, precision %u, depth %u stub.\n", iface, precision, depth);
281 return E_NOTIMPL;
284 static void STDMETHODCALLTYPE d2d_blend_transform_SetCached(ID2D1BlendTransform *iface,
285 BOOL is_cached)
287 FIXME("iface %p, is_cached %d stub.\n", iface, is_cached);
290 static void STDMETHODCALLTYPE d2d_blend_transform_SetDescription(ID2D1BlendTransform *iface,
291 const D2D1_BLEND_DESCRIPTION *description)
293 struct d2d_transform *transform = impl_from_ID2D1BlendTransform(iface);
295 TRACE("iface %p, description %p.\n", iface, description);
297 transform->blend_desc = *description;
300 static void STDMETHODCALLTYPE d2d_blend_transform_GetDescription(ID2D1BlendTransform *iface,
301 D2D1_BLEND_DESCRIPTION *description)
303 struct d2d_transform *transform = impl_from_ID2D1BlendTransform(iface);
305 TRACE("iface %p, description %p.\n", iface, description);
307 *description = transform->blend_desc;
310 static const ID2D1BlendTransformVtbl d2d_blend_transform_vtbl =
312 d2d_blend_transform_QueryInterface,
313 d2d_blend_transform_AddRef,
314 d2d_blend_transform_Release,
315 d2d_blend_transform_GetInputCount,
316 d2d_blend_transform_SetOutputBuffer,
317 d2d_blend_transform_SetCached,
318 d2d_blend_transform_SetDescription,
319 d2d_blend_transform_GetDescription,
322 static HRESULT d2d_blend_transform_create(UINT32 input_count, const D2D1_BLEND_DESCRIPTION *blend_desc,
323 ID2D1BlendTransform **transform)
325 struct d2d_transform *object;
327 *transform = NULL;
329 if (!input_count)
330 return E_INVALIDARG;
332 if (!(object = calloc(1, sizeof(*object))))
333 return E_OUTOFMEMORY;
335 object->ID2D1TransformNode_iface.lpVtbl = (ID2D1TransformNodeVtbl *)&d2d_blend_transform_vtbl;
336 object->refcount = 1;
337 object->input_count = input_count;
338 object->blend_desc = *blend_desc;
340 *transform = (ID2D1BlendTransform *)&object->ID2D1TransformNode_iface;
342 return S_OK;
345 static HRESULT STDMETHODCALLTYPE d2d_border_transform_QueryInterface(ID2D1BorderTransform *iface,
346 REFIID iid, void **out)
348 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
350 if (IsEqualGUID(iid, &IID_ID2D1BorderTransform)
351 || IsEqualGUID(iid, &IID_ID2D1ConcreteTransform)
352 || IsEqualGUID(iid, &IID_ID2D1TransformNode)
353 || IsEqualGUID(iid, &IID_IUnknown))
355 *out = iface;
356 ID2D1BorderTransform_AddRef(iface);
357 return S_OK;
360 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
361 *out = NULL;
362 return E_NOINTERFACE;
365 static ULONG STDMETHODCALLTYPE d2d_border_transform_AddRef(ID2D1BorderTransform *iface)
367 struct d2d_transform *transform = impl_from_ID2D1BorderTransform(iface);
368 ULONG refcount = InterlockedIncrement(&transform->refcount);
370 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
372 return refcount;
375 static ULONG STDMETHODCALLTYPE d2d_border_transform_Release(ID2D1BorderTransform *iface)
377 struct d2d_transform *transform = impl_from_ID2D1BorderTransform(iface);
378 ULONG refcount = InterlockedDecrement(&transform->refcount);
380 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
382 if (!refcount)
383 free(transform);
385 return refcount;
388 static UINT32 STDMETHODCALLTYPE d2d_border_transform_GetInputCount(ID2D1BorderTransform *iface)
390 TRACE("iface %p.\n", iface);
392 return 1;
395 static HRESULT STDMETHODCALLTYPE d2d_border_transform_SetOutputBuffer(
396 ID2D1BorderTransform *iface, D2D1_BUFFER_PRECISION precision, D2D1_CHANNEL_DEPTH depth)
398 FIXME("iface %p, precision %u, depth %u stub.\n", iface, precision, depth);
400 return E_NOTIMPL;
403 static void STDMETHODCALLTYPE d2d_border_transform_SetCached(
404 ID2D1BorderTransform *iface, BOOL is_cached)
406 FIXME("iface %p, is_cached %d stub.\n", iface, is_cached);
409 static void STDMETHODCALLTYPE d2d_border_transform_SetExtendModeX(
410 ID2D1BorderTransform *iface, D2D1_EXTEND_MODE mode)
412 struct d2d_transform *transform = impl_from_ID2D1BorderTransform(iface);
414 TRACE("iface %p.\n", iface);
416 switch (mode)
418 case D2D1_EXTEND_MODE_CLAMP:
419 case D2D1_EXTEND_MODE_WRAP:
420 case D2D1_EXTEND_MODE_MIRROR:
421 transform->border.mode_x = mode;
422 break;
423 default:
428 static void STDMETHODCALLTYPE d2d_border_transform_SetExtendModeY(
429 ID2D1BorderTransform *iface, D2D1_EXTEND_MODE mode)
431 struct d2d_transform *transform = impl_from_ID2D1BorderTransform(iface);
433 TRACE("iface %p.\n", iface);
435 switch (mode)
437 case D2D1_EXTEND_MODE_CLAMP:
438 case D2D1_EXTEND_MODE_WRAP:
439 case D2D1_EXTEND_MODE_MIRROR:
440 transform->border.mode_y = mode;
441 break;
442 default:
447 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_border_transform_GetExtendModeX(
448 ID2D1BorderTransform *iface)
450 struct d2d_transform *transform = impl_from_ID2D1BorderTransform(iface);
452 TRACE("iface %p.\n", iface);
454 return transform->border.mode_x;
457 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_border_transform_GetExtendModeY(
458 ID2D1BorderTransform *iface)
460 struct d2d_transform *transform = impl_from_ID2D1BorderTransform(iface);
462 TRACE("iface %p.\n", iface);
464 return transform->border.mode_y;
467 static const ID2D1BorderTransformVtbl d2d_border_transform_vtbl =
469 d2d_border_transform_QueryInterface,
470 d2d_border_transform_AddRef,
471 d2d_border_transform_Release,
472 d2d_border_transform_GetInputCount,
473 d2d_border_transform_SetOutputBuffer,
474 d2d_border_transform_SetCached,
475 d2d_border_transform_SetExtendModeX,
476 d2d_border_transform_SetExtendModeY,
477 d2d_border_transform_GetExtendModeX,
478 d2d_border_transform_GetExtendModeY,
481 static HRESULT d2d_border_transform_create(D2D1_EXTEND_MODE mode_x, D2D1_EXTEND_MODE mode_y,
482 ID2D1BorderTransform **transform)
484 struct d2d_transform *object;
486 *transform = NULL;
488 if (!(object = calloc(1, sizeof(*object))))
489 return E_OUTOFMEMORY;
491 object->ID2D1TransformNode_iface.lpVtbl = (ID2D1TransformNodeVtbl *)&d2d_border_transform_vtbl;
492 object->refcount = 1;
493 object->border.mode_x = mode_x;
494 object->border.mode_y = mode_y;
496 *transform = (ID2D1BorderTransform *)&object->ID2D1TransformNode_iface;
498 return S_OK;
501 static HRESULT STDMETHODCALLTYPE d2d_bounds_adjustment_transform_QueryInterface(
502 ID2D1BoundsAdjustmentTransform *iface, REFIID iid, void **out)
504 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
506 if (IsEqualGUID(iid, &IID_ID2D1BoundsAdjustmentTransform)
507 || IsEqualGUID(iid, &IID_ID2D1TransformNode)
508 || IsEqualGUID(iid, &IID_IUnknown))
510 *out = iface;
511 ID2D1BoundsAdjustmentTransform_AddRef(iface);
512 return S_OK;
515 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
516 *out = NULL;
517 return E_NOINTERFACE;
520 static ULONG STDMETHODCALLTYPE d2d_bounds_adjustment_transform_AddRef(
521 ID2D1BoundsAdjustmentTransform *iface)
523 struct d2d_transform *transform = impl_from_ID2D1BoundsAdjustmentTransform(iface);
524 ULONG refcount = InterlockedIncrement(&transform->refcount);
526 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
528 return refcount;
531 static ULONG STDMETHODCALLTYPE d2d_bounds_adjustment_transform_Release(
532 ID2D1BoundsAdjustmentTransform *iface)
534 struct d2d_transform *transform = impl_from_ID2D1BoundsAdjustmentTransform(iface);
535 ULONG refcount = InterlockedDecrement(&transform->refcount);
537 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
539 if (!refcount)
540 free(transform);
542 return refcount;
545 static UINT32 STDMETHODCALLTYPE d2d_bounds_adjustment_transform_GetInputCount(
546 ID2D1BoundsAdjustmentTransform *iface)
548 TRACE("iface %p.\n", iface);
550 return 1;
553 static void STDMETHODCALLTYPE d2d_bounds_adjustment_transform_SetOutputBounds(
554 ID2D1BoundsAdjustmentTransform *iface, const D2D1_RECT_L *bounds)
556 struct d2d_transform *transform = impl_from_ID2D1BoundsAdjustmentTransform(iface);
558 TRACE("iface %p.\n", iface);
560 transform->bounds = *bounds;
563 static void STDMETHODCALLTYPE d2d_bounds_adjustment_transform_GetOutputBounds(
564 ID2D1BoundsAdjustmentTransform *iface, D2D1_RECT_L *bounds)
566 struct d2d_transform *transform = impl_from_ID2D1BoundsAdjustmentTransform(iface);
568 TRACE("iface %p.\n", iface);
570 *bounds = transform->bounds;
573 static const ID2D1BoundsAdjustmentTransformVtbl d2d_bounds_adjustment_transform_vtbl =
575 d2d_bounds_adjustment_transform_QueryInterface,
576 d2d_bounds_adjustment_transform_AddRef,
577 d2d_bounds_adjustment_transform_Release,
578 d2d_bounds_adjustment_transform_GetInputCount,
579 d2d_bounds_adjustment_transform_SetOutputBounds,
580 d2d_bounds_adjustment_transform_GetOutputBounds,
583 static HRESULT d2d_bounds_adjustment_transform_create(const D2D1_RECT_L *rect,
584 ID2D1BoundsAdjustmentTransform **transform)
586 struct d2d_transform *object;
588 *transform = NULL;
590 if (!(object = calloc(1, sizeof(*object))))
591 return E_OUTOFMEMORY;
593 object->ID2D1TransformNode_iface.lpVtbl = (ID2D1TransformNodeVtbl *)&d2d_bounds_adjustment_transform_vtbl;
594 object->refcount = 1;
595 object->bounds = *rect;
597 *transform = (ID2D1BoundsAdjustmentTransform *)&object->ID2D1TransformNode_iface;
599 return S_OK;
602 static struct d2d_transform_node * d2d_transform_graph_get_node(const struct d2d_transform_graph *graph,
603 ID2D1TransformNode *object)
605 struct d2d_transform_node *node;
607 LIST_FOR_EACH_ENTRY(node, &graph->nodes, struct d2d_transform_node, entry)
609 if (node->object == object)
610 return node;
613 return NULL;
616 static HRESULT d2d_transform_graph_add_node(struct d2d_transform_graph *graph,
617 ID2D1TransformNode *object)
619 struct d2d_transform_node *node;
621 if (!(node = calloc(1, sizeof(*node))))
622 return E_OUTOFMEMORY;
623 node->input_count = ID2D1TransformNode_GetInputCount(object);
624 if (!(node->inputs = calloc(node->input_count, sizeof(*node->inputs))))
626 free(node);
627 return E_OUTOFMEMORY;
630 node->object = object;
631 ID2D1TransformNode_AddRef(node->object);
632 list_add_tail(&graph->nodes, &node->entry);
634 return S_OK;
637 static void d2d_transform_node_disconnect(struct d2d_transform_node *node)
639 struct d2d_transform_node *output = node->output;
640 unsigned int i;
642 if (!output)
643 return;
645 for (i = 0; i < output->input_count; ++i)
647 if (output->inputs[i] == node)
649 output->inputs[i] = NULL;
650 break;
655 static void d2d_transform_graph_delete_node(struct d2d_transform_graph *graph,
656 struct d2d_transform_node *node)
658 unsigned int i;
660 list_remove(&node->entry);
661 ID2D1TransformNode_Release(node->object);
663 for (i = 0; i < graph->input_count; ++i)
665 if (graph->inputs[i].node == node)
666 memset(&graph->inputs[i].node, 0, sizeof(graph->inputs[i].node));
669 if (graph->output == node)
670 graph->output = NULL;
672 if (node->render_info)
673 ID2D1DrawInfo_Release(&node->render_info->ID2D1DrawInfo_iface);
675 d2d_transform_node_disconnect(node);
677 free(node->inputs);
678 free(node);
681 static void d2d_transform_graph_clear(struct d2d_transform_graph *graph)
683 struct d2d_transform_node *node, *node_next;
685 LIST_FOR_EACH_ENTRY_SAFE(node, node_next, &graph->nodes, struct d2d_transform_node, entry)
687 d2d_transform_graph_delete_node(graph, node);
689 graph->passthrough = false;
692 static inline struct d2d_transform_graph *impl_from_ID2D1TransformGraph(ID2D1TransformGraph *iface)
694 return CONTAINING_RECORD(iface, struct d2d_transform_graph, ID2D1TransformGraph_iface);
697 static HRESULT STDMETHODCALLTYPE d2d_transform_graph_QueryInterface(ID2D1TransformGraph *iface, REFIID iid, void **out)
699 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
701 if (IsEqualGUID(iid, &IID_ID2D1TransformGraph)
702 || IsEqualGUID(iid, &IID_IUnknown))
704 ID2D1TransformGraph_AddRef(iface);
705 *out = iface;
706 return S_OK;
709 *out = NULL;
710 return E_NOINTERFACE;
713 static ULONG STDMETHODCALLTYPE d2d_transform_graph_AddRef(ID2D1TransformGraph *iface)
715 struct d2d_transform_graph *graph =impl_from_ID2D1TransformGraph(iface);
716 ULONG refcount = InterlockedIncrement(&graph->refcount);
718 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
720 return refcount;
723 static ULONG STDMETHODCALLTYPE d2d_transform_graph_Release(ID2D1TransformGraph *iface)
725 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
726 ULONG refcount = InterlockedDecrement(&graph->refcount);
728 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
730 if (!refcount)
732 d2d_transform_graph_clear(graph);
733 free(graph->inputs);
734 free(graph);
737 return refcount;
740 static UINT32 STDMETHODCALLTYPE d2d_transform_graph_GetInputCount(ID2D1TransformGraph *iface)
742 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
744 TRACE("iface %p.\n", iface);
746 return graph->input_count;
749 static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetSingleTransformNode(ID2D1TransformGraph *iface,
750 ID2D1TransformNode *object)
752 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
753 struct d2d_transform_node *node;
754 unsigned int i, input_count;
755 HRESULT hr;
757 TRACE("iface %p, object %p.\n", iface, object);
759 d2d_transform_graph_clear(graph);
760 if (FAILED(hr = d2d_transform_graph_add_node(graph, object)))
761 return hr;
763 node = d2d_transform_graph_get_node(graph, object);
764 graph->output = node;
766 input_count = ID2D1TransformNode_GetInputCount(object);
767 if (graph->input_count != input_count)
768 return E_INVALIDARG;
770 for (i = 0; i < graph->input_count; ++i)
772 graph->inputs[i].node = node;
773 graph->inputs[i].index = i;
776 return S_OK;
779 static HRESULT STDMETHODCALLTYPE d2d_transform_graph_AddNode(ID2D1TransformGraph *iface,
780 ID2D1TransformNode *object)
782 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
784 TRACE("iface %p, object %p.\n", iface, object);
786 if (d2d_transform_graph_get_node(graph, object))
787 return E_INVALIDARG;
789 return d2d_transform_graph_add_node(graph, object);
792 static HRESULT STDMETHODCALLTYPE d2d_transform_graph_RemoveNode(ID2D1TransformGraph *iface,
793 ID2D1TransformNode *object)
795 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
796 struct d2d_transform_node *node;
798 TRACE("iface %p, object %p.\n", iface, object);
800 if (!(node = d2d_transform_graph_get_node(graph, object)))
801 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
803 d2d_transform_graph_delete_node(graph, node);
804 return S_OK;
807 static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetOutputNode(ID2D1TransformGraph *iface,
808 ID2D1TransformNode *object)
810 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
811 struct d2d_transform_node *node;
813 TRACE("iface %p, object %p.\n", iface, object);
815 if (!(node = d2d_transform_graph_get_node(graph, object)))
816 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
818 graph->output = node;
819 graph->passthrough = false;
821 return S_OK;
824 static HRESULT STDMETHODCALLTYPE d2d_transform_graph_ConnectNode(ID2D1TransformGraph *iface,
825 ID2D1TransformNode *from_node, ID2D1TransformNode *to_node, UINT32 index)
827 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
828 struct d2d_transform_node *from, *to;
830 TRACE("iface %p, from_node %p, to_node %p, index %u.\n", iface, from_node, to_node, index);
832 if (!(from = d2d_transform_graph_get_node(graph, from_node)))
833 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
835 if (!(to = d2d_transform_graph_get_node(graph, to_node)))
836 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
838 if (index >= to->input_count)
839 return E_INVALIDARG;
841 d2d_transform_node_disconnect(from);
842 to->inputs[index] = from;
843 from->output = to;
845 return S_OK;
848 static HRESULT STDMETHODCALLTYPE d2d_transform_graph_ConnectToEffectInput(ID2D1TransformGraph *iface,
849 UINT32 input_index, ID2D1TransformNode *object, UINT32 node_index)
851 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
852 struct d2d_transform_node *node;
853 unsigned int count;
855 TRACE("iface %p, input_index %u, object %p, node_index %u.\n", iface, input_index, object, node_index);
857 if (!(node = d2d_transform_graph_get_node(graph, object)))
858 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
860 if (input_index >= graph->input_count)
861 return E_INVALIDARG;
863 count = ID2D1TransformNode_GetInputCount(object);
864 if (node_index >= count)
865 return E_INVALIDARG;
867 graph->inputs[input_index].node = node;
868 graph->inputs[input_index].index = node_index;
869 graph->passthrough = false;
871 return S_OK;
874 static void STDMETHODCALLTYPE d2d_transform_graph_Clear(ID2D1TransformGraph *iface)
876 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
878 TRACE("iface %p.\n", iface);
880 d2d_transform_graph_clear(graph);
883 static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetPassthroughGraph(ID2D1TransformGraph *iface, UINT32 index)
885 struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
887 TRACE("iface %p, index %u.\n", iface, index);
889 if (index >= graph->input_count)
890 return E_INVALIDARG;
892 d2d_transform_graph_clear(graph);
894 graph->passthrough = true;
895 graph->passthrough_input = index;
897 return S_OK;
900 static const ID2D1TransformGraphVtbl d2d_transform_graph_vtbl =
902 d2d_transform_graph_QueryInterface,
903 d2d_transform_graph_AddRef,
904 d2d_transform_graph_Release,
905 d2d_transform_graph_GetInputCount,
906 d2d_transform_graph_SetSingleTransformNode,
907 d2d_transform_graph_AddNode,
908 d2d_transform_graph_RemoveNode,
909 d2d_transform_graph_SetOutputNode,
910 d2d_transform_graph_ConnectNode,
911 d2d_transform_graph_ConnectToEffectInput,
912 d2d_transform_graph_Clear,
913 d2d_transform_graph_SetPassthroughGraph,
916 static HRESULT d2d_transform_graph_create(UINT32 input_count, struct d2d_transform_graph **graph)
918 struct d2d_transform_graph *object;
920 if (!(object = calloc(1, sizeof(*object))))
921 return E_OUTOFMEMORY;
923 object->ID2D1TransformGraph_iface.lpVtbl = &d2d_transform_graph_vtbl;
924 object->refcount = 1;
925 list_init(&object->nodes);
927 if (!(object->inputs = calloc(input_count, sizeof(*object->inputs))))
929 free(object);
930 return E_OUTOFMEMORY;
932 object->input_count = input_count;
934 *graph = object;
936 return S_OK;
939 static HRESULT STDMETHODCALLTYPE d2d_effect_impl_QueryInterface(ID2D1EffectImpl *iface, REFIID iid, void **out)
941 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
943 if (IsEqualGUID(iid, &IID_ID2D1EffectImpl)
944 || IsEqualGUID(iid, &IID_IUnknown))
946 ID2D1EffectImpl_AddRef(iface);
947 *out = iface;
948 return S_OK;
951 *out = NULL;
952 return E_NOINTERFACE;
955 static ULONG STDMETHODCALLTYPE d2d_effect_impl_AddRef(ID2D1EffectImpl *iface)
957 return 2;
960 static ULONG STDMETHODCALLTYPE d2d_effect_impl_Release(ID2D1EffectImpl *iface)
962 return 1;
965 static HRESULT STDMETHODCALLTYPE d2d_effect_impl_Initialize(ID2D1EffectImpl *iface,
966 ID2D1EffectContext *context, ID2D1TransformGraph *graph)
968 return S_OK;
971 static HRESULT STDMETHODCALLTYPE d2d_effect_impl_PrepareForRender(ID2D1EffectImpl *iface, D2D1_CHANGE_TYPE type)
973 return S_OK;
976 static HRESULT STDMETHODCALLTYPE d2d_effect_impl_SetGraph(ID2D1EffectImpl *iface, ID2D1TransformGraph *graph)
978 return S_OK;
981 static const ID2D1EffectImplVtbl d2d_effect_impl_vtbl =
983 d2d_effect_impl_QueryInterface,
984 d2d_effect_impl_AddRef,
985 d2d_effect_impl_Release,
986 d2d_effect_impl_Initialize,
987 d2d_effect_impl_PrepareForRender,
988 d2d_effect_impl_SetGraph,
991 static HRESULT STDMETHODCALLTYPE builtin_factory_stub(IUnknown **effect_impl)
993 static ID2D1EffectImpl builtin_stub = { &d2d_effect_impl_vtbl };
995 *effect_impl = (IUnknown *)&builtin_stub;
997 return S_OK;
1000 static const WCHAR _2d_affine_transform_description[] =
1001 L"<?xml version='1.0'?> \
1002 <Effect> \
1003 <Property name='DisplayName' type='string' value='2D Affine Transform'/> \
1004 <Property name='Author' type='string' value='The Wine Project'/> \
1005 <Property name='Category' type='string' value='Stub'/> \
1006 <Property name='Description' type='string' value='2D Affine Transform'/> \
1007 <Inputs> \
1008 <Input name='Source'/> \
1009 </Inputs> \
1010 </Effect>";
1012 static const WCHAR _3d_perspective_transform_description[] =
1013 L"<?xml version='1.0'?> \
1014 <Effect> \
1015 <Property name='DisplayName' type='string' value='3D Perspective Transform'/> \
1016 <Property name='Author' type='string' value='The Wine Project'/> \
1017 <Property name='Category' type='string' value='Stub'/> \
1018 <Property name='Description' type='string' value='3D Perspective Transform'/> \
1019 <Inputs> \
1020 <Input name='Source'/> \
1021 </Inputs> \
1022 </Effect>";
1024 static const WCHAR composite_description[] =
1025 L"<?xml version='1.0'?> \
1026 <Effect> \
1027 <Property name='DisplayName' type='string' value='Composite'/> \
1028 <Property name='Author' type='string' value='The Wine Project'/> \
1029 <Property name='Category' type='string' value='Stub'/> \
1030 <Property name='Description' type='string' value='Composite'/> \
1031 <Inputs minimum='1' maximum='0xffffffff' > \
1032 <Input name='Source1'/> \
1033 <Input name='Source2'/> \
1034 </Inputs> \
1035 </Effect>";
1037 static const WCHAR crop_description[] =
1038 L"<?xml version='1.0'?> \
1039 <Effect> \
1040 <Property name='DisplayName' type='string' value='Crop'/> \
1041 <Property name='Author' type='string' value='The Wine Project'/> \
1042 <Property name='Category' type='string' value='Stub'/> \
1043 <Property name='Description' type='string' value='Crop'/> \
1044 <Inputs > \
1045 <Input name='Source'/> \
1046 </Inputs> \
1047 <Property name='Rect' type='vector4' /> \
1048 </Effect>";
1050 static const WCHAR shadow_description[] =
1051 L"<?xml version='1.0'?> \
1052 <Effect> \
1053 <Property name='DisplayName' type='string' value='Shadow'/> \
1054 <Property name='Author' type='string' value='The Wine Project'/> \
1055 <Property name='Category' type='string' value='Stub'/> \
1056 <Property name='Description' type='string' value='Shadow'/> \
1057 <Inputs > \
1058 <Input name='Source'/> \
1059 </Inputs> \
1060 </Effect>";
1062 static const WCHAR grayscale_description[] =
1063 L"<?xml version='1.0'?> \
1064 <Effect> \
1065 <Property name='DisplayName' type='string' value='Grayscale'/> \
1066 <Property name='Author' type='string' value='The Wine Project'/> \
1067 <Property name='Category' type='string' value='Stub'/> \
1068 <Property name='Description' type='string' value='Grayscale'/> \
1069 <Inputs > \
1070 <Input name='Source'/> \
1071 </Inputs> \
1072 </Effect>";
1074 void d2d_effects_init_builtins(struct d2d_factory *factory)
1076 static const struct builtin_description
1078 const CLSID *clsid;
1079 const WCHAR *description;
1081 builtin_effects[] =
1083 { &CLSID_D2D12DAffineTransform, _2d_affine_transform_description },
1084 { &CLSID_D2D13DPerspectiveTransform, _3d_perspective_transform_description},
1085 { &CLSID_D2D1Composite, composite_description },
1086 { &CLSID_D2D1Crop, crop_description },
1087 { &CLSID_D2D1Shadow, shadow_description },
1088 { &CLSID_D2D1Grayscale, grayscale_description },
1090 unsigned int i;
1091 HRESULT hr;
1093 for (i = 0; i < ARRAY_SIZE(builtin_effects); ++i)
1095 if (FAILED(hr = d2d_factory_register_builtin_effect(factory, builtin_effects[i].clsid, builtin_effects[i].description,
1096 NULL, 0, builtin_factory_stub)))
1098 WARN("Failed to register the effect %s, hr %#lx.\n", wine_dbgstr_guid(builtin_effects[i].clsid), hr);
1103 /* Same syntax is used for value and default values. */
1104 static HRESULT d2d_effect_parse_float_array(D2D1_PROPERTY_TYPE type, const WCHAR *value,
1105 float *vec)
1107 unsigned int i, num_components;
1108 WCHAR *end_ptr;
1110 /* Type values are sequential. */
1111 switch (type)
1113 case D2D1_PROPERTY_TYPE_VECTOR2:
1114 case D2D1_PROPERTY_TYPE_VECTOR3:
1115 case D2D1_PROPERTY_TYPE_VECTOR4:
1116 num_components = (type - D2D1_PROPERTY_TYPE_VECTOR2) + 2;
1117 break;
1118 case D2D1_PROPERTY_TYPE_MATRIX_3X2:
1119 num_components = 6;
1120 break;
1121 case D2D1_PROPERTY_TYPE_MATRIX_4X3:
1122 case D2D1_PROPERTY_TYPE_MATRIX_4X4:
1123 case D2D1_PROPERTY_TYPE_MATRIX_5X4:
1124 num_components = (type - D2D1_PROPERTY_TYPE_MATRIX_4X3) * 4 + 12;
1125 break;
1126 default:
1127 return E_UNEXPECTED;
1130 if (*(value++) != '(') return E_INVALIDARG;
1132 for (i = 0; i < num_components; ++i)
1134 vec[i] = wcstof(value, &end_ptr);
1135 if (value == end_ptr) return E_INVALIDARG;
1136 value = end_ptr;
1138 /* Trailing characters after last component are ignored. */
1139 if (i == num_components - 1) continue;
1140 if (*(value++) != ',') return E_INVALIDARG;
1143 return S_OK;
1146 static HRESULT d2d_effect_properties_internal_add(struct d2d_effect_properties *props,
1147 const WCHAR *name, UINT32 index, BOOL subprop, D2D1_PROPERTY_TYPE type, const WCHAR *value)
1149 static const UINT32 sizes[] =
1151 [D2D1_PROPERTY_TYPE_UNKNOWN] = 0,
1152 [D2D1_PROPERTY_TYPE_STRING] = 0,
1153 [D2D1_PROPERTY_TYPE_BOOL] = sizeof(BOOL),
1154 [D2D1_PROPERTY_TYPE_UINT32] = sizeof(UINT32),
1155 [D2D1_PROPERTY_TYPE_INT32] = sizeof(INT32),
1156 [D2D1_PROPERTY_TYPE_FLOAT] = sizeof(float),
1157 [D2D1_PROPERTY_TYPE_VECTOR2] = sizeof(D2D_VECTOR_2F),
1158 [D2D1_PROPERTY_TYPE_VECTOR3] = sizeof(D2D_VECTOR_3F),
1159 [D2D1_PROPERTY_TYPE_VECTOR4] = sizeof(D2D_VECTOR_4F),
1160 [D2D1_PROPERTY_TYPE_BLOB] = 0 /* FIXME */,
1161 [D2D1_PROPERTY_TYPE_IUNKNOWN] = sizeof(IUnknown *),
1162 [D2D1_PROPERTY_TYPE_ENUM] = sizeof(UINT32),
1163 [D2D1_PROPERTY_TYPE_ARRAY] = sizeof(UINT32),
1164 [D2D1_PROPERTY_TYPE_CLSID] = sizeof(CLSID),
1165 [D2D1_PROPERTY_TYPE_MATRIX_3X2] = sizeof(D2D_MATRIX_3X2_F),
1166 [D2D1_PROPERTY_TYPE_MATRIX_4X3] = sizeof(D2D_MATRIX_4X3_F),
1167 [D2D1_PROPERTY_TYPE_MATRIX_4X4] = sizeof(D2D_MATRIX_4X4_F),
1168 [D2D1_PROPERTY_TYPE_MATRIX_5X4] = sizeof(D2D_MATRIX_5X4_F),
1169 [D2D1_PROPERTY_TYPE_COLOR_CONTEXT] = sizeof(ID2D1ColorContext *),
1171 struct d2d_effect_property *p;
1172 HRESULT hr;
1174 assert(type >= D2D1_PROPERTY_TYPE_STRING && type <= D2D1_PROPERTY_TYPE_COLOR_CONTEXT);
1176 if (type == D2D1_PROPERTY_TYPE_BLOB)
1178 FIXME("Ignoring property %s of type %u.\n", wine_dbgstr_w(name), type);
1179 return S_OK;
1182 if (!d2d_array_reserve((void **)&props->properties, &props->size, props->count + 1,
1183 sizeof(*props->properties)))
1185 return E_OUTOFMEMORY;
1188 /* TODO: we could save some space for properties that have both getter and setter. */
1189 if (!d2d_array_reserve((void **)&props->data.ptr, &props->data.size,
1190 props->data.count + sizes[type], sizeof(*props->data.ptr)))
1192 return E_OUTOFMEMORY;
1194 props->data.count += sizes[type];
1196 p = &props->properties[props->count++];
1197 memset(p, 0, sizeof(*p));
1198 p->index = index;
1199 if (p->index < 0x80000000)
1201 props->custom_count++;
1202 /* FIXME: this should probably be controlled by subproperty */
1203 p->readonly = FALSE;
1205 else if (subprop)
1206 p->readonly = TRUE;
1207 else
1208 p->readonly = index != D2D1_PROPERTY_CACHED && index != D2D1_PROPERTY_PRECISION;
1209 p->name = wcsdup(name);
1210 p->type = type;
1211 if (p->type == D2D1_PROPERTY_TYPE_STRING)
1213 p->data.ptr = wcsdup(value);
1214 p->size = value ? (wcslen(value) + 1) * sizeof(WCHAR) : sizeof(WCHAR);
1216 else
1218 void *src = NULL;
1219 UINT32 _uint32;
1220 float _vec[20];
1221 CLSID _clsid;
1222 BOOL _bool;
1224 p->data.offset = props->offset;
1225 p->size = sizes[type];
1226 props->offset += p->size;
1228 if (value)
1230 switch (p->type)
1232 case D2D1_PROPERTY_TYPE_UINT32:
1233 case D2D1_PROPERTY_TYPE_INT32:
1234 _uint32 = wcstoul(value, NULL, 0);
1235 src = &_uint32;
1236 break;
1237 case D2D1_PROPERTY_TYPE_ENUM:
1238 _uint32 = wcstoul(value, NULL, 10);
1239 src = &_uint32;
1240 break;
1241 case D2D1_PROPERTY_TYPE_BOOL:
1242 if (!wcscmp(value, L"true")) _bool = TRUE;
1243 else if (!wcscmp(value, L"false")) _bool = FALSE;
1244 else return E_INVALIDARG;
1245 src = &_bool;
1246 break;
1247 case D2D1_PROPERTY_TYPE_CLSID:
1248 CLSIDFromString(value, &_clsid);
1249 src = &_clsid;
1250 break;
1251 case D2D1_PROPERTY_TYPE_VECTOR2:
1252 case D2D1_PROPERTY_TYPE_VECTOR3:
1253 case D2D1_PROPERTY_TYPE_VECTOR4:
1254 case D2D1_PROPERTY_TYPE_MATRIX_3X2:
1255 case D2D1_PROPERTY_TYPE_MATRIX_4X3:
1256 case D2D1_PROPERTY_TYPE_MATRIX_4X4:
1257 case D2D1_PROPERTY_TYPE_MATRIX_5X4:
1258 if (FAILED(hr = d2d_effect_parse_float_array(p->type, value, _vec)))
1260 WARN("Failed to parse float array %s for type %u.\n",
1261 wine_dbgstr_w(value), p->type);
1262 return hr;
1264 src = _vec;
1265 break;
1266 case D2D1_PROPERTY_TYPE_IUNKNOWN:
1267 case D2D1_PROPERTY_TYPE_COLOR_CONTEXT:
1268 break;
1269 default:
1270 FIXME("Initial value for property type %u is not handled.\n", p->type);
1273 if (src && p->size) memcpy(props->data.ptr + p->data.offset, src, p->size);
1275 else if (p->size)
1276 memset(props->data.ptr + p->data.offset, 0, p->size);
1279 return S_OK;
1282 HRESULT d2d_effect_properties_add(struct d2d_effect_properties *props, const WCHAR *name,
1283 UINT32 index, D2D1_PROPERTY_TYPE type, const WCHAR *value)
1285 return d2d_effect_properties_internal_add(props, name, index, FALSE, type, value);
1288 HRESULT d2d_effect_subproperties_add(struct d2d_effect_properties *props, const WCHAR *name,
1289 UINT32 index, D2D1_PROPERTY_TYPE type, const WCHAR *value)
1291 return d2d_effect_properties_internal_add(props, name, index, TRUE, type, value);
1294 static HRESULT d2d_effect_duplicate_properties(struct d2d_effect *effect,
1295 struct d2d_effect_properties *dst, const struct d2d_effect_properties *src)
1297 HRESULT hr;
1298 size_t i;
1300 *dst = *src;
1301 dst->effect = effect;
1303 if (!(dst->data.ptr = malloc(dst->data.size)))
1304 return E_OUTOFMEMORY;
1305 memcpy(dst->data.ptr, src->data.ptr, dst->data.size);
1307 if (!(dst->properties = calloc(dst->size, sizeof(*dst->properties))))
1308 return E_OUTOFMEMORY;
1310 for (i = 0; i < dst->count; ++i)
1312 struct d2d_effect_property *d = &dst->properties[i];
1313 const struct d2d_effect_property *s = &src->properties[i];
1315 *d = *s;
1316 d->name = wcsdup(s->name);
1317 if (d->type == D2D1_PROPERTY_TYPE_STRING)
1318 d->data.ptr = wcsdup((WCHAR *)s->data.ptr);
1320 if (s->subproperties)
1322 if (!(d->subproperties = calloc(1, sizeof(*d->subproperties))))
1323 return E_OUTOFMEMORY;
1324 if (FAILED(hr = d2d_effect_duplicate_properties(effect, d->subproperties, s->subproperties)))
1325 return hr;
1329 return S_OK;
1332 static struct d2d_effect_property * d2d_effect_properties_get_property_by_index(
1333 const struct d2d_effect_properties *properties, UINT32 index)
1335 unsigned int i;
1337 for (i = 0; i < properties->count; ++i)
1339 if (properties->properties[i].index == index)
1340 return &properties->properties[i];
1343 return NULL;
1346 struct d2d_effect_property * d2d_effect_properties_get_property_by_name(
1347 const struct d2d_effect_properties *properties, const WCHAR *name)
1349 unsigned int i;
1351 for (i = 0; i < properties->count; ++i)
1353 if (!wcscmp(properties->properties[i].name, name))
1354 return &properties->properties[i];
1357 return NULL;
1360 static UINT32 d2d_effect_properties_get_value_size(const struct d2d_effect_properties *properties,
1361 UINT32 index)
1363 struct d2d_effect *effect = properties->effect;
1364 struct d2d_effect_property *prop;
1365 UINT32 size;
1367 if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
1368 return 0;
1370 if (prop->get_function)
1372 if (FAILED(prop->get_function((IUnknown *)effect->impl, NULL, 0, &size))) return 0;
1373 return size;
1376 return prop->size;
1379 static HRESULT d2d_effect_return_string(const WCHAR *str, WCHAR *buffer, UINT32 buffer_size)
1381 UINT32 size = str ? wcslen(str) : 0;
1382 if (size >= buffer_size) return D2DERR_INSUFFICIENT_BUFFER;
1383 if (str) memcpy(buffer, str, (size + 1) * sizeof(*buffer));
1384 else *buffer = 0;
1385 return S_OK;
1388 static HRESULT d2d_effect_property_get_value(const struct d2d_effect_properties *properties,
1389 const struct d2d_effect_property *prop, D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 size)
1391 struct d2d_effect *effect = properties->effect;
1392 UINT32 actual_size;
1394 memset(value, 0, size);
1396 if (type != D2D1_PROPERTY_TYPE_UNKNOWN && prop->type != type) return E_INVALIDARG;
1397 if (prop->type != D2D1_PROPERTY_TYPE_STRING && prop->size != size) return E_INVALIDARG;
1399 if (prop->get_function)
1400 return prop->get_function((IUnknown *)effect->impl, value, size, &actual_size);
1402 switch (prop->type)
1404 case D2D1_PROPERTY_TYPE_BLOB:
1405 FIXME("Unimplemented for type %u.\n", prop->type);
1406 return E_NOTIMPL;
1407 case D2D1_PROPERTY_TYPE_STRING:
1408 return d2d_effect_return_string(prop->data.ptr, (WCHAR *)value, size / sizeof(WCHAR));
1409 default:
1410 memcpy(value, properties->data.ptr + prop->data.offset, size);
1411 break;
1414 return S_OK;
1417 HRESULT d2d_effect_property_get_uint32_value(const struct d2d_effect_properties *properties,
1418 const struct d2d_effect_property *prop, UINT32 *value)
1420 return d2d_effect_property_get_value(properties, prop, D2D1_PROPERTY_TYPE_UINT32,
1421 (BYTE *)value, sizeof(*value));
1424 static HRESULT d2d_effect_property_set_value(struct d2d_effect_properties *properties,
1425 struct d2d_effect_property *prop, D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 size)
1427 struct d2d_effect *effect = properties->effect;
1428 if (prop->readonly || !effect) return E_INVALIDARG;
1429 if (type != D2D1_PROPERTY_TYPE_UNKNOWN && prop->type != type) return E_INVALIDARG;
1430 if (prop->get_function && !prop->set_function) return E_INVALIDARG;
1431 if (prop->index < 0x80000000 && !prop->set_function) return E_INVALIDARG;
1433 if (prop->set_function)
1434 return prop->set_function((IUnknown *)effect->impl, value, size);
1436 if (prop->size != size) return E_INVALIDARG;
1438 switch (prop->type)
1440 case D2D1_PROPERTY_TYPE_BOOL:
1441 case D2D1_PROPERTY_TYPE_UINT32:
1442 case D2D1_PROPERTY_TYPE_ENUM:
1443 memcpy(properties->data.ptr + prop->data.offset, value, size);
1444 break;
1445 default:
1446 FIXME("Unhandled type %u.\n", prop->type);
1449 return S_OK;
1452 void d2d_effect_properties_cleanup(struct d2d_effect_properties *props)
1454 struct d2d_effect_property *p;
1455 size_t i;
1457 for (i = 0; i < props->count; ++i)
1459 p = &props->properties[i];
1460 free(p->name);
1461 if (p->type == D2D1_PROPERTY_TYPE_STRING)
1462 free(p->data.ptr);
1463 if (p->subproperties)
1465 d2d_effect_properties_cleanup(p->subproperties);
1466 free(p->subproperties);
1469 free(props->properties);
1470 free(props->data.ptr);
1473 static inline struct d2d_effect_context *impl_from_ID2D1EffectContext(ID2D1EffectContext *iface)
1475 return CONTAINING_RECORD(iface, struct d2d_effect_context, ID2D1EffectContext_iface);
1478 static HRESULT STDMETHODCALLTYPE d2d_effect_context_QueryInterface(ID2D1EffectContext *iface, REFIID iid, void **out)
1480 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1482 if (IsEqualGUID(iid, &IID_ID2D1EffectContext)
1483 || IsEqualGUID(iid, &IID_IUnknown))
1485 ID2D1EffectContext_AddRef(iface);
1486 *out = iface;
1487 return S_OK;
1490 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1492 *out = NULL;
1493 return E_NOINTERFACE;
1496 static ULONG STDMETHODCALLTYPE d2d_effect_context_AddRef(ID2D1EffectContext *iface)
1498 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1499 ULONG refcount = InterlockedIncrement(&effect_context->refcount);
1501 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
1503 return refcount;
1506 static ULONG STDMETHODCALLTYPE d2d_effect_context_Release(ID2D1EffectContext *iface)
1508 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1509 ULONG refcount = InterlockedDecrement(&effect_context->refcount);
1511 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
1513 if (!refcount)
1515 ID2D1DeviceContext6_Release(&effect_context->device_context->ID2D1DeviceContext6_iface);
1516 free(effect_context);
1519 return refcount;
1522 static void STDMETHODCALLTYPE d2d_effect_context_GetDpi(ID2D1EffectContext *iface, float *dpi_x, float *dpi_y)
1524 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1526 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
1528 ID2D1DeviceContext6_GetDpi(&effect_context->device_context->ID2D1DeviceContext6_iface, dpi_x, dpi_y);
1531 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateEffect(ID2D1EffectContext *iface,
1532 REFCLSID clsid, ID2D1Effect **effect)
1534 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1536 TRACE("iface %p, clsid %s, effect %p.\n", iface, debugstr_guid(clsid), effect);
1538 return ID2D1DeviceContext6_CreateEffect(&effect_context->device_context->ID2D1DeviceContext6_iface,
1539 clsid, effect);
1542 static HRESULT STDMETHODCALLTYPE d2d_effect_context_GetMaximumSupportedFeatureLevel(ID2D1EffectContext *iface,
1543 const D3D_FEATURE_LEVEL *levels, UINT32 level_count, D3D_FEATURE_LEVEL *max_level)
1545 FIXME("iface %p, levels %p, level_count %u, max_level %p stub!\n", iface, levels, level_count, max_level);
1547 return E_NOTIMPL;
1550 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateTransformNodeFromEffect(ID2D1EffectContext *iface,
1551 ID2D1Effect *effect, ID2D1TransformNode **node)
1553 FIXME("iface %p, effect %p, node %p stub!\n", iface, effect, node);
1555 return E_NOTIMPL;
1558 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateBlendTransform(ID2D1EffectContext *iface,
1559 UINT32 num_inputs, const D2D1_BLEND_DESCRIPTION *description, ID2D1BlendTransform **transform)
1561 TRACE("iface %p, num_inputs %u, description %p, transform %p,\n", iface, num_inputs, description, transform);
1563 return d2d_blend_transform_create(num_inputs, description, transform);
1566 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateBorderTransform(ID2D1EffectContext *iface,
1567 D2D1_EXTEND_MODE mode_x, D2D1_EXTEND_MODE mode_y, ID2D1BorderTransform **transform)
1569 TRACE("iface %p, mode_x %#x, mode_y %#x, transform %p.\n", iface, mode_x, mode_y, transform);
1571 return d2d_border_transform_create(mode_x, mode_y, transform);
1574 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateOffsetTransform(ID2D1EffectContext *iface,
1575 D2D1_POINT_2L offset, ID2D1OffsetTransform **transform)
1577 TRACE("iface %p, offset %s, transform %p.\n", iface, debug_d2d_point_2l(&offset), transform);
1579 return d2d_offset_transform_create(offset, transform);
1582 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateBoundsAdjustmentTransform(ID2D1EffectContext *iface,
1583 const D2D1_RECT_L *output_rect, ID2D1BoundsAdjustmentTransform **transform)
1585 TRACE("iface %p, output_rect %s, transform %p.\n", iface, debug_d2d_rect_l(output_rect), transform);
1587 return d2d_bounds_adjustment_transform_create(output_rect, transform);
1590 static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadPixelShader(ID2D1EffectContext *iface,
1591 REFGUID shader_id, const BYTE *buffer, UINT32 buffer_size)
1593 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1594 struct d2d_device *device = effect_context->device_context->device;
1595 ID3D11PixelShader *shader;
1596 HRESULT hr;
1598 TRACE("iface %p, shader_id %s, buffer %p, buffer_size %u.\n",
1599 iface, debugstr_guid(shader_id), buffer, buffer_size);
1601 if (d2d_device_get_indexed_object(&device->shaders, shader_id, NULL))
1602 return S_OK;
1604 if (FAILED(hr = ID3D11Device1_CreatePixelShader(effect_context->device_context->d3d_device,
1605 buffer, buffer_size, NULL, &shader)))
1607 WARN("Failed to create a pixel shader, hr %#lx.\n", hr);
1608 return hr;
1611 hr = d2d_device_add_indexed_object(&device->shaders, shader_id, (IUnknown *)shader);
1612 ID3D11PixelShader_Release(shader);
1614 return hr;
1617 static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadVertexShader(ID2D1EffectContext *iface,
1618 REFGUID shader_id, const BYTE *buffer, UINT32 buffer_size)
1620 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1621 struct d2d_device *device = effect_context->device_context->device;
1622 ID3D11VertexShader *shader;
1623 HRESULT hr;
1625 TRACE("iface %p, shader_id %s, buffer %p, buffer_size %u.\n",
1626 iface, debugstr_guid(shader_id), buffer, buffer_size);
1628 if (d2d_device_get_indexed_object(&device->shaders, shader_id, NULL))
1629 return S_OK;
1631 if (FAILED(hr = ID3D11Device1_CreateVertexShader(effect_context->device_context->d3d_device,
1632 buffer, buffer_size, NULL, &shader)))
1634 WARN("Failed to create vertex shader, hr %#lx.\n", hr);
1635 return hr;
1638 hr = d2d_device_add_indexed_object(&device->shaders, shader_id, (IUnknown *)shader);
1639 ID3D11VertexShader_Release(shader);
1641 return hr;
1644 static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadComputeShader(ID2D1EffectContext *iface,
1645 REFGUID shader_id, const BYTE *buffer, UINT32 buffer_size)
1647 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1648 struct d2d_device *device = effect_context->device_context->device;
1649 ID3D11ComputeShader *shader;
1650 HRESULT hr;
1652 TRACE("iface %p, shader_id %s, buffer %p, buffer_size %u.\n",
1653 iface, debugstr_guid(shader_id), buffer, buffer_size);
1655 if (d2d_device_get_indexed_object(&device->shaders, shader_id, NULL))
1656 return S_OK;
1658 if (FAILED(hr = ID3D11Device1_CreateComputeShader(effect_context->device_context->d3d_device,
1659 buffer, buffer_size, NULL, &shader)))
1661 WARN("Failed to create a compute shader, hr %#lx.\n", hr);
1662 return hr;
1665 hr = d2d_device_add_indexed_object(&device->shaders, shader_id, (IUnknown *)shader);
1666 ID3D11ComputeShader_Release(shader);
1668 return hr;
1671 static BOOL STDMETHODCALLTYPE d2d_effect_context_IsShaderLoaded(ID2D1EffectContext *iface, REFGUID shader_id)
1673 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1674 struct d2d_device *device = effect_context->device_context->device;
1676 TRACE("iface %p, shader_id %s.\n", iface, debugstr_guid(shader_id));
1678 return d2d_device_get_indexed_object(&device->shaders, shader_id, NULL);
1681 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateResourceTexture(ID2D1EffectContext *iface,
1682 const GUID *id, const D2D1_RESOURCE_TEXTURE_PROPERTIES *texture_properties,
1683 const BYTE *data, const UINT32 *strides, UINT32 data_size, ID2D1ResourceTexture **texture)
1685 FIXME("iface %p, id %s, texture_properties %p, data %p, strides %p, data_size %u, texture %p stub!\n",
1686 iface, debugstr_guid(id), texture_properties, data, strides, data_size, texture);
1688 return E_NOTIMPL;
1691 static HRESULT STDMETHODCALLTYPE d2d_effect_context_FindResourceTexture(ID2D1EffectContext *iface,
1692 const GUID *id, ID2D1ResourceTexture **texture)
1694 FIXME("iface %p, id %s, texture %p stub!\n", iface, debugstr_guid(id), texture);
1696 return E_NOTIMPL;
1699 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateVertexBuffer(ID2D1EffectContext *iface,
1700 const D2D1_VERTEX_BUFFER_PROPERTIES *buffer_properties, const GUID *id,
1701 const D2D1_CUSTOM_VERTEX_BUFFER_PROPERTIES *custom_buffer_properties,
1702 ID2D1VertexBuffer **buffer)
1704 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1705 struct d2d_device_context *context = effect_context->device_context;
1706 HRESULT hr;
1708 FIXME("iface %p, buffer_properties %p, id %s, custom_buffer_properties %p, buffer %p stub!\n",
1709 iface, buffer_properties, debugstr_guid(id), custom_buffer_properties, buffer);
1711 if (id && d2d_device_get_indexed_object(&context->vertex_buffers, id, (IUnknown **)buffer))
1712 return S_OK;
1714 if (SUCCEEDED(hr = d2d_vertex_buffer_create(buffer)))
1716 if (id)
1717 hr = d2d_device_add_indexed_object(&context->vertex_buffers, id, (IUnknown *)*buffer);
1720 if (FAILED(hr))
1721 *buffer = NULL;
1723 return hr;
1726 static HRESULT STDMETHODCALLTYPE d2d_effect_context_FindVertexBuffer(ID2D1EffectContext *iface,
1727 const GUID *id, ID2D1VertexBuffer **buffer)
1729 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1730 struct d2d_device_context *context = effect_context->device_context;
1732 TRACE("iface %p, id %s, buffer %p.\n", iface, debugstr_guid(id), buffer);
1734 if (!d2d_device_get_indexed_object(&context->vertex_buffers, id, (IUnknown **)buffer))
1735 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1737 return S_OK;
1740 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateColorContext(ID2D1EffectContext *iface,
1741 D2D1_COLOR_SPACE space, const BYTE *profile, UINT32 profile_size, ID2D1ColorContext **color_context)
1743 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1745 TRACE("iface %p, space %#x, profile %p, profile_size %u, color_context %p.\n",
1746 iface, space, profile, profile_size, color_context);
1748 return ID2D1DeviceContext6_CreateColorContext(&effect_context->device_context->ID2D1DeviceContext6_iface,
1749 space, profile, profile_size, color_context);
1752 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateColorContextFromFilename(ID2D1EffectContext *iface,
1753 const WCHAR *filename, ID2D1ColorContext **color_context)
1755 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1757 TRACE("iface %p, filename %s, color_context %p.\n", iface, debugstr_w(filename), color_context);
1759 return ID2D1DeviceContext6_CreateColorContextFromFilename(&effect_context->device_context->ID2D1DeviceContext6_iface,
1760 filename, color_context);
1763 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateColorContextFromWicColorContext(ID2D1EffectContext *iface,
1764 IWICColorContext *wic_color_context, ID2D1ColorContext **color_context)
1766 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1768 TRACE("iface %p, wic_color_context %p, color_context %p.\n", iface, wic_color_context, color_context);
1770 return ID2D1DeviceContext6_CreateColorContextFromWicColorContext(&effect_context->device_context->ID2D1DeviceContext6_iface,
1771 wic_color_context, color_context);
1774 static HRESULT STDMETHODCALLTYPE d2d_effect_context_CheckFeatureSupport(ID2D1EffectContext *iface,
1775 D2D1_FEATURE feature, void *data, UINT32 data_size)
1777 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1778 D3D11_FEATURE d3d11_feature;
1780 TRACE("iface %p, feature %#x, data %p, data_size %u.\n", iface, feature, data, data_size);
1782 /* Data structures are compatible. */
1783 switch (feature)
1785 case D2D1_FEATURE_DOUBLES: d3d11_feature = D3D11_FEATURE_DOUBLES; break;
1786 case D2D1_FEATURE_D3D10_X_HARDWARE_OPTIONS: d3d11_feature = D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS; break;
1787 default:
1788 WARN("Unexpected feature index %d.\n", feature);
1789 return E_INVALIDARG;
1792 return ID3D11Device1_CheckFeatureSupport(effect_context->device_context->d3d_device,
1793 d3d11_feature, data, data_size);
1796 static BOOL STDMETHODCALLTYPE d2d_effect_context_IsBufferPrecisionSupported(ID2D1EffectContext *iface,
1797 D2D1_BUFFER_PRECISION precision)
1799 struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
1801 TRACE("iface %p, precision %u.\n", iface, precision);
1803 return ID2D1DeviceContext6_IsBufferPrecisionSupported(&effect_context->device_context->ID2D1DeviceContext6_iface,
1804 precision);
1807 static const ID2D1EffectContextVtbl d2d_effect_context_vtbl =
1809 d2d_effect_context_QueryInterface,
1810 d2d_effect_context_AddRef,
1811 d2d_effect_context_Release,
1812 d2d_effect_context_GetDpi,
1813 d2d_effect_context_CreateEffect,
1814 d2d_effect_context_GetMaximumSupportedFeatureLevel,
1815 d2d_effect_context_CreateTransformNodeFromEffect,
1816 d2d_effect_context_CreateBlendTransform,
1817 d2d_effect_context_CreateBorderTransform,
1818 d2d_effect_context_CreateOffsetTransform,
1819 d2d_effect_context_CreateBoundsAdjustmentTransform,
1820 d2d_effect_context_LoadPixelShader,
1821 d2d_effect_context_LoadVertexShader,
1822 d2d_effect_context_LoadComputeShader,
1823 d2d_effect_context_IsShaderLoaded,
1824 d2d_effect_context_CreateResourceTexture,
1825 d2d_effect_context_FindResourceTexture,
1826 d2d_effect_context_CreateVertexBuffer,
1827 d2d_effect_context_FindVertexBuffer,
1828 d2d_effect_context_CreateColorContext,
1829 d2d_effect_context_CreateColorContextFromFilename,
1830 d2d_effect_context_CreateColorContextFromWicColorContext,
1831 d2d_effect_context_CheckFeatureSupport,
1832 d2d_effect_context_IsBufferPrecisionSupported,
1835 void d2d_effect_context_init(struct d2d_effect_context *effect_context, struct d2d_device_context *device_context)
1837 effect_context->ID2D1EffectContext_iface.lpVtbl = &d2d_effect_context_vtbl;
1838 effect_context->refcount = 1;
1839 effect_context->device_context = device_context;
1840 ID2D1DeviceContext6_AddRef(&device_context->ID2D1DeviceContext6_iface);
1843 static inline struct d2d_effect *impl_from_ID2D1Effect(ID2D1Effect *iface)
1845 return CONTAINING_RECORD(iface, struct d2d_effect, ID2D1Effect_iface);
1848 static void d2d_effect_cleanup(struct d2d_effect *effect)
1850 unsigned int i;
1852 for (i = 0; i < effect->input_count; ++i)
1854 if (effect->inputs[i])
1855 ID2D1Image_Release(effect->inputs[i]);
1857 free(effect->inputs);
1858 ID2D1EffectContext_Release(&effect->effect_context->ID2D1EffectContext_iface);
1859 if (effect->graph)
1860 ID2D1TransformGraph_Release(&effect->graph->ID2D1TransformGraph_iface);
1861 //d2d_effect_properties_cleanup(&effect->properties);
1862 if (effect->impl)
1863 ID2D1EffectImpl_Release(effect->impl);
1866 static HRESULT STDMETHODCALLTYPE d2d_effect_QueryInterface(ID2D1Effect *iface, REFIID iid, void **out)
1868 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1869 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1871 if (IsEqualGUID(iid, &IID_ID2D1Effect)
1872 || IsEqualGUID(iid, &IID_ID2D1Properties)
1873 || IsEqualGUID(iid, &IID_IUnknown))
1875 ID2D1Effect_AddRef(iface);
1876 *out = iface;
1877 return S_OK;
1880 if (IsEqualGUID(iid, &IID_ID2D1Image)
1881 || IsEqualGUID(iid, &IID_ID2D1Resource))
1883 ID2D1Image_AddRef(&effect->ID2D1Image_iface);
1884 *out = &effect->ID2D1Image_iface;
1885 return S_OK;
1888 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1890 *out = NULL;
1891 return E_NOINTERFACE;
1894 static ULONG STDMETHODCALLTYPE d2d_effect_AddRef(ID2D1Effect *iface)
1896 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1897 ULONG refcount = InterlockedIncrement(&effect->refcount);
1899 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
1901 return refcount;
1904 static ULONG STDMETHODCALLTYPE d2d_effect_Release(ID2D1Effect *iface)
1906 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1907 ULONG refcount = InterlockedDecrement(&effect->refcount);
1909 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
1911 if (!refcount)
1913 d2d_effect_cleanup(effect);
1914 free(effect);
1917 return refcount;
1920 static UINT32 STDMETHODCALLTYPE d2d_effect_GetPropertyCount(ID2D1Effect *iface)
1922 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1924 TRACE("iface %p.\n", iface);
1926 return ID2D1Properties_GetPropertyCount(&effect->properties.ID2D1Properties_iface);
1929 static HRESULT STDMETHODCALLTYPE d2d_effect_GetPropertyName(ID2D1Effect *iface, UINT32 index,
1930 WCHAR *name, UINT32 name_count)
1932 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1934 TRACE("iface %p, index %u, name %p, name_count %u.\n", iface, index, name, name_count);
1936 return ID2D1Properties_GetPropertyName(&effect->properties.ID2D1Properties_iface,
1937 index, name, name_count);
1940 static UINT32 STDMETHODCALLTYPE d2d_effect_GetPropertyNameLength(ID2D1Effect *iface, UINT32 index)
1942 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1944 TRACE("iface %p, index %u.\n", iface, index);
1946 return ID2D1Properties_GetPropertyNameLength(&effect->properties.ID2D1Properties_iface, index);
1949 static D2D1_PROPERTY_TYPE STDMETHODCALLTYPE d2d_effect_GetType(ID2D1Effect *iface, UINT32 index)
1951 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1953 TRACE("iface %p, index %#x.\n", iface, index);
1955 return ID2D1Properties_GetType(&effect->properties.ID2D1Properties_iface, index);
1958 static UINT32 STDMETHODCALLTYPE d2d_effect_GetPropertyIndex(ID2D1Effect *iface, const WCHAR *name)
1960 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1962 TRACE("iface %p, name %s.\n", iface, debugstr_w(name));
1964 return ID2D1Properties_GetPropertyIndex(&effect->properties.ID2D1Properties_iface, name);
1967 static HRESULT STDMETHODCALLTYPE d2d_effect_SetValueByName(ID2D1Effect *iface, const WCHAR *name,
1968 D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 value_size)
1970 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1972 TRACE("iface %p, name %s, type %u, value %p, value_size %u.\n", iface, debugstr_w(name),
1973 type, value, value_size);
1975 return ID2D1Properties_SetValueByName(&effect->properties.ID2D1Properties_iface, name,
1976 type, value, value_size);
1979 static HRESULT STDMETHODCALLTYPE d2d_effect_SetValue(ID2D1Effect *iface, UINT32 index, D2D1_PROPERTY_TYPE type,
1980 const BYTE *value, UINT32 value_size)
1982 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1984 TRACE("iface %p, index %#x, type %u, value %p, value_size %u.\n", iface, index, type, value, value_size);
1986 return ID2D1Properties_SetValue(&effect->properties.ID2D1Properties_iface, index, type,
1987 value, value_size);
1990 static HRESULT STDMETHODCALLTYPE d2d_effect_GetValueByName(ID2D1Effect *iface, const WCHAR *name,
1991 D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 value_size)
1993 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
1995 TRACE("iface %p, name %s, type %#x, value %p, value_size %u.\n", iface, debugstr_w(name), type,
1996 value, value_size);
1998 return ID2D1Properties_GetValueByName(&effect->properties.ID2D1Properties_iface, name, type,
1999 value, value_size);
2002 static HRESULT d2d_effect_get_value(struct d2d_effect *effect, UINT32 index, D2D1_PROPERTY_TYPE type,
2003 BYTE *value, UINT32 value_size)
2005 return ID2D1Properties_GetValue(&effect->properties.ID2D1Properties_iface, index, type, value, value_size);
2008 static HRESULT STDMETHODCALLTYPE d2d_effect_GetValue(ID2D1Effect *iface, UINT32 index, D2D1_PROPERTY_TYPE type,
2009 BYTE *value, UINT32 value_size)
2011 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
2013 TRACE("iface %p, index %#x, type %u, value %p, value_size %u.\n", iface, index, type, value, value_size);
2015 return d2d_effect_get_value(effect, index, type, value, value_size);
2018 static UINT32 STDMETHODCALLTYPE d2d_effect_GetValueSize(ID2D1Effect *iface, UINT32 index)
2020 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
2022 TRACE("iface %p, index %#x.\n", iface, index);
2024 return ID2D1Properties_GetValueSize(&effect->properties.ID2D1Properties_iface, index);
2027 static HRESULT STDMETHODCALLTYPE d2d_effect_GetSubProperties(ID2D1Effect *iface, UINT32 index,
2028 ID2D1Properties **props)
2030 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
2032 TRACE("iface %p, index %u, props %p.\n", iface, index, props);
2034 return ID2D1Properties_GetSubProperties(&effect->properties.ID2D1Properties_iface, index, props);
2037 static void STDMETHODCALLTYPE d2d_effect_SetInput(ID2D1Effect *iface, UINT32 index, ID2D1Image *input, BOOL invalidate)
2039 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
2041 TRACE("iface %p, index %u, input %p, invalidate %#x.\n", iface, index, input, invalidate);
2043 if (index >= effect->input_count)
2044 return;
2046 ID2D1Image_AddRef(input);
2047 if (effect->inputs[index])
2048 ID2D1Image_Release(effect->inputs[index]);
2049 effect->inputs[index] = input;
2052 static HRESULT d2d_effect_set_input_count(struct d2d_effect *effect, UINT32 count)
2054 bool initialized = effect->inputs != NULL;
2055 HRESULT hr = S_OK;
2056 unsigned int i;
2058 if (count == effect->input_count)
2059 return S_OK;
2061 if (count < effect->input_count)
2063 for (i = count; i < effect->input_count; ++i)
2065 if (effect->inputs[i])
2066 ID2D1Image_Release(effect->inputs[i]);
2069 else
2071 if (!d2d_array_reserve((void **)&effect->inputs, &effect->inputs_size,
2072 count, sizeof(*effect->inputs)))
2074 ERR("Failed to resize inputs array.\n");
2075 return E_OUTOFMEMORY;
2078 memset(&effect->inputs[effect->input_count], 0, sizeof(*effect->inputs) * (count - effect->input_count));
2080 effect->input_count = count;
2082 if (initialized)
2084 ID2D1TransformGraph_Release(&effect->graph->ID2D1TransformGraph_iface);
2085 effect->graph = NULL;
2087 if (SUCCEEDED(hr = d2d_transform_graph_create(count, &effect->graph)))
2089 if (FAILED(hr = ID2D1EffectImpl_SetGraph(effect->impl, &effect->graph->ID2D1TransformGraph_iface)))
2090 WARN("Failed to set a new transform graph, hr %#lx.\n", hr);
2094 return hr;
2097 static HRESULT STDMETHODCALLTYPE d2d_effect_SetInputCount(ID2D1Effect *iface, UINT32 count)
2099 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
2100 unsigned int min_inputs, max_inputs;
2102 TRACE("iface %p, count %u.\n", iface, count);
2104 d2d_effect_get_value(effect, D2D1_PROPERTY_MIN_INPUTS, D2D1_PROPERTY_TYPE_UINT32,
2105 (BYTE *)&min_inputs, sizeof(min_inputs));
2106 d2d_effect_get_value(effect, D2D1_PROPERTY_MAX_INPUTS, D2D1_PROPERTY_TYPE_UINT32,
2107 (BYTE *)&max_inputs, sizeof(max_inputs));
2109 if (count < min_inputs || count > max_inputs)
2110 return E_INVALIDARG;
2112 return d2d_effect_set_input_count(effect, count);
2115 static void STDMETHODCALLTYPE d2d_effect_GetInput(ID2D1Effect *iface, UINT32 index, ID2D1Image **input)
2117 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
2119 TRACE("iface %p, index %u, input %p.\n", iface, index, input);
2121 if (index < effect->input_count && effect->inputs[index])
2122 ID2D1Image_AddRef(*input = effect->inputs[index]);
2123 else
2124 *input = NULL;
2127 static UINT32 STDMETHODCALLTYPE d2d_effect_GetInputCount(ID2D1Effect *iface)
2129 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
2131 TRACE("iface %p.\n", iface);
2133 return effect->input_count;
2136 static void STDMETHODCALLTYPE d2d_effect_GetOutput(ID2D1Effect *iface, ID2D1Image **output)
2138 struct d2d_effect *effect = impl_from_ID2D1Effect(iface);
2140 TRACE("iface %p, output %p.\n", iface, output);
2142 ID2D1Image_AddRef(*output = &effect->ID2D1Image_iface);
2145 static const ID2D1EffectVtbl d2d_effect_vtbl =
2147 d2d_effect_QueryInterface,
2148 d2d_effect_AddRef,
2149 d2d_effect_Release,
2150 d2d_effect_GetPropertyCount,
2151 d2d_effect_GetPropertyName,
2152 d2d_effect_GetPropertyNameLength,
2153 d2d_effect_GetType,
2154 d2d_effect_GetPropertyIndex,
2155 d2d_effect_SetValueByName,
2156 d2d_effect_SetValue,
2157 d2d_effect_GetValueByName,
2158 d2d_effect_GetValue,
2159 d2d_effect_GetValueSize,
2160 d2d_effect_GetSubProperties,
2161 d2d_effect_SetInput,
2162 d2d_effect_SetInputCount,
2163 d2d_effect_GetInput,
2164 d2d_effect_GetInputCount,
2165 d2d_effect_GetOutput,
2168 static inline struct d2d_effect *impl_from_ID2D1Image(ID2D1Image *iface)
2170 return CONTAINING_RECORD(iface, struct d2d_effect, ID2D1Image_iface);
2173 static HRESULT STDMETHODCALLTYPE d2d_effect_image_QueryInterface(ID2D1Image *iface, REFIID iid, void **out)
2175 struct d2d_effect *effect = impl_from_ID2D1Image(iface);
2177 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2179 return d2d_effect_QueryInterface(&effect->ID2D1Effect_iface, iid, out);
2182 static ULONG STDMETHODCALLTYPE d2d_effect_image_AddRef(ID2D1Image *iface)
2184 struct d2d_effect *effect = impl_from_ID2D1Image(iface);
2186 TRACE("iface %p.\n", iface);
2188 return d2d_effect_AddRef(&effect->ID2D1Effect_iface);
2191 static ULONG STDMETHODCALLTYPE d2d_effect_image_Release(ID2D1Image *iface)
2193 struct d2d_effect *effect = impl_from_ID2D1Image(iface);
2195 TRACE("iface %p.\n", iface);
2197 return d2d_effect_Release(&effect->ID2D1Effect_iface);
2200 static void STDMETHODCALLTYPE d2d_effect_image_GetFactory(ID2D1Image *iface, ID2D1Factory **factory)
2202 struct d2d_effect *effect = impl_from_ID2D1Image(iface);
2204 TRACE("iface %p, factory %p.\n", iface, factory);
2206 ID2D1Factory_AddRef(*factory = effect->effect_context->device_context->factory);
2209 static const ID2D1ImageVtbl d2d_effect_image_vtbl =
2211 d2d_effect_image_QueryInterface,
2212 d2d_effect_image_AddRef,
2213 d2d_effect_image_Release,
2214 d2d_effect_image_GetFactory,
2217 static inline struct d2d_effect_properties *impl_from_ID2D1Properties(ID2D1Properties *iface)
2219 return CONTAINING_RECORD(iface, struct d2d_effect_properties, ID2D1Properties_iface);
2222 static HRESULT STDMETHODCALLTYPE d2d_effect_properties_QueryInterface(ID2D1Properties *iface,
2223 REFIID riid, void **obj)
2225 if (IsEqualGUID(riid, &IID_ID2D1Properties) ||
2226 IsEqualGUID(riid, &IID_IUnknown))
2228 *obj = iface;
2229 ID2D1Properties_AddRef(iface);
2230 return S_OK;
2233 *obj = NULL;
2234 return E_NOINTERFACE;
2237 static ULONG STDMETHODCALLTYPE d2d_effect_properties_AddRef(ID2D1Properties *iface)
2239 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2241 if (properties->effect)
2242 return ID2D1Effect_AddRef(&properties->effect->ID2D1Effect_iface);
2244 return InterlockedIncrement(&properties->refcount);
2247 static ULONG STDMETHODCALLTYPE d2d_effect_properties_Release(ID2D1Properties *iface)
2249 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2250 ULONG refcount;
2252 if (properties->effect)
2253 return ID2D1Effect_Release(&properties->effect->ID2D1Effect_iface);
2255 refcount = InterlockedDecrement(&properties->refcount);
2257 if (!refcount)
2259 d2d_effect_properties_cleanup(properties);
2260 free(properties);
2263 return refcount;
2266 static UINT32 STDMETHODCALLTYPE d2d_effect_properties_GetPropertyCount(ID2D1Properties *iface)
2268 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2270 TRACE("iface %p.\n", iface);
2272 return properties->custom_count;
2275 static HRESULT STDMETHODCALLTYPE d2d_effect_properties_GetPropertyName(ID2D1Properties *iface,
2276 UINT32 index, WCHAR *name, UINT32 name_count)
2278 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2279 struct d2d_effect_property *prop;
2281 TRACE("iface %p, index %u, name %p, name_count %u.\n", iface, index, name, name_count);
2283 if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
2284 return D2DERR_INVALID_PROPERTY;
2286 return d2d_effect_return_string(prop->name, name, name_count);
2289 static UINT32 STDMETHODCALLTYPE d2d_effect_properties_GetPropertyNameLength(ID2D1Properties *iface,
2290 UINT32 index)
2292 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2293 struct d2d_effect_property *prop;
2295 TRACE("iface %p, index %u.\n", iface, index);
2297 if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
2298 return D2DERR_INVALID_PROPERTY;
2300 return wcslen(prop->name);
2303 static D2D1_PROPERTY_TYPE STDMETHODCALLTYPE d2d_effect_properties_GetType(ID2D1Properties *iface,
2304 UINT32 index)
2306 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2307 struct d2d_effect_property *prop;
2309 TRACE("iface %p, index %#x.\n", iface, index);
2311 if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
2312 return D2D1_PROPERTY_TYPE_UNKNOWN;
2314 return prop->type;
2317 static UINT32 STDMETHODCALLTYPE d2d_effect_properties_GetPropertyIndex(ID2D1Properties *iface,
2318 const WCHAR *name)
2320 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2321 struct d2d_effect_property *prop;
2323 TRACE("iface %p, name %s.\n", iface, debugstr_w(name));
2325 if (!(prop = d2d_effect_properties_get_property_by_name(properties, name)))
2326 return D2D1_INVALID_PROPERTY_INDEX;
2328 return prop->index;
2331 static HRESULT STDMETHODCALLTYPE d2d_effect_properties_SetValueByName(ID2D1Properties *iface,
2332 const WCHAR *name, D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 value_size)
2334 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2335 struct d2d_effect_property *prop;
2337 TRACE("iface %p, name %s, type %u, value %p, value_size %u.\n", iface, debugstr_w(name),
2338 type, value, value_size);
2340 if (!(prop = d2d_effect_properties_get_property_by_name(properties, name)))
2341 return D2DERR_INVALID_PROPERTY;
2343 return d2d_effect_property_set_value(properties, prop, type, value, value_size);
2346 static HRESULT STDMETHODCALLTYPE d2d_effect_properties_SetValue(ID2D1Properties *iface,
2347 UINT32 index, D2D1_PROPERTY_TYPE type, const BYTE *value, UINT32 value_size)
2349 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2350 struct d2d_effect_property *prop;
2352 TRACE("iface %p, index %#x, type %u, value %p, value_size %u.\n", iface, index, type, value, value_size);
2354 if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
2355 return D2DERR_INVALID_PROPERTY;
2357 return d2d_effect_property_set_value(properties, prop, type, value, value_size);
2360 static HRESULT STDMETHODCALLTYPE d2d_effect_properties_GetValueByName(ID2D1Properties *iface,
2361 const WCHAR *name, D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 value_size)
2363 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2364 struct d2d_effect_property *prop;
2366 TRACE("iface %p, name %s, type %#x, value %p, value_size %u.\n", iface, debugstr_w(name), type,
2367 value, value_size);
2369 if (!(prop = d2d_effect_properties_get_property_by_name(properties, name)))
2370 return D2DERR_INVALID_PROPERTY;
2372 return d2d_effect_property_get_value(properties, prop, type, value, value_size);
2375 static HRESULT STDMETHODCALLTYPE d2d_effect_properties_GetValue(ID2D1Properties *iface,
2376 UINT32 index, D2D1_PROPERTY_TYPE type, BYTE *value, UINT32 value_size)
2378 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2379 struct d2d_effect_property *prop;
2381 TRACE("iface %p, index %#x, type %u, value %p, value_size %u.\n", iface, index, type, value, value_size);
2383 if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
2384 return D2DERR_INVALID_PROPERTY;
2386 return d2d_effect_property_get_value(properties, prop, type, value, value_size);
2389 static UINT32 STDMETHODCALLTYPE d2d_effect_properties_GetValueSize(ID2D1Properties *iface,
2390 UINT32 index)
2392 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2394 TRACE("iface %p, index %#x.\n", iface, index);
2396 return d2d_effect_properties_get_value_size(properties, index);
2399 static HRESULT STDMETHODCALLTYPE d2d_effect_properties_GetSubProperties(ID2D1Properties *iface,
2400 UINT32 index, ID2D1Properties **props)
2402 struct d2d_effect_properties *properties = impl_from_ID2D1Properties(iface);
2403 struct d2d_effect_property *prop;
2405 TRACE("iface %p, index %u, props %p.\n", iface, index, props);
2407 if (!(prop = d2d_effect_properties_get_property_by_index(properties, index)))
2408 return D2DERR_INVALID_PROPERTY;
2410 if (!prop->subproperties) return D2DERR_NO_SUBPROPERTIES;
2412 *props = &prop->subproperties->ID2D1Properties_iface;
2413 ID2D1Properties_AddRef(*props);
2414 return S_OK;
2417 static const ID2D1PropertiesVtbl d2d_effect_properties_vtbl =
2419 d2d_effect_properties_QueryInterface,
2420 d2d_effect_properties_AddRef,
2421 d2d_effect_properties_Release,
2422 d2d_effect_properties_GetPropertyCount,
2423 d2d_effect_properties_GetPropertyName,
2424 d2d_effect_properties_GetPropertyNameLength,
2425 d2d_effect_properties_GetType,
2426 d2d_effect_properties_GetPropertyIndex,
2427 d2d_effect_properties_SetValueByName,
2428 d2d_effect_properties_SetValue,
2429 d2d_effect_properties_GetValueByName,
2430 d2d_effect_properties_GetValue,
2431 d2d_effect_properties_GetValueSize,
2432 d2d_effect_properties_GetSubProperties,
2435 void d2d_effect_init_properties(struct d2d_effect *effect,
2436 struct d2d_effect_properties *properties)
2438 properties->ID2D1Properties_iface.lpVtbl = &d2d_effect_properties_vtbl;
2439 properties->effect = effect;
2440 properties->refcount = 1;
2443 static struct d2d_render_info *impl_from_ID2D1DrawInfo(ID2D1DrawInfo *iface)
2445 return CONTAINING_RECORD(iface, struct d2d_render_info, ID2D1DrawInfo_iface);
2448 static HRESULT STDMETHODCALLTYPE d2d_draw_info_QueryInterface(ID2D1DrawInfo *iface, REFIID iid,
2449 void **obj)
2451 TRACE("iface %p, iid %s, obj %p.\n", iface, debugstr_guid(iid), obj);
2453 if (IsEqualGUID(iid, &IID_ID2D1DrawInfo)
2454 || IsEqualGUID(iid, &IID_ID2D1RenderInfo)
2455 || IsEqualGUID(iid, &IID_IUnknown))
2457 *obj = iface;
2458 ID2D1DrawInfo_AddRef(iface);
2459 return S_OK;
2462 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
2464 *obj = NULL;
2466 return E_NOINTERFACE;
2469 static ULONG STDMETHODCALLTYPE d2d_draw_info_AddRef(ID2D1DrawInfo *iface)
2471 struct d2d_render_info *render_info = impl_from_ID2D1DrawInfo(iface);
2472 ULONG refcount = InterlockedIncrement(&render_info->refcount);
2474 TRACE("iface %p refcount %lu.\n", iface, refcount);
2476 return refcount;
2479 static ULONG STDMETHODCALLTYPE d2d_draw_info_Release(ID2D1DrawInfo *iface)
2481 struct d2d_render_info *render_info = impl_from_ID2D1DrawInfo(iface);
2482 ULONG refcount = InterlockedDecrement(&render_info->refcount);
2484 TRACE("iface %p refcount %lu.\n", iface, refcount);
2486 if (!refcount)
2487 free(render_info);
2489 return refcount;
2492 static HRESULT STDMETHODCALLTYPE d2d_draw_info_SetInputDescription(ID2D1DrawInfo *iface,
2493 UINT32 index, D2D1_INPUT_DESCRIPTION description)
2495 FIXME("iface %p, index %u stub.\n", iface, index);
2497 return E_NOTIMPL;
2500 static HRESULT STDMETHODCALLTYPE d2d_draw_info_SetOutputBuffer(ID2D1DrawInfo *iface,
2501 D2D1_BUFFER_PRECISION precision, D2D1_CHANNEL_DEPTH depth)
2503 FIXME("iface %p, precision %u, depth %u stub.\n", iface, precision, depth);
2505 return E_NOTIMPL;
2508 static void STDMETHODCALLTYPE d2d_draw_info_SetCached(ID2D1DrawInfo *iface, BOOL is_cached)
2510 FIXME("iface %p, is_cached %d stub.\n", iface, is_cached);
2513 static void STDMETHODCALLTYPE d2d_draw_info_SetInstructionCountHint(ID2D1DrawInfo *iface,
2514 UINT32 count)
2516 FIXME("iface %p, count %u stub.\n", iface, count);
2519 static HRESULT STDMETHODCALLTYPE d2d_draw_info_SetPixelShaderConstantBuffer(ID2D1DrawInfo *iface,
2520 const BYTE *buffer, UINT32 size)
2522 FIXME("iface %p, buffer %p, size %u stub.\n", iface, buffer, size);
2524 return E_NOTIMPL;
2527 static HRESULT STDMETHODCALLTYPE d2d_draw_info_SetResourceTexture(ID2D1DrawInfo *iface,
2528 UINT32 index, ID2D1ResourceTexture *texture)
2530 FIXME("iface %p, index %u, texture %p stub.\n", iface, index, texture);
2532 return E_NOTIMPL;
2535 static HRESULT STDMETHODCALLTYPE d2d_draw_info_SetVertexShaderConstantBuffer(ID2D1DrawInfo *iface,
2536 const BYTE *buffer, UINT32 size)
2538 FIXME("iface %p, buffer %p, size %u stub.\n", iface, buffer, size);
2540 return E_NOTIMPL;
2543 static HRESULT STDMETHODCALLTYPE d2d_draw_info_SetPixelShader(ID2D1DrawInfo *iface,
2544 REFGUID id, D2D1_PIXEL_OPTIONS options)
2546 struct d2d_render_info *render_info = impl_from_ID2D1DrawInfo(iface);
2548 TRACE("iface %p, id %s, options %u.\n", iface, debugstr_guid(id), options);
2550 render_info->mask |= D2D_RENDER_INFO_PIXEL_SHADER;
2551 render_info->pixel_shader = *id;
2552 return S_OK;
2555 static HRESULT STDMETHODCALLTYPE d2d_draw_info_SetVertexProcessing(ID2D1DrawInfo *iface,
2556 ID2D1VertexBuffer *buffer, D2D1_VERTEX_OPTIONS options,
2557 const D2D1_BLEND_DESCRIPTION *description, const D2D1_VERTEX_RANGE *range,
2558 const GUID *shader)
2560 FIXME("iface %p, buffer %p, options %#x, description %p, range %p, shader %s stub.\n",
2561 iface, buffer, options, description, range, debugstr_guid(shader));
2563 return E_NOTIMPL;
2566 static const ID2D1DrawInfoVtbl d2d_draw_info_vtbl =
2568 d2d_draw_info_QueryInterface,
2569 d2d_draw_info_AddRef,
2570 d2d_draw_info_Release,
2571 d2d_draw_info_SetInputDescription,
2572 d2d_draw_info_SetOutputBuffer,
2573 d2d_draw_info_SetCached,
2574 d2d_draw_info_SetInstructionCountHint,
2575 d2d_draw_info_SetPixelShaderConstantBuffer,
2576 d2d_draw_info_SetResourceTexture,
2577 d2d_draw_info_SetVertexShaderConstantBuffer,
2578 d2d_draw_info_SetPixelShader,
2579 d2d_draw_info_SetVertexProcessing,
2582 static HRESULT d2d_effect_render_info_create(struct d2d_render_info **obj)
2584 struct d2d_render_info *object;
2586 if (!(object = calloc(1, sizeof(*object))))
2587 return E_OUTOFMEMORY;
2589 object->ID2D1DrawInfo_iface.lpVtbl = &d2d_draw_info_vtbl;
2590 object->refcount = 1;
2592 *obj = object;
2594 return S_OK;
2597 static bool d2d_transform_node_needs_render_info(const struct d2d_transform_node *node)
2599 static const GUID *iids[] =
2601 &IID_ID2D1SourceTransform,
2602 &IID_ID2D1ComputeTransform,
2603 &IID_ID2D1DrawTransform,
2605 unsigned int i;
2606 IUnknown *obj;
2608 for (i = 0; i < ARRAY_SIZE(iids); ++i)
2610 if (SUCCEEDED(ID2D1TransformNode_QueryInterface(node->object, iids[i], (void **)&obj)))
2612 IUnknown_Release(obj);
2613 return true;
2617 return false;
2620 static HRESULT d2d_effect_transform_graph_initialize_nodes(struct d2d_transform_graph *graph)
2622 ID2D1DrawTransform *draw_transform;
2623 struct d2d_transform_node *node;
2624 HRESULT hr;
2626 LIST_FOR_EACH_ENTRY(node, &graph->nodes, struct d2d_transform_node, entry)
2628 if (d2d_transform_node_needs_render_info(node))
2630 if (FAILED(hr = d2d_effect_render_info_create(&node->render_info)))
2631 return hr;
2634 if (SUCCEEDED(ID2D1TransformNode_QueryInterface(node->object, &IID_ID2D1DrawTransform,
2635 (void **)&draw_transform)))
2637 hr = ID2D1DrawTransform_SetDrawInfo(draw_transform, &node->render_info->ID2D1DrawInfo_iface);
2638 ID2D1DrawTransform_Release(draw_transform);
2639 if (FAILED(hr))
2641 WARN("Failed to set draw info, hr %#lx.\n", hr);
2642 return hr;
2645 else
2647 FIXME("Unsupported node %p.\n", node);
2648 return E_NOTIMPL;
2652 return S_OK;
2655 HRESULT d2d_effect_create(struct d2d_device_context *context, const CLSID *effect_id,
2656 ID2D1Effect **effect)
2658 struct d2d_effect_context *effect_context;
2659 const struct d2d_effect_registration *reg;
2660 struct d2d_effect *object;
2661 UINT32 input_count;
2662 WCHAR clsidW[39];
2663 HRESULT hr;
2665 if (!(reg = d2d_factory_get_registered_effect(context->factory, effect_id)))
2667 WARN("Effect id %s not found.\n", wine_dbgstr_guid(effect_id));
2668 return D2DERR_EFFECT_IS_NOT_REGISTERED;
2671 if (!(effect_context = calloc(1, sizeof(*effect_context))))
2672 return E_OUTOFMEMORY;
2673 d2d_effect_context_init(effect_context, context);
2675 if (!(object = calloc(1, sizeof(*object))))
2677 ID2D1EffectContext_Release(&effect_context->ID2D1EffectContext_iface);
2678 return E_OUTOFMEMORY;
2681 object->ID2D1Effect_iface.lpVtbl = &d2d_effect_vtbl;
2682 object->ID2D1Image_iface.lpVtbl = &d2d_effect_image_vtbl;
2683 object->refcount = 1;
2684 object->effect_context = effect_context;
2686 /* Create properties */
2687 d2d_effect_duplicate_properties(object, &object->properties, reg->properties);
2689 StringFromGUID2(effect_id, clsidW, ARRAY_SIZE(clsidW));
2690 d2d_effect_properties_add(&object->properties, L"CLSID", D2D1_PROPERTY_CLSID, D2D1_PROPERTY_TYPE_CLSID, clsidW);
2691 d2d_effect_properties_add(&object->properties, L"Cached", D2D1_PROPERTY_CACHED, D2D1_PROPERTY_TYPE_BOOL, L"false");
2692 d2d_effect_properties_add(&object->properties, L"Precision", D2D1_PROPERTY_PRECISION, D2D1_PROPERTY_TYPE_ENUM, L"0");
2694 /* Sync instance input count with default input count from the description. */
2695 d2d_effect_get_value(object, D2D1_PROPERTY_INPUTS, D2D1_PROPERTY_TYPE_ARRAY, (BYTE *)&input_count, sizeof(input_count));
2696 d2d_effect_set_input_count(object, input_count);
2698 if (FAILED(hr = d2d_transform_graph_create(input_count, &object->graph)))
2700 ID2D1EffectContext_Release(&effect_context->ID2D1EffectContext_iface);
2701 return hr;
2704 if (FAILED(hr = reg->factory((IUnknown **)&object->impl)))
2706 WARN("Failed to create implementation object, hr %#lx.\n", hr);
2707 ID2D1Effect_Release(&object->ID2D1Effect_iface);
2708 return hr;
2711 if (FAILED(hr = ID2D1EffectImpl_Initialize(object->impl, &effect_context->ID2D1EffectContext_iface,
2712 &object->graph->ID2D1TransformGraph_iface)))
2714 WARN("Failed to initialize effect, hr %#lx.\n", hr);
2715 ID2D1Effect_Release(&object->ID2D1Effect_iface);
2716 return hr;
2719 if (FAILED(hr = d2d_effect_transform_graph_initialize_nodes(object->graph)))
2721 WARN("Failed to initialize graph nodes, hr %#lx.\n", hr);
2722 ID2D1Effect_Release(&object->ID2D1Effect_iface);
2723 return hr;
2726 *effect = &object->ID2D1Effect_iface;
2728 TRACE("Created effect %p.\n", *effect);
2730 return S_OK;