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 d2d_effect_properties_cleanup(®
->properties
);
39 static inline struct d2d_factory
*impl_from_ID2D1Factory3(ID2D1Factory3
*iface
)
41 return CONTAINING_RECORD(iface
, struct d2d_factory
, ID2D1Factory3_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(ID2D1Factory3
*iface
, REFIID iid
, void **out
)
102 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
104 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
106 if ((IsEqualGUID(iid
, &IID_ID2D1Factory3
) && d2d_settings
.max_version_factory
>= 3)
107 || (IsEqualGUID(iid
, &IID_ID2D1Factory2
) && d2d_settings
.max_version_factory
>= 2)
108 || (IsEqualGUID(iid
, &IID_ID2D1Factory1
) && d2d_settings
.max_version_factory
>= 1)
109 || IsEqualGUID(iid
, &IID_ID2D1Factory
)
110 || IsEqualGUID(iid
, &IID_IUnknown
))
112 ID2D1Factory3_AddRef(iface
);
116 else if (IsEqualGUID(iid
, &IID_ID2D1Multithread
))
118 ID2D1Factory3_AddRef(iface
);
119 *out
= &factory
->ID2D1Multithread_iface
;
123 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
126 return E_NOINTERFACE
;
129 static ULONG STDMETHODCALLTYPE
d2d_factory_AddRef(ID2D1Factory3
*iface
)
131 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
132 ULONG refcount
= InterlockedIncrement(&factory
->refcount
);
134 TRACE("%p increasing refcount to %lu.\n", iface
, refcount
);
139 static ULONG STDMETHODCALLTYPE
d2d_factory_Release(ID2D1Factory3
*iface
)
141 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
142 ULONG refcount
= InterlockedDecrement(&factory
->refcount
);
143 struct d2d_effect_registration
*reg
, *reg2
;
145 TRACE("%p decreasing refcount to %lu.\n", iface
, refcount
);
150 ID3D10Device1_Release(factory
->device
);
151 LIST_FOR_EACH_ENTRY_SAFE(reg
, reg2
, &factory
->effects
, struct d2d_effect_registration
, entry
)
153 d2d_effect_registration_cleanup(reg
);
155 DeleteCriticalSection(&factory
->cs
);
162 static HRESULT STDMETHODCALLTYPE
d2d_factory_ReloadSystemMetrics(ID2D1Factory3
*iface
)
164 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
166 TRACE("iface %p.\n", iface
);
168 return d2d_factory_reload_sysmetrics(factory
);
171 static void STDMETHODCALLTYPE
d2d_factory_GetDesktopDpi(ID2D1Factory3
*iface
, float *dpi_x
, float *dpi_y
)
173 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
175 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface
, dpi_x
, dpi_y
);
177 *dpi_x
= factory
->dpi_x
;
178 *dpi_y
= factory
->dpi_y
;
181 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateRectangleGeometry(ID2D1Factory3
*iface
,
182 const D2D1_RECT_F
*rect
, ID2D1RectangleGeometry
**geometry
)
184 struct d2d_geometry
*object
;
187 TRACE("iface %p, rect %s, geometry %p.\n", iface
, debug_d2d_rect_f(rect
), geometry
);
189 if (!(object
= calloc(1, sizeof(*object
))))
190 return E_OUTOFMEMORY
;
192 if (FAILED(hr
= d2d_rectangle_geometry_init(object
, (ID2D1Factory
*)iface
, rect
)))
194 WARN("Failed to initialise rectangle geometry, hr %#lx.\n", hr
);
199 TRACE("Created rectangle geometry %p.\n", object
);
200 *geometry
= (ID2D1RectangleGeometry
*)&object
->ID2D1Geometry_iface
;
205 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateRoundedRectangleGeometry(ID2D1Factory3
*iface
,
206 const D2D1_ROUNDED_RECT
*rounded_rect
, ID2D1RoundedRectangleGeometry
**geometry
)
208 struct d2d_geometry
*object
;
211 TRACE("iface %p, rounded_rect %s, geometry %p.\n", iface
, debug_d2d_rounded_rect(rounded_rect
), geometry
);
213 if (!(object
= calloc(1, sizeof(*object
))))
214 return E_OUTOFMEMORY
;
216 if (FAILED(hr
= d2d_rounded_rectangle_geometry_init(object
, (ID2D1Factory
*)iface
, rounded_rect
)))
218 WARN("Failed to initialise rounded rectangle geometry, hr %#lx.\n", hr
);
223 TRACE("Created rounded rectangle geometry %p.\n", object
);
224 *geometry
= (ID2D1RoundedRectangleGeometry
*)&object
->ID2D1Geometry_iface
;
229 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateEllipseGeometry(ID2D1Factory3
*iface
,
230 const D2D1_ELLIPSE
*ellipse
, ID2D1EllipseGeometry
**geometry
)
232 struct d2d_geometry
*object
;
235 TRACE("iface %p, ellipse %s, geometry %p.\n", iface
, debug_d2d_ellipse(ellipse
), geometry
);
237 if (!(object
= calloc(1, sizeof(*object
))))
238 return E_OUTOFMEMORY
;
240 if (FAILED(hr
= d2d_ellipse_geometry_init(object
, (ID2D1Factory
*)iface
, ellipse
)))
242 WARN("Failed to initialise ellipse geometry, hr %#lx.\n", hr
);
247 TRACE("Created ellipse geometry %p.\n", object
);
248 *geometry
= (ID2D1EllipseGeometry
*)&object
->ID2D1Geometry_iface
;
253 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateGeometryGroup(ID2D1Factory3
*iface
,
254 D2D1_FILL_MODE fill_mode
, ID2D1Geometry
**geometries
, UINT32 geometry_count
, ID2D1GeometryGroup
**group
)
256 struct d2d_geometry
*object
;
259 TRACE("iface %p, fill_mode %#x, geometries %p, geometry_count %u, group %p.\n",
260 iface
, fill_mode
, geometries
, geometry_count
, group
);
262 if (!(object
= calloc(1, sizeof(*object
))))
263 return E_OUTOFMEMORY
;
265 if (FAILED(hr
= d2d_geometry_group_init(object
, (ID2D1Factory
*)iface
, fill_mode
, geometries
, geometry_count
)))
267 WARN("Failed to initialise geometry group, hr %#lx.\n", hr
);
272 TRACE("Created geometry group %p.\n", object
);
273 *group
= (ID2D1GeometryGroup
*)&object
->ID2D1Geometry_iface
;
278 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateTransformedGeometry(ID2D1Factory3
*iface
,
279 ID2D1Geometry
*src_geometry
, const D2D1_MATRIX_3X2_F
*transform
,
280 ID2D1TransformedGeometry
**transformed_geometry
)
282 struct d2d_geometry
*object
;
284 TRACE("iface %p, src_geometry %p, transform %p, transformed_geometry %p.\n",
285 iface
, src_geometry
, transform
, transformed_geometry
);
287 if (!(object
= calloc(1, sizeof(*object
))))
288 return E_OUTOFMEMORY
;
290 d2d_transformed_geometry_init(object
, (ID2D1Factory
*)iface
, src_geometry
, transform
);
292 TRACE("Created transformed geometry %p.\n", object
);
293 *transformed_geometry
= (ID2D1TransformedGeometry
*)&object
->ID2D1Geometry_iface
;
298 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreatePathGeometry(ID2D1Factory3
*iface
, ID2D1PathGeometry
**geometry
)
300 struct d2d_geometry
*object
;
302 TRACE("iface %p, geometry %p.\n", iface
, geometry
);
304 if (!(object
= calloc(1, sizeof(*object
))))
305 return E_OUTOFMEMORY
;
307 d2d_path_geometry_init(object
, (ID2D1Factory
*)iface
);
309 TRACE("Created path geometry %p.\n", object
);
310 *geometry
= (ID2D1PathGeometry
*)&object
->ID2D1Geometry_iface
;
315 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateStrokeStyle(ID2D1Factory3
*iface
,
316 const D2D1_STROKE_STYLE_PROPERTIES
*desc
, const float *dashes
, UINT32 dash_count
,
317 ID2D1StrokeStyle
**stroke_style
)
319 struct d2d_stroke_style
*object
;
320 D2D1_STROKE_STYLE_PROPERTIES1 desc1
;
323 TRACE("iface %p, desc %p, dashes %p, dash_count %u, stroke_style %p.\n",
324 iface
, desc
, dashes
, dash_count
, stroke_style
);
326 if (!(object
= calloc(1, sizeof(*object
))))
327 return E_OUTOFMEMORY
;
329 desc1
.startCap
= desc
->startCap
;
330 desc1
.endCap
= desc
->endCap
;
331 desc1
.dashCap
= desc
->dashCap
;
332 desc1
.lineJoin
= desc
->lineJoin
;
333 desc1
.miterLimit
= desc
->miterLimit
;
334 desc1
.dashStyle
= desc
->dashStyle
;
335 desc1
.dashOffset
= desc
->dashOffset
;
336 desc1
.transformType
= D2D1_STROKE_TRANSFORM_TYPE_NORMAL
;
338 if (FAILED(hr
= d2d_stroke_style_init(object
, (ID2D1Factory
*)iface
, &desc1
, dashes
, dash_count
)))
340 WARN("Failed to initialise stroke style, hr %#lx.\n", hr
);
345 TRACE("Created stroke style %p.\n", object
);
346 *stroke_style
= (ID2D1StrokeStyle
*)&object
->ID2D1StrokeStyle1_iface
;
351 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDrawingStateBlock(ID2D1Factory3
*iface
,
352 const D2D1_DRAWING_STATE_DESCRIPTION
*desc
, IDWriteRenderingParams
*text_rendering_params
,
353 ID2D1DrawingStateBlock
**state_block
)
355 D2D1_DRAWING_STATE_DESCRIPTION1 state_desc
;
356 struct d2d_state_block
*object
;
358 TRACE("iface %p, desc %p, text_rendering_params %p, state_block %p.\n",
359 iface
, desc
, text_rendering_params
, state_block
);
361 if (!(object
= calloc(1, sizeof(*object
))))
362 return E_OUTOFMEMORY
;
366 memcpy(&state_desc
, desc
, sizeof(*desc
));
367 state_desc
.primitiveBlend
= D2D1_PRIMITIVE_BLEND_SOURCE_OVER
;
368 state_desc
.unitMode
= D2D1_UNIT_MODE_DIPS
;
371 d2d_state_block_init(object
, (ID2D1Factory
*)iface
, desc
? &state_desc
: NULL
, text_rendering_params
);
373 TRACE("Created state block %p.\n", object
);
374 *state_block
= (ID2D1DrawingStateBlock
*)&object
->ID2D1DrawingStateBlock1_iface
;
379 static HRESULT
d2d_factory_get_device(struct d2d_factory
*factory
, ID3D10Device1
**device
)
383 if (!factory
->device
&& FAILED(hr
= D3D10CreateDevice1(NULL
, D3D10_DRIVER_TYPE_HARDWARE
, NULL
, D3D10_CREATE_DEVICE_BGRA_SUPPORT
,
384 D3D10_FEATURE_LEVEL_10_0
, D3D10_1_SDK_VERSION
, &factory
->device
)))
385 WARN("Failed to create device, hr %#lx.\n", hr
);
387 *device
= factory
->device
;
391 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateWicBitmapRenderTarget(ID2D1Factory3
*iface
,
392 IWICBitmap
*target
, const D2D1_RENDER_TARGET_PROPERTIES
*desc
, ID2D1RenderTarget
**render_target
)
394 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
395 struct d2d_wic_render_target
*object
;
396 ID3D10Device1
*device
;
399 TRACE("iface %p, target %p, desc %p, render_target %p.\n", iface
, target
, desc
, render_target
);
401 if (!(object
= calloc(1, sizeof(*object
))))
402 return E_OUTOFMEMORY
;
404 if (FAILED(hr
= d2d_factory_get_device(factory
, &device
)))
410 if (FAILED(hr
= d2d_wic_render_target_init(object
, (ID2D1Factory1
*)iface
, device
, target
, desc
)))
412 WARN("Failed to initialise render target, hr %#lx.\n", hr
);
417 TRACE("Created render target %p.\n", object
);
418 *render_target
= object
->dxgi_target
;
423 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateHwndRenderTarget(ID2D1Factory3
*iface
,
424 const D2D1_RENDER_TARGET_PROPERTIES
*desc
, const D2D1_HWND_RENDER_TARGET_PROPERTIES
*hwnd_rt_desc
,
425 ID2D1HwndRenderTarget
**render_target
)
427 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
428 struct d2d_hwnd_render_target
*object
;
429 ID3D10Device1
*device
;
432 TRACE("iface %p, desc %p, hwnd_rt_desc %p, render_target %p.\n", iface
, desc
, hwnd_rt_desc
, render_target
);
434 if (FAILED(hr
= d2d_factory_get_device(factory
, &device
)))
437 if (!(object
= calloc(1, sizeof(*object
))))
438 return E_OUTOFMEMORY
;
440 if (FAILED(hr
= d2d_hwnd_render_target_init(object
, (ID2D1Factory1
*)iface
, device
, desc
, hwnd_rt_desc
)))
442 WARN("Failed to initialise render target, hr %#lx.\n", hr
);
447 TRACE("Created render target %p.\n", object
);
448 *render_target
= &object
->ID2D1HwndRenderTarget_iface
;
453 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDxgiSurfaceRenderTarget(ID2D1Factory3
*iface
,
454 IDXGISurface
*surface
, const D2D1_RENDER_TARGET_PROPERTIES
*desc
, ID2D1RenderTarget
**render_target
)
456 IDXGIDevice
*dxgi_device
;
460 TRACE("iface %p, surface %p, desc %p, render_target %p.\n", iface
, surface
, desc
, render_target
);
462 if (FAILED(hr
= IDXGISurface_GetDevice(surface
, &IID_IDXGIDevice
, (void **)&dxgi_device
)))
464 WARN("Failed to get DXGI device, hr %#lx.\n", hr
);
468 hr
= ID2D1Factory1_CreateDevice((ID2D1Factory1
*)iface
, dxgi_device
, &device
);
469 IDXGIDevice_Release(dxgi_device
);
472 WARN("Failed to create D2D device, hr %#lx.\n", hr
);
476 hr
= d2d_d3d_create_render_target(unsafe_impl_from_ID2D1Device((ID2D1Device1
*)device
), surface
,
477 NULL
, NULL
, desc
, (void **)render_target
);
478 ID2D1Device_Release(device
);
482 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDCRenderTarget(ID2D1Factory3
*iface
,
483 const D2D1_RENDER_TARGET_PROPERTIES
*desc
, ID2D1DCRenderTarget
**render_target
)
485 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
486 struct d2d_dc_render_target
*object
;
487 ID3D10Device1
*device
;
490 TRACE("iface %p, desc %p, render_target %p.\n", iface
, desc
, render_target
);
492 if (FAILED(hr
= d2d_factory_get_device(factory
, &device
)))
495 if (!(object
= calloc(1, sizeof(*object
))))
496 return E_OUTOFMEMORY
;
498 if (FAILED(hr
= d2d_dc_render_target_init(object
, (ID2D1Factory1
*)iface
, device
, desc
)))
500 WARN("Failed to initialise render target, hr %#lx.\n", hr
);
505 TRACE("Created render target %p.\n", object
);
506 *render_target
= &object
->ID2D1DCRenderTarget_iface
;
511 static HRESULT
d2d_factory_create_device(ID2D1Factory3
*iface
, IDXGIDevice
*dxgi_device
,
512 ID2D1Device1
**device
) {
513 struct d2d_device
*object
;
515 if (!(object
= calloc(1, sizeof(*object
))))
516 return E_OUTOFMEMORY
;
518 d2d_device_init(object
, (ID2D1Factory1
*)iface
, dxgi_device
);
520 TRACE("Create device %p.\n", object
);
521 *device
= &object
->ID2D1Device1_iface
;
526 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDevice(ID2D1Factory3
*iface
,
527 IDXGIDevice
*dxgi_device
, ID2D1Device
**device
)
529 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
531 return d2d_factory_create_device(iface
, dxgi_device
, (ID2D1Device1
**)device
);
534 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateStrokeStyle1(ID2D1Factory3
*iface
,
535 const D2D1_STROKE_STYLE_PROPERTIES1
*desc
, const float *dashes
, UINT32 dash_count
,
536 ID2D1StrokeStyle1
**stroke_style
)
538 struct d2d_stroke_style
*object
;
541 TRACE("iface %p, desc %p, dashes %p, dash_count %u, stroke_style %p.\n",
542 iface
, desc
, dashes
, dash_count
, stroke_style
);
544 if (!(object
= calloc(1, sizeof(*object
))))
545 return E_OUTOFMEMORY
;
547 if (FAILED(hr
= d2d_stroke_style_init(object
, (ID2D1Factory
*)iface
,
548 desc
, dashes
, dash_count
)))
550 WARN("Failed to initialise stroke style, hr %#lx.\n", hr
);
555 TRACE("Created stroke style %p.\n", object
);
556 *stroke_style
= &object
->ID2D1StrokeStyle1_iface
;
561 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreatePathGeometry1(ID2D1Factory3
*iface
, ID2D1PathGeometry1
**geometry
)
563 struct d2d_geometry
*object
;
565 TRACE("iface %p, geometry %p.\n", iface
, geometry
);
567 if (!(object
= calloc(1, sizeof(*object
))))
568 return E_OUTOFMEMORY
;
570 d2d_path_geometry_init(object
, (ID2D1Factory
*)iface
);
572 TRACE("Created path geometry %p.\n", object
);
573 *geometry
= (ID2D1PathGeometry1
*)&object
->ID2D1Geometry_iface
;
578 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateDrawingStateBlock1(ID2D1Factory3
*iface
,
579 const D2D1_DRAWING_STATE_DESCRIPTION1
*desc
, IDWriteRenderingParams
*text_rendering_params
,
580 ID2D1DrawingStateBlock1
**state_block
)
582 struct d2d_state_block
*object
;
584 TRACE("iface %p, desc %p, text_rendering_params %p, state_block %p.\n",
585 iface
, desc
, text_rendering_params
, state_block
);
587 if (!(object
= calloc(1, sizeof(*object
))))
588 return E_OUTOFMEMORY
;
590 d2d_state_block_init(object
, (ID2D1Factory
*)iface
, desc
, text_rendering_params
);
592 TRACE("Created state block %p.\n", object
);
593 *state_block
= &object
->ID2D1DrawingStateBlock1_iface
;
598 static HRESULT STDMETHODCALLTYPE
d2d_factory_CreateGdiMetafile(ID2D1Factory3
*iface
,
599 IStream
*stream
, ID2D1GdiMetafile
**metafile
)
601 FIXME("iface %p, stream %p, metafile %p stub!\n", iface
, stream
, metafile
);
606 static HRESULT
parse_effect_get_next_xml_node(IXmlReader
*reader
, XmlNodeType expected_type
,
607 const WCHAR
*expected_name
, unsigned int *depth
)
609 const WCHAR
*node_name
;
610 XmlNodeType node_type
;
613 assert(expected_type
!= XmlNodeType_Whitespace
);
615 while ((hr
= IXmlReader_Read(reader
, &node_type
)) == S_OK
)
617 if (node_type
== XmlNodeType_Whitespace
)
620 if (expected_type
!= XmlNodeType_None
&& node_type
!= expected_type
)
621 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
625 if (FAILED(hr
= IXmlReader_GetLocalName(reader
, &node_name
, NULL
)))
628 if (wcscmp(node_name
, expected_name
))
629 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
633 IXmlReader_GetDepth(reader
, depth
);
640 static HRESULT
parse_effect_skip_element(IXmlReader
*reader
, unsigned int element_depth
)
642 XmlNodeType node_type
;
646 if (IXmlReader_IsEmptyElement(reader
)) return S_OK
;
648 while ((hr
= IXmlReader_Read(reader
, &node_type
)) == S_OK
)
650 IXmlReader_GetDepth(reader
, &depth
);
651 if (node_type
== XmlNodeType_EndElement
&& depth
== element_depth
+ 1)
660 static HRESULT
parse_effect_get_attribute(IXmlReader
*reader
, const WCHAR
*name
, WCHAR
**ret
)
666 if (IXmlReader_MoveToAttributeByName(reader
, name
, NULL
) != S_OK
)
668 if (IXmlReader_GetValue(reader
, &value
, NULL
) != S_OK
)
670 if (!(*ret
= wcsdup(value
)))
671 return E_OUTOFMEMORY
;
676 static HRESULT
parse_effect_get_property_type(IXmlReader
*reader
, D2D1_PROPERTY_TYPE
*type
)
678 static const WCHAR
*types
[] =
680 L
"", /* D2D1_PROPERTY_TYPE_UNKNOWN */
681 L
"string", /* D2D1_PROPERTY_TYPE_STRING */
682 L
"bool", /* D2D1_PROPERTY_TYPE_BOOL */
683 L
"uint32", /* D2D1_PROPERTY_TYPE_UINT32 */
684 L
"int32", /* D2D1_PROPERTY_TYPE_INT32 */
685 L
"float", /* D2D1_PROPERTY_TYPE_FLOAT */
686 L
"vector2", /* D2D1_PROPERTY_TYPE_VECTOR2 */
687 L
"vector3", /* D2D1_PROPERTY_TYPE_VECTOR3 */
688 L
"vector4", /* D2D1_PROPERTY_TYPE_VECTOR4 */
689 L
"blob", /* D2D1_PROPERTY_TYPE_BLOB */
690 L
"iunknown", /* D2D1_PROPERTY_TYPE_IUNKNOWN */
691 L
"enum", /* D2D1_PROPERTY_TYPE_ENUM */
692 L
"array", /* D2D1_PROPERTY_TYPE_ARRAY */
693 L
"clsid", /* D2D1_PROPERTY_TYPE_CLSID */
694 L
"matrix3x2", /* D2D1_PROPERTY_TYPE_MATRIX_3X2 */
695 L
"matrix4x3", /* D2D1_PROPERTY_TYPE_MATRIX_4X3 */
696 L
"matrix4x4", /* D2D1_PROPERTY_TYPE_MATRIX_4X4 */
697 L
"matrix5x4", /* D2D1_PROPERTY_TYPE_MATRIX_5X4 */
698 L
"colorcontext", /* D2D1_PROPERTY_TYPE_COLOR_CONTEXT */
704 if (FAILED(hr
= parse_effect_get_attribute(reader
, L
"type", &value
))) return hr
;
706 *type
= D2D1_PROPERTY_TYPE_UNKNOWN
;
708 for (i
= 0; i
< ARRAY_SIZE(types
); ++i
)
710 if (!wcscmp(value
, types
[i
]))
719 return *type
== D2D1_PROPERTY_TYPE_UNKNOWN
? E_INVALIDARG
: S_OK
;
722 static struct d2d_effect_property
* parse_effect_get_property(const struct d2d_effect_registration
*effect
,
727 for (i
= 0; i
< effect
->properties
.count
; ++i
)
729 if (!wcscmp(name
, effect
->properties
.properties
[i
].name
))
730 return &effect
->properties
.properties
[i
];
736 static UINT32
parse_effect_get_property_index(struct d2d_effect_properties
*props
,
739 if (!wcscmp(name
, L
"DisplayName")) return D2D1_PROPERTY_DISPLAYNAME
;
740 if (!wcscmp(name
, L
"Author")) return D2D1_PROPERTY_AUTHOR
;
741 if (!wcscmp(name
, L
"Category")) return D2D1_PROPERTY_CATEGORY
;
742 if (!wcscmp(name
, L
"Description")) return D2D1_PROPERTY_DESCRIPTION
;
743 return props
->custom_count
;
746 static HRESULT
parse_effect_property(IXmlReader
*reader
, struct d2d_effect_registration
*effect
)
748 WCHAR
*name
= NULL
, *value
= NULL
;
749 D2D1_PROPERTY_TYPE type
;
754 if (FAILED(hr
= parse_effect_get_attribute(reader
, L
"name", &name
)))
757 if (FAILED(hr
= parse_effect_get_property_type(reader
, &type
)))
763 /* Check for duplicates. */
764 if (parse_effect_get_property(effect
, name
))
767 parse_effect_get_attribute(reader
, L
"value", &value
);
771 /* FIXME: sub properties are ignored */
772 IXmlReader_MoveToElement(reader
);
773 IXmlReader_GetDepth(reader
, &depth
);
774 hr
= parse_effect_skip_element(reader
, depth
);
779 index
= parse_effect_get_property_index(&effect
->properties
, name
);
780 hr
= d2d_effect_properties_add(&effect
->properties
, name
, index
, type
, value
);
789 static HRESULT
parse_effect_inputs(IXmlReader
*reader
, struct d2d_effect_registration
*effect
)
791 struct d2d_effect_property
*inputs
, *min_inputs
, *max_inputs
;
792 struct d2d_effect_properties
*subproperties
;
793 UINT32 min_inputs_value
, max_inputs_value
;
794 unsigned int depth
, input_count
= 0;
795 XmlNodeType node_type
;
800 if (FAILED(hr
= d2d_effect_properties_add(&effect
->properties
, L
"Inputs",
801 D2D1_PROPERTY_INPUTS
, D2D1_PROPERTY_TYPE_ARRAY
, NULL
)))
804 if (!(inputs
= d2d_effect_properties_get_property_by_name(&effect
->properties
, L
"Inputs")))
806 if (!(inputs
->subproperties
= calloc(1, sizeof(*inputs
->subproperties
))))
807 return E_OUTOFMEMORY
;
808 subproperties
= inputs
->subproperties
;
810 d2d_effect_subproperties_add(subproperties
, L
"IsReadOnly", D2D1_SUBPROPERTY_ISREADONLY
,
811 D2D1_PROPERTY_TYPE_BOOL
, L
"true");
812 d2d_effect_subproperties_add(subproperties
, L
"DisplayName", D2D1_SUBPROPERTY_DISPLAYNAME
,
813 D2D1_PROPERTY_TYPE_STRING
, L
"Inputs");
815 if (SUCCEEDED(parse_effect_get_attribute(reader
, L
"minimum", &value
)))
817 hr
= d2d_effect_properties_add(&effect
->properties
, L
"MinInputs", D2D1_PROPERTY_MIN_INPUTS
,
818 D2D1_PROPERTY_TYPE_UINT32
, value
);
820 if (FAILED(hr
)) return hr
;
822 if (SUCCEEDED(parse_effect_get_attribute(reader
, L
"maximum", &value
)))
824 hr
= d2d_effect_properties_add(&effect
->properties
, L
"MaxInputs", D2D1_PROPERTY_MAX_INPUTS
,
825 D2D1_PROPERTY_TYPE_UINT32
, value
);
827 if (FAILED(hr
)) return hr
;
830 min_inputs
= d2d_effect_properties_get_property_by_name(&effect
->properties
, L
"MinInputs");
831 max_inputs
= d2d_effect_properties_get_property_by_name(&effect
->properties
, L
"MaxInputs");
833 if (!IXmlReader_IsEmptyElement(reader
))
835 while (parse_effect_get_next_xml_node(reader
, XmlNodeType_None
, L
"Input", &depth
) == S_OK
)
837 if (FAILED(hr
= IXmlReader_GetNodeType(reader
, &node_type
))) return hr
;
838 if (node_type
== XmlNodeType_EndElement
) continue;
839 if (node_type
!= XmlNodeType_Element
) return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
841 if (FAILED(hr
= parse_effect_get_attribute(reader
, L
"name", &name
))) return hr
;
843 swprintf(buffW
, ARRAY_SIZE(buffW
), L
"%lu", input_count
);
844 d2d_effect_subproperties_add(subproperties
, buffW
, input_count
, D2D1_PROPERTY_TYPE_STRING
, name
);
849 *(UINT32
*)(effect
->properties
.data
.ptr
+ inputs
->data
.offset
) = input_count
;
851 if (FAILED(hr
= IXmlReader_GetNodeType(reader
, &node_type
))) return hr
;
852 if (node_type
!= XmlNodeType_EndElement
) return HRESULT_FROM_WIN32(ERROR_NOT_FOUND
);
856 d2d_effect_property_get_uint32_value(&effect
->properties
, min_inputs
, &min_inputs_value
);
858 d2d_effect_property_get_uint32_value(&effect
->properties
, max_inputs
, &max_inputs_value
);
860 /* Validate the range */
861 if (min_inputs
&& max_inputs
)
863 if (min_inputs_value
> max_inputs_value
)
865 WARN("Invalid input count range %u - %u.\n", min_inputs_value
, max_inputs_value
);
870 /* Validate actual input count with specified range. */
871 if (min_inputs
&& min_inputs_value
> input_count
)
873 WARN("Too few inputs were declared, expected at least %u.\n", min_inputs_value
);
877 if (max_inputs
&& max_inputs_value
< input_count
)
879 WARN("Too many inputs were declared, expected at most %u.\n", max_inputs_value
);
883 /* Apply default value to a missing property. If both properties are missing, add them. */
884 if (min_inputs
!= max_inputs
)
886 swprintf(buffW
, ARRAY_SIZE(buffW
), L
"%lu", min_inputs
? min_inputs_value
: max_inputs_value
);
888 hr
= d2d_effect_properties_add(&effect
->properties
, L
"MaxInputs", D2D1_PROPERTY_MAX_INPUTS
, D2D1_PROPERTY_TYPE_UINT32
, buffW
);
890 hr
= d2d_effect_properties_add(&effect
->properties
, L
"MinInputs", D2D1_PROPERTY_MIN_INPUTS
, D2D1_PROPERTY_TYPE_UINT32
, buffW
);
892 else if (!min_inputs
)
894 swprintf(buffW
, ARRAY_SIZE(buffW
), L
"%lu", input_count
);
895 hr
= d2d_effect_properties_add(&effect
->properties
, L
"MinInputs", D2D1_PROPERTY_MIN_INPUTS
, D2D1_PROPERTY_TYPE_UINT32
, buffW
);
897 hr
= d2d_effect_properties_add(&effect
->properties
, L
"MaxInputs", D2D1_PROPERTY_MAX_INPUTS
, D2D1_PROPERTY_TYPE_UINT32
, buffW
);
903 static HRESULT
parse_effect_xml(IXmlReader
*reader
, struct d2d_effect_registration
*effect
)
905 const WCHAR
*node_name
;
906 XmlNodeType node_type
;
910 /* Xml declaration node is mandatory. */
911 if ((hr
= parse_effect_get_next_xml_node(reader
, XmlNodeType_XmlDeclaration
, L
"xml", NULL
)) != S_OK
)
914 /* Top level "Effect" element. */
915 if ((hr
= parse_effect_get_next_xml_node(reader
, XmlNodeType_Element
, L
"Effect", NULL
)) != S_OK
)
918 /* Loop inside effect node */
919 while ((hr
= parse_effect_get_next_xml_node(reader
, XmlNodeType_None
, NULL
, &depth
)) == S_OK
)
921 if (FAILED(hr
= IXmlReader_GetNodeType(reader
, &node_type
))) return hr
;
922 if (node_type
!= XmlNodeType_Element
&& node_type
!= XmlNodeType_EndElement
) continue;
923 if (FAILED(hr
= IXmlReader_GetLocalName(reader
, &node_name
, NULL
))) return hr
;
924 if (node_type
== XmlNodeType_EndElement
) break;
926 if (!wcscmp(node_name
, L
"Property"))
927 hr
= parse_effect_property(reader
, effect
);
928 else if (!wcscmp(node_name
, L
"Inputs"))
929 hr
= parse_effect_inputs(reader
, effect
);
932 WARN("Unexpected element %s.\n", debugstr_w(node_name
));
933 hr
= parse_effect_skip_element(reader
, depth
);
943 static HRESULT
d2d_factory_register_effect_from_stream(struct d2d_factory
*factory
,
944 REFCLSID effect_id
, IStream
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
,
945 UINT32 binding_count
, PD2D1_EFFECT_FACTORY effect_factory
, BOOL builtin
)
947 struct d2d_effect_registration
*effect
;
952 LIST_FOR_EACH_ENTRY_REV(effect
, &factory
->effects
, struct d2d_effect_registration
, entry
)
954 if (IsEqualGUID(effect_id
, &effect
->id
))
956 if (effect
->builtin
) return E_INVALIDARG
;
957 ++effect
->registration_count
;
962 if (FAILED(hr
= CreateXmlReader(&IID_IXmlReader
, (void **)&reader
, NULL
)))
965 if (FAILED(hr
= IXmlReader_SetInput(reader
, (IUnknown
*)property_xml
)))
967 IXmlReader_Release(reader
);
971 if (!(effect
= calloc(1, sizeof(*effect
))))
973 IXmlReader_Release(reader
);
974 return E_OUTOFMEMORY
;
976 effect
->builtin
= builtin
;
978 hr
= parse_effect_xml(reader
, effect
);
979 IXmlReader_Release(reader
);
982 WARN("Failed to parse effect xml, hr %#lx.\n", hr
);
983 d2d_effect_registration_cleanup(effect
);
987 /* Check required properties. */
988 if (!parse_effect_get_property(effect
, L
"DisplayName")
989 || !parse_effect_get_property(effect
, L
"Author")
990 || !parse_effect_get_property(effect
, L
"Category")
991 || !parse_effect_get_property(effect
, L
"Description")
992 || !parse_effect_get_property(effect
, L
"Inputs"))
994 WARN("Missing required properties.\n");
995 d2d_effect_registration_cleanup(effect
);
999 /* Bind getter and setter. */
1000 for (i
= 0; i
< binding_count
; ++i
)
1002 struct d2d_effect_property
*property
;
1004 if (!(property
= parse_effect_get_property(effect
, bindings
[i
].propertyName
)))
1006 WARN("Failed to bind to missing property.\n");
1007 d2d_effect_registration_cleanup(effect
);
1008 return D2DERR_INVALID_PROPERTY
;
1011 property
->get_function
= bindings
[i
].getFunction
;
1012 property
->set_function
= bindings
[i
].setFunction
;
1015 effect
->registration_count
= 1;
1016 effect
->id
= *effect_id
;
1017 effect
->factory
= effect_factory
;
1018 d2d_factory_register_effect(factory
, effect
);
1023 static HRESULT STDMETHODCALLTYPE
d2d_factory_RegisterEffectFromStream(ID2D1Factory3
*iface
,
1024 REFCLSID effect_id
, IStream
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
,
1025 UINT32 binding_count
, PD2D1_EFFECT_FACTORY effect_factory
)
1027 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
1029 TRACE("iface %p, effect_id %s, property_xml %p, bindings %p, binding_count %u, effect_factory %p.\n",
1030 iface
, debugstr_guid(effect_id
), property_xml
, bindings
, binding_count
, effect_factory
);
1032 d2d_factory_init_builtin_effects(factory
);
1034 return d2d_factory_register_effect_from_stream(factory
, effect_id
, property_xml
, bindings
,
1035 binding_count
, effect_factory
, FALSE
);
1038 static HRESULT
d2d_factory_register_effect_from_string(struct d2d_factory
*factory
,
1039 REFCLSID effect_id
, const WCHAR
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
,
1040 UINT32 binding_count
, PD2D1_EFFECT_FACTORY effect_factory
, BOOL builtin
)
1042 static const LARGE_INTEGER zero
;
1047 if (FAILED(hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
)))
1050 size
= sizeof(*property_xml
) * (wcslen(property_xml
) + 1);
1051 if (SUCCEEDED(hr
= IStream_Write(stream
, property_xml
, size
, NULL
)))
1052 hr
= IStream_Seek(stream
, zero
, SEEK_SET
, NULL
);
1055 hr
= d2d_factory_register_effect_from_stream(factory
, effect_id
, stream
, bindings
,
1056 binding_count
, effect_factory
, builtin
);
1058 IStream_Release(stream
);
1062 HRESULT
d2d_factory_register_builtin_effect(struct d2d_factory
*factory
, REFCLSID effect_id
,
1063 const WCHAR
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
, UINT32 binding_count
,
1064 PD2D1_EFFECT_FACTORY effect_factory
)
1066 return d2d_factory_register_effect_from_string(factory
, effect_id
, property_xml
, bindings
,
1067 binding_count
, effect_factory
, TRUE
);
1070 static HRESULT STDMETHODCALLTYPE
d2d_factory_RegisterEffectFromString(ID2D1Factory3
*iface
,
1071 REFCLSID effect_id
, const WCHAR
*property_xml
, const D2D1_PROPERTY_BINDING
*bindings
,
1072 UINT32 binding_count
, PD2D1_EFFECT_FACTORY effect_factory
)
1074 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
1076 TRACE("iface %p, effect_id %s, property_xml %s, bindings %p, binding_count %u, effect_factory %p.\n",
1077 iface
, debugstr_guid(effect_id
), debugstr_w(property_xml
), bindings
, binding_count
, effect_factory
);
1079 d2d_factory_init_builtin_effects(factory
);
1081 return d2d_factory_register_effect_from_string(factory
, effect_id
, property_xml
, bindings
,
1082 binding_count
, effect_factory
, FALSE
);
1085 static HRESULT STDMETHODCALLTYPE
d2d_factory_UnregisterEffect(ID2D1Factory3
*iface
, REFCLSID effect_id
)
1087 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
1088 struct d2d_effect_registration
*effect
;
1090 TRACE("iface %p, effect_id %s.\n", iface
, debugstr_guid(effect_id
));
1092 d2d_factory_init_builtin_effects(factory
);
1094 LIST_FOR_EACH_ENTRY_REV(effect
, &factory
->effects
, struct d2d_effect_registration
, entry
)
1096 if (IsEqualGUID(effect_id
, &effect
->id
))
1098 if (effect
->builtin
) break;
1099 if (!--effect
->registration_count
)
1101 list_remove(&effect
->entry
);
1102 d2d_effect_registration_cleanup(effect
);
1108 return D2DERR_EFFECT_IS_NOT_REGISTERED
;
1111 static HRESULT STDMETHODCALLTYPE
d2d_factory_GetRegisteredEffects(ID2D1Factory3
*iface
,
1112 CLSID
*effects
, UINT32 effect_count
, UINT32
*returned
, UINT32
*registered
)
1114 struct d2d_factory
*factory
= impl_from_ID2D1Factory3(iface
);
1115 struct d2d_effect_registration
*effect
;
1118 TRACE("iface %p, effects %p, effect_count %u, returned %p, registered %p.\n",
1119 iface
, effects
, effect_count
, returned
, registered
);
1121 if (!returned
) returned
= &ret
;
1122 if (!registered
) registered
= ®
;
1127 d2d_factory_init_builtin_effects(factory
);
1129 LIST_FOR_EACH_ENTRY(effect
, &factory
->effects
, struct d2d_effect_registration
, entry
)
1131 if (effects
&& effect_count
)
1133 *effects
= effect
->id
;
1142 if (!effects
) return S_OK
;
1143 return *returned
== *registered
? S_OK
: D2DERR_INSUFFICIENT_BUFFER
;
1146 static HRESULT STDMETHODCALLTYPE
d2d_factory_GetEffectProperties(ID2D1Factory3
*iface
,
1147 REFCLSID effect_id
, ID2D1Properties
**props
)
1149 FIXME("iface %p, effect_id %s, props %p stub!\n", iface
, debugstr_guid(effect_id
), props
);
1154 static HRESULT STDMETHODCALLTYPE
d2d_factory_ID2D1Factory2_CreateDevice(ID2D1Factory3
*iface
, IDXGIDevice
*dxgi_device
,
1155 ID2D1Device1
**device
)
1157 TRACE("iface %p, dxgi_device %p, device %p.\n", iface
, dxgi_device
, device
);
1159 return d2d_factory_create_device(iface
, dxgi_device
, device
);
1162 static HRESULT STDMETHODCALLTYPE
d2d_factory_ID2D1Factory3_CreateDevice(ID2D1Factory3
*iface
, IDXGIDevice
*dxgi_device
,
1163 ID2D1Device2
**device
)
1165 FIXME("iface %p, dxgi_device %p, device %p stub!\n", iface
, dxgi_device
, device
);
1170 static const struct ID2D1Factory3Vtbl d2d_factory_vtbl
=
1172 d2d_factory_QueryInterface
,
1174 d2d_factory_Release
,
1175 d2d_factory_ReloadSystemMetrics
,
1176 d2d_factory_GetDesktopDpi
,
1177 d2d_factory_CreateRectangleGeometry
,
1178 d2d_factory_CreateRoundedRectangleGeometry
,
1179 d2d_factory_CreateEllipseGeometry
,
1180 d2d_factory_CreateGeometryGroup
,
1181 d2d_factory_CreateTransformedGeometry
,
1182 d2d_factory_CreatePathGeometry
,
1183 d2d_factory_CreateStrokeStyle
,
1184 d2d_factory_CreateDrawingStateBlock
,
1185 d2d_factory_CreateWicBitmapRenderTarget
,
1186 d2d_factory_CreateHwndRenderTarget
,
1187 d2d_factory_CreateDxgiSurfaceRenderTarget
,
1188 d2d_factory_CreateDCRenderTarget
,
1189 d2d_factory_CreateDevice
,
1190 d2d_factory_CreateStrokeStyle1
,
1191 d2d_factory_CreatePathGeometry1
,
1192 d2d_factory_CreateDrawingStateBlock1
,
1193 d2d_factory_CreateGdiMetafile
,
1194 d2d_factory_RegisterEffectFromStream
,
1195 d2d_factory_RegisterEffectFromString
,
1196 d2d_factory_UnregisterEffect
,
1197 d2d_factory_GetRegisteredEffects
,
1198 d2d_factory_GetEffectProperties
,
1199 d2d_factory_ID2D1Factory2_CreateDevice
,
1200 d2d_factory_ID2D1Factory3_CreateDevice
,
1203 static HRESULT STDMETHODCALLTYPE
d2d_factory_mt_QueryInterface(ID2D1Multithread
*iface
, REFIID iid
, void **out
)
1205 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1206 return d2d_factory_QueryInterface(&factory
->ID2D1Factory3_iface
, iid
, out
);
1209 static ULONG STDMETHODCALLTYPE
d2d_factory_mt_AddRef(ID2D1Multithread
*iface
)
1211 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1212 return d2d_factory_AddRef(&factory
->ID2D1Factory3_iface
);
1215 static ULONG STDMETHODCALLTYPE
d2d_factory_mt_Release(ID2D1Multithread
*iface
)
1217 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1218 return d2d_factory_Release(&factory
->ID2D1Factory3_iface
);
1221 static BOOL STDMETHODCALLTYPE
d2d_factory_mt_GetMultithreadProtected(ID2D1Multithread
*iface
)
1226 static void STDMETHODCALLTYPE
d2d_factory_mt_Enter(ID2D1Multithread
*iface
)
1228 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1230 TRACE("%p.\n", iface
);
1232 EnterCriticalSection(&factory
->cs
);
1235 static void STDMETHODCALLTYPE
d2d_factory_mt_Leave(ID2D1Multithread
*iface
)
1237 struct d2d_factory
*factory
= impl_from_ID2D1Multithread(iface
);
1239 TRACE("%p.\n", iface
);
1241 LeaveCriticalSection(&factory
->cs
);
1244 static BOOL STDMETHODCALLTYPE
d2d_factory_st_GetMultithreadProtected(ID2D1Multithread
*iface
)
1249 static void STDMETHODCALLTYPE
d2d_factory_st_Enter(ID2D1Multithread
*iface
)
1253 static void STDMETHODCALLTYPE
d2d_factory_st_Leave(ID2D1Multithread
*iface
)
1257 static const struct ID2D1MultithreadVtbl d2d_factory_multithread_vtbl
=
1259 d2d_factory_mt_QueryInterface
,
1260 d2d_factory_mt_AddRef
,
1261 d2d_factory_mt_Release
,
1262 d2d_factory_mt_GetMultithreadProtected
,
1263 d2d_factory_mt_Enter
,
1264 d2d_factory_mt_Leave
,
1267 static const struct ID2D1MultithreadVtbl d2d_factory_multithread_noop_vtbl
=
1269 d2d_factory_mt_QueryInterface
,
1270 d2d_factory_mt_AddRef
,
1271 d2d_factory_mt_Release
,
1272 d2d_factory_st_GetMultithreadProtected
,
1273 d2d_factory_st_Enter
,
1274 d2d_factory_st_Leave
,
1277 static void d2d_factory_init(struct d2d_factory
*factory
, D2D1_FACTORY_TYPE factory_type
,
1278 const D2D1_FACTORY_OPTIONS
*factory_options
)
1280 if (factory_options
&& factory_options
->debugLevel
!= D2D1_DEBUG_LEVEL_NONE
)
1281 WARN("Ignoring debug level %#x.\n", factory_options
->debugLevel
);
1283 factory
->ID2D1Factory3_iface
.lpVtbl
= &d2d_factory_vtbl
;
1284 factory
->ID2D1Multithread_iface
.lpVtbl
= factory_type
== D2D1_FACTORY_TYPE_SINGLE_THREADED
?
1285 &d2d_factory_multithread_noop_vtbl
: &d2d_factory_multithread_vtbl
;
1286 factory
->factory_type
= factory_type
;
1287 factory
->refcount
= 1;
1288 d2d_factory_reload_sysmetrics(factory
);
1289 list_init(&factory
->effects
);
1290 InitializeCriticalSection(&factory
->cs
);
1291 InitOnceInitialize(&factory
->init_builtins
);
1294 HRESULT WINAPI
D2D1CreateFactory(D2D1_FACTORY_TYPE factory_type
, REFIID iid
,
1295 const D2D1_FACTORY_OPTIONS
*factory_options
, void **factory
)
1297 struct d2d_factory
*object
;
1300 TRACE("factory_type %#x, iid %s, factory_options %p, factory %p.\n",
1301 factory_type
, debugstr_guid(iid
), factory_options
, factory
);
1303 if (factory_type
!= D2D1_FACTORY_TYPE_SINGLE_THREADED
&&
1304 factory_type
!= D2D1_FACTORY_TYPE_MULTI_THREADED
)
1306 return E_INVALIDARG
;
1309 if (!(object
= calloc(1, sizeof(*object
))))
1310 return E_OUTOFMEMORY
;
1312 d2d_factory_init(object
, factory_type
, factory_options
);
1314 TRACE("Created factory %p.\n", object
);
1316 hr
= ID2D1Factory3_QueryInterface(&object
->ID2D1Factory3_iface
, iid
, factory
);
1317 ID2D1Factory3_Release(&object
->ID2D1Factory3_iface
);
1322 void WINAPI
D2D1MakeRotateMatrix(float angle
, D2D1_POINT_2F center
, D2D1_MATRIX_3X2_F
*matrix
)
1324 float theta
, sin_theta
, cos_theta
;
1326 TRACE("angle %.8e, center %s, matrix %p.\n", angle
, debug_d2d_point_2f(¢er
), matrix
);
1328 theta
= angle
* (M_PI
/ 180.0f
);
1329 sin_theta
= sinf(theta
);
1330 cos_theta
= cosf(theta
);
1332 /* translate(center) * rotate(theta) * translate(-center) */
1333 matrix
->_11
= cos_theta
;
1334 matrix
->_12
= sin_theta
;
1335 matrix
->_21
= -sin_theta
;
1336 matrix
->_22
= cos_theta
;
1337 matrix
->_31
= center
.x
- center
.x
* cos_theta
+ center
.y
* sin_theta
;
1338 matrix
->_32
= center
.y
- center
.x
* sin_theta
- center
.y
* cos_theta
;
1341 void WINAPI
D2D1MakeSkewMatrix(float angle_x
, float angle_y
, D2D1_POINT_2F center
, D2D1_MATRIX_3X2_F
*matrix
)
1345 TRACE("angle_x %.8e, angle_y %.8e, center %s, matrix %p.\n", angle_x
, angle_y
, debug_d2d_point_2f(¢er
), matrix
);
1347 tan_x
= tan(angle_x
* (M_PI
/ 180.0f
));
1348 tan_y
= tan(angle_y
* (M_PI
/ 180.0f
));
1350 /* translate(-center) * skew() * translate(center) */
1352 matrix
->_12
= tan_y
;
1353 matrix
->_21
= tan_x
;
1355 matrix
->_31
= -tan_x
* center
.y
;
1356 matrix
->_32
= -tan_y
* center
.x
;
1359 BOOL WINAPI
D2D1IsMatrixInvertible(const D2D1_MATRIX_3X2_F
*matrix
)
1361 TRACE("matrix %p.\n", matrix
);
1363 return (matrix
->_11
* matrix
->_22
- matrix
->_21
* matrix
->_12
) != 0.0f
;
1366 BOOL WINAPI
D2D1InvertMatrix(D2D1_MATRIX_3X2_F
*matrix
)
1368 D2D1_MATRIX_3X2_F m
= *matrix
;
1370 TRACE("matrix %p.\n", matrix
);
1372 return d2d_matrix_invert(matrix
, &m
);
1375 HRESULT WINAPI
D2D1CreateDevice(IDXGIDevice
*dxgi_device
,
1376 const D2D1_CREATION_PROPERTIES
*properties
, ID2D1Device
**device
)
1378 D2D1_CREATION_PROPERTIES default_properties
= {0};
1379 D2D1_FACTORY_OPTIONS factory_options
;
1380 D2D1_FACTORY_TYPE factory_type
;
1381 ID3D11Device
*d3d_device
;
1382 ID2D1Factory1
*factory
;
1385 TRACE("dxgi_device %p, properties %p, device %p.\n", dxgi_device
, properties
, device
);
1389 if (SUCCEEDED(IDXGIDevice_QueryInterface(dxgi_device
, &IID_ID3D11Device
, (void **)&d3d_device
)))
1391 if (!(ID3D11Device_GetCreationFlags(d3d_device
) & D3D11_CREATE_DEVICE_SINGLETHREADED
))
1392 default_properties
.threadingMode
= D2D1_THREADING_MODE_MULTI_THREADED
;
1393 ID3D11Device_Release(d3d_device
);
1395 properties
= &default_properties
;
1398 switch (properties
->threadingMode
)
1400 case D2D1_THREADING_MODE_SINGLE_THREADED
:
1401 factory_type
= D2D1_FACTORY_TYPE_SINGLE_THREADED
;
1403 case D2D1_THREADING_MODE_MULTI_THREADED
:
1404 factory_type
= D2D1_FACTORY_TYPE_MULTI_THREADED
;
1407 return E_INVALIDARG
;
1410 factory_options
.debugLevel
= properties
->debugLevel
;
1411 if (FAILED(hr
= D2D1CreateFactory(factory_type
, &IID_ID2D1Factory1
, &factory_options
, (void **)&factory
)))
1414 hr
= ID2D1Factory1_CreateDevice(factory
, dxgi_device
, device
);
1415 ID2D1Factory1_Release(factory
);
1419 void WINAPI
D2D1SinCos(float angle
, float *s
, float *c
)
1421 TRACE("angle %.8e, s %p, c %p.\n", angle
, s
, c
);
1427 float WINAPI
D2D1Tan(float angle
)
1429 TRACE("angle %.8e.\n", angle
);
1434 float WINAPI
D2D1Vec3Length(float x
, float y
, float z
)
1436 TRACE("x %.8e, y %.8e, z %.8e.\n", x
, y
, z
);
1438 return sqrtf(x
* x
+ y
* y
+ z
* z
);
1441 /* See IEC 61966-2-1:1999; also described in the EXT_texture_sRGB OpenGL
1442 * extension, among others. */
1443 static float srgb_transfer_function(float x
)
1449 else if (x
<= 0.0031308f
)
1452 return 1.055f
* powf(x
, 1.0f
/ 2.4f
) - 0.055f
;
1455 static float srgb_inverse_transfer_function(float x
)
1461 else if (x
<= 0.04045f
)
1464 return powf((x
+ 0.055f
) / 1.055f
, 2.4f
);
1467 D2D1_COLOR_F WINAPI
D2D1ConvertColorSpace(D2D1_COLOR_SPACE src_colour_space
,
1468 D2D1_COLOR_SPACE dst_colour_space
, const D2D1_COLOR_F
*colour
)
1472 TRACE("src_colour_space %#x, dst_colour_space %#x, colour %s.\n",
1473 src_colour_space
, dst_colour_space
, debug_d2d_color_f(colour
));
1475 if (src_colour_space
== D2D1_COLOR_SPACE_CUSTOM
|| dst_colour_space
== D2D1_COLOR_SPACE_CUSTOM
)
1485 if (src_colour_space
== dst_colour_space
)
1488 if (src_colour_space
== D2D1_COLOR_SPACE_SRGB
&& dst_colour_space
== D2D1_COLOR_SPACE_SCRGB
)
1490 ret
.r
= srgb_inverse_transfer_function(colour
->r
);
1491 ret
.g
= srgb_inverse_transfer_function(colour
->g
);
1492 ret
.b
= srgb_inverse_transfer_function(colour
->b
);
1498 if (src_colour_space
== D2D1_COLOR_SPACE_SCRGB
&& dst_colour_space
== D2D1_COLOR_SPACE_SRGB
)
1500 ret
.r
= srgb_transfer_function(colour
->r
);
1501 ret
.g
= srgb_transfer_function(colour
->g
);
1502 ret
.b
= srgb_transfer_function(colour
->b
);
1508 FIXME("Unhandled conversion from source colour space %#x to destination colour space %#x.\n",
1509 src_colour_space
, dst_colour_space
);
1518 static bool get_config_key_u32(HKEY default_key
, HKEY application_key
, const char *name
, uint32_t *value
)
1523 size
= sizeof(data
);
1524 if (application_key
&& !RegQueryValueExA(application_key
,
1525 name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
)
1528 size
= sizeof(data
);
1529 if (default_key
&& !RegQueryValueExA(default_key
,
1530 name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
)
1540 static void d2d_settings_init(void)
1542 HKEY default_key
, tmp_key
, application_key
= NULL
;
1543 char buffer
[MAX_PATH
+ 10];
1546 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Direct2D", &default_key
))
1549 len
= GetModuleFileNameA(0, buffer
, MAX_PATH
);
1550 if (len
&& len
< MAX_PATH
)
1552 char *p
, *appname
= buffer
;
1554 if ((p
= strrchr(appname
, '/')))
1556 if ((p
= strrchr(appname
, '\\')))
1558 strcat(appname
, "\\Direct2D");
1560 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\AppDefaults", &tmp_key
))
1562 if (RegOpenKeyA(tmp_key
, appname
, &application_key
))
1563 application_key
= NULL
;
1564 RegCloseKey(tmp_key
);
1568 if (!default_key
&& !application_key
)
1571 if (get_config_key_u32(default_key
, application_key
, "max_version_factory", &d2d_settings
.max_version_factory
))
1572 ERR_(winediag
)("Limiting maximum Direct2D factory version to %#x.\n", d2d_settings
.max_version_factory
);
1574 if (application_key
)
1575 RegCloseKey(application_key
);
1577 RegCloseKey(default_key
);
1580 BOOL WINAPI
DllMain(HINSTANCE inst
, DWORD reason
, void *reserved
)
1582 if (reason
== DLL_PROCESS_ATTACH
)
1583 d2d_settings_init();