2 * Copyright 2014 Henri Verbeet 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 #define D2D1_INIT_GUID
20 #include "d2d1_private.h"
23 #include "wine/list.h"
25 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
26 WINE_DEFAULT_DEBUG_CHANNEL(d2d
);
28 struct d2d_settings d2d_settings
=
30 ~0u, /* No ID2D1Factory version limit by default. */
33 static void d2d_effect_registration_cleanup(struct d2d_effect_registration
*reg
)
35 ID2D1Properties_Release(®
->properties
->ID2D1Properties_iface
);
39 static inline struct d2d_factory
*impl_from_ID2D1Factory7(ID2D1Factory7
*iface
)
41 return CONTAINING_RECORD(iface
, struct d2d_factory
, ID2D1Factory7_iface
);
44 static inline struct d2d_factory
*impl_from_ID2D1Multithread(ID2D1Multithread
*iface
)
46 return CONTAINING_RECORD(iface
, struct d2d_factory
, ID2D1Multithread_iface
);
49 static BOOL WINAPI
d2d_factory_builtins_initonce(INIT_ONCE
*once
, void *param
, void **context
)
51 d2d_effects_init_builtins(param
);
56 static void d2d_factory_init_builtin_effects(struct d2d_factory
*factory
)
58 InitOnceExecuteOnce(&factory
->init_builtins
, d2d_factory_builtins_initonce
, factory
, NULL
);
61 void d2d_factory_register_effect(struct d2d_factory
*factory
, struct d2d_effect_registration
*effect
)
63 list_add_tail(&factory
->effects
, &effect
->entry
);
66 struct d2d_effect_registration
* d2d_factory_get_registered_effect(ID2D1Factory
*iface
,
69 struct d2d_factory
*factory
= unsafe_impl_from_ID2D1Factory(iface
);
70 struct d2d_effect_registration
*reg
;
72 d2d_factory_init_builtin_effects(factory
);
74 LIST_FOR_EACH_ENTRY(reg
, &factory
->effects
, struct d2d_effect_registration
, entry
)
76 if (IsEqualGUID(id
, ®
->id
)) return reg
;
82 static HRESULT
d2d_factory_reload_sysmetrics(struct d2d_factory
*factory
)
86 if (!(hdc
= GetDC(NULL
)))
88 factory
->dpi_x
= factory
->dpi_y
= 96.0f
;
92 factory
->dpi_x
= GetDeviceCaps(hdc
, LOGPIXELSX
);
93 factory
->dpi_y
= GetDeviceCaps(hdc
, LOGPIXELSY
);
100 static HRESULT STDMETHODCALLTYPE
d2d_factory_QueryInterface(ID2D1Factory7
*iface
, REFIID iid
, void **out
)
102 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
104 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
106 if ((IsEqualGUID(iid
, &IID_ID2D1Factory7
) && d2d_settings
.max_version_factory
>= 7)
107 || (IsEqualGUID(iid
, &IID_ID2D1Factory6
) && d2d_settings
.max_version_factory
>= 6)
108 || (IsEqualGUID(iid
, &IID_ID2D1Factory5
) && d2d_settings
.max_version_factory
>= 5)
109 || (IsEqualGUID(iid
, &IID_ID2D1Factory4
) && d2d_settings
.max_version_factory
>= 4)
110 || (IsEqualGUID(iid
, &IID_ID2D1Factory3
) && d2d_settings
.max_version_factory
>= 3)
111 || (IsEqualGUID(iid
, &IID_ID2D1Factory2
) && d2d_settings
.max_version_factory
>= 2)
112 || (IsEqualGUID(iid
, &IID_ID2D1Factory1
) && d2d_settings
.max_version_factory
>= 1)
113 || IsEqualGUID(iid
, &IID_ID2D1Factory
)
114 || IsEqualGUID(iid
, &IID_IUnknown
))
116 ID2D1Factory7_AddRef(iface
);
120 else if (IsEqualGUID(iid
, &IID_ID2D1Multithread
))
122 ID2D1Factory7_AddRef(iface
);
123 *out
= &factory
->ID2D1Multithread_iface
;
127 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
130 return E_NOINTERFACE
;
133 static ULONG STDMETHODCALLTYPE
d2d_factory_AddRef(ID2D1Factory7
*iface
)
135 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
136 ULONG refcount
= InterlockedIncrement(&factory
->refcount
);
138 TRACE("%p increasing refcount to %lu.\n", iface
, refcount
);
143 static ULONG STDMETHODCALLTYPE
d2d_factory_Release(ID2D1Factory7
*iface
)
145 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
146 ULONG refcount
= InterlockedDecrement(&factory
->refcount
);
147 struct d2d_effect_registration
*reg
, *reg2
;
149 TRACE("%p decreasing refcount to %lu.\n", iface
, refcount
);
154 ID3D10Device1_Release(factory
->device
);
155 LIST_FOR_EACH_ENTRY_SAFE(reg
, reg2
, &factory
->effects
, struct d2d_effect_registration
, entry
)
157 d2d_effect_registration_cleanup(reg
);
159 DeleteCriticalSection(&factory
->cs
);
166 static HRESULT STDMETHODCALLTYPE
d2d_factory_ReloadSystemMetrics(ID2D1Factory7
*iface
)
168 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
170 TRACE("iface %p.\n", iface
);
172 return d2d_factory_reload_sysmetrics(factory
);
175 static void STDMETHODCALLTYPE
d2d_factory_GetDesktopDpi(ID2D1Factory7
*iface
, float *dpi_x
, float *dpi_y
)
177 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
179 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface
, dpi_x
, dpi_y
);
181 *dpi_x
= factory
->dpi_x
;
182 *dpi_y
= factory
->dpi_y
;
185 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateRectangleGeometry(ID2D1Factory7
*iface
,
186 const D2D1_RECT_F
*rect
, ID2D1RectangleGeometry
**geometry
)
188 struct d2d_geometry
*object
;
191 TRACE("iface %p, rect %s, geometry %p.\n", iface
, debug_d2d_rect_f(rect
), geometry
);
193 if (!(object
= calloc(1, sizeof(*object
))))
194 return E_OUTOFMEMORY
;
196 if (FAILED(hr
= d2d_rectangle_geometry_init(object
, (ID2D1Factory
*)iface
, rect
)))
198 WARN("Failed to initialise rectangle geometry, hr %#lx.\n", hr
);
203 TRACE("Created rectangle geometry %p.\n", object
);
204 *geometry
= (ID2D1RectangleGeometry
*)&object
->ID2D1Geometry_iface
;
209 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateRoundedRectangleGeometry(ID2D1Factory7
*iface
,
210 const D2D1_ROUNDED_RECT
*rounded_rect
, ID2D1RoundedRectangleGeometry
**geometry
)
212 struct d2d_geometry
*object
;
215 TRACE("iface %p, rounded_rect %s, geometry %p.\n", iface
, debug_d2d_rounded_rect(rounded_rect
), geometry
);
217 if (!(object
= calloc(1, sizeof(*object
))))
218 return E_OUTOFMEMORY
;
220 if (FAILED(hr
= d2d_rounded_rectangle_geometry_init(object
, (ID2D1Factory
*)iface
, rounded_rect
)))
222 WARN("Failed to initialise rounded rectangle geometry, hr %#lx.\n", hr
);
227 TRACE("Created rounded rectangle geometry %p.\n", object
);
228 *geometry
= (ID2D1RoundedRectangleGeometry
*)&object
->ID2D1Geometry_iface
;
233 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateEllipseGeometry(ID2D1Factory7
*iface
,
234 const D2D1_ELLIPSE
*ellipse
, ID2D1EllipseGeometry
**geometry
)
236 struct d2d_geometry
*object
;
239 TRACE("iface %p, ellipse %s, geometry %p.\n", iface
, debug_d2d_ellipse(ellipse
), geometry
);
241 if (!(object
= calloc(1, sizeof(*object
))))
242 return E_OUTOFMEMORY
;
244 if (FAILED(hr
= d2d_ellipse_geometry_init(object
, (ID2D1Factory
*)iface
, ellipse
)))
246 WARN("Failed to initialise ellipse geometry, hr %#lx.\n", hr
);
251 TRACE("Created ellipse geometry %p.\n", object
);
252 *geometry
= (ID2D1EllipseGeometry
*)&object
->ID2D1Geometry_iface
;
257 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateGeometryGroup(ID2D1Factory7
*iface
,
258 D2D1_FILL_MODE fill_mode
, ID2D1Geometry
**geometries
, UINT32 geometry_count
, ID2D1GeometryGroup
**group
)
260 struct d2d_geometry
*object
;
263 TRACE("iface %p, fill_mode %#x, geometries %p, geometry_count %u, group %p.\n",
264 iface
, fill_mode
, geometries
, geometry_count
, group
);
266 if (!(object
= calloc(1, sizeof(*object
))))
267 return E_OUTOFMEMORY
;
269 if (FAILED(hr
= d2d_geometry_group_init(object
, (ID2D1Factory
*)iface
, fill_mode
, geometries
, geometry_count
)))
271 WARN("Failed to initialise geometry group, hr %#lx.\n", hr
);
276 TRACE("Created geometry group %p.\n", object
);
277 *group
= (ID2D1GeometryGroup
*)&object
->ID2D1Geometry_iface
;
282 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateTransformedGeometry(ID2D1Factory7
*iface
,
283 ID2D1Geometry
*src_geometry
, const D2D1_MATRIX_3X2_F
*transform
,
284 ID2D1TransformedGeometry
**transformed_geometry
)
286 struct d2d_geometry
*object
;
288 TRACE("iface %p, src_geometry %p, transform %p, transformed_geometry %p.\n",
289 iface
, src_geometry
, transform
, transformed_geometry
);
291 if (!(object
= calloc(1, sizeof(*object
))))
292 return E_OUTOFMEMORY
;
294 d2d_transformed_geometry_init(object
, (ID2D1Factory
*)iface
, src_geometry
, transform
);
296 TRACE("Created transformed geometry %p.\n", object
);
297 *transformed_geometry
= (ID2D1TransformedGeometry
*)&object
->ID2D1Geometry_iface
;
302 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreatePathGeometry(ID2D1Factory7
*iface
,
303 ID2D1PathGeometry
**geometry
)
305 struct d2d_geometry
*object
;
307 TRACE("iface %p, geometry %p.\n", iface
, geometry
);
309 if (!(object
= calloc(1, sizeof(*object
))))
310 return E_OUTOFMEMORY
;
312 d2d_path_geometry_init(object
, (ID2D1Factory
*)iface
);
314 TRACE("Created path geometry %p.\n", object
);
315 *geometry
= (ID2D1PathGeometry
*)&object
->ID2D1Geometry_iface
;
320 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateStrokeStyle(ID2D1Factory7
*iface
,
321 const D2D1_STROKE_STYLE_PROPERTIES
*desc
, const float *dashes
, UINT32 dash_count
,
322 ID2D1StrokeStyle
**stroke_style
)
324 struct d2d_stroke_style
*object
;
325 D2D1_STROKE_STYLE_PROPERTIES1 desc1
;
328 TRACE("iface %p, desc %p, dashes %p, dash_count %u, stroke_style %p.\n",
329 iface
, desc
, dashes
, dash_count
, stroke_style
);
331 if (!(object
= calloc(1, sizeof(*object
))))
332 return E_OUTOFMEMORY
;
334 desc1
.startCap
= desc
->startCap
;
335 desc1
.endCap
= desc
->endCap
;
336 desc1
.dashCap
= desc
->dashCap
;
337 desc1
.lineJoin
= desc
->lineJoin
;
338 desc1
.miterLimit
= desc
->miterLimit
;
339 desc1
.dashStyle
= desc
->dashStyle
;
340 desc1
.dashOffset
= desc
->dashOffset
;
341 desc1
.transformType
= D2D1_STROKE_TRANSFORM_TYPE_NORMAL
;
343 if (FAILED(hr
= d2d_stroke_style_init(object
, (ID2D1Factory
*)iface
, &desc1
, dashes
, dash_count
)))
345 WARN("Failed to initialise stroke style, hr %#lx.\n", hr
);
350 TRACE("Created stroke style %p.\n", object
);
351 *stroke_style
= (ID2D1StrokeStyle
*)&object
->ID2D1StrokeStyle1_iface
;
356 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDrawingStateBlock(ID2D1Factory7
*iface
,
357 const D2D1_DRAWING_STATE_DESCRIPTION
*desc
, IDWriteRenderingParams
*text_rendering_params
,
358 ID2D1DrawingStateBlock
**state_block
)
360 D2D1_DRAWING_STATE_DESCRIPTION1 state_desc
;
361 struct d2d_state_block
*object
;
363 TRACE("iface %p, desc %p, text_rendering_params %p, state_block %p.\n",
364 iface
, desc
, text_rendering_params
, state_block
);
366 if (!(object
= calloc(1, sizeof(*object
))))
367 return E_OUTOFMEMORY
;
371 memcpy(&state_desc
, desc
, sizeof(*desc
));
372 state_desc
.primitiveBlend
= D2D1_PRIMITIVE_BLEND_SOURCE_OVER
;
373 state_desc
.unitMode
= D2D1_UNIT_MODE_DIPS
;
376 d2d_state_block_init(object
, (ID2D1Factory
*)iface
, desc
? &state_desc
: NULL
, text_rendering_params
);
378 TRACE("Created state block %p.\n", object
);
379 *state_block
= (ID2D1DrawingStateBlock
*)&object
->ID2D1DrawingStateBlock1_iface
;
384 static HRESULT
d2d_factory_get_device(struct d2d_factory
*factory
, ID3D10Device1
**device
)
388 if (!factory
->device
&& FAILED(hr
= D3D10CreateDevice1(NULL
, D3D10_DRIVER_TYPE_HARDWARE
, NULL
, D3D10_CREATE_DEVICE_BGRA_SUPPORT
,
389 D3D10_FEATURE_LEVEL_10_0
, D3D10_1_SDK_VERSION
, &factory
->device
)))
390 WARN("Failed to create device, hr %#lx.\n", hr
);
392 *device
= factory
->device
;
396 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateWicBitmapRenderTarget(ID2D1Factory7
*iface
,
397 IWICBitmap
*target
, const D2D1_RENDER_TARGET_PROPERTIES
*desc
, ID2D1RenderTarget
**render_target
)
399 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
400 struct d2d_wic_render_target
*object
;
401 ID3D10Device1
*device
;
404 TRACE("iface %p, target %p, desc %p, render_target %p.\n", iface
, target
, desc
, render_target
);
406 if (!(object
= calloc(1, sizeof(*object
))))
407 return E_OUTOFMEMORY
;
409 if (FAILED(hr
= d2d_factory_get_device(factory
, &device
)))
415 if (FAILED(hr
= d2d_wic_render_target_init(object
, (ID2D1Factory1
*)iface
, device
, target
, desc
)))
417 WARN("Failed to initialise render target, hr %#lx.\n", hr
);
422 TRACE("Created render target %p.\n", object
);
423 *render_target
= object
->dxgi_target
;
428 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateHwndRenderTarget(ID2D1Factory7
*iface
,
429 const D2D1_RENDER_TARGET_PROPERTIES
*desc
, const D2D1_HWND_RENDER_TARGET_PROPERTIES
*hwnd_rt_desc
,
430 ID2D1HwndRenderTarget
**render_target
)
432 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
433 struct d2d_hwnd_render_target
*object
;
434 ID3D10Device1
*device
;
437 TRACE("iface %p, desc %p, hwnd_rt_desc %p, render_target %p.\n", iface
, desc
, hwnd_rt_desc
, render_target
);
439 if (FAILED(hr
= d2d_factory_get_device(factory
, &device
)))
442 if (!(object
= calloc(1, sizeof(*object
))))
443 return E_OUTOFMEMORY
;
445 if (FAILED(hr
= d2d_hwnd_render_target_init(object
, (ID2D1Factory1
*)iface
, device
, desc
, hwnd_rt_desc
)))
447 WARN("Failed to initialise render target, hr %#lx.\n", hr
);
452 TRACE("Created render target %p.\n", object
);
453 *render_target
= &object
->ID2D1HwndRenderTarget_iface
;
458 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDxgiSurfaceRenderTarget(ID2D1Factory7
*iface
,
459 IDXGISurface
*surface
, const D2D1_RENDER_TARGET_PROPERTIES
*desc
, ID2D1RenderTarget
**render_target
)
461 IDXGIDevice
*dxgi_device
;
465 TRACE("iface %p, surface %p, desc %p, render_target %p.\n", iface
, surface
, desc
, render_target
);
467 if (FAILED(hr
= IDXGISurface_GetDevice(surface
, &IID_IDXGIDevice
, (void **)&dxgi_device
)))
469 WARN("Failed to get DXGI device, hr %#lx.\n", hr
);
473 hr
= ID2D1Factory1_CreateDevice((ID2D1Factory1
*)iface
, dxgi_device
, &device
);
474 IDXGIDevice_Release(dxgi_device
);
477 WARN("Failed to create D2D device, hr %#lx.\n", hr
);
481 hr
= d2d_d3d_create_render_target(unsafe_impl_from_ID2D1Device((ID2D1Device1
*)device
), surface
,
482 NULL
, NULL
, desc
, (void **)render_target
);
483 ID2D1Device_Release(device
);
487 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDCRenderTarget(ID2D1Factory7
*iface
,
488 const D2D1_RENDER_TARGET_PROPERTIES
*desc
, ID2D1DCRenderTarget
**render_target
)
490 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
491 struct d2d_dc_render_target
*object
;
492 ID3D10Device1
*device
;
495 TRACE("iface %p, desc %p, render_target %p.\n", iface
, desc
, render_target
);
497 if (FAILED(hr
= d2d_factory_get_device(factory
, &device
)))
500 if (!(object
= calloc(1, sizeof(*object
))))
501 return E_OUTOFMEMORY
;
503 if (FAILED(hr
= d2d_dc_render_target_init(object
, (ID2D1Factory1
*)iface
, device
, desc
)))
505 WARN("Failed to initialise render target, hr %#lx.\n", hr
);
510 TRACE("Created render target %p.\n", object
);
511 *render_target
= &object
->ID2D1DCRenderTarget_iface
;
516 static HRESULT
d2d_factory_create_device(struct d2d_factory
*factory
, IDXGIDevice
*dxgi_device
,
517 REFIID iid
, void **device
)
519 struct d2d_device
*object
;
522 if (!(object
= calloc(1, sizeof(*object
))))
523 return E_OUTOFMEMORY
;
525 d2d_device_init(object
, factory
, dxgi_device
);
527 TRACE("Create device %p.\n", object
);
529 hr
= ID2D1Device6_QueryInterface(&object
->ID2D1Device6_iface
, iid
, device
);
530 ID2D1Device6_Release(&object
->ID2D1Device6_iface
);
535 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDevice(ID2D1Factory7
*iface
,
536 IDXGIDevice
*dxgi_device
, ID2D1Device
**device
)
538 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
540 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
542 return d2d_factory_create_device(factory
, dxgi_device
, &IID_ID2D1Device
, (void **)device
);
545 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateStrokeStyle1(ID2D1Factory7
*iface
,
546 const D2D1_STROKE_STYLE_PROPERTIES1
*desc
, const float *dashes
, UINT32 dash_count
,
547 ID2D1StrokeStyle1
**stroke_style
)
549 struct d2d_stroke_style
*object
;
552 TRACE("iface %p, desc %p, dashes %p, dash_count %u, stroke_style %p.\n",
553 iface
, desc
, dashes
, dash_count
, stroke_style
);
555 if (!(object
= calloc(1, sizeof(*object
))))
556 return E_OUTOFMEMORY
;
558 if (FAILED(hr
= d2d_stroke_style_init(object
, (ID2D1Factory
*)iface
,
559 desc
, dashes
, dash_count
)))
561 WARN("Failed to initialise stroke style, hr %#lx.\n", hr
);
566 TRACE("Created stroke style %p.\n", object
);
567 *stroke_style
= &object
->ID2D1StrokeStyle1_iface
;
572 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreatePathGeometry1(ID2D1Factory7
*iface
,
573 ID2D1PathGeometry1
**geometry
)
575 struct d2d_geometry
*object
;
577 TRACE("iface %p, geometry %p.\n", iface
, geometry
);
579 if (!(object
= calloc(1, sizeof(*object
))))
580 return E_OUTOFMEMORY
;
582 d2d_path_geometry_init(object
, (ID2D1Factory
*)iface
);
584 TRACE("Created path geometry %p.\n", object
);
585 *geometry
= (ID2D1PathGeometry1
*)&object
->ID2D1Geometry_iface
;
590 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDrawingStateBlock1(ID2D1Factory7
*iface
,
591 const D2D1_DRAWING_STATE_DESCRIPTION1
*desc
, IDWriteRenderingParams
*text_rendering_params
,
592 ID2D1DrawingStateBlock1
**state_block
)
594 struct d2d_state_block
*object
;
596 TRACE("iface %p, desc %p, text_rendering_params %p, state_block %p.\n",
597 iface
, desc
, text_rendering_params
, state_block
);
599 if (!(object
= calloc(1, sizeof(*object
))))
600 return E_OUTOFMEMORY
;
602 d2d_state_block_init(object
, (ID2D1Factory
*)iface
, desc
, text_rendering_params
);
604 TRACE("Created state block %p.\n", object
);
605 *state_block
= &object
->ID2D1DrawingStateBlock1_iface
;
610 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateGdiMetafile(ID2D1Factory7
*iface
,
611 IStream
*stream
, ID2D1GdiMetafile
**metafile
)
613 FIXME("iface %p, stream %p, metafile %p stub!\n", iface
, stream
, metafile
);
618 static HRESULT
parse_effect_get_next_xml_node(IXmlReader
*reader
, XmlNodeType expected_type
,
619 const WCHAR
*expected_name
, unsigned int *depth
)
621 const WCHAR
*node_name
;
622 XmlNodeType node_type
;
625 assert(expected_type
!= XmlNodeType_Whitespace
);
627 while ((hr
= IXmlReader_Read(reader
, &node_type
)) == S_OK
)
629 if (node_type
== XmlNodeType_Whitespace
)
632 if (expected_type
!= XmlNodeType_None
&& node_type
!= expected_type
)
633 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
637 if (FAILED(hr
= IXmlReader_GetLocalName(reader
, &node_name
, NULL
)))
640 if (wcscmp(node_name
, expected_name
))
641 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
645 IXmlReader_GetDepth(reader
, depth
);
652 static HRESULT
parse_effect_skip_element(IXmlReader
*reader
, unsigned int element_depth
)
654 XmlNodeType node_type
;
658 if (IXmlReader_IsEmptyElement(reader
)) return S_OK
;
660 while ((hr
= IXmlReader_Read(reader
, &node_type
)) == S_OK
)
662 IXmlReader_GetDepth(reader
, &depth
);
663 if (node_type
== XmlNodeType_EndElement
&& depth
== element_depth
+ 1)
672 static HRESULT
parse_effect_get_attribute(IXmlReader
*reader
, const WCHAR
*name
, WCHAR
**ret
)
678 if (IXmlReader_MoveToAttributeByName(reader
, name
, NULL
) != S_OK
)
680 if (IXmlReader_GetValue(reader
, &value
, NULL
) != S_OK
)
682 if (!(*ret
= wcsdup(value
)))
683 return E_OUTOFMEMORY
;
688 static HRESULT
parse_effect_get_property_type(IXmlReader
*reader
, D2D1_PROPERTY_TYPE
*type
)
690 static const WCHAR
*types
[] =
692 [D2D1_PROPERTY_TYPE_UNKNOWN
] = L
"",
693 [D2D1_PROPERTY_TYPE_STRING
] = L
"string",
694 [D2D1_PROPERTY_TYPE_BOOL
] = L
"bool",
695 [D2D1_PROPERTY_TYPE_UINT32
] = L
"uint32",
696 [D2D1_PROPERTY_TYPE_INT32
] = L
"int32",
697 [D2D1_PROPERTY_TYPE_FLOAT
] = L
"float",
698 [D2D1_PROPERTY_TYPE_VECTOR2
] = L
"vector2",
699 [D2D1_PROPERTY_TYPE_VECTOR3
] = L
"vector3",
700 [D2D1_PROPERTY_TYPE_VECTOR4
] = L
"vector4",
701 [D2D1_PROPERTY_TYPE_BLOB
] = L
"blob",
702 [D2D1_PROPERTY_TYPE_IUNKNOWN
] = L
"iunknown",
703 [D2D1_PROPERTY_TYPE_ENUM
] = L
"enum",
704 [D2D1_PROPERTY_TYPE_ARRAY
] = L
"array",
705 [D2D1_PROPERTY_TYPE_CLSID
] = L
"clsid",
706 [D2D1_PROPERTY_TYPE_MATRIX_3X2
] = L
"matrix3x2",
707 [D2D1_PROPERTY_TYPE_MATRIX_4X3
] = L
"matrix4x3",
708 [D2D1_PROPERTY_TYPE_MATRIX_4X4
] = L
"matrix4x4",
709 [D2D1_PROPERTY_TYPE_MATRIX_5X4
] = L
"matrix5x4",
710 [D2D1_PROPERTY_TYPE_COLOR_CONTEXT
] = L
"colorcontext",
716 if (FAILED(hr
= parse_effect_get_attribute(reader
, L
"type", &value
))) return hr
;
718 *type
= D2D1_PROPERTY_TYPE_UNKNOWN
;
720 for (i
= 0; i
< ARRAY_SIZE(types
); ++i
)
722 if (!wcscmp(value
, types
[i
]))
731 return *type
== D2D1_PROPERTY_TYPE_UNKNOWN
? E_INVALIDARG
: S_OK
;
734 static struct d2d_effect_property
* parse_effect_get_property(const struct d2d_effect_registration
*effect
,
739 for (i
= 0; i
< effect
->properties
->count
; ++i
)
741 if (!wcscmp(name
, effect
->properties
->properties
[i
].name
))
742 return &effect
->properties
->properties
[i
];
748 static UINT32
parse_effect_get_property_index(struct d2d_effect_properties
*props
,
751 if (!wcscmp(name
, L
"DisplayName")) return D2D1_PROPERTY_DISPLAYNAME
;
752 if (!wcscmp(name
, L
"Author")) return D2D1_PROPERTY_AUTHOR
;
753 if (!wcscmp(name
, L
"Category")) return D2D1_PROPERTY_CATEGORY
;
754 if (!wcscmp(name
, L
"Description")) return D2D1_PROPERTY_DESCRIPTION
;
755 return props
->custom_count
;
758 static HRESULT
parse_effect_property(IXmlReader
*reader
, struct d2d_effect_registration
*effect
)
760 WCHAR
*name
= NULL
, *value
= NULL
;
761 D2D1_PROPERTY_TYPE type
;
766 if (FAILED(hr
= parse_effect_get_attribute(reader
, L
"name", &name
)))
769 if (FAILED(hr
= parse_effect_get_property_type(reader
, &type
)))
775 /* Check for duplicates. */
776 if (parse_effect_get_property(effect
, name
))
779 parse_effect_get_attribute(reader
, L
"value", &value
);
783 /* FIXME: sub properties are ignored */
784 IXmlReader_MoveToElement(reader
);
785 IXmlReader_GetDepth(reader
, &depth
);
786 hr
= parse_effect_skip_element(reader
, depth
);
791 index
= parse_effect_get_property_index(effect
->properties
, name
);
792 hr
= d2d_effect_properties_add(effect
->properties
, name
, index
, type
, value
);
801 static HRESULT
parse_effect_inputs(IXmlReader
*reader
, struct d2d_effect_registration
*effect
)
803 struct d2d_effect_property
*inputs
, *min_inputs
, *max_inputs
;
804 struct d2d_effect_properties
*subproperties
;
805 UINT32 min_inputs_value
, max_inputs_value
;
806 unsigned int depth
, input_count
= 0;
807 XmlNodeType node_type
;
812 if (FAILED(hr
= d2d_effect_properties_add(effect
->properties
, L
"Inputs",
813 D2D1_PROPERTY_INPUTS
, D2D1_PROPERTY_TYPE_ARRAY
, NULL
)))
816 if (!(inputs
= d2d_effect_properties_get_property_by_name(effect
->properties
, L
"Inputs")))
818 if (!(inputs
->subproperties
= calloc(1, sizeof(*inputs
->subproperties
))))
819 return E_OUTOFMEMORY
;
820 d2d_effect_init_properties(NULL
, inputs
->subproperties
);
821 subproperties
= inputs
->subproperties
;
823 d2d_effect_subproperties_add(subproperties
, L
"IsReadOnly", D2D1_SUBPROPERTY_ISREADONLY
,
824 D2D1_PROPERTY_TYPE_BOOL
, L
"true");
825 d2d_effect_subproperties_add(subproperties
, L
"DisplayName", D2D1_SUBPROPERTY_DISPLAYNAME
,
826 D2D1_PROPERTY_TYPE_STRING
, L
"Inputs");
828 if (SUCCEEDED(parse_effect_get_attribute(reader
, L
"minimum", &value
)))
830 hr
= d2d_effect_properties_add(effect
->properties
, L
"MinInputs", D2D1_PROPERTY_MIN_INPUTS
,
831 D2D1_PROPERTY_TYPE_UINT32
, value
);
833 if (FAILED(hr
)) return hr
;
835 if (SUCCEEDED(parse_effect_get_attribute(reader
, L
"maximum", &value
)))
837 hr
= d2d_effect_properties_add(effect
->properties
, L
"MaxInputs", D2D1_PROPERTY_MAX_INPUTS
,
838 D2D1_PROPERTY_TYPE_UINT32
, value
);
840 if (FAILED(hr
)) return hr
;
843 min_inputs
= d2d_effect_properties_get_property_by_name(effect
->properties
, L
"MinInputs");
844 max_inputs
= d2d_effect_properties_get_property_by_name(effect
->properties
, L
"MaxInputs");
846 if (!IXmlReader_IsEmptyElement(reader
))
848 while (parse_effect_get_next_xml_node(reader
, XmlNodeType_None
, L
"Input", &depth
) == S_OK
)
850 if (FAILED(hr
= IXmlReader_GetNodeType(reader
, &node_type
))) return hr
;
851 if (node_type
== XmlNodeType_EndElement
) continue;
852 if (node_type
!= XmlNodeType_Element
) return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
854 if (FAILED(hr
= parse_effect_get_attribute(reader
, L
"name", &name
))) return hr
;
856 swprintf(buffW
, ARRAY_SIZE(buffW
), L
"%lu", input_count
);
857 d2d_effect_subproperties_add(subproperties
, buffW
, input_count
, D2D1_PROPERTY_TYPE_STRING
, name
);
862 *(UINT32
*)(effect
->properties
->data
.ptr
+ inputs
->data
.offset
) = input_count
;
864 if (FAILED(hr
= IXmlReader_GetNodeType(reader
, &node_type
))) return hr
;
865 if (node_type
!= XmlNodeType_EndElement
) return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
869 d2d_effect_property_get_uint32_value(effect
->properties
, min_inputs
, &min_inputs_value
);
871 d2d_effect_property_get_uint32_value(effect
->properties
, max_inputs
, &max_inputs_value
);
873 /* Validate the range */
874 if (min_inputs
&& max_inputs
)
876 if (min_inputs_value
> max_inputs_value
)
878 WARN("Invalid input count range %u - %u.\n", min_inputs_value
, max_inputs_value
);
883 /* Validate actual input count with specified range. */
884 if (min_inputs
&& min_inputs_value
> input_count
)
886 WARN("Too few inputs were declared, expected at least %u.\n", min_inputs_value
);
890 if (max_inputs
&& max_inputs_value
< input_count
)
892 WARN("Too many inputs were declared, expected at most %u.\n", max_inputs_value
);
896 /* Apply default value to a missing property. If both properties are missing, add them. */
897 if (min_inputs
!= max_inputs
)
899 swprintf(buffW
, ARRAY_SIZE(buffW
), L
"%lu", min_inputs
? min_inputs_value
: max_inputs_value
);
901 hr
= d2d_effect_properties_add(effect
->properties
, L
"MaxInputs", D2D1_PROPERTY_MAX_INPUTS
, D2D1_PROPERTY_TYPE_UINT32
, buffW
);
903 hr
= d2d_effect_properties_add(effect
->properties
, L
"MinInputs", D2D1_PROPERTY_MIN_INPUTS
, D2D1_PROPERTY_TYPE_UINT32
, buffW
);
905 else if (!min_inputs
)
907 swprintf(buffW
, ARRAY_SIZE(buffW
), L
"%lu", input_count
);
908 hr
= d2d_effect_properties_add(effect
->properties
, L
"MinInputs", D2D1_PROPERTY_MIN_INPUTS
, D2D1_PROPERTY_TYPE_UINT32
, buffW
);
910 hr
= d2d_effect_properties_add(effect
->properties
, L
"MaxInputs", D2D1_PROPERTY_MAX_INPUTS
, D2D1_PROPERTY_TYPE_UINT32
, buffW
);
916 static HRESULT
parse_effect_xml(IXmlReader
*reader
, struct d2d_effect_registration
*effect
)
918 const WCHAR
*node_name
;
919 XmlNodeType node_type
;
923 /* Xml declaration node is mandatory. */
924 if ((hr
= parse_effect_get_next_xml_node(reader
, XmlNodeType_XmlDeclaration
, L
"xml", NULL
)) != S_OK
)
927 /* Top level "Effect" element. */
928 if ((hr
= parse_effect_get_next_xml_node(reader
, XmlNodeType_Element
, L
"Effect", NULL
)) != S_OK
)
931 /* Loop inside effect node */
932 while ((hr
= parse_effect_get_next_xml_node(reader
, XmlNodeType_None
, NULL
, &depth
)) == S_OK
)
934 if (FAILED(hr
= IXmlReader_GetNodeType(reader
, &node_type
))) return hr
;
935 if (node_type
!= XmlNodeType_Element
&& node_type
!= XmlNodeType_EndElement
) continue;
936 if (FAILED(hr
= IXmlReader_GetLocalName(reader
, &node_name
, NULL
))) return hr
;
937 if (node_type
== XmlNodeType_EndElement
) break;
939 if (!wcscmp(node_name
, L
"Property"))
940 hr
= parse_effect_property(reader
, effect
);
941 else if (!wcscmp(node_name
, L
"Inputs"))
942 hr
= parse_effect_inputs(reader
, effect
);
945 WARN("Unexpected element %s.\n", debugstr_w(node_name
));
946 hr
= parse_effect_skip_element(reader
, depth
);
956 static HRESULT
d2d_factory_register_effect_from_stream(struct d2d_factory
*factory
,
957 REFCLSID effect_id
, IStream
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
,
958 UINT32 binding_count
, PD2D1_EFFECT_FACTORY effect_factory
, BOOL builtin
)
960 struct d2d_effect_registration
*effect
;
965 LIST_FOR_EACH_ENTRY_REV(effect
, &factory
->effects
, struct d2d_effect_registration
, entry
)
967 if (IsEqualGUID(effect_id
, &effect
->id
))
969 if (effect
->builtin
) return E_INVALIDARG
;
970 ++effect
->registration_count
;
975 if (FAILED(hr
= CreateXmlReader(&IID_IXmlReader
, (void **)&reader
, NULL
)))
978 if (FAILED(hr
= IXmlReader_SetInput(reader
, (IUnknown
*)property_xml
)))
980 IXmlReader_Release(reader
);
984 if (!(effect
= calloc(1, sizeof(*effect
))))
986 IXmlReader_Release(reader
);
987 return E_OUTOFMEMORY
;
989 if (!(effect
->properties
= calloc(1, sizeof(*effect
->properties
))))
991 IXmlReader_Release(reader
);
993 return E_OUTOFMEMORY
;
995 d2d_effect_init_properties(NULL
, effect
->properties
);
996 effect
->builtin
= builtin
;
998 hr
= parse_effect_xml(reader
, effect
);
999 IXmlReader_Release(reader
);
1002 WARN("Failed to parse effect xml, hr %#lx.\n", hr
);
1003 d2d_effect_registration_cleanup(effect
);
1007 /* Check required properties. */
1008 if (!parse_effect_get_property(effect
, L
"DisplayName")
1009 || !parse_effect_get_property(effect
, L
"Author")
1010 || !parse_effect_get_property(effect
, L
"Category")
1011 || !parse_effect_get_property(effect
, L
"Description")
1012 || !parse_effect_get_property(effect
, L
"Inputs"))
1014 WARN("Missing required properties.\n");
1015 d2d_effect_registration_cleanup(effect
);
1016 return E_INVALIDARG
;
1019 /* Bind getter and setter. */
1020 for (i
= 0; i
< binding_count
; ++i
)
1022 struct d2d_effect_property
*property
;
1024 if (!(property
= parse_effect_get_property(effect
, bindings
[i
].propertyName
)))
1026 WARN("Failed to bind to missing property.\n");
1027 d2d_effect_registration_cleanup(effect
);
1028 return D2DERR_INVALID_PROPERTY
;
1031 property
->get_function
= bindings
[i
].getFunction
;
1032 property
->set_function
= bindings
[i
].setFunction
;
1035 effect
->registration_count
= 1;
1036 effect
->id
= *effect_id
;
1037 effect
->factory
= effect_factory
;
1039 d2d_factory_register_effect(factory
, effect
);
1044 static HRESULT STDMETHODCALLTYPE
d2d_factory_RegisterEffectFromStream(ID2D1Factory7
*iface
,
1045 REFCLSID effect_id
, IStream
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
,
1046 UINT32 binding_count
, PD2D1_EFFECT_FACTORY effect_factory
)
1048 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1050 TRACE("iface %p, effect_id %s, property_xml %p, bindings %p, binding_count %u, effect_factory %p.\n",
1051 iface
, debugstr_guid(effect_id
), property_xml
, bindings
, binding_count
, effect_factory
);
1053 d2d_factory_init_builtin_effects(factory
);
1055 return d2d_factory_register_effect_from_stream(factory
, effect_id
, property_xml
, bindings
,
1056 binding_count
, effect_factory
, FALSE
);
1059 static HRESULT
d2d_factory_register_effect_from_string(struct d2d_factory
*factory
,
1060 REFCLSID effect_id
, const WCHAR
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
,
1061 UINT32 binding_count
, PD2D1_EFFECT_FACTORY effect_factory
, BOOL builtin
)
1063 static const LARGE_INTEGER zero
;
1068 if (FAILED(hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
)))
1071 size
= sizeof(*property_xml
) * (wcslen(property_xml
) + 1);
1072 if (SUCCEEDED(hr
= IStream_Write(stream
, property_xml
, size
, NULL
)))
1073 hr
= IStream_Seek(stream
, zero
, SEEK_SET
, NULL
);
1076 hr
= d2d_factory_register_effect_from_stream(factory
, effect_id
, stream
, bindings
,
1077 binding_count
, effect_factory
, builtin
);
1079 IStream_Release(stream
);
1083 HRESULT
d2d_factory_register_builtin_effect(struct d2d_factory
*factory
, REFCLSID effect_id
,
1084 const WCHAR
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
, UINT32 binding_count
,
1085 PD2D1_EFFECT_FACTORY effect_factory
)
1087 return d2d_factory_register_effect_from_string(factory
, effect_id
, property_xml
, bindings
,
1088 binding_count
, effect_factory
, TRUE
);
1091 static HRESULT STDMETHODCALLTYPE
d2d_factory_RegisterEffectFromString(ID2D1Factory7
*iface
,
1092 REFCLSID effect_id
, const WCHAR
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
,
1093 UINT32 binding_count
, PD2D1_EFFECT_FACTORY effect_factory
)
1095 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1097 TRACE("iface %p, effect_id %s, property_xml %s, bindings %p, binding_count %u, effect_factory %p.\n",
1098 iface
, debugstr_guid(effect_id
), debugstr_w(property_xml
), bindings
, binding_count
, effect_factory
);
1100 d2d_factory_init_builtin_effects(factory
);
1102 return d2d_factory_register_effect_from_string(factory
, effect_id
, property_xml
, bindings
,
1103 binding_count
, effect_factory
, FALSE
);
1106 static HRESULT STDMETHODCALLTYPE
d2d_factory_UnregisterEffect(ID2D1Factory7
*iface
, REFCLSID effect_id
)
1108 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1109 struct d2d_effect_registration
*effect
;
1111 TRACE("iface %p, effect_id %s.\n", iface
, debugstr_guid(effect_id
));
1113 d2d_factory_init_builtin_effects(factory
);
1115 LIST_FOR_EACH_ENTRY_REV(effect
, &factory
->effects
, struct d2d_effect_registration
, entry
)
1117 if (IsEqualGUID(effect_id
, &effect
->id
))
1119 if (effect
->builtin
) break;
1120 if (!--effect
->registration_count
)
1122 list_remove(&effect
->entry
);
1123 d2d_effect_registration_cleanup(effect
);
1129 return D2DERR_EFFECT_IS_NOT_REGISTERED
;
1132 static HRESULT STDMETHODCALLTYPE
d2d_factory_GetRegisteredEffects(ID2D1Factory7
*iface
,
1133 CLSID
*effects
, UINT32 effect_count
, UINT32
*returned
, UINT32
*registered
)
1135 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1136 struct d2d_effect_registration
*effect
;
1139 TRACE("iface %p, effects %p, effect_count %u, returned %p, registered %p.\n",
1140 iface
, effects
, effect_count
, returned
, registered
);
1142 if (!returned
) returned
= &ret
;
1143 if (!registered
) registered
= ®
;
1148 d2d_factory_init_builtin_effects(factory
);
1150 LIST_FOR_EACH_ENTRY(effect
, &factory
->effects
, struct d2d_effect_registration
, entry
)
1152 if (effects
&& effect_count
)
1154 *effects
= effect
->id
;
1163 if (!effects
) return S_OK
;
1164 return *returned
== *registered
? S_OK
: D2DERR_INSUFFICIENT_BUFFER
;
1167 static HRESULT STDMETHODCALLTYPE
d2d_factory_GetEffectProperties(ID2D1Factory7
*iface
,
1168 REFCLSID effect_id
, ID2D1Properties
**props
)
1170 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1171 const struct d2d_effect_registration
*reg
;
1173 TRACE("iface %p, effect_id %s, props %p.\n", iface
, debugstr_guid(effect_id
), props
);
1175 d2d_factory_init_builtin_effects(factory
);
1177 if (!(reg
= d2d_factory_get_registered_effect((ID2D1Factory
*)iface
, effect_id
)))
1179 WARN("Effect id %s not found.\n", wine_dbgstr_guid(effect_id
));
1180 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
1183 *props
= ®
->properties
->ID2D1Properties_iface
;
1184 ID2D1Properties_AddRef(*props
);
1189 static HRESULT STDMETHODCALLTYPE
d2d_factory_ID2D1Factory2_CreateDevice(ID2D1Factory7
*iface
,
1190 IDXGIDevice
*dxgi_device
, ID2D1Device1
**device
)
1192 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1194 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
1196 return d2d_factory_create_device(factory
, dxgi_device
, &IID_ID2D1Device1
, (void **)device
);
1199 static HRESULT STDMETHODCALLTYPE
d2d_factory_ID2D1Factory3_CreateDevice(ID2D1Factory7
*iface
,
1200 IDXGIDevice
*dxgi_device
, ID2D1Device2
**device
)
1202 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1204 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
1206 return d2d_factory_create_device(factory
, dxgi_device
, &IID_ID2D1Device2
, (void **)device
);
1209 static HRESULT STDMETHODCALLTYPE
d2d_factory_ID2D1Factory4_CreateDevice(ID2D1Factory7
*iface
,
1210 IDXGIDevice
*dxgi_device
, ID2D1Device3
**device
)
1212 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1214 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
1216 return d2d_factory_create_device(factory
, dxgi_device
, &IID_ID2D1Device3
, (void **)device
);
1219 static HRESULT STDMETHODCALLTYPE
d2d_factory_ID2D1Factory5_CreateDevice(ID2D1Factory7
*iface
,
1220 IDXGIDevice
*dxgi_device
, ID2D1Device4
**device
)
1222 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1224 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
1226 return d2d_factory_create_device(factory
, dxgi_device
, &IID_ID2D1Device4
, (void **)device
);
1229 static HRESULT STDMETHODCALLTYPE
d2d_factory_ID2D1Factory6_CreateDevice(ID2D1Factory7
*iface
,
1230 IDXGIDevice
*dxgi_device
, ID2D1Device5
**device
)
1232 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1234 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
1236 return d2d_factory_create_device(factory
, dxgi_device
, &IID_ID2D1Device5
, (void **)device
);
1239 static HRESULT STDMETHODCALLTYPE
d2d_factory_ID2D1Factory7_CreateDevice(ID2D1Factory7
*iface
,
1240 IDXGIDevice
*dxgi_device
, ID2D1Device6
**device
)
1242 struct d2d_factory
*factory
= impl_from_ID2D1Factory7(iface
);
1244 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
1246 return d2d_factory_create_device(factory
, dxgi_device
, &IID_ID2D1Device6
, (void **)device
);
1249 static const struct ID2D1Factory7Vtbl d2d_factory_vtbl
=
1251 d2d_factory_QueryInterface
,
1253 d2d_factory_Release
,
1254 d2d_factory_ReloadSystemMetrics
,
1255 d2d_factory_GetDesktopDpi
,
1256 d2d_factory_CreateRectangleGeometry
,
1257 d2d_factory_CreateRoundedRectangleGeometry
,
1258 d2d_factory_CreateEllipseGeometry
,
1259 d2d_factory_CreateGeometryGroup
,
1260 d2d_factory_CreateTransformedGeometry
,
1261 d2d_factory_CreatePathGeometry
,
1262 d2d_factory_CreateStrokeStyle
,
1263 d2d_factory_CreateDrawingStateBlock
,
1264 d2d_factory_CreateWicBitmapRenderTarget
,
1265 d2d_factory_CreateHwndRenderTarget
,
1266 d2d_factory_CreateDxgiSurfaceRenderTarget
,
1267 d2d_factory_CreateDCRenderTarget
,
1268 d2d_factory_CreateDevice
,
1269 d2d_factory_CreateStrokeStyle1
,
1270 d2d_factory_CreatePathGeometry1
,
1271 d2d_factory_CreateDrawingStateBlock1
,
1272 d2d_factory_CreateGdiMetafile
,
1273 d2d_factory_RegisterEffectFromStream
,
1274 d2d_factory_RegisterEffectFromString
,
1275 d2d_factory_UnregisterEffect
,
1276 d2d_factory_GetRegisteredEffects
,
1277 d2d_factory_GetEffectProperties
,
1278 d2d_factory_ID2D1Factory2_CreateDevice
,
1279 d2d_factory_ID2D1Factory3_CreateDevice
,
1280 d2d_factory_ID2D1Factory4_CreateDevice
,
1281 d2d_factory_ID2D1Factory5_CreateDevice
,
1282 d2d_factory_ID2D1Factory6_CreateDevice
,
1283 d2d_factory_ID2D1Factory7_CreateDevice
,
1286 static HRESULT STDMETHODCALLTYPE
d2d_factory_mt_QueryInterface(ID2D1Multithread
*iface
, REFIID iid
, void **out
)
1288 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1289 return d2d_factory_QueryInterface(&factory
->ID2D1Factory7_iface
, iid
, out
);
1292 static ULONG STDMETHODCALLTYPE
d2d_factory_mt_AddRef(ID2D1Multithread
*iface
)
1294 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1295 return d2d_factory_AddRef(&factory
->ID2D1Factory7_iface
);
1298 static ULONG STDMETHODCALLTYPE
d2d_factory_mt_Release(ID2D1Multithread
*iface
)
1300 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1301 return d2d_factory_Release(&factory
->ID2D1Factory7_iface
);
1304 static BOOL STDMETHODCALLTYPE
d2d_factory_mt_GetMultithreadProtected(ID2D1Multithread
*iface
)
1309 static void STDMETHODCALLTYPE
d2d_factory_mt_Enter(ID2D1Multithread
*iface
)
1311 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1313 TRACE("%p.\n", iface
);
1315 EnterCriticalSection(&factory
->cs
);
1318 static void STDMETHODCALLTYPE
d2d_factory_mt_Leave(ID2D1Multithread
*iface
)
1320 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1322 TRACE("%p.\n", iface
);
1324 LeaveCriticalSection(&factory
->cs
);
1327 static BOOL STDMETHODCALLTYPE
d2d_factory_st_GetMultithreadProtected(ID2D1Multithread
*iface
)
1332 static void STDMETHODCALLTYPE
d2d_factory_st_Enter(ID2D1Multithread
*iface
)
1336 static void STDMETHODCALLTYPE
d2d_factory_st_Leave(ID2D1Multithread
*iface
)
1340 static const struct ID2D1MultithreadVtbl d2d_factory_multithread_vtbl
=
1342 d2d_factory_mt_QueryInterface
,
1343 d2d_factory_mt_AddRef
,
1344 d2d_factory_mt_Release
,
1345 d2d_factory_mt_GetMultithreadProtected
,
1346 d2d_factory_mt_Enter
,
1347 d2d_factory_mt_Leave
,
1350 static const struct ID2D1MultithreadVtbl d2d_factory_multithread_noop_vtbl
=
1352 d2d_factory_mt_QueryInterface
,
1353 d2d_factory_mt_AddRef
,
1354 d2d_factory_mt_Release
,
1355 d2d_factory_st_GetMultithreadProtected
,
1356 d2d_factory_st_Enter
,
1357 d2d_factory_st_Leave
,
1360 static void d2d_factory_init(struct d2d_factory
*factory
, D2D1_FACTORY_TYPE factory_type
,
1361 const D2D1_FACTORY_OPTIONS
*factory_options
)
1363 if (factory_options
&& factory_options
->debugLevel
!= D2D1_DEBUG_LEVEL_NONE
)
1364 WARN("Ignoring debug level %#x.\n", factory_options
->debugLevel
);
1366 factory
->ID2D1Factory7_iface
.lpVtbl
= &d2d_factory_vtbl
;
1367 factory
->ID2D1Multithread_iface
.lpVtbl
= factory_type
== D2D1_FACTORY_TYPE_SINGLE_THREADED
?
1368 &d2d_factory_multithread_noop_vtbl
: &d2d_factory_multithread_vtbl
;
1369 factory
->factory_type
= factory_type
;
1370 factory
->refcount
= 1;
1371 d2d_factory_reload_sysmetrics(factory
);
1372 list_init(&factory
->effects
);
1373 InitializeCriticalSection(&factory
->cs
);
1374 InitOnceInitialize(&factory
->init_builtins
);
1377 HRESULT WINAPI
D2D1CreateFactory(D2D1_FACTORY_TYPE factory_type
, REFIID iid
,
1378 const D2D1_FACTORY_OPTIONS
*factory_options
, void **factory
)
1380 struct d2d_factory
*object
;
1383 TRACE("factory_type %#x, iid %s, factory_options %p, factory %p.\n",
1384 factory_type
, debugstr_guid(iid
), factory_options
, factory
);
1386 if (factory_type
!= D2D1_FACTORY_TYPE_SINGLE_THREADED
&&
1387 factory_type
!= D2D1_FACTORY_TYPE_MULTI_THREADED
)
1389 return E_INVALIDARG
;
1392 if (!(object
= calloc(1, sizeof(*object
))))
1393 return E_OUTOFMEMORY
;
1395 d2d_factory_init(object
, factory_type
, factory_options
);
1397 TRACE("Created factory %p.\n", object
);
1399 hr
= ID2D1Factory7_QueryInterface(&object
->ID2D1Factory7_iface
, iid
, factory
);
1400 ID2D1Factory7_Release(&object
->ID2D1Factory7_iface
);
1405 void WINAPI
D2D1MakeRotateMatrix(float angle
, D2D1_POINT_2F center
, D2D1_MATRIX_3X2_F
*matrix
)
1407 float theta
, sin_theta
, cos_theta
;
1409 TRACE("angle %.8e, center %s, matrix %p.\n", angle
, debug_d2d_point_2f(¢er
), matrix
);
1411 theta
= angle
* (M_PI
/ 180.0f
);
1412 sin_theta
= sinf(theta
);
1413 cos_theta
= cosf(theta
);
1415 /* translate(center) * rotate(theta) * translate(-center) */
1416 matrix
->_11
= cos_theta
;
1417 matrix
->_12
= sin_theta
;
1418 matrix
->_21
= -sin_theta
;
1419 matrix
->_22
= cos_theta
;
1420 matrix
->_31
= center
.x
- center
.x
* cos_theta
+ center
.y
* sin_theta
;
1421 matrix
->_32
= center
.y
- center
.x
* sin_theta
- center
.y
* cos_theta
;
1424 void WINAPI
D2D1MakeSkewMatrix(float angle_x
, float angle_y
, D2D1_POINT_2F center
, D2D1_MATRIX_3X2_F
*matrix
)
1428 TRACE("angle_x %.8e, angle_y %.8e, center %s, matrix %p.\n", angle_x
, angle_y
, debug_d2d_point_2f(¢er
), matrix
);
1430 tan_x
= tan(angle_x
* (M_PI
/ 180.0f
));
1431 tan_y
= tan(angle_y
* (M_PI
/ 180.0f
));
1433 /* translate(-center) * skew() * translate(center) */
1435 matrix
->_12
= tan_y
;
1436 matrix
->_21
= tan_x
;
1438 matrix
->_31
= -tan_x
* center
.y
;
1439 matrix
->_32
= -tan_y
* center
.x
;
1442 BOOL WINAPI
D2D1IsMatrixInvertible(const D2D1_MATRIX_3X2_F
*matrix
)
1444 TRACE("matrix %p.\n", matrix
);
1446 return (matrix
->_11
* matrix
->_22
- matrix
->_21
* matrix
->_12
) != 0.0f
;
1449 BOOL WINAPI
D2D1InvertMatrix(D2D1_MATRIX_3X2_F
*matrix
)
1451 D2D1_MATRIX_3X2_F m
= *matrix
;
1453 TRACE("matrix %p.\n", matrix
);
1455 return d2d_matrix_invert(matrix
, &m
);
1458 HRESULT WINAPI
D2D1CreateDevice(IDXGIDevice
*dxgi_device
,
1459 const D2D1_CREATION_PROPERTIES
*properties
, ID2D1Device
**device
)
1461 D2D1_CREATION_PROPERTIES default_properties
= {0};
1462 D2D1_FACTORY_OPTIONS factory_options
;
1463 D2D1_FACTORY_TYPE factory_type
;
1464 ID3D11Device
*d3d_device
;
1465 ID2D1Factory1
*factory
;
1468 TRACE("dxgi_device %p, properties %p, device %p.\n", dxgi_device
, properties
, device
);
1472 if (SUCCEEDED(IDXGIDevice_QueryInterface(dxgi_device
, &IID_ID3D11Device
, (void **)&d3d_device
)))
1474 if (!(ID3D11Device_GetCreationFlags(d3d_device
) & D3D11_CREATE_DEVICE_SINGLETHREADED
))
1475 default_properties
.threadingMode
= D2D1_THREADING_MODE_MULTI_THREADED
;
1476 ID3D11Device_Release(d3d_device
);
1478 properties
= &default_properties
;
1481 switch (properties
->threadingMode
)
1483 case D2D1_THREADING_MODE_SINGLE_THREADED
:
1484 factory_type
= D2D1_FACTORY_TYPE_SINGLE_THREADED
;
1486 case D2D1_THREADING_MODE_MULTI_THREADED
:
1487 factory_type
= D2D1_FACTORY_TYPE_MULTI_THREADED
;
1490 return E_INVALIDARG
;
1493 factory_options
.debugLevel
= properties
->debugLevel
;
1494 if (FAILED(hr
= D2D1CreateFactory(factory_type
, &IID_ID2D1Factory1
, &factory_options
, (void **)&factory
)))
1497 hr
= ID2D1Factory1_CreateDevice(factory
, dxgi_device
, device
);
1498 ID2D1Factory1_Release(factory
);
1502 void WINAPI
D2D1SinCos(float angle
, float *s
, float *c
)
1504 TRACE("angle %.8e, s %p, c %p.\n", angle
, s
, c
);
1510 float WINAPI
D2D1Tan(float angle
)
1512 TRACE("angle %.8e.\n", angle
);
1517 float WINAPI
D2D1Vec3Length(float x
, float y
, float z
)
1519 TRACE("x %.8e, y %.8e, z %.8e.\n", x
, y
, z
);
1521 return sqrtf(x
* x
+ y
* y
+ z
* z
);
1524 /* See IEC 61966-2-1:1999; also described in the EXT_texture_sRGB OpenGL
1525 * extension, among others. */
1526 static float srgb_transfer_function(float x
)
1532 else if (x
<= 0.0031308f
)
1535 return 1.055f
* powf(x
, 1.0f
/ 2.4f
) - 0.055f
;
1538 static float srgb_inverse_transfer_function(float x
)
1544 else if (x
<= 0.04045f
)
1547 return powf((x
+ 0.055f
) / 1.055f
, 2.4f
);
1550 D2D1_COLOR_F WINAPI
D2D1ConvertColorSpace(D2D1_COLOR_SPACE src_colour_space
,
1551 D2D1_COLOR_SPACE dst_colour_space
, const D2D1_COLOR_F
*colour
)
1555 TRACE("src_colour_space %#x, dst_colour_space %#x, colour %s.\n",
1556 src_colour_space
, dst_colour_space
, debug_d2d_color_f(colour
));
1558 if (src_colour_space
== D2D1_COLOR_SPACE_CUSTOM
|| dst_colour_space
== D2D1_COLOR_SPACE_CUSTOM
)
1568 if (src_colour_space
== dst_colour_space
)
1571 if (src_colour_space
== D2D1_COLOR_SPACE_SRGB
&& dst_colour_space
== D2D1_COLOR_SPACE_SCRGB
)
1573 ret
.r
= srgb_inverse_transfer_function(colour
->r
);
1574 ret
.g
= srgb_inverse_transfer_function(colour
->g
);
1575 ret
.b
= srgb_inverse_transfer_function(colour
->b
);
1581 if (src_colour_space
== D2D1_COLOR_SPACE_SCRGB
&& dst_colour_space
== D2D1_COLOR_SPACE_SRGB
)
1583 ret
.r
= srgb_transfer_function(colour
->r
);
1584 ret
.g
= srgb_transfer_function(colour
->g
);
1585 ret
.b
= srgb_transfer_function(colour
->b
);
1591 FIXME("Unhandled conversion from source colour space %#x to destination colour space %#x.\n",
1592 src_colour_space
, dst_colour_space
);
1601 static bool get_config_key_u32(HKEY default_key
, HKEY application_key
, const char *name
, uint32_t *value
)
1606 size
= sizeof(data
);
1607 if (application_key
&& !RegQueryValueExA(application_key
,
1608 name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
)
1611 size
= sizeof(data
);
1612 if (default_key
&& !RegQueryValueExA(default_key
,
1613 name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
)
1623 static void d2d_settings_init(void)
1625 HKEY default_key
, tmp_key
, application_key
= NULL
;
1626 char buffer
[MAX_PATH
+ 10];
1629 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Direct2D", &default_key
))
1632 len
= GetModuleFileNameA(0, buffer
, MAX_PATH
);
1633 if (len
&& len
< MAX_PATH
)
1635 char *p
, *appname
= buffer
;
1637 if ((p
= strrchr(appname
, '/')))
1639 if ((p
= strrchr(appname
, '\\')))
1641 strcat(appname
, "\\Direct2D");
1643 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\AppDefaults", &tmp_key
))
1645 if (RegOpenKeyA(tmp_key
, appname
, &application_key
))
1646 application_key
= NULL
;
1647 RegCloseKey(tmp_key
);
1651 if (!default_key
&& !application_key
)
1654 if (get_config_key_u32(default_key
, application_key
, "max_version_factory", &d2d_settings
.max_version_factory
))
1655 ERR_(winediag
)("Limiting maximum Direct2D factory version to %#x.\n", d2d_settings
.max_version_factory
);
1657 if (application_key
)
1658 RegCloseKey(application_key
);
1660 RegCloseKey(default_key
);
1663 BOOL WINAPI
DllMain(HINSTANCE inst
, DWORD reason
, void *reserved
)
1665 if (reason
== DLL_PROCESS_ATTACH
)
1666 d2d_settings_init();