d2d1: Implement UnregisterEffect().
[wine.git] / dlls / d2d1 / factory.c
blob5c79d1791ff41671792b201d3a7a3a18c705cd07
1 /*
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"
22 #include "xmllite.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 struct d2d_effect_property
35 WCHAR *name;
36 D2D1_PROPERTY_TYPE type;
37 BYTE *value;
38 PD2D1_PROPERTY_SET_FUNCTION set_function;
39 PD2D1_PROPERTY_GET_FUNCTION get_function;
42 struct d2d_effect_registration
44 struct list entry;
45 PD2D1_EFFECT_FACTORY factory;
46 UINT32 registration_count;
47 CLSID id;
49 UINT32 input_count;
51 struct d2d_effect_property *properties;
52 size_t property_size;
53 size_t property_count;
56 static void d2d_effect_registration_cleanup(struct d2d_effect_registration *reg)
58 size_t i;
60 for (i = 0; i < reg->property_count; ++i)
62 free(reg->properties[i].name);
63 free(reg->properties[i].value);
65 free(reg->properties);
66 free(reg);
69 struct d2d_factory
71 ID2D1Factory3 ID2D1Factory3_iface;
72 ID2D1Multithread ID2D1Multithread_iface;
73 LONG refcount;
75 ID3D10Device1 *device;
77 float dpi_x;
78 float dpi_y;
80 struct list effects;
82 CRITICAL_SECTION cs;
85 static inline struct d2d_factory *impl_from_ID2D1Factory3(ID2D1Factory3 *iface)
87 return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Factory3_iface);
90 static inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *iface)
92 return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Multithread_iface);
95 static HRESULT d2d_factory_reload_sysmetrics(struct d2d_factory *factory)
97 HDC hdc;
99 if (!(hdc = GetDC(NULL)))
101 factory->dpi_x = factory->dpi_y = 96.0f;
102 return E_FAIL;
105 factory->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
106 factory->dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
108 ReleaseDC(NULL, hdc);
110 return S_OK;
113 static HRESULT STDMETHODCALLTYPE d2d_factory_QueryInterface(ID2D1Factory3 *iface, REFIID iid, void **out)
115 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
117 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
119 if ((IsEqualGUID(iid, &IID_ID2D1Factory3) && d2d_settings.max_version_factory >= 3)
120 || (IsEqualGUID(iid, &IID_ID2D1Factory2) && d2d_settings.max_version_factory >= 2)
121 || (IsEqualGUID(iid, &IID_ID2D1Factory1) && d2d_settings.max_version_factory >= 1)
122 || IsEqualGUID(iid, &IID_ID2D1Factory)
123 || IsEqualGUID(iid, &IID_IUnknown))
125 ID2D1Factory3_AddRef(iface);
126 *out = iface;
127 return S_OK;
129 else if (IsEqualGUID(iid, &IID_ID2D1Multithread))
131 ID2D1Factory3_AddRef(iface);
132 *out = &factory->ID2D1Multithread_iface;
133 return S_OK;
136 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
138 *out = NULL;
139 return E_NOINTERFACE;
142 static ULONG STDMETHODCALLTYPE d2d_factory_AddRef(ID2D1Factory3 *iface)
144 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
145 ULONG refcount = InterlockedIncrement(&factory->refcount);
147 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
149 return refcount;
152 static ULONG STDMETHODCALLTYPE d2d_factory_Release(ID2D1Factory3 *iface)
154 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
155 ULONG refcount = InterlockedDecrement(&factory->refcount);
156 struct d2d_effect_registration *reg, *reg2;
158 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
160 if (!refcount)
162 if (factory->device)
163 ID3D10Device1_Release(factory->device);
164 LIST_FOR_EACH_ENTRY_SAFE(reg, reg2, &factory->effects, struct d2d_effect_registration, entry)
166 d2d_effect_registration_cleanup(reg);
168 DeleteCriticalSection(&factory->cs);
169 free(factory);
172 return refcount;
175 static HRESULT STDMETHODCALLTYPE d2d_factory_ReloadSystemMetrics(ID2D1Factory3 *iface)
177 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
179 TRACE("iface %p.\n", iface);
181 return d2d_factory_reload_sysmetrics(factory);
184 static void STDMETHODCALLTYPE d2d_factory_GetDesktopDpi(ID2D1Factory3 *iface, float *dpi_x, float *dpi_y)
186 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
188 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
190 *dpi_x = factory->dpi_x;
191 *dpi_y = factory->dpi_y;
194 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateRectangleGeometry(ID2D1Factory3 *iface,
195 const D2D1_RECT_F *rect, ID2D1RectangleGeometry **geometry)
197 struct d2d_geometry *object;
198 HRESULT hr;
200 TRACE("iface %p, rect %s, geometry %p.\n", iface, debug_d2d_rect_f(rect), geometry);
202 if (!(object = calloc(1, sizeof(*object))))
203 return E_OUTOFMEMORY;
205 if (FAILED(hr = d2d_rectangle_geometry_init(object, (ID2D1Factory *)iface, rect)))
207 WARN("Failed to initialise rectangle geometry, hr %#lx.\n", hr);
208 free(object);
209 return hr;
212 TRACE("Created rectangle geometry %p.\n", object);
213 *geometry = (ID2D1RectangleGeometry *)&object->ID2D1Geometry_iface;
215 return S_OK;
218 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateRoundedRectangleGeometry(ID2D1Factory3 *iface,
219 const D2D1_ROUNDED_RECT *rounded_rect, ID2D1RoundedRectangleGeometry **geometry)
221 struct d2d_geometry *object;
222 HRESULT hr;
224 TRACE("iface %p, rounded_rect %s, geometry %p.\n", iface, debug_d2d_rounded_rect(rounded_rect), geometry);
226 if (!(object = calloc(1, sizeof(*object))))
227 return E_OUTOFMEMORY;
229 if (FAILED(hr = d2d_rounded_rectangle_geometry_init(object, (ID2D1Factory *)iface, rounded_rect)))
231 WARN("Failed to initialise rounded rectangle geometry, hr %#lx.\n", hr);
232 free(object);
233 return hr;
236 TRACE("Created rounded rectangle geometry %p.\n", object);
237 *geometry = (ID2D1RoundedRectangleGeometry *)&object->ID2D1Geometry_iface;
239 return S_OK;
242 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateEllipseGeometry(ID2D1Factory3 *iface,
243 const D2D1_ELLIPSE *ellipse, ID2D1EllipseGeometry **geometry)
245 struct d2d_geometry *object;
246 HRESULT hr;
248 TRACE("iface %p, ellipse %s, geometry %p.\n", iface, debug_d2d_ellipse(ellipse), geometry);
250 if (!(object = calloc(1, sizeof(*object))))
251 return E_OUTOFMEMORY;
253 if (FAILED(hr = d2d_ellipse_geometry_init(object, (ID2D1Factory *)iface, ellipse)))
255 WARN("Failed to initialise ellipse geometry, hr %#lx.\n", hr);
256 free(object);
257 return hr;
260 TRACE("Created ellipse geometry %p.\n", object);
261 *geometry = (ID2D1EllipseGeometry *)&object->ID2D1Geometry_iface;
263 return S_OK;
266 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateGeometryGroup(ID2D1Factory3 *iface,
267 D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, UINT32 geometry_count, ID2D1GeometryGroup **group)
269 struct d2d_geometry *object;
270 HRESULT hr;
272 TRACE("iface %p, fill_mode %#x, geometries %p, geometry_count %u, group %p.\n",
273 iface, fill_mode, geometries, geometry_count, group);
275 if (!(object = calloc(1, sizeof(*object))))
276 return E_OUTOFMEMORY;
278 if (FAILED(hr = d2d_geometry_group_init(object, (ID2D1Factory *)iface, fill_mode, geometries, geometry_count)))
280 WARN("Failed to initialise geometry group, hr %#lx.\n", hr);
281 free(object);
282 return hr;
285 TRACE("Created geometry group %p.\n", object);
286 *group = (ID2D1GeometryGroup *)&object->ID2D1Geometry_iface;
288 return S_OK;
291 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateTransformedGeometry(ID2D1Factory3 *iface,
292 ID2D1Geometry *src_geometry, const D2D1_MATRIX_3X2_F *transform,
293 ID2D1TransformedGeometry **transformed_geometry)
295 struct d2d_geometry *object;
297 TRACE("iface %p, src_geometry %p, transform %p, transformed_geometry %p.\n",
298 iface, src_geometry, transform, transformed_geometry);
300 if (!(object = calloc(1, sizeof(*object))))
301 return E_OUTOFMEMORY;
303 d2d_transformed_geometry_init(object, (ID2D1Factory *)iface, src_geometry, transform);
305 TRACE("Created transformed geometry %p.\n", object);
306 *transformed_geometry = (ID2D1TransformedGeometry *)&object->ID2D1Geometry_iface;
308 return S_OK;
311 static HRESULT STDMETHODCALLTYPE d2d_factory_CreatePathGeometry(ID2D1Factory3 *iface, ID2D1PathGeometry **geometry)
313 struct d2d_geometry *object;
315 TRACE("iface %p, geometry %p.\n", iface, geometry);
317 if (!(object = calloc(1, sizeof(*object))))
318 return E_OUTOFMEMORY;
320 d2d_path_geometry_init(object, (ID2D1Factory *)iface);
322 TRACE("Created path geometry %p.\n", object);
323 *geometry = (ID2D1PathGeometry *)&object->ID2D1Geometry_iface;
325 return S_OK;
328 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateStrokeStyle(ID2D1Factory3 *iface,
329 const D2D1_STROKE_STYLE_PROPERTIES *desc, const float *dashes, UINT32 dash_count,
330 ID2D1StrokeStyle **stroke_style)
332 struct d2d_stroke_style *object;
333 D2D1_STROKE_STYLE_PROPERTIES1 desc1;
334 HRESULT hr;
336 TRACE("iface %p, desc %p, dashes %p, dash_count %u, stroke_style %p.\n",
337 iface, desc, dashes, dash_count, stroke_style);
339 if (!(object = calloc(1, sizeof(*object))))
340 return E_OUTOFMEMORY;
342 desc1.startCap = desc->startCap;
343 desc1.endCap = desc->endCap;
344 desc1.dashCap = desc->dashCap;
345 desc1.lineJoin = desc->lineJoin;
346 desc1.miterLimit = desc->miterLimit;
347 desc1.dashStyle = desc->dashStyle;
348 desc1.dashOffset = desc->dashOffset;
349 desc1.transformType = D2D1_STROKE_TRANSFORM_TYPE_NORMAL;
351 if (FAILED(hr = d2d_stroke_style_init(object, (ID2D1Factory *)iface, &desc1, dashes, dash_count)))
353 WARN("Failed to initialise stroke style, hr %#lx.\n", hr);
354 free(object);
355 return hr;
358 TRACE("Created stroke style %p.\n", object);
359 *stroke_style = (ID2D1StrokeStyle *)&object->ID2D1StrokeStyle1_iface;
361 return S_OK;
364 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateDrawingStateBlock(ID2D1Factory3 *iface,
365 const D2D1_DRAWING_STATE_DESCRIPTION *desc, IDWriteRenderingParams *text_rendering_params,
366 ID2D1DrawingStateBlock **state_block)
368 D2D1_DRAWING_STATE_DESCRIPTION1 state_desc;
369 struct d2d_state_block *object;
371 TRACE("iface %p, desc %p, text_rendering_params %p, state_block %p.\n",
372 iface, desc, text_rendering_params, state_block);
374 if (!(object = calloc(1, sizeof(*object))))
375 return E_OUTOFMEMORY;
377 if (desc)
379 memcpy(&state_desc, desc, sizeof(*desc));
380 state_desc.primitiveBlend = D2D1_PRIMITIVE_BLEND_SOURCE_OVER;
381 state_desc.unitMode = D2D1_UNIT_MODE_DIPS;
384 d2d_state_block_init(object, (ID2D1Factory *)iface, desc ? &state_desc : NULL, text_rendering_params);
386 TRACE("Created state block %p.\n", object);
387 *state_block = (ID2D1DrawingStateBlock *)&object->ID2D1DrawingStateBlock1_iface;
389 return S_OK;
392 static HRESULT d2d_factory_get_device(struct d2d_factory *factory, ID3D10Device1 **device)
394 HRESULT hr = S_OK;
396 if (!factory->device && FAILED(hr = D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, D3D10_CREATE_DEVICE_BGRA_SUPPORT,
397 D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &factory->device)))
398 WARN("Failed to create device, hr %#lx.\n", hr);
400 *device = factory->device;
401 return hr;
404 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateWicBitmapRenderTarget(ID2D1Factory3 *iface,
405 IWICBitmap *target, const D2D1_RENDER_TARGET_PROPERTIES *desc, ID2D1RenderTarget **render_target)
407 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
408 struct d2d_wic_render_target *object;
409 ID3D10Device1 *device;
410 HRESULT hr;
412 TRACE("iface %p, target %p, desc %p, render_target %p.\n", iface, target, desc, render_target);
414 if (!(object = calloc(1, sizeof(*object))))
415 return E_OUTOFMEMORY;
417 if (FAILED(hr = d2d_factory_get_device(factory, &device)))
419 free(object);
420 return hr;
423 if (FAILED(hr = d2d_wic_render_target_init(object, (ID2D1Factory1 *)iface, device, target, desc)))
425 WARN("Failed to initialise render target, hr %#lx.\n", hr);
426 free(object);
427 return hr;
430 TRACE("Created render target %p.\n", object);
431 *render_target = object->dxgi_target;
433 return S_OK;
436 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateHwndRenderTarget(ID2D1Factory3 *iface,
437 const D2D1_RENDER_TARGET_PROPERTIES *desc, const D2D1_HWND_RENDER_TARGET_PROPERTIES *hwnd_rt_desc,
438 ID2D1HwndRenderTarget **render_target)
440 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
441 struct d2d_hwnd_render_target *object;
442 ID3D10Device1 *device;
443 HRESULT hr;
445 TRACE("iface %p, desc %p, hwnd_rt_desc %p, render_target %p.\n", iface, desc, hwnd_rt_desc, render_target);
447 if (FAILED(hr = d2d_factory_get_device(factory, &device)))
448 return hr;
450 if (!(object = calloc(1, sizeof(*object))))
451 return E_OUTOFMEMORY;
453 if (FAILED(hr = d2d_hwnd_render_target_init(object, (ID2D1Factory1 *)iface, device, desc, hwnd_rt_desc)))
455 WARN("Failed to initialise render target, hr %#lx.\n", hr);
456 free(object);
457 return hr;
460 TRACE("Created render target %p.\n", object);
461 *render_target = &object->ID2D1HwndRenderTarget_iface;
463 return S_OK;
466 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateDxgiSurfaceRenderTarget(ID2D1Factory3 *iface,
467 IDXGISurface *surface, const D2D1_RENDER_TARGET_PROPERTIES *desc, ID2D1RenderTarget **render_target)
469 IDXGIDevice *dxgi_device;
470 ID2D1Device *device;
471 HRESULT hr;
473 TRACE("iface %p, surface %p, desc %p, render_target %p.\n", iface, surface, desc, render_target);
475 if (FAILED(hr = IDXGISurface_GetDevice(surface, &IID_IDXGIDevice, (void **)&dxgi_device)))
477 WARN("Failed to get DXGI device, hr %#lx.\n", hr);
478 return hr;
481 hr = ID2D1Factory1_CreateDevice((ID2D1Factory1 *)iface, dxgi_device, &device);
482 IDXGIDevice_Release(dxgi_device);
483 if (FAILED(hr))
485 WARN("Failed to create D2D device, hr %#lx.\n", hr);
486 return hr;
489 hr = d2d_d3d_create_render_target(device, surface, NULL, NULL, desc, (void **)render_target);
490 ID2D1Device_Release(device);
491 return hr;
494 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateDCRenderTarget(ID2D1Factory3 *iface,
495 const D2D1_RENDER_TARGET_PROPERTIES *desc, ID2D1DCRenderTarget **render_target)
497 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
498 struct d2d_dc_render_target *object;
499 ID3D10Device1 *device;
500 HRESULT hr;
502 TRACE("iface %p, desc %p, render_target %p.\n", iface, desc, render_target);
504 if (FAILED(hr = d2d_factory_get_device(factory, &device)))
505 return hr;
507 if (!(object = calloc(1, sizeof(*object))))
508 return E_OUTOFMEMORY;
510 if (FAILED(hr = d2d_dc_render_target_init(object, (ID2D1Factory1 *)iface, device, desc)))
512 WARN("Failed to initialise render target, hr %#lx.\n", hr);
513 free(object);
514 return hr;
517 TRACE("Created render target %p.\n", object);
518 *render_target = &object->ID2D1DCRenderTarget_iface;
520 return S_OK;
523 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateDevice(ID2D1Factory3 *iface,
524 IDXGIDevice *dxgi_device, ID2D1Device **device)
526 struct d2d_device *object;
528 TRACE("iface %p, dxgi_device %p, device %p.\n", iface, dxgi_device, device);
530 if (!(object = calloc(1, sizeof(*object))))
531 return E_OUTOFMEMORY;
533 d2d_device_init(object, (ID2D1Factory1 *)iface, dxgi_device);
535 TRACE("Create device %p.\n", object);
536 *device = &object->ID2D1Device_iface;
538 return S_OK;
541 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateStrokeStyle1(ID2D1Factory3 *iface,
542 const D2D1_STROKE_STYLE_PROPERTIES1 *desc, const float *dashes, UINT32 dash_count,
543 ID2D1StrokeStyle1 **stroke_style)
545 struct d2d_stroke_style *object;
546 HRESULT hr;
548 TRACE("iface %p, desc %p, dashes %p, dash_count %u, stroke_style %p.\n",
549 iface, desc, dashes, dash_count, stroke_style);
551 if (!(object = calloc(1, sizeof(*object))))
552 return E_OUTOFMEMORY;
554 if (FAILED(hr = d2d_stroke_style_init(object, (ID2D1Factory *)iface,
555 desc, dashes, dash_count)))
557 WARN("Failed to initialise stroke style, hr %#lx.\n", hr);
558 free(object);
559 return hr;
562 TRACE("Created stroke style %p.\n", object);
563 *stroke_style = &object->ID2D1StrokeStyle1_iface;
565 return S_OK;
568 static HRESULT STDMETHODCALLTYPE d2d_factory_CreatePathGeometry1(ID2D1Factory3 *iface, ID2D1PathGeometry1 **geometry)
570 struct d2d_geometry *object;
572 TRACE("iface %p, geometry %p.\n", iface, geometry);
574 if (!(object = calloc(1, sizeof(*object))))
575 return E_OUTOFMEMORY;
577 d2d_path_geometry_init(object, (ID2D1Factory *)iface);
579 TRACE("Created path geometry %p.\n", object);
580 *geometry = (ID2D1PathGeometry1 *)&object->ID2D1Geometry_iface;
582 return S_OK;
585 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateDrawingStateBlock1(ID2D1Factory3 *iface,
586 const D2D1_DRAWING_STATE_DESCRIPTION1 *desc, IDWriteRenderingParams *text_rendering_params,
587 ID2D1DrawingStateBlock1 **state_block)
589 struct d2d_state_block *object;
591 TRACE("iface %p, desc %p, text_rendering_params %p, state_block %p.\n",
592 iface, desc, text_rendering_params, state_block);
594 if (!(object = calloc(1, sizeof(*object))))
595 return E_OUTOFMEMORY;
597 d2d_state_block_init(object, (ID2D1Factory *)iface, desc, text_rendering_params);
599 TRACE("Created state block %p.\n", object);
600 *state_block = &object->ID2D1DrawingStateBlock1_iface;
602 return S_OK;
605 static HRESULT STDMETHODCALLTYPE d2d_factory_CreateGdiMetafile(ID2D1Factory3 *iface,
606 IStream *stream, ID2D1GdiMetafile **metafile)
608 FIXME("iface %p, stream %p, metafile %p stub!\n", iface, stream, metafile);
610 return E_NOTIMPL;
613 static HRESULT parse_effect_get_next_xml_node(IXmlReader *reader, XmlNodeType expected_type,
614 const WCHAR *expected_name, unsigned int *depth)
616 const WCHAR *node_name;
617 XmlNodeType node_type;
618 HRESULT hr;
620 assert(expected_type != XmlNodeType_Whitespace);
622 while ((hr = IXmlReader_Read(reader, &node_type)) == S_OK)
624 if (node_type == XmlNodeType_Whitespace)
625 continue;
627 if (expected_type != XmlNodeType_None && node_type != expected_type)
628 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
630 if (expected_name)
632 if (FAILED(hr = IXmlReader_GetLocalName(reader, &node_name, NULL)))
633 return hr;
635 if (wcscmp(node_name, expected_name))
636 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
639 if (depth)
640 IXmlReader_GetDepth(reader, depth);
641 return S_OK;
644 return hr;
647 static HRESULT parse_effect_skip_element(IXmlReader *reader, unsigned int element_depth)
649 XmlNodeType node_type;
650 unsigned int depth;
651 HRESULT hr;
653 if (IXmlReader_IsEmptyElement(reader)) return S_OK;
655 while ((hr = IXmlReader_Read(reader, &node_type)) == S_OK)
657 IXmlReader_GetDepth(reader, &depth);
658 if (node_type == XmlNodeType_EndElement && depth == element_depth + 1)
660 return S_OK;
664 return hr;
667 static HRESULT parse_effect_get_attribute(IXmlReader *reader, const WCHAR *name, WCHAR **ret)
669 const WCHAR *value;
671 *ret = NULL;
673 if (IXmlReader_MoveToAttributeByName(reader, name, NULL) != S_OK)
674 return E_INVALIDARG;
675 if (IXmlReader_GetValue(reader, &value, NULL) != S_OK)
676 return E_INVALIDARG;
677 if (!(*ret = wcsdup(value)))
678 return E_OUTOFMEMORY;
680 return S_OK;
683 static HRESULT parse_effect_get_property_type(IXmlReader *reader, D2D1_PROPERTY_TYPE *type)
685 static const WCHAR *types[] =
687 L"", /* D2D1_PROPERTY_TYPE_UNKNOWN */
688 L"string", /* D2D1_PROPERTY_TYPE_STRING */
689 L"bool", /* D2D1_PROPERTY_TYPE_BOOL */
690 L"uint32", /* D2D1_PROPERTY_TYPE_UINT32 */
691 L"int32", /* D2D1_PROPERTY_TYPE_INT32 */
692 L"float", /* D2D1_PROPERTY_TYPE_FLOAT */
693 L"vector2", /* D2D1_PROPERTY_TYPE_VECTOR2 */
694 L"vector3", /* D2D1_PROPERTY_TYPE_VECTOR3 */
695 L"vector4", /* D2D1_PROPERTY_TYPE_VECTOR4 */
696 L"blob", /* D2D1_PROPERTY_TYPE_BLOB */
697 L"iunknown", /* D2D1_PROPERTY_TYPE_IUNKNOWN */
698 L"enum", /* D2D1_PROPERTY_TYPE_ENUM */
699 L"array", /* D2D1_PROPERTY_TYPE_ARRAY */
700 L"clsid", /* D2D1_PROPERTY_TYPE_CLSID */
701 L"matrix3x2", /* D2D1_PROPERTY_TYPE_MATRIX_3X2 */
702 L"matrix4x3", /* D2D1_PROPERTY_TYPE_MATRIX_4X3 */
703 L"matrix4x4", /* D2D1_PROPERTY_TYPE_MATRIX_4X4 */
704 L"matrix5x4", /* D2D1_PROPERTY_TYPE_MATRIX_5X4 */
705 L"colorcontext", /* D2D1_PROPERTY_TYPE_COLOR_CONTEXT */
707 unsigned int i;
708 WCHAR *value;
709 HRESULT hr;
711 if (FAILED(hr = parse_effect_get_attribute(reader, L"type", &value))) return hr;
713 *type = D2D1_PROPERTY_TYPE_UNKNOWN;
715 for (i = 0; i < ARRAY_SIZE(types); ++i)
717 if (!wcscmp(value, types[i]))
719 *type = i;
720 break;
724 free(value);
726 return *type == D2D1_PROPERTY_TYPE_UNKNOWN ? E_INVALIDARG : S_OK;
729 static struct d2d_effect_property * parse_effect_get_property(const struct d2d_effect_registration *effect,
730 const WCHAR *name)
732 unsigned int i;
734 for (i = 0; i < effect->property_count; ++i)
736 if (!wcscmp(name, effect->properties[i].name))
737 return &effect->properties[i];
740 return NULL;
743 static HRESULT parse_effect_add_property(struct d2d_effect_registration *effect, WCHAR *name,
744 D2D1_PROPERTY_TYPE type, BYTE *value)
746 struct d2d_effect_property *property;
748 if (!d2d_array_reserve((void **)&effect->properties, &effect->property_size,
749 effect->property_count + 1, sizeof(*effect->properties)))
751 return E_OUTOFMEMORY;
754 property = &effect->properties[effect->property_count++];
755 property->name = name;
756 property->type = type;
757 property->value = value;
758 property->set_function = NULL;
759 property->get_function = NULL;
761 return S_OK;
764 static HRESULT parse_effect_property(IXmlReader *reader, struct d2d_effect_registration *effect)
766 WCHAR *name = NULL, *value = NULL;
767 D2D1_PROPERTY_TYPE type;
768 unsigned int depth;
769 HRESULT hr;
771 if (FAILED(hr = parse_effect_get_attribute(reader, L"name", &name)))
772 return hr;
774 if (FAILED(hr = parse_effect_get_property_type(reader, &type)))
776 free(name);
777 return hr;
780 /* Check for duplicates. */
781 if (parse_effect_get_property(effect, name))
782 hr = E_INVALIDARG;
784 parse_effect_get_attribute(reader, L"value", &value);
786 if (SUCCEEDED(hr))
788 /* FIXME: sub properties are ignored */
789 IXmlReader_MoveToElement(reader);
790 IXmlReader_GetDepth(reader, &depth);
791 hr = parse_effect_skip_element(reader, depth);
794 if (SUCCEEDED(hr))
795 hr = parse_effect_add_property(effect, name, type, (BYTE *)value);
797 if (FAILED(hr))
799 free(value);
800 free(name);
803 return hr;
806 static HRESULT parse_effect_xml(IXmlReader *reader, struct d2d_effect_registration *effect)
808 const WCHAR *node_name;
809 XmlNodeType node_type;
810 unsigned int depth;
811 HRESULT hr;
813 /* Xml declaration node is mandatory. */
814 if ((hr = parse_effect_get_next_xml_node(reader, XmlNodeType_XmlDeclaration, L"xml", NULL)) != S_OK)
815 return hr;
817 /* Top level "Effect" element. */
818 if ((hr = parse_effect_get_next_xml_node(reader, XmlNodeType_Element, L"Effect", NULL)) != S_OK)
819 return hr;
821 /* Loop inside effect node */
822 while ((hr = parse_effect_get_next_xml_node(reader, XmlNodeType_None, NULL, &depth)) == S_OK)
824 if (FAILED(hr = IXmlReader_GetNodeType(reader, &node_type))) return hr;
825 if (node_type != XmlNodeType_Element && node_type != XmlNodeType_EndElement) continue;
826 if (FAILED(hr = IXmlReader_GetLocalName(reader, &node_name, NULL))) return hr;
827 if (node_type == XmlNodeType_EndElement) break;
829 if (!wcscmp(node_name, L"Property"))
830 hr = parse_effect_property(reader, effect);
831 else if (!wcscmp(node_name, L"Inputs"))
832 hr = parse_effect_skip_element(reader, depth);
833 else
835 WARN("Unexpected element %s.\n", debugstr_w(node_name));
836 hr = parse_effect_skip_element(reader, depth);
839 if (FAILED(hr))
840 return hr;
843 return hr;
846 static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromStream(ID2D1Factory3 *iface,
847 REFCLSID effect_id, IStream *property_xml, const D2D1_PROPERTY_BINDING *bindings,
848 UINT32 binding_count, PD2D1_EFFECT_FACTORY effect_factory)
850 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
851 struct d2d_effect_registration *effect;
852 IXmlReader *reader;
853 unsigned int i;
854 HRESULT hr;
856 TRACE("iface %p, effect_id %s, property_xml %p, bindings %p, binding_count %u, effect_factory %p.\n",
857 iface, debugstr_guid(effect_id), property_xml, bindings, binding_count, effect_factory);
859 LIST_FOR_EACH_ENTRY(effect, &factory->effects, struct d2d_effect_registration, entry)
861 if (IsEqualGUID(effect_id, &effect->id))
863 ++effect->registration_count;
864 return S_OK;
868 if (FAILED(hr = CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL)))
869 return hr;
871 if (FAILED(hr = IXmlReader_SetInput(reader, (IUnknown *)property_xml)))
873 IXmlReader_Release(reader);
874 return hr;
877 if (!(effect = calloc(1, sizeof(*effect))))
879 IXmlReader_Release(reader);
880 return E_OUTOFMEMORY;
883 hr = parse_effect_xml(reader, effect);
884 IXmlReader_Release(reader);
885 if (FAILED(hr))
887 WARN("Failed to parse effect xml, hr %#lx.\n", hr);
888 d2d_effect_registration_cleanup(effect);
889 return hr;
892 /* Check required properties. */
893 if (!parse_effect_get_property(effect, L"DisplayName")
894 || !parse_effect_get_property(effect, L"Author")
895 || !parse_effect_get_property(effect, L"Category")
896 || !parse_effect_get_property(effect, L"Description"))
898 WARN("Missing required properties.\n");
899 d2d_effect_registration_cleanup(effect);
900 return E_INVALIDARG;
903 /* Bind getter and setter. */
904 for (i = 0; i < binding_count; ++i)
906 struct d2d_effect_property *property;
908 if (!(property = parse_effect_get_property(effect, bindings[i].propertyName)))
910 WARN("Failed to bind to missing property.\n");
911 d2d_effect_registration_cleanup(effect);
912 return D2DERR_INVALID_PROPERTY;
915 property->get_function = bindings[i].getFunction;
916 property->set_function = bindings[i].setFunction;
919 effect->registration_count = 1;
920 effect->id = *effect_id;
921 effect->factory = effect_factory;
922 list_add_tail(&factory->effects, &effect->entry);
924 return S_OK;
927 static HRESULT STDMETHODCALLTYPE d2d_factory_RegisterEffectFromString(ID2D1Factory3 *iface,
928 REFCLSID effect_id, const WCHAR *property_xml, const D2D1_PROPERTY_BINDING *bindings,
929 UINT32 binding_count, PD2D1_EFFECT_FACTORY effect_factory)
931 static const LARGE_INTEGER zero;
932 IStream *stream;
933 ULONG size;
934 HRESULT hr;
936 TRACE("iface %p, effect_id %s, property_xml %s, bindings %p, binding_count %u, effect_factory %p.\n",
937 iface, debugstr_guid(effect_id), debugstr_w(property_xml), bindings, binding_count, effect_factory);
939 if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &stream)))
940 return hr;
942 size = sizeof(*property_xml) * (wcslen(property_xml) + 1);
943 if (SUCCEEDED(hr = IStream_Write(stream, property_xml, size, NULL)))
944 hr = IStream_Seek(stream, zero, SEEK_SET, NULL);
946 if (SUCCEEDED(hr))
947 hr = ID2D1Factory3_RegisterEffectFromStream(iface, effect_id, stream, bindings,
948 binding_count, effect_factory);
950 IStream_Release(stream);
951 return hr;
954 static HRESULT STDMETHODCALLTYPE d2d_factory_UnregisterEffect(ID2D1Factory3 *iface, REFCLSID effect_id)
956 struct d2d_factory *factory = impl_from_ID2D1Factory3(iface);
957 struct d2d_effect_registration *effect;
959 TRACE("iface %p, effect_id %s.\n", iface, debugstr_guid(effect_id));
961 LIST_FOR_EACH_ENTRY(effect, &factory->effects, struct d2d_effect_registration, entry)
963 if (IsEqualGUID(effect_id, &effect->id))
965 if (!--effect->registration_count)
967 list_remove(&effect->entry);
968 d2d_effect_registration_cleanup(effect);
970 return S_OK;
974 return D2DERR_EFFECT_IS_NOT_REGISTERED;
977 static HRESULT STDMETHODCALLTYPE d2d_factory_GetRegisteredEffects(ID2D1Factory3 *iface,
978 CLSID *effects, UINT32 effect_count, UINT32 *returned, UINT32 *registered)
980 FIXME("iface %p, effects %p, effect_count %u, returned %p, registered %p stub!\n",
981 iface, effects, effect_count, returned, registered);
983 return E_NOTIMPL;
986 static HRESULT STDMETHODCALLTYPE d2d_factory_GetEffectProperties(ID2D1Factory3 *iface,
987 REFCLSID effect_id, ID2D1Properties **props)
989 FIXME("iface %p, effect_id %s, props %p stub!\n", iface, debugstr_guid(effect_id), props);
991 return E_NOTIMPL;
994 static HRESULT STDMETHODCALLTYPE d2d_factory_ID2D1Factory2_CreateDevice(ID2D1Factory3 *iface, IDXGIDevice *dxgi_device,
995 ID2D1Device1 **device)
997 FIXME("iface %p, dxgi_device %p, device %p stub!\n", iface, dxgi_device, device);
999 return E_NOTIMPL;
1002 static HRESULT STDMETHODCALLTYPE d2d_factory_ID2D1Factory3_CreateDevice(ID2D1Factory3 *iface, IDXGIDevice *dxgi_device,
1003 ID2D1Device2 **device)
1005 FIXME("iface %p, dxgi_device %p, device %p stub!\n", iface, dxgi_device, device);
1007 return E_NOTIMPL;
1010 static const struct ID2D1Factory3Vtbl d2d_factory_vtbl =
1012 d2d_factory_QueryInterface,
1013 d2d_factory_AddRef,
1014 d2d_factory_Release,
1015 d2d_factory_ReloadSystemMetrics,
1016 d2d_factory_GetDesktopDpi,
1017 d2d_factory_CreateRectangleGeometry,
1018 d2d_factory_CreateRoundedRectangleGeometry,
1019 d2d_factory_CreateEllipseGeometry,
1020 d2d_factory_CreateGeometryGroup,
1021 d2d_factory_CreateTransformedGeometry,
1022 d2d_factory_CreatePathGeometry,
1023 d2d_factory_CreateStrokeStyle,
1024 d2d_factory_CreateDrawingStateBlock,
1025 d2d_factory_CreateWicBitmapRenderTarget,
1026 d2d_factory_CreateHwndRenderTarget,
1027 d2d_factory_CreateDxgiSurfaceRenderTarget,
1028 d2d_factory_CreateDCRenderTarget,
1029 d2d_factory_CreateDevice,
1030 d2d_factory_CreateStrokeStyle1,
1031 d2d_factory_CreatePathGeometry1,
1032 d2d_factory_CreateDrawingStateBlock1,
1033 d2d_factory_CreateGdiMetafile,
1034 d2d_factory_RegisterEffectFromStream,
1035 d2d_factory_RegisterEffectFromString,
1036 d2d_factory_UnregisterEffect,
1037 d2d_factory_GetRegisteredEffects,
1038 d2d_factory_GetEffectProperties,
1039 d2d_factory_ID2D1Factory2_CreateDevice,
1040 d2d_factory_ID2D1Factory3_CreateDevice,
1043 static HRESULT STDMETHODCALLTYPE d2d_factory_mt_QueryInterface(ID2D1Multithread *iface, REFIID iid, void **out)
1045 struct d2d_factory *factory = impl_from_ID2D1Multithread(iface);
1046 return d2d_factory_QueryInterface(&factory->ID2D1Factory3_iface, iid, out);
1049 static ULONG STDMETHODCALLTYPE d2d_factory_mt_AddRef(ID2D1Multithread *iface)
1051 struct d2d_factory *factory = impl_from_ID2D1Multithread(iface);
1052 return d2d_factory_AddRef(&factory->ID2D1Factory3_iface);
1055 static ULONG STDMETHODCALLTYPE d2d_factory_mt_Release(ID2D1Multithread *iface)
1057 struct d2d_factory *factory = impl_from_ID2D1Multithread(iface);
1058 return d2d_factory_Release(&factory->ID2D1Factory3_iface);
1061 static BOOL STDMETHODCALLTYPE d2d_factory_mt_GetMultithreadProtected(ID2D1Multithread *iface)
1063 return TRUE;
1066 static void STDMETHODCALLTYPE d2d_factory_mt_Enter(ID2D1Multithread *iface)
1068 struct d2d_factory *factory = impl_from_ID2D1Multithread(iface);
1070 TRACE("%p.\n", iface);
1072 EnterCriticalSection(&factory->cs);
1075 static void STDMETHODCALLTYPE d2d_factory_mt_Leave(ID2D1Multithread *iface)
1077 struct d2d_factory *factory = impl_from_ID2D1Multithread(iface);
1079 TRACE("%p.\n", iface);
1081 LeaveCriticalSection(&factory->cs);
1084 static BOOL STDMETHODCALLTYPE d2d_factory_st_GetMultithreadProtected(ID2D1Multithread *iface)
1086 return FALSE;
1089 static void STDMETHODCALLTYPE d2d_factory_st_Enter(ID2D1Multithread *iface)
1093 static void STDMETHODCALLTYPE d2d_factory_st_Leave(ID2D1Multithread *iface)
1097 static const struct ID2D1MultithreadVtbl d2d_factory_multithread_vtbl =
1099 d2d_factory_mt_QueryInterface,
1100 d2d_factory_mt_AddRef,
1101 d2d_factory_mt_Release,
1102 d2d_factory_mt_GetMultithreadProtected,
1103 d2d_factory_mt_Enter,
1104 d2d_factory_mt_Leave,
1107 static const struct ID2D1MultithreadVtbl d2d_factory_multithread_noop_vtbl =
1109 d2d_factory_mt_QueryInterface,
1110 d2d_factory_mt_AddRef,
1111 d2d_factory_mt_Release,
1112 d2d_factory_st_GetMultithreadProtected,
1113 d2d_factory_st_Enter,
1114 d2d_factory_st_Leave,
1117 static void d2d_factory_init(struct d2d_factory *factory, D2D1_FACTORY_TYPE factory_type,
1118 const D2D1_FACTORY_OPTIONS *factory_options)
1120 if (factory_options && factory_options->debugLevel != D2D1_DEBUG_LEVEL_NONE)
1121 WARN("Ignoring debug level %#x.\n", factory_options->debugLevel);
1123 factory->ID2D1Factory3_iface.lpVtbl = &d2d_factory_vtbl;
1124 factory->ID2D1Multithread_iface.lpVtbl = factory_type == D2D1_FACTORY_TYPE_SINGLE_THREADED ?
1125 &d2d_factory_multithread_noop_vtbl : &d2d_factory_multithread_vtbl;
1126 factory->refcount = 1;
1127 d2d_factory_reload_sysmetrics(factory);
1128 list_init(&factory->effects);
1129 InitializeCriticalSection(&factory->cs);
1132 HRESULT WINAPI D2D1CreateFactory(D2D1_FACTORY_TYPE factory_type, REFIID iid,
1133 const D2D1_FACTORY_OPTIONS *factory_options, void **factory)
1135 struct d2d_factory *object;
1136 HRESULT hr;
1138 TRACE("factory_type %#x, iid %s, factory_options %p, factory %p.\n",
1139 factory_type, debugstr_guid(iid), factory_options, factory);
1141 if (factory_type != D2D1_FACTORY_TYPE_SINGLE_THREADED &&
1142 factory_type != D2D1_FACTORY_TYPE_MULTI_THREADED)
1144 return E_INVALIDARG;
1147 if (!(object = calloc(1, sizeof(*object))))
1148 return E_OUTOFMEMORY;
1150 d2d_factory_init(object, factory_type, factory_options);
1152 TRACE("Created factory %p.\n", object);
1154 hr = ID2D1Factory3_QueryInterface(&object->ID2D1Factory3_iface, iid, factory);
1155 ID2D1Factory3_Release(&object->ID2D1Factory3_iface);
1157 return hr;
1160 void WINAPI D2D1MakeRotateMatrix(float angle, D2D1_POINT_2F center, D2D1_MATRIX_3X2_F *matrix)
1162 float theta, sin_theta, cos_theta;
1164 TRACE("angle %.8e, center %s, matrix %p.\n", angle, debug_d2d_point_2f(&center), matrix);
1166 theta = angle * (M_PI / 180.0f);
1167 sin_theta = sinf(theta);
1168 cos_theta = cosf(theta);
1170 /* translate(center) * rotate(theta) * translate(-center) */
1171 matrix->_11 = cos_theta;
1172 matrix->_12 = sin_theta;
1173 matrix->_21 = -sin_theta;
1174 matrix->_22 = cos_theta;
1175 matrix->_31 = center.x - center.x * cos_theta + center.y * sin_theta;
1176 matrix->_32 = center.y - center.x * sin_theta - center.y * cos_theta;
1179 void WINAPI D2D1MakeSkewMatrix(float angle_x, float angle_y, D2D1_POINT_2F center, D2D1_MATRIX_3X2_F *matrix)
1181 float tan_x, tan_y;
1183 TRACE("angle_x %.8e, angle_y %.8e, center %s, matrix %p.\n", angle_x, angle_y, debug_d2d_point_2f(&center), matrix);
1185 tan_x = tan(angle_x * (M_PI / 180.0f));
1186 tan_y = tan(angle_y * (M_PI / 180.0f));
1188 /* translate(-center) * skew() * translate(center) */
1189 matrix->_11 = 1.0f;
1190 matrix->_12 = tan_y;
1191 matrix->_21 = tan_x;
1192 matrix->_22 = 1.0f;
1193 matrix->_31 = -tan_x * center.y;
1194 matrix->_32 = -tan_y * center.x;
1197 BOOL WINAPI D2D1IsMatrixInvertible(const D2D1_MATRIX_3X2_F *matrix)
1199 TRACE("matrix %p.\n", matrix);
1201 return (matrix->_11 * matrix->_22 - matrix->_21 * matrix->_12) != 0.0f;
1204 BOOL WINAPI D2D1InvertMatrix(D2D1_MATRIX_3X2_F *matrix)
1206 D2D1_MATRIX_3X2_F m = *matrix;
1208 TRACE("matrix %p.\n", matrix);
1210 return d2d_matrix_invert(matrix, &m);
1213 HRESULT WINAPI D2D1CreateDevice(IDXGIDevice *dxgi_device,
1214 const D2D1_CREATION_PROPERTIES *properties, ID2D1Device **device)
1216 D2D1_CREATION_PROPERTIES default_properties = {0};
1217 D2D1_FACTORY_OPTIONS factory_options;
1218 ID3D11Device *d3d_device;
1219 ID2D1Factory1 *factory;
1220 HRESULT hr;
1222 TRACE("dxgi_device %p, properties %p, device %p.\n", dxgi_device, properties, device);
1224 if (!properties)
1226 if (SUCCEEDED(IDXGIDevice_QueryInterface(dxgi_device, &IID_ID3D11Device, (void **)&d3d_device)))
1228 if (!(ID3D11Device_GetCreationFlags(d3d_device) & D3D11_CREATE_DEVICE_SINGLETHREADED))
1229 default_properties.threadingMode = D2D1_THREADING_MODE_MULTI_THREADED;
1230 ID3D11Device_Release(d3d_device);
1232 properties = &default_properties;
1235 factory_options.debugLevel = properties->debugLevel;
1236 if (FAILED(hr = D2D1CreateFactory(properties->threadingMode,
1237 &IID_ID2D1Factory1, &factory_options, (void **)&factory)))
1238 return hr;
1240 hr = ID2D1Factory1_CreateDevice(factory, dxgi_device, device);
1241 ID2D1Factory1_Release(factory);
1242 return hr;
1245 void WINAPI D2D1SinCos(float angle, float *s, float *c)
1247 TRACE("angle %.8e, s %p, c %p.\n", angle, s, c);
1249 *s = sinf(angle);
1250 *c = cosf(angle);
1253 float WINAPI D2D1Tan(float angle)
1255 TRACE("angle %.8e.\n", angle);
1257 return tanf(angle);
1260 float WINAPI D2D1Vec3Length(float x, float y, float z)
1262 TRACE("x %.8e, y %.8e, z %.8e.\n", x, y, z);
1264 return sqrtf(x * x + y * y + z * z);
1267 /* See IEC 61966-2-1:1999; also described in the EXT_texture_sRGB OpenGL
1268 * extension, among others. */
1269 static float srgb_transfer_function(float x)
1271 if (x <= 0.0f)
1272 return 0.0f;
1273 else if (x >= 1.0f)
1274 return 1.0f;
1275 else if (x <= 0.0031308f)
1276 return 12.92f * x;
1277 else
1278 return 1.055f * powf(x, 1.0f / 2.4f) - 0.055f;
1281 static float srgb_inverse_transfer_function(float x)
1283 if (x <= 0.0f)
1284 return 0.0f;
1285 else if (x >= 1.0f)
1286 return 1.0f;
1287 else if (x <= 0.04045f)
1288 return x / 12.92f;
1289 else
1290 return powf((x + 0.055f) / 1.055f, 2.4f);
1293 D2D1_COLOR_F WINAPI D2D1ConvertColorSpace(D2D1_COLOR_SPACE src_colour_space,
1294 D2D1_COLOR_SPACE dst_colour_space, const D2D1_COLOR_F *colour)
1296 D2D1_COLOR_F ret;
1298 TRACE("src_colour_space %#x, dst_colour_space %#x, colour %s.\n",
1299 src_colour_space, dst_colour_space, debug_d2d_color_f(colour));
1301 if (src_colour_space == D2D1_COLOR_SPACE_CUSTOM || dst_colour_space == D2D1_COLOR_SPACE_CUSTOM)
1303 ret.r = 0.0f;
1304 ret.g = 0.0f;
1305 ret.b = 0.0f;
1306 ret.a = 0.0f;
1308 return ret;
1311 if (src_colour_space == dst_colour_space)
1312 return *colour;
1314 if (src_colour_space == D2D1_COLOR_SPACE_SRGB && dst_colour_space == D2D1_COLOR_SPACE_SCRGB)
1316 ret.r = srgb_inverse_transfer_function(colour->r);
1317 ret.g = srgb_inverse_transfer_function(colour->g);
1318 ret.b = srgb_inverse_transfer_function(colour->b);
1319 ret.a = colour->a;
1321 return ret;
1324 if (src_colour_space == D2D1_COLOR_SPACE_SCRGB && dst_colour_space == D2D1_COLOR_SPACE_SRGB)
1326 ret.r = srgb_transfer_function(colour->r);
1327 ret.g = srgb_transfer_function(colour->g);
1328 ret.b = srgb_transfer_function(colour->b);
1329 ret.a = colour->a;
1331 return ret;
1334 FIXME("Unhandled conversion from source colour space %#x to destination colour space %#x.\n",
1335 src_colour_space, dst_colour_space);
1336 ret.r = 0.0f;
1337 ret.g = 0.0f;
1338 ret.b = 0.0f;
1339 ret.a = 0.0f;
1341 return ret;
1344 static bool get_config_key_u32(HKEY default_key, HKEY application_key, const char *name, uint32_t *value)
1346 DWORD type, size;
1347 uint32_t data;
1349 size = sizeof(data);
1350 if (application_key && !RegQueryValueExA(application_key,
1351 name, 0, &type, (BYTE *)&data, &size) && type == REG_DWORD)
1352 goto success;
1354 size = sizeof(data);
1355 if (default_key && !RegQueryValueExA(default_key,
1356 name, 0, &type, (BYTE *)&data, &size) && type == REG_DWORD)
1357 goto success;
1359 return false;
1361 success:
1362 *value = data;
1363 return true;
1366 static void d2d_settings_init(void)
1368 HKEY default_key, tmp_key, application_key = NULL;
1369 char buffer[MAX_PATH + 10];
1370 DWORD len;
1372 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Direct2D", &default_key))
1373 default_key = NULL;
1375 len = GetModuleFileNameA(0, buffer, MAX_PATH);
1376 if (len && len < MAX_PATH)
1378 char *p, *appname = buffer;
1380 if ((p = strrchr(appname, '/')))
1381 appname = p + 1;
1382 if ((p = strrchr(appname, '\\')))
1383 appname = p + 1;
1384 strcat(appname, "\\Direct2D");
1386 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmp_key))
1388 if (RegOpenKeyA(tmp_key, appname, &application_key))
1389 application_key = NULL;
1390 RegCloseKey(tmp_key);
1394 if (!default_key && !application_key)
1395 return;
1397 if (get_config_key_u32(default_key, application_key, "max_version_factory", &d2d_settings.max_version_factory))
1398 ERR_(winediag)("Limiting maximum Direct2D factory version to %#x.\n", d2d_settings.max_version_factory);
1400 if (application_key)
1401 RegCloseKey(application_key);
1402 if (default_key)
1403 RegCloseKey(default_key);
1406 BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved)
1408 if (reason == DLL_PROCESS_ATTACH)
1409 d2d_settings_init();
1410 return TRUE;