windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / d2d1 / device.c
blob3cc23c0325bc194dd637b34b31d98d4f14a5898e
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 #include "d2d1_private.h"
20 #include <d3dcompiler.h>
22 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
24 #define INITIAL_CLIP_STACK_SIZE 4
26 static const D2D1_MATRIX_3X2_F identity =
27 {{{
28 1.0f, 0.0f,
29 0.0f, 1.0f,
30 0.0f, 0.0f,
31 }}};
33 struct d2d_draw_text_layout_ctx
35 ID2D1Brush *brush;
36 D2D1_DRAW_TEXT_OPTIONS options;
39 static inline struct d2d_device *impl_from_ID2D1Device(ID2D1Device1 *iface)
41 return CONTAINING_RECORD(iface, struct d2d_device, ID2D1Device1_iface);
44 static ID2D1Brush *d2d_draw_get_text_brush(struct d2d_draw_text_layout_ctx *context, IUnknown *effect)
46 ID2D1Brush *brush = NULL;
48 if (effect && SUCCEEDED(IUnknown_QueryInterface(effect, &IID_ID2D1Brush, (void**)&brush)))
49 return brush;
51 ID2D1Brush_AddRef(context->brush);
52 return context->brush;
55 static void d2d_rect_intersect(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
57 if (src->left > dst->left)
58 dst->left = src->left;
59 if (src->top > dst->top)
60 dst->top = src->top;
61 if (src->right < dst->right)
62 dst->right = src->right;
63 if (src->bottom < dst->bottom)
64 dst->bottom = src->bottom;
67 static void d2d_rect_set(D2D1_RECT_F *dst, float left, float top, float right, float bottom)
69 dst->left = left;
70 dst->top = top;
71 dst->right = right;
72 dst->bottom = bottom;
75 static void d2d_size_set(D2D1_SIZE_U *dst, float width, float height)
77 dst->width = width;
78 dst->height = height;
81 static BOOL d2d_clip_stack_init(struct d2d_clip_stack *stack)
83 if (!(stack->stack = malloc(INITIAL_CLIP_STACK_SIZE * sizeof(*stack->stack))))
84 return FALSE;
86 stack->size = INITIAL_CLIP_STACK_SIZE;
87 stack->count = 0;
89 return TRUE;
92 static void d2d_clip_stack_cleanup(struct d2d_clip_stack *stack)
94 free(stack->stack);
97 static BOOL d2d_clip_stack_push(struct d2d_clip_stack *stack, const D2D1_RECT_F *rect)
99 D2D1_RECT_F r;
101 if (!d2d_array_reserve((void **)&stack->stack, &stack->size, stack->count + 1, sizeof(*stack->stack)))
102 return FALSE;
104 r = *rect;
105 if (stack->count)
106 d2d_rect_intersect(&r, &stack->stack[stack->count - 1]);
107 stack->stack[stack->count++] = r;
109 return TRUE;
112 static void d2d_clip_stack_pop(struct d2d_clip_stack *stack)
114 if (!stack->count)
115 return;
116 --stack->count;
119 static void d2d_device_context_draw(struct d2d_device_context *render_target, enum d2d_shape_type shape_type,
120 ID3D11Buffer *ib, unsigned int index_count, ID3D11Buffer *vb, unsigned int vb_stride,
121 struct d2d_brush *brush, struct d2d_brush *opacity_brush)
123 struct d2d_shape_resources *shape_resources = &render_target->shape_resources[shape_type];
124 ID3DDeviceContextState *prev_state;
125 ID3D11Device1 *device = render_target->d3d_device;
126 ID3D11DeviceContext1 *context;
127 ID3D11Buffer *vs_cb = render_target->vs_cb, *ps_cb = render_target->ps_cb;
128 D3D11_RECT scissor_rect;
129 unsigned int offset;
130 D3D11_VIEWPORT vp;
132 vp.TopLeftX = 0;
133 vp.TopLeftY = 0;
134 vp.Width = render_target->pixel_size.width;
135 vp.Height = render_target->pixel_size.height;
136 vp.MinDepth = 0.0f;
137 vp.MaxDepth = 1.0f;
139 if (render_target->cs)
140 EnterCriticalSection(render_target->cs);
142 ID3D11Device1_GetImmediateContext1(device, &context);
143 ID3D11DeviceContext1_SwapDeviceContextState(context, render_target->d3d_state, &prev_state);
145 ID3D11DeviceContext1_IASetInputLayout(context, shape_resources->il);
146 ID3D11DeviceContext1_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
147 ID3D11DeviceContext1_IASetIndexBuffer(context, ib, DXGI_FORMAT_R16_UINT, 0);
148 offset = 0;
149 ID3D11DeviceContext1_IASetVertexBuffers(context, 0, 1, &vb, &vb_stride, &offset);
150 ID3D11DeviceContext1_VSSetConstantBuffers(context, 0, 1, &vs_cb);
151 ID3D11DeviceContext1_VSSetShader(context, shape_resources->vs, NULL, 0);
152 ID3D11DeviceContext1_PSSetConstantBuffers(context, 0, 1, &ps_cb);
153 ID3D11DeviceContext1_PSSetShader(context, render_target->ps, NULL, 0);
154 ID3D11DeviceContext1_RSSetViewports(context, 1, &vp);
155 if (render_target->clip_stack.count)
157 const D2D1_RECT_F *clip_rect;
159 clip_rect = &render_target->clip_stack.stack[render_target->clip_stack.count - 1];
160 scissor_rect.left = ceilf(clip_rect->left - 0.5f);
161 scissor_rect.top = ceilf(clip_rect->top - 0.5f);
162 scissor_rect.right = ceilf(clip_rect->right - 0.5f);
163 scissor_rect.bottom = ceilf(clip_rect->bottom - 0.5f);
165 else
167 scissor_rect.left = 0.0f;
168 scissor_rect.top = 0.0f;
169 scissor_rect.right = render_target->pixel_size.width;
170 scissor_rect.bottom = render_target->pixel_size.height;
172 ID3D11DeviceContext1_RSSetScissorRects(context, 1, &scissor_rect);
173 ID3D11DeviceContext1_RSSetState(context, render_target->rs);
174 ID3D11DeviceContext1_OMSetRenderTargets(context, 1, &render_target->target.bitmap->rtv, NULL);
175 if (brush)
177 ID3D11DeviceContext1_OMSetBlendState(context, render_target->bs, NULL, D3D11_DEFAULT_SAMPLE_MASK);
178 d2d_brush_bind_resources(brush, render_target, 0);
180 else
182 ID3D11DeviceContext1_OMSetBlendState(context, NULL, NULL, D3D11_DEFAULT_SAMPLE_MASK);
184 if (opacity_brush)
185 d2d_brush_bind_resources(opacity_brush, render_target, 1);
187 if (ib)
188 ID3D11DeviceContext1_DrawIndexed(context, index_count, 0, 0);
189 else
190 ID3D11DeviceContext1_Draw(context, index_count, 0);
192 ID3D11DeviceContext1_SwapDeviceContextState(context, prev_state, NULL);
193 ID3D11DeviceContext1_Release(context);
194 ID3DDeviceContextState_Release(prev_state);
196 if (render_target->cs)
197 LeaveCriticalSection(render_target->cs);
200 static void d2d_device_context_set_error(struct d2d_device_context *context, HRESULT code)
202 context->error.code = code;
203 context->error.tag1 = context->drawing_state.tag1;
204 context->error.tag2 = context->drawing_state.tag2;
207 static inline struct d2d_device_context *impl_from_IUnknown(IUnknown *iface)
209 return CONTAINING_RECORD(iface, struct d2d_device_context, IUnknown_iface);
212 static inline struct d2d_device_context *impl_from_ID2D1DeviceContext(ID2D1DeviceContext1 *iface)
214 return CONTAINING_RECORD(iface, struct d2d_device_context, ID2D1DeviceContext1_iface);
217 static HRESULT STDMETHODCALLTYPE d2d_device_context_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out)
219 struct d2d_device_context *context = impl_from_IUnknown(iface);
221 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
223 if (IsEqualGUID(iid, &IID_ID2D1DeviceContext1)
224 || IsEqualGUID(iid, &IID_ID2D1DeviceContext)
225 || IsEqualGUID(iid, &IID_ID2D1RenderTarget)
226 || IsEqualGUID(iid, &IID_ID2D1Resource)
227 || IsEqualGUID(iid, &IID_IUnknown))
229 ID2D1DeviceContext1_AddRef(&context->ID2D1DeviceContext1_iface);
230 *out = &context->ID2D1DeviceContext1_iface;
231 return S_OK;
233 else if (IsEqualGUID(iid, &IID_ID2D1GdiInteropRenderTarget))
235 ID2D1GdiInteropRenderTarget_AddRef(&context->ID2D1GdiInteropRenderTarget_iface);
236 *out = &context->ID2D1GdiInteropRenderTarget_iface;
237 return S_OK;
240 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
242 *out = NULL;
243 return E_NOINTERFACE;
246 static ULONG STDMETHODCALLTYPE d2d_device_context_inner_AddRef(IUnknown *iface)
248 struct d2d_device_context *context = impl_from_IUnknown(iface);
249 ULONG refcount = InterlockedIncrement(&context->refcount);
251 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
253 return refcount;
256 static ULONG STDMETHODCALLTYPE d2d_device_context_inner_Release(IUnknown *iface)
258 struct d2d_device_context *context = impl_from_IUnknown(iface);
259 ULONG refcount = InterlockedDecrement(&context->refcount);
261 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
263 if (!refcount)
265 unsigned int i, j, k;
267 d2d_clip_stack_cleanup(&context->clip_stack);
268 IDWriteRenderingParams_Release(context->default_text_rendering_params);
269 if (context->text_rendering_params)
270 IDWriteRenderingParams_Release(context->text_rendering_params);
271 if (context->bs)
272 ID3D11BlendState_Release(context->bs);
273 ID3D11RasterizerState_Release(context->rs);
274 ID3D11Buffer_Release(context->vb);
275 ID3D11Buffer_Release(context->ib);
276 ID3D11Buffer_Release(context->ps_cb);
277 ID3D11PixelShader_Release(context->ps);
278 ID3D11Buffer_Release(context->vs_cb);
279 for (i = 0; i < D2D_SHAPE_TYPE_COUNT; ++i)
281 ID3D11VertexShader_Release(context->shape_resources[i].vs);
282 ID3D11InputLayout_Release(context->shape_resources[i].il);
284 for (i = 0; i < D2D_SAMPLER_INTERPOLATION_MODE_COUNT; ++i)
286 for (j = 0; j < D2D_SAMPLER_EXTEND_MODE_COUNT; ++j)
288 for (k = 0; k < D2D_SAMPLER_EXTEND_MODE_COUNT; ++k)
290 if (context->sampler_states[i][j][k])
291 ID3D11SamplerState_Release(context->sampler_states[i][j][k]);
295 if (context->d3d_state)
296 ID3DDeviceContextState_Release(context->d3d_state);
297 if (context->target.object)
298 IUnknown_Release(context->target.object);
299 ID3D11Device1_Release(context->d3d_device);
300 ID2D1Factory_Release(context->factory);
301 ID2D1Device1_Release(&context->device->ID2D1Device1_iface);
302 free(context);
305 return refcount;
308 static const struct IUnknownVtbl d2d_device_context_inner_unknown_vtbl =
310 d2d_device_context_inner_QueryInterface,
311 d2d_device_context_inner_AddRef,
312 d2d_device_context_inner_Release,
315 static HRESULT STDMETHODCALLTYPE d2d_device_context_QueryInterface(ID2D1DeviceContext1 *iface, REFIID iid, void **out)
317 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
319 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
321 return IUnknown_QueryInterface(context->outer_unknown, iid, out);
324 static ULONG STDMETHODCALLTYPE d2d_device_context_AddRef(ID2D1DeviceContext1 *iface)
326 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
328 TRACE("iface %p.\n", iface);
330 return IUnknown_AddRef(context->outer_unknown);
333 static ULONG STDMETHODCALLTYPE d2d_device_context_Release(ID2D1DeviceContext1 *iface)
335 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
337 TRACE("iface %p.\n", iface);
339 return IUnknown_Release(context->outer_unknown);
342 static void STDMETHODCALLTYPE d2d_device_context_GetFactory(ID2D1DeviceContext1 *iface, ID2D1Factory **factory)
344 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
346 TRACE("iface %p, factory %p.\n", iface, factory);
348 *factory = render_target->factory;
349 ID2D1Factory_AddRef(*factory);
352 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmap(ID2D1DeviceContext1 *iface,
353 D2D1_SIZE_U size, const void *src_data, UINT32 pitch, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
355 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
356 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
357 struct d2d_bitmap *object;
358 HRESULT hr;
360 TRACE("iface %p, size {%u, %u}, src_data %p, pitch %u, desc %p, bitmap %p.\n",
361 iface, size.width, size.height, src_data, pitch, desc, bitmap);
363 if (desc)
365 memcpy(&bitmap_desc, desc, sizeof(*desc));
366 bitmap_desc.bitmapOptions = 0;
367 bitmap_desc.colorContext = NULL;
370 if (SUCCEEDED(hr = d2d_bitmap_create(context, size, src_data, pitch, desc ? &bitmap_desc : NULL, &object)))
371 *bitmap = (ID2D1Bitmap *)&object->ID2D1Bitmap1_iface;
373 return hr;
376 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmapFromWicBitmap(ID2D1DeviceContext1 *iface,
377 IWICBitmapSource *bitmap_source, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
379 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
380 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
381 struct d2d_bitmap *object;
382 HRESULT hr;
384 TRACE("iface %p, bitmap_source %p, desc %p, bitmap %p.\n",
385 iface, bitmap_source, desc, bitmap);
387 if (desc)
389 memcpy(&bitmap_desc, desc, sizeof(*desc));
390 bitmap_desc.bitmapOptions = 0;
391 bitmap_desc.colorContext = NULL;
394 if (SUCCEEDED(hr = d2d_bitmap_create_from_wic_bitmap(context, bitmap_source, desc ? &bitmap_desc : NULL, &object)))
395 *bitmap = (ID2D1Bitmap *)&object->ID2D1Bitmap1_iface;
397 return hr;
400 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSharedBitmap(ID2D1DeviceContext1 *iface,
401 REFIID iid, void *data, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
403 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
404 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
405 struct d2d_bitmap *object;
406 HRESULT hr;
408 TRACE("iface %p, iid %s, data %p, desc %p, bitmap %p.\n",
409 iface, debugstr_guid(iid), data, desc, bitmap);
411 if (desc)
413 memcpy(&bitmap_desc, desc, sizeof(*desc));
414 if (IsEqualIID(iid, &IID_IDXGISurface) || IsEqualIID(iid, &IID_IDXGISurface1))
415 bitmap_desc.bitmapOptions = d2d_get_bitmap_options_for_surface(data);
416 else
417 bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
418 bitmap_desc.colorContext = NULL;
421 if (SUCCEEDED(hr = d2d_bitmap_create_shared(context, iid, data, desc ? &bitmap_desc : NULL, &object)))
422 *bitmap = (ID2D1Bitmap *)&object->ID2D1Bitmap1_iface;
424 return hr;
427 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmapBrush(ID2D1DeviceContext1 *iface,
428 ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc,
429 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1BitmapBrush **brush)
431 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
432 struct d2d_brush *object;
433 HRESULT hr;
435 TRACE("iface %p, bitmap %p, bitmap_brush_desc %p, brush_desc %p, brush %p.\n",
436 iface, bitmap, bitmap_brush_desc, brush_desc, brush);
438 if (SUCCEEDED(hr = d2d_bitmap_brush_create(context->factory, bitmap, (const D2D1_BITMAP_BRUSH_PROPERTIES1 *)bitmap_brush_desc,
439 brush_desc, &object)))
440 *brush = (ID2D1BitmapBrush *)&object->ID2D1Brush_iface;
442 return hr;
445 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSolidColorBrush(ID2D1DeviceContext1 *iface,
446 const D2D1_COLOR_F *color, const D2D1_BRUSH_PROPERTIES *desc, ID2D1SolidColorBrush **brush)
448 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
449 struct d2d_brush *object;
450 HRESULT hr;
452 TRACE("iface %p, color %p, desc %p, brush %p.\n", iface, color, desc, brush);
454 if (SUCCEEDED(hr = d2d_solid_color_brush_create(render_target->factory, color, desc, &object)))
455 *brush = (ID2D1SolidColorBrush *)&object->ID2D1Brush_iface;
457 return hr;
460 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateGradientStopCollection(ID2D1DeviceContext1 *iface,
461 const D2D1_GRADIENT_STOP *stops, UINT32 stop_count, D2D1_GAMMA gamma, D2D1_EXTEND_MODE extend_mode,
462 ID2D1GradientStopCollection **gradient)
464 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
465 struct d2d_gradient *object;
466 HRESULT hr;
468 TRACE("iface %p, stops %p, stop_count %u, gamma %#x, extend_mode %#x, gradient %p.\n",
469 iface, stops, stop_count, gamma, extend_mode, gradient);
471 if (SUCCEEDED(hr = d2d_gradient_create(render_target->factory, render_target->d3d_device,
472 stops, stop_count, gamma, extend_mode, &object)))
473 *gradient = &object->ID2D1GradientStopCollection_iface;
475 return hr;
478 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateLinearGradientBrush(ID2D1DeviceContext1 *iface,
479 const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
480 ID2D1GradientStopCollection *gradient, ID2D1LinearGradientBrush **brush)
482 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
483 struct d2d_brush *object;
484 HRESULT hr;
486 TRACE("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p.\n",
487 iface, gradient_brush_desc, brush_desc, gradient, brush);
489 if (SUCCEEDED(hr = d2d_linear_gradient_brush_create(render_target->factory, gradient_brush_desc, brush_desc,
490 gradient, &object)))
491 *brush = (ID2D1LinearGradientBrush *)&object->ID2D1Brush_iface;
493 return hr;
496 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateRadialGradientBrush(ID2D1DeviceContext1 *iface,
497 const D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
498 ID2D1GradientStopCollection *gradient, ID2D1RadialGradientBrush **brush)
500 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
501 struct d2d_brush *object;
502 HRESULT hr;
504 TRACE("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p.\n",
505 iface, gradient_brush_desc, brush_desc, gradient, brush);
507 if (SUCCEEDED(hr = d2d_radial_gradient_brush_create(render_target->factory,
508 gradient_brush_desc, brush_desc, gradient, &object)))
509 *brush = (ID2D1RadialGradientBrush *)&object->ID2D1Brush_iface;
511 return hr;
514 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateCompatibleRenderTarget(ID2D1DeviceContext1 *iface,
515 const D2D1_SIZE_F *size, const D2D1_SIZE_U *pixel_size, const D2D1_PIXEL_FORMAT *format,
516 D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS options, ID2D1BitmapRenderTarget **rt)
518 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
519 struct d2d_bitmap_render_target *object;
520 HRESULT hr;
522 TRACE("iface %p, size %p, pixel_size %p, format %p, options %#x, render_target %p.\n",
523 iface, size, pixel_size, format, options, rt);
525 if (!(object = calloc(1, sizeof(*object))))
526 return E_OUTOFMEMORY;
528 if (FAILED(hr = d2d_bitmap_render_target_init(object, render_target, size, pixel_size,
529 format, options)))
531 WARN("Failed to initialise render target, hr %#lx.\n", hr);
532 free(object);
533 return hr;
536 TRACE("Created render target %p.\n", object);
537 *rt = &object->ID2D1BitmapRenderTarget_iface;
539 return S_OK;
542 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateLayer(ID2D1DeviceContext1 *iface,
543 const D2D1_SIZE_F *size, ID2D1Layer **layer)
545 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
546 struct d2d_layer *object;
547 HRESULT hr;
549 TRACE("iface %p, size %p, layer %p.\n", iface, size, layer);
551 if (SUCCEEDED(hr = d2d_layer_create(render_target->factory, size, &object)))
552 *layer = &object->ID2D1Layer_iface;
554 return hr;
557 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateMesh(ID2D1DeviceContext1 *iface, ID2D1Mesh **mesh)
559 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
560 struct d2d_mesh *object;
561 HRESULT hr;
563 TRACE("iface %p, mesh %p.\n", iface, mesh);
565 if (SUCCEEDED(hr = d2d_mesh_create(render_target->factory, &object)))
566 *mesh = &object->ID2D1Mesh_iface;
568 return hr;
571 static void STDMETHODCALLTYPE d2d_device_context_DrawLine(ID2D1DeviceContext1 *iface,
572 D2D1_POINT_2F p0, D2D1_POINT_2F p1, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
574 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
575 ID2D1PathGeometry *geometry;
576 ID2D1GeometrySink *sink;
577 HRESULT hr;
579 TRACE("iface %p, p0 %s, p1 %s, brush %p, stroke_width %.8e, stroke_style %p.\n",
580 iface, debug_d2d_point_2f(&p0), debug_d2d_point_2f(&p1), brush, stroke_width, stroke_style);
582 if (context->target.type == D2D_TARGET_COMMAND_LIST)
584 d2d_command_list_draw_line(context->target.command_list, context, p0, p1, brush, stroke_width, stroke_style);
585 return;
588 if (FAILED(hr = ID2D1Factory_CreatePathGeometry(context->factory, &geometry)))
590 WARN("Failed to create path geometry, hr %#lx.\n", hr);
591 return;
594 if (FAILED(hr = ID2D1PathGeometry_Open(geometry, &sink)))
596 WARN("Failed to open geometry sink, hr %#lx.\n", hr);
597 ID2D1PathGeometry_Release(geometry);
598 return;
601 ID2D1GeometrySink_BeginFigure(sink, p0, D2D1_FIGURE_BEGIN_HOLLOW);
602 ID2D1GeometrySink_AddLine(sink, p1);
603 ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
604 if (FAILED(hr = ID2D1GeometrySink_Close(sink)))
605 WARN("Failed to close geometry sink, hr %#lx.\n", hr);
606 ID2D1GeometrySink_Release(sink);
608 ID2D1DeviceContext1_DrawGeometry(iface, (ID2D1Geometry *)geometry, brush, stroke_width, stroke_style);
609 ID2D1PathGeometry_Release(geometry);
612 static void STDMETHODCALLTYPE d2d_device_context_DrawRectangle(ID2D1DeviceContext1 *iface,
613 const D2D1_RECT_F *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
615 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
616 ID2D1RectangleGeometry *geometry;
617 HRESULT hr;
619 TRACE("iface %p, rect %s, brush %p, stroke_width %.8e, stroke_style %p.\n",
620 iface, debug_d2d_rect_f(rect), brush, stroke_width, stroke_style);
622 if (context->target.type == D2D_TARGET_COMMAND_LIST)
624 d2d_command_list_draw_rectangle(context->target.command_list, context, rect, brush, stroke_width, stroke_style);
625 return;
628 if (FAILED(hr = ID2D1Factory_CreateRectangleGeometry(context->factory, rect, &geometry)))
630 ERR("Failed to create geometry, hr %#lx.\n", hr);
631 return;
634 ID2D1DeviceContext1_DrawGeometry(iface, (ID2D1Geometry *)geometry, brush, stroke_width, stroke_style);
635 ID2D1RectangleGeometry_Release(geometry);
638 static void STDMETHODCALLTYPE d2d_device_context_FillRectangle(ID2D1DeviceContext1 *iface,
639 const D2D1_RECT_F *rect, ID2D1Brush *brush)
641 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
642 ID2D1RectangleGeometry *geometry;
643 HRESULT hr;
645 TRACE("iface %p, rect %s, brush %p.\n", iface, debug_d2d_rect_f(rect), brush);
647 if (context->target.type == D2D_TARGET_COMMAND_LIST)
649 d2d_command_list_fill_rectangle(context->target.command_list, context, rect, brush);
650 return;
653 if (FAILED(hr = ID2D1Factory_CreateRectangleGeometry(context->factory, rect, &geometry)))
655 ERR("Failed to create geometry, hr %#lx.\n", hr);
656 return;
659 ID2D1DeviceContext1_FillGeometry(iface, (ID2D1Geometry *)geometry, brush, NULL);
660 ID2D1RectangleGeometry_Release(geometry);
663 static void STDMETHODCALLTYPE d2d_device_context_DrawRoundedRectangle(ID2D1DeviceContext1 *iface,
664 const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
666 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
667 ID2D1RoundedRectangleGeometry *geometry;
668 HRESULT hr;
670 TRACE("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p.\n",
671 iface, rect, brush, stroke_width, stroke_style);
673 if (FAILED(hr = ID2D1Factory_CreateRoundedRectangleGeometry(render_target->factory, rect, &geometry)))
675 ERR("Failed to create geometry, hr %#lx.\n", hr);
676 return;
679 ID2D1DeviceContext1_DrawGeometry(iface, (ID2D1Geometry *)geometry, brush, stroke_width, stroke_style);
680 ID2D1RoundedRectangleGeometry_Release(geometry);
683 static void STDMETHODCALLTYPE d2d_device_context_FillRoundedRectangle(ID2D1DeviceContext1 *iface,
684 const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush)
686 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
687 ID2D1RoundedRectangleGeometry *geometry;
688 HRESULT hr;
690 TRACE("iface %p, rect %p, brush %p.\n", iface, rect, brush);
692 if (FAILED(hr = ID2D1Factory_CreateRoundedRectangleGeometry(render_target->factory, rect, &geometry)))
694 ERR("Failed to create geometry, hr %#lx.\n", hr);
695 return;
698 ID2D1DeviceContext1_FillGeometry(iface, (ID2D1Geometry *)geometry, brush, NULL);
699 ID2D1RoundedRectangleGeometry_Release(geometry);
702 static void STDMETHODCALLTYPE d2d_device_context_DrawEllipse(ID2D1DeviceContext1 *iface,
703 const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
705 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
706 ID2D1EllipseGeometry *geometry;
707 HRESULT hr;
709 TRACE("iface %p, ellipse %p, brush %p, stroke_width %.8e, stroke_style %p.\n",
710 iface, ellipse, brush, stroke_width, stroke_style);
712 if (FAILED(hr = ID2D1Factory_CreateEllipseGeometry(render_target->factory, ellipse, &geometry)))
714 ERR("Failed to create geometry, hr %#lx.\n", hr);
715 return;
718 ID2D1DeviceContext1_DrawGeometry(iface, (ID2D1Geometry *)geometry, brush, stroke_width, stroke_style);
719 ID2D1EllipseGeometry_Release(geometry);
722 static void STDMETHODCALLTYPE d2d_device_context_FillEllipse(ID2D1DeviceContext1 *iface,
723 const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush)
725 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
726 ID2D1EllipseGeometry *geometry;
727 HRESULT hr;
729 TRACE("iface %p, ellipse %p, brush %p.\n", iface, ellipse, brush);
731 if (FAILED(hr = ID2D1Factory_CreateEllipseGeometry(render_target->factory, ellipse, &geometry)))
733 ERR("Failed to create geometry, hr %#lx.\n", hr);
734 return;
737 ID2D1DeviceContext1_FillGeometry(iface, (ID2D1Geometry *)geometry, brush, NULL);
738 ID2D1EllipseGeometry_Release(geometry);
741 static HRESULT d2d_device_context_update_ps_cb(struct d2d_device_context *context,
742 struct d2d_brush *brush, struct d2d_brush *opacity_brush, BOOL outline, BOOL is_arc)
744 D3D11_MAPPED_SUBRESOURCE map_desc;
745 ID3D11DeviceContext *d3d_context;
746 struct d2d_ps_cb *cb_data;
747 HRESULT hr;
749 ID3D11Device1_GetImmediateContext(context->d3d_device, &d3d_context);
751 if (FAILED(hr = ID3D11DeviceContext_Map(d3d_context, (ID3D11Resource *)context->ps_cb,
752 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc)))
754 WARN("Failed to map constant buffer, hr %#lx.\n", hr);
755 ID3D11DeviceContext_Release(d3d_context);
756 return hr;
759 cb_data = map_desc.pData;
760 cb_data->outline = outline;
761 cb_data->is_arc = is_arc;
762 cb_data->pad[0] = 0;
763 cb_data->pad[1] = 0;
764 if (!d2d_brush_fill_cb(brush, &cb_data->colour_brush))
765 WARN("Failed to initialize colour brush buffer.\n");
766 if (!d2d_brush_fill_cb(opacity_brush, &cb_data->opacity_brush))
767 WARN("Failed to initialize opacity brush buffer.\n");
769 ID3D11DeviceContext_Unmap(d3d_context, (ID3D11Resource *)context->ps_cb, 0);
770 ID3D11DeviceContext_Release(d3d_context);
772 return hr;
775 static HRESULT d2d_device_context_update_vs_cb(struct d2d_device_context *context,
776 const D2D_MATRIX_3X2_F *geometry_transform, float stroke_width)
778 D3D11_MAPPED_SUBRESOURCE map_desc;
779 ID3D11DeviceContext *d3d_context;
780 const D2D1_MATRIX_3X2_F *w;
781 struct d2d_vs_cb *cb_data;
782 float tmp_x, tmp_y;
783 HRESULT hr;
785 ID3D11Device1_GetImmediateContext(context->d3d_device, &d3d_context);
787 if (FAILED(hr = ID3D11DeviceContext_Map(d3d_context, (ID3D11Resource *)context->vs_cb,
788 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc)))
790 WARN("Failed to map constant buffer, hr %#lx.\n", hr);
791 ID3D11DeviceContext_Release(d3d_context);
792 return hr;
795 cb_data = map_desc.pData;
796 cb_data->transform_geometry._11 = geometry_transform->_11;
797 cb_data->transform_geometry._21 = geometry_transform->_21;
798 cb_data->transform_geometry._31 = geometry_transform->_31;
799 cb_data->transform_geometry.pad0 = 0.0f;
800 cb_data->transform_geometry._12 = geometry_transform->_12;
801 cb_data->transform_geometry._22 = geometry_transform->_22;
802 cb_data->transform_geometry._32 = geometry_transform->_32;
803 cb_data->transform_geometry.stroke_width = stroke_width;
805 w = &context->drawing_state.transform;
807 tmp_x = context->desc.dpiX / 96.0f;
808 cb_data->transform_rtx.x = w->_11 * tmp_x;
809 cb_data->transform_rtx.y = w->_21 * tmp_x;
810 cb_data->transform_rtx.z = w->_31 * tmp_x;
811 cb_data->transform_rtx.w = 2.0f / context->pixel_size.width;
813 tmp_y = context->desc.dpiY / 96.0f;
814 cb_data->transform_rty.x = w->_12 * tmp_y;
815 cb_data->transform_rty.y = w->_22 * tmp_y;
816 cb_data->transform_rty.z = w->_32 * tmp_y;
817 cb_data->transform_rty.w = -2.0f / context->pixel_size.height;
819 ID3D11DeviceContext_Unmap(d3d_context, (ID3D11Resource *)context->vs_cb, 0);
820 ID3D11DeviceContext_Release(d3d_context);
822 return S_OK;
825 static void d2d_device_context_draw_geometry(struct d2d_device_context *render_target,
826 const struct d2d_geometry *geometry, struct d2d_brush *brush, float stroke_width)
828 D3D11_SUBRESOURCE_DATA buffer_data;
829 D3D11_BUFFER_DESC buffer_desc;
830 ID3D11Buffer *ib, *vb;
831 HRESULT hr;
833 if (FAILED(hr = d2d_device_context_update_vs_cb(render_target, &geometry->transform, stroke_width)))
835 WARN("Failed to update vs constant buffer, hr %#lx.\n", hr);
836 return;
839 if (FAILED(hr = d2d_device_context_update_ps_cb(render_target, brush, NULL, TRUE, FALSE)))
841 WARN("Failed to update ps constant buffer, hr %#lx.\n", hr);
842 return;
845 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
846 buffer_desc.CPUAccessFlags = 0;
847 buffer_desc.MiscFlags = 0;
849 buffer_data.SysMemPitch = 0;
850 buffer_data.SysMemSlicePitch = 0;
852 if (geometry->outline.face_count)
854 buffer_desc.ByteWidth = geometry->outline.face_count * sizeof(*geometry->outline.faces);
855 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
856 buffer_data.pSysMem = geometry->outline.faces;
858 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &ib)))
860 WARN("Failed to create index buffer, hr %#lx.\n", hr);
861 return;
864 buffer_desc.ByteWidth = geometry->outline.vertex_count * sizeof(*geometry->outline.vertices);
865 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
866 buffer_data.pSysMem = geometry->outline.vertices;
868 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
870 ERR("Failed to create vertex buffer, hr %#lx.\n", hr);
871 ID3D11Buffer_Release(ib);
872 return;
875 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_OUTLINE, ib, 3 * geometry->outline.face_count, vb,
876 sizeof(*geometry->outline.vertices), brush, NULL);
878 ID3D11Buffer_Release(vb);
879 ID3D11Buffer_Release(ib);
882 if (geometry->outline.bezier_face_count)
884 buffer_desc.ByteWidth = geometry->outline.bezier_face_count * sizeof(*geometry->outline.bezier_faces);
885 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
886 buffer_data.pSysMem = geometry->outline.bezier_faces;
888 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &ib)))
890 WARN("Failed to create curves index buffer, hr %#lx.\n", hr);
891 return;
894 buffer_desc.ByteWidth = geometry->outline.bezier_count * sizeof(*geometry->outline.beziers);
895 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
896 buffer_data.pSysMem = geometry->outline.beziers;
898 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
900 ERR("Failed to create curves vertex buffer, hr %#lx.\n", hr);
901 ID3D11Buffer_Release(ib);
902 return;
905 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_BEZIER_OUTLINE, ib,
906 3 * geometry->outline.bezier_face_count, vb,
907 sizeof(*geometry->outline.beziers), brush, NULL);
909 ID3D11Buffer_Release(vb);
910 ID3D11Buffer_Release(ib);
913 if (geometry->outline.arc_face_count)
915 buffer_desc.ByteWidth = geometry->outline.arc_face_count * sizeof(*geometry->outline.arc_faces);
916 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
917 buffer_data.pSysMem = geometry->outline.arc_faces;
919 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &ib)))
921 WARN("Failed to create arcs index buffer, hr %#lx.\n", hr);
922 return;
925 buffer_desc.ByteWidth = geometry->outline.arc_count * sizeof(*geometry->outline.arcs);
926 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
927 buffer_data.pSysMem = geometry->outline.arcs;
929 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
931 ERR("Failed to create arcs vertex buffer, hr %#lx.\n", hr);
932 ID3D11Buffer_Release(ib);
933 return;
936 if (SUCCEEDED(d2d_device_context_update_ps_cb(render_target, brush, NULL, TRUE, TRUE)))
937 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_ARC_OUTLINE, ib,
938 3 * geometry->outline.arc_face_count, vb,
939 sizeof(*geometry->outline.arcs), brush, NULL);
941 ID3D11Buffer_Release(vb);
942 ID3D11Buffer_Release(ib);
946 static void STDMETHODCALLTYPE d2d_device_context_DrawGeometry(ID2D1DeviceContext1 *iface,
947 ID2D1Geometry *geometry, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
949 const struct d2d_geometry *geometry_impl = unsafe_impl_from_ID2D1Geometry(geometry);
950 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
951 struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
952 struct d2d_stroke_style *stroke_style_impl = unsafe_impl_from_ID2D1StrokeStyle(stroke_style);
954 TRACE("iface %p, geometry %p, brush %p, stroke_width %.8e, stroke_style %p.\n",
955 iface, geometry, brush, stroke_width, stroke_style);
957 if (context->target.type == D2D_TARGET_COMMAND_LIST)
959 d2d_command_list_draw_geometry(context->target.command_list, context, geometry, brush,
960 stroke_width, stroke_style);
961 return;
964 if (stroke_style)
965 FIXME("Ignoring stroke style %p.\n", stroke_style);
967 if (stroke_style_impl)
969 if (stroke_style_impl->desc.transformType == D2D1_STROKE_TRANSFORM_TYPE_FIXED)
970 stroke_width /= context->drawing_state.transform.m11;
973 d2d_device_context_draw_geometry(context, geometry_impl, brush_impl, stroke_width);
976 static void d2d_device_context_fill_geometry(struct d2d_device_context *render_target,
977 const struct d2d_geometry *geometry, struct d2d_brush *brush, struct d2d_brush *opacity_brush)
979 D3D11_SUBRESOURCE_DATA buffer_data;
980 D3D11_BUFFER_DESC buffer_desc;
981 ID3D11Buffer *ib, *vb;
982 HRESULT hr;
984 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
985 buffer_desc.CPUAccessFlags = 0;
986 buffer_desc.MiscFlags = 0;
988 buffer_data.SysMemPitch = 0;
989 buffer_data.SysMemSlicePitch = 0;
991 if (FAILED(hr = d2d_device_context_update_vs_cb(render_target, &geometry->transform, 0.0f)))
993 WARN("Failed to update vs constant buffer, hr %#lx.\n", hr);
994 return;
997 if (FAILED(hr = d2d_device_context_update_ps_cb(render_target, brush, opacity_brush, FALSE, FALSE)))
999 WARN("Failed to update ps constant buffer, hr %#lx.\n", hr);
1000 return;
1003 if (geometry->fill.face_count)
1005 buffer_desc.ByteWidth = geometry->fill.face_count * sizeof(*geometry->fill.faces);
1006 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
1007 buffer_data.pSysMem = geometry->fill.faces;
1009 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &ib)))
1011 WARN("Failed to create index buffer, hr %#lx.\n", hr);
1012 return;
1015 buffer_desc.ByteWidth = geometry->fill.vertex_count * sizeof(*geometry->fill.vertices);
1016 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1017 buffer_data.pSysMem = geometry->fill.vertices;
1019 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
1021 ERR("Failed to create vertex buffer, hr %#lx.\n", hr);
1022 ID3D11Buffer_Release(ib);
1023 return;
1026 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_TRIANGLE, ib, 3 * geometry->fill.face_count, vb,
1027 sizeof(*geometry->fill.vertices), brush, opacity_brush);
1029 ID3D11Buffer_Release(vb);
1030 ID3D11Buffer_Release(ib);
1033 if (geometry->fill.bezier_vertex_count)
1035 buffer_desc.ByteWidth = geometry->fill.bezier_vertex_count * sizeof(*geometry->fill.bezier_vertices);
1036 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1037 buffer_data.pSysMem = geometry->fill.bezier_vertices;
1039 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
1041 ERR("Failed to create curves vertex buffer, hr %#lx.\n", hr);
1042 return;
1045 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_CURVE, NULL, geometry->fill.bezier_vertex_count, vb,
1046 sizeof(*geometry->fill.bezier_vertices), brush, opacity_brush);
1048 ID3D11Buffer_Release(vb);
1051 if (geometry->fill.arc_vertex_count)
1053 buffer_desc.ByteWidth = geometry->fill.arc_vertex_count * sizeof(*geometry->fill.arc_vertices);
1054 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1055 buffer_data.pSysMem = geometry->fill.arc_vertices;
1057 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
1059 ERR("Failed to create arc vertex buffer, hr %#lx.\n", hr);
1060 return;
1063 if (SUCCEEDED(d2d_device_context_update_ps_cb(render_target, brush, opacity_brush, FALSE, TRUE)))
1064 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_CURVE, NULL, geometry->fill.arc_vertex_count, vb,
1065 sizeof(*geometry->fill.arc_vertices), brush, opacity_brush);
1067 ID3D11Buffer_Release(vb);
1071 static void STDMETHODCALLTYPE d2d_device_context_FillGeometry(ID2D1DeviceContext1 *iface,
1072 ID2D1Geometry *geometry, ID2D1Brush *brush, ID2D1Brush *opacity_brush)
1074 const struct d2d_geometry *geometry_impl = unsafe_impl_from_ID2D1Geometry(geometry);
1075 struct d2d_brush *opacity_brush_impl = unsafe_impl_from_ID2D1Brush(opacity_brush);
1076 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1077 struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
1079 TRACE("iface %p, geometry %p, brush %p, opacity_brush %p.\n", iface, geometry, brush, opacity_brush);
1081 if (FAILED(context->error.code))
1082 return;
1084 if (opacity_brush && brush_impl->type != D2D_BRUSH_TYPE_BITMAP)
1086 d2d_device_context_set_error(context, D2DERR_INCOMPATIBLE_BRUSH_TYPES);
1087 return;
1090 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1091 d2d_command_list_fill_geometry(context->target.command_list, context, geometry, brush, opacity_brush);
1092 else
1093 d2d_device_context_fill_geometry(context, geometry_impl, brush_impl, opacity_brush_impl);
1096 static void STDMETHODCALLTYPE d2d_device_context_FillMesh(ID2D1DeviceContext1 *iface,
1097 ID2D1Mesh *mesh, ID2D1Brush *brush)
1099 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1101 FIXME("iface %p, mesh %p, brush %p stub!\n", iface, mesh, brush);
1103 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1104 d2d_command_list_fill_mesh(context->target.command_list, context, mesh, brush);
1107 static void STDMETHODCALLTYPE d2d_device_context_FillOpacityMask(ID2D1DeviceContext1 *iface,
1108 ID2D1Bitmap *mask, ID2D1Brush *brush, D2D1_OPACITY_MASK_CONTENT content,
1109 const D2D1_RECT_F *dst_rect, const D2D1_RECT_F *src_rect)
1111 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1113 FIXME("iface %p, mask %p, brush %p, content %#x, dst_rect %s, src_rect %s stub!\n",
1114 iface, mask, brush, content, debug_d2d_rect_f(dst_rect), debug_d2d_rect_f(src_rect));
1116 if (FAILED(context->error.code))
1117 return;
1119 if (context->drawing_state.antialiasMode != D2D1_ANTIALIAS_MODE_ALIASED)
1121 d2d_device_context_set_error(context, D2DERR_WRONG_STATE);
1122 return;
1125 if ((unsigned int)content > D2D1_OPACITY_MASK_CONTENT_TEXT_GDI_COMPATIBLE)
1127 d2d_device_context_set_error(context, E_INVALIDARG);
1128 return;
1131 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1132 d2d_command_list_fill_opacity_mask(context->target.command_list, context, mask, brush, dst_rect, src_rect);
1135 static void d2d_device_context_draw_bitmap(struct d2d_device_context *context, ID2D1Bitmap *bitmap,
1136 const D2D1_RECT_F *dst_rect, float opacity, D2D1_INTERPOLATION_MODE interpolation_mode,
1137 const D2D1_RECT_F *src_rect, const D2D1_POINT_2F *offset,
1138 const D2D1_MATRIX_4X4_F *perspective_transform)
1140 D2D1_BITMAP_BRUSH_PROPERTIES1 bitmap_brush_desc;
1141 D2D1_BRUSH_PROPERTIES brush_desc;
1142 struct d2d_brush *brush;
1143 D2D1_SIZE_F size;
1144 D2D1_RECT_F s, d;
1145 HRESULT hr;
1147 if (perspective_transform)
1148 FIXME("Perspective transform is ignored.\n");
1150 size = ID2D1Bitmap_GetSize(bitmap);
1151 d2d_rect_set(&s, 0.0f, 0.0f, size.width, size.height);
1152 if (src_rect && src_rect->left <= src_rect->right
1153 && src_rect->top <= src_rect->bottom)
1155 d2d_rect_intersect(&s, src_rect);
1158 if (s.left == s.right || s.top == s.bottom)
1159 return;
1161 if (dst_rect)
1163 d = *dst_rect;
1165 else
1167 d.left = 0.0f;
1168 d.top = 0.0f;
1169 d.right = s.right - s.left;
1170 d.bottom = s.bottom - s.top;
1173 if (offset)
1175 d.left += offset->x;
1176 d.top += offset->y;
1177 d.right += offset->x;
1178 d.bottom += offset->y;
1181 bitmap_brush_desc.extendModeX = D2D1_EXTEND_MODE_CLAMP;
1182 bitmap_brush_desc.extendModeY = D2D1_EXTEND_MODE_CLAMP;
1183 bitmap_brush_desc.interpolationMode = interpolation_mode;
1185 brush_desc.opacity = opacity;
1186 brush_desc.transform._11 = fabsf((d.right - d.left) / (s.right - s.left));
1187 brush_desc.transform._21 = 0.0f;
1188 brush_desc.transform._31 = min(d.left, d.right) - min(s.left, s.right) * brush_desc.transform._11;
1189 brush_desc.transform._12 = 0.0f;
1190 brush_desc.transform._22 = fabsf((d.bottom - d.top) / (s.bottom - s.top));
1191 brush_desc.transform._32 = min(d.top, d.bottom) - min(s.top, s.bottom) * brush_desc.transform._22;
1193 if (FAILED(hr = d2d_bitmap_brush_create(context->factory, bitmap, &bitmap_brush_desc, &brush_desc, &brush)))
1195 ERR("Failed to create bitmap brush, hr %#lx.\n", hr);
1196 return;
1199 d2d_device_context_FillRectangle(&context->ID2D1DeviceContext1_iface, &d, &brush->ID2D1Brush_iface);
1200 ID2D1Brush_Release(&brush->ID2D1Brush_iface);
1203 static void STDMETHODCALLTYPE d2d_device_context_DrawBitmap(ID2D1DeviceContext1 *iface,
1204 ID2D1Bitmap *bitmap, const D2D1_RECT_F *dst_rect, float opacity,
1205 D2D1_BITMAP_INTERPOLATION_MODE interpolation_mode, const D2D1_RECT_F *src_rect)
1207 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1209 TRACE("iface %p, bitmap %p, dst_rect %s, opacity %.8e, interpolation_mode %#x, src_rect %s.\n",
1210 iface, bitmap, debug_d2d_rect_f(dst_rect), opacity, interpolation_mode, debug_d2d_rect_f(src_rect));
1212 if (interpolation_mode != D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
1213 && interpolation_mode != D2D1_BITMAP_INTERPOLATION_MODE_LINEAR)
1215 d2d_device_context_set_error(context, E_INVALIDARG);
1216 return;
1219 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1221 d2d_command_list_draw_bitmap(context->target.command_list, bitmap, dst_rect, opacity,
1222 d2d1_1_interp_mode_from_d2d1(interpolation_mode), src_rect, NULL);
1224 else
1226 d2d_device_context_draw_bitmap(context, bitmap, dst_rect, opacity,
1227 d2d1_1_interp_mode_from_d2d1(interpolation_mode), src_rect, NULL, NULL);
1231 static void STDMETHODCALLTYPE d2d_device_context_DrawText(ID2D1DeviceContext1 *iface,
1232 const WCHAR *string, UINT32 string_len, IDWriteTextFormat *text_format, const D2D1_RECT_F *layout_rect,
1233 ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options, DWRITE_MEASURING_MODE measuring_mode)
1235 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1236 IDWriteTextLayout *text_layout;
1237 IDWriteFactory *dwrite_factory;
1238 D2D1_POINT_2F origin;
1239 float width, height;
1240 HRESULT hr;
1242 TRACE("iface %p, string %s, string_len %u, text_format %p, layout_rect %s, "
1243 "brush %p, options %#x, measuring_mode %#x.\n",
1244 iface, debugstr_wn(string, string_len), string_len, text_format, debug_d2d_rect_f(layout_rect),
1245 brush, options, measuring_mode);
1247 if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
1248 &IID_IDWriteFactory, (IUnknown **)&dwrite_factory)))
1250 ERR("Failed to create dwrite factory, hr %#lx.\n", hr);
1251 return;
1254 width = max(0.0f, layout_rect->right - layout_rect->left);
1255 height = max(0.0f, layout_rect->bottom - layout_rect->top);
1256 if (measuring_mode == DWRITE_MEASURING_MODE_NATURAL)
1257 hr = IDWriteFactory_CreateTextLayout(dwrite_factory, string, string_len, text_format,
1258 width, height, &text_layout);
1259 else
1260 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(dwrite_factory, string, string_len, text_format,
1261 width, height, render_target->desc.dpiX / 96.0f, (DWRITE_MATRIX *)&render_target->drawing_state.transform,
1262 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, &text_layout);
1263 IDWriteFactory_Release(dwrite_factory);
1264 if (FAILED(hr))
1266 ERR("Failed to create text layout, hr %#lx.\n", hr);
1267 return;
1270 d2d_point_set(&origin, min(layout_rect->left, layout_rect->right), min(layout_rect->top, layout_rect->bottom));
1271 ID2D1DeviceContext1_DrawTextLayout(iface, origin, text_layout, brush, options);
1272 IDWriteTextLayout_Release(text_layout);
1275 static void STDMETHODCALLTYPE d2d_device_context_DrawTextLayout(ID2D1DeviceContext1 *iface,
1276 D2D1_POINT_2F origin, IDWriteTextLayout *layout, ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options)
1278 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1279 struct d2d_draw_text_layout_ctx ctx;
1280 HRESULT hr;
1282 TRACE("iface %p, origin %s, layout %p, brush %p, options %#x.\n",
1283 iface, debug_d2d_point_2f(&origin), layout, brush, options);
1285 ctx.brush = brush;
1286 ctx.options = options;
1288 if (FAILED(hr = IDWriteTextLayout_Draw(layout,
1289 &ctx, &render_target->IDWriteTextRenderer_iface, origin.x, origin.y)))
1290 FIXME("Failed to draw text layout, hr %#lx.\n", hr);
1293 static D2D1_ANTIALIAS_MODE d2d_device_context_set_aa_mode_from_text_aa_mode(struct d2d_device_context *rt)
1295 D2D1_ANTIALIAS_MODE prev_antialias_mode = rt->drawing_state.antialiasMode;
1296 rt->drawing_state.antialiasMode = rt->drawing_state.textAntialiasMode == D2D1_TEXT_ANTIALIAS_MODE_ALIASED ?
1297 D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
1298 return prev_antialias_mode;
1301 static void d2d_device_context_draw_glyph_run_outline(struct d2d_device_context *render_target,
1302 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush)
1304 D2D1_MATRIX_3X2_F *transform, prev_transform;
1305 D2D1_ANTIALIAS_MODE prev_antialias_mode;
1306 ID2D1PathGeometry *geometry;
1307 ID2D1GeometrySink *sink;
1308 HRESULT hr;
1310 if (FAILED(hr = ID2D1Factory_CreatePathGeometry(render_target->factory, &geometry)))
1312 ERR("Failed to create geometry, hr %#lx.\n", hr);
1313 return;
1316 if (FAILED(hr = ID2D1PathGeometry_Open(geometry, &sink)))
1318 ERR("Failed to open geometry sink, hr %#lx.\n", hr);
1319 ID2D1PathGeometry_Release(geometry);
1320 return;
1323 if (FAILED(hr = IDWriteFontFace_GetGlyphRunOutline(glyph_run->fontFace, glyph_run->fontEmSize,
1324 glyph_run->glyphIndices, glyph_run->glyphAdvances, glyph_run->glyphOffsets, glyph_run->glyphCount,
1325 glyph_run->isSideways, glyph_run->bidiLevel & 1, (IDWriteGeometrySink *)sink)))
1327 ERR("Failed to get glyph run outline, hr %#lx.\n", hr);
1328 ID2D1GeometrySink_Release(sink);
1329 ID2D1PathGeometry_Release(geometry);
1330 return;
1333 if (FAILED(hr = ID2D1GeometrySink_Close(sink)))
1334 ERR("Failed to close geometry sink, hr %#lx.\n", hr);
1335 ID2D1GeometrySink_Release(sink);
1337 transform = &render_target->drawing_state.transform;
1338 prev_transform = *transform;
1339 transform->_31 += baseline_origin.x * transform->_11 + baseline_origin.y * transform->_21;
1340 transform->_32 += baseline_origin.x * transform->_12 + baseline_origin.y * transform->_22;
1341 prev_antialias_mode = d2d_device_context_set_aa_mode_from_text_aa_mode(render_target);
1342 d2d_device_context_fill_geometry(render_target, unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)geometry),
1343 unsafe_impl_from_ID2D1Brush(brush), NULL);
1344 render_target->drawing_state.antialiasMode = prev_antialias_mode;
1345 *transform = prev_transform;
1347 ID2D1PathGeometry_Release(geometry);
1350 static void d2d_device_context_draw_glyph_run_bitmap(struct d2d_device_context *render_target,
1351 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
1352 DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode,
1353 DWRITE_TEXT_ANTIALIAS_MODE antialias_mode)
1355 ID2D1RectangleGeometry *geometry = NULL;
1356 ID2D1BitmapBrush *opacity_brush = NULL;
1357 D2D1_BITMAP_PROPERTIES bitmap_desc;
1358 ID2D1Bitmap *opacity_bitmap = NULL;
1359 IDWriteGlyphRunAnalysis *analysis;
1360 DWRITE_TEXTURE_TYPE texture_type;
1361 D2D1_BRUSH_PROPERTIES brush_desc;
1362 IDWriteFactory2 *dwrite_factory;
1363 D2D1_MATRIX_3X2_F *transform, m;
1364 void *opacity_values = NULL;
1365 size_t opacity_values_size;
1366 D2D1_SIZE_U bitmap_size;
1367 float scale_x, scale_y;
1368 D2D1_RECT_F run_rect;
1369 RECT bounds;
1370 HRESULT hr;
1372 if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
1373 &IID_IDWriteFactory2, (IUnknown **)&dwrite_factory)))
1375 ERR("Failed to create dwrite factory, hr %#lx.\n", hr);
1376 return;
1379 transform = &render_target->drawing_state.transform;
1381 scale_x = render_target->desc.dpiX / 96.0f;
1382 m._11 = transform->_11 * scale_x;
1383 m._21 = transform->_21 * scale_x;
1384 m._31 = transform->_31 * scale_x;
1386 scale_y = render_target->desc.dpiY / 96.0f;
1387 m._12 = transform->_12 * scale_y;
1388 m._22 = transform->_22 * scale_y;
1389 m._32 = transform->_32 * scale_y;
1391 hr = IDWriteFactory2_CreateGlyphRunAnalysis(dwrite_factory, glyph_run, (DWRITE_MATRIX *)&m,
1392 rendering_mode, measuring_mode, DWRITE_GRID_FIT_MODE_DEFAULT, antialias_mode,
1393 baseline_origin.x, baseline_origin.y, &analysis);
1394 IDWriteFactory2_Release(dwrite_factory);
1395 if (FAILED(hr))
1397 ERR("Failed to create glyph run analysis, hr %#lx.\n", hr);
1398 return;
1401 if (rendering_mode == DWRITE_RENDERING_MODE_ALIASED || antialias_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
1402 texture_type = DWRITE_TEXTURE_ALIASED_1x1;
1403 else
1404 texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
1406 if (FAILED(hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, texture_type, &bounds)))
1408 ERR("Failed to get alpha texture bounds, hr %#lx.\n", hr);
1409 goto done;
1412 d2d_size_set(&bitmap_size, bounds.right - bounds.left, bounds.bottom - bounds.top);
1413 if (!bitmap_size.width || !bitmap_size.height)
1415 /* Empty run, nothing to do. */
1416 goto done;
1419 if (texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
1420 bitmap_size.width *= 3;
1421 if (!(opacity_values = calloc(bitmap_size.height, bitmap_size.width)))
1423 ERR("Failed to allocate opacity values.\n");
1424 goto done;
1426 opacity_values_size = bitmap_size.height * bitmap_size.width;
1428 if (FAILED(hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis,
1429 texture_type, &bounds, opacity_values, opacity_values_size)))
1431 ERR("Failed to create alpha texture, hr %#lx.\n", hr);
1432 goto done;
1435 bitmap_desc.pixelFormat.format = DXGI_FORMAT_A8_UNORM;
1436 bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
1437 bitmap_desc.dpiX = render_target->desc.dpiX;
1438 if (texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
1439 bitmap_desc.dpiX *= 3.0f;
1440 bitmap_desc.dpiY = render_target->desc.dpiY;
1441 if (FAILED(hr = d2d_device_context_CreateBitmap(&render_target->ID2D1DeviceContext1_iface,
1442 bitmap_size, opacity_values, bitmap_size.width, &bitmap_desc, &opacity_bitmap)))
1444 ERR("Failed to create opacity bitmap, hr %#lx.\n", hr);
1445 goto done;
1448 d2d_rect_set(&run_rect, bounds.left / scale_x, bounds.top / scale_y,
1449 bounds.right / scale_x, bounds.bottom / scale_y);
1451 brush_desc.opacity = 1.0f;
1452 brush_desc.transform._11 = 1.0f;
1453 brush_desc.transform._12 = 0.0f;
1454 brush_desc.transform._21 = 0.0f;
1455 brush_desc.transform._22 = 1.0f;
1456 brush_desc.transform._31 = run_rect.left;
1457 brush_desc.transform._32 = run_rect.top;
1458 if (FAILED(hr = d2d_device_context_CreateBitmapBrush(&render_target->ID2D1DeviceContext1_iface,
1459 opacity_bitmap, NULL, &brush_desc, &opacity_brush)))
1461 ERR("Failed to create opacity bitmap brush, hr %#lx.\n", hr);
1462 goto done;
1465 if (FAILED(hr = ID2D1Factory_CreateRectangleGeometry(render_target->factory, &run_rect, &geometry)))
1467 ERR("Failed to create geometry, hr %#lx.\n", hr);
1468 goto done;
1471 m = *transform;
1472 *transform = identity;
1473 d2d_device_context_fill_geometry(render_target, unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)geometry),
1474 unsafe_impl_from_ID2D1Brush(brush), unsafe_impl_from_ID2D1Brush((ID2D1Brush *)opacity_brush));
1475 *transform = m;
1477 done:
1478 if (geometry)
1479 ID2D1RectangleGeometry_Release(geometry);
1480 if (opacity_brush)
1481 ID2D1BitmapBrush_Release(opacity_brush);
1482 if (opacity_bitmap)
1483 ID2D1Bitmap_Release(opacity_bitmap);
1484 free(opacity_values);
1485 IDWriteGlyphRunAnalysis_Release(analysis);
1488 static void d2d_device_context_draw_glyph_run(struct d2d_device_context *context,
1489 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run,
1490 const DWRITE_GLYPH_RUN_DESCRIPTION *glyph_run_desc, ID2D1Brush *brush, DWRITE_MEASURING_MODE measuring_mode)
1492 DWRITE_TEXT_ANTIALIAS_MODE antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
1493 IDWriteRenderingParams *rendering_params;
1494 DWRITE_RENDERING_MODE rendering_mode;
1495 HRESULT hr;
1497 if (FAILED(context->error.code))
1498 return;
1500 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1502 d2d_command_list_draw_glyph_run(context->target.command_list, context, baseline_origin, glyph_run,
1503 glyph_run_desc, brush, measuring_mode);
1504 return;
1507 rendering_params = context->text_rendering_params ? context->text_rendering_params
1508 : context->default_text_rendering_params;
1510 rendering_mode = IDWriteRenderingParams_GetRenderingMode(rendering_params);
1512 switch (context->drawing_state.textAntialiasMode)
1514 case D2D1_TEXT_ANTIALIAS_MODE_ALIASED:
1515 if (rendering_mode == DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL
1516 || rendering_mode == DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC
1517 || rendering_mode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL
1518 || rendering_mode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC)
1519 d2d_device_context_set_error(context, E_INVALIDARG);
1520 break;
1522 case D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE:
1523 if (rendering_mode == DWRITE_RENDERING_MODE_ALIASED
1524 || rendering_mode == DWRITE_RENDERING_MODE_OUTLINE)
1525 d2d_device_context_set_error(context, E_INVALIDARG);
1526 break;
1528 case D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE:
1529 if (rendering_mode == DWRITE_RENDERING_MODE_ALIASED)
1530 d2d_device_context_set_error(context, E_INVALIDARG);
1531 break;
1533 default:
1534 break;
1537 if (FAILED(context->error.code))
1538 return;
1540 rendering_mode = DWRITE_RENDERING_MODE_DEFAULT;
1541 switch (context->drawing_state.textAntialiasMode)
1543 case D2D1_TEXT_ANTIALIAS_MODE_DEFAULT:
1544 if (IDWriteRenderingParams_GetClearTypeLevel(rendering_params) > 0.0f)
1545 antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
1546 break;
1548 case D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE:
1549 antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
1550 break;
1552 case D2D1_TEXT_ANTIALIAS_MODE_ALIASED:
1553 rendering_mode = DWRITE_RENDERING_MODE_ALIASED;
1554 break;
1556 default:
1557 break;
1560 if (rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
1562 if (FAILED(hr = IDWriteFontFace_GetRecommendedRenderingMode(glyph_run->fontFace, glyph_run->fontEmSize,
1563 max(context->desc.dpiX, context->desc.dpiY) / 96.0f,
1564 measuring_mode, rendering_params, &rendering_mode)))
1566 ERR("Failed to get recommended rendering mode, hr %#lx.\n", hr);
1567 rendering_mode = DWRITE_RENDERING_MODE_OUTLINE;
1571 if (rendering_mode == DWRITE_RENDERING_MODE_OUTLINE)
1572 d2d_device_context_draw_glyph_run_outline(context, baseline_origin, glyph_run, brush);
1573 else
1574 d2d_device_context_draw_glyph_run_bitmap(context, baseline_origin, glyph_run, brush,
1575 rendering_mode, measuring_mode, antialias_mode);
1578 static void STDMETHODCALLTYPE d2d_device_context_DrawGlyphRun(ID2D1DeviceContext1 *iface,
1579 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
1580 DWRITE_MEASURING_MODE measuring_mode)
1582 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1584 TRACE("iface %p, baseline_origin %s, glyph_run %p, brush %p, measuring_mode %#x.\n",
1585 iface, debug_d2d_point_2f(&baseline_origin), glyph_run, brush, measuring_mode);
1587 d2d_device_context_draw_glyph_run(context, baseline_origin, glyph_run, NULL, brush, measuring_mode);
1590 static void STDMETHODCALLTYPE d2d_device_context_SetTransform(ID2D1DeviceContext1 *iface,
1591 const D2D1_MATRIX_3X2_F *transform)
1593 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1595 TRACE("iface %p, transform %p.\n", iface, transform);
1597 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1598 d2d_command_list_set_transform(context->target.command_list, transform);
1600 context->drawing_state.transform = *transform;
1603 static void STDMETHODCALLTYPE d2d_device_context_GetTransform(ID2D1DeviceContext1 *iface,
1604 D2D1_MATRIX_3X2_F *transform)
1606 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1608 TRACE("iface %p, transform %p.\n", iface, transform);
1610 *transform = render_target->drawing_state.transform;
1613 static void STDMETHODCALLTYPE d2d_device_context_SetAntialiasMode(ID2D1DeviceContext1 *iface,
1614 D2D1_ANTIALIAS_MODE antialias_mode)
1616 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1618 TRACE("iface %p, antialias_mode %#x stub!\n", iface, antialias_mode);
1620 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1621 d2d_command_list_set_antialias_mode(context->target.command_list, antialias_mode);
1623 context->drawing_state.antialiasMode = antialias_mode;
1626 static D2D1_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_device_context_GetAntialiasMode(ID2D1DeviceContext1 *iface)
1628 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1630 TRACE("iface %p.\n", iface);
1632 return render_target->drawing_state.antialiasMode;
1635 static void STDMETHODCALLTYPE d2d_device_context_SetTextAntialiasMode(ID2D1DeviceContext1 *iface,
1636 D2D1_TEXT_ANTIALIAS_MODE antialias_mode)
1638 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1640 TRACE("iface %p, antialias_mode %#x.\n", iface, antialias_mode);
1642 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1643 d2d_command_list_set_text_antialias_mode(context->target.command_list, antialias_mode);
1645 context->drawing_state.textAntialiasMode = antialias_mode;
1648 static D2D1_TEXT_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_device_context_GetTextAntialiasMode(ID2D1DeviceContext1 *iface)
1650 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1652 TRACE("iface %p.\n", iface);
1654 return render_target->drawing_state.textAntialiasMode;
1657 static void STDMETHODCALLTYPE d2d_device_context_SetTextRenderingParams(ID2D1DeviceContext1 *iface,
1658 IDWriteRenderingParams *text_rendering_params)
1660 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1662 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
1664 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1665 d2d_command_list_set_text_rendering_params(context->target.command_list, text_rendering_params);
1667 if (text_rendering_params)
1668 IDWriteRenderingParams_AddRef(text_rendering_params);
1669 if (context->text_rendering_params)
1670 IDWriteRenderingParams_Release(context->text_rendering_params);
1671 context->text_rendering_params = text_rendering_params;
1674 static void STDMETHODCALLTYPE d2d_device_context_GetTextRenderingParams(ID2D1DeviceContext1 *iface,
1675 IDWriteRenderingParams **text_rendering_params)
1677 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1679 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
1681 if ((*text_rendering_params = render_target->text_rendering_params))
1682 IDWriteRenderingParams_AddRef(*text_rendering_params);
1685 static void STDMETHODCALLTYPE d2d_device_context_SetTags(ID2D1DeviceContext1 *iface, D2D1_TAG tag1, D2D1_TAG tag2)
1687 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1689 TRACE("iface %p, tag1 %s, tag2 %s.\n", iface, wine_dbgstr_longlong(tag1), wine_dbgstr_longlong(tag2));
1691 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1692 d2d_command_list_set_tags(context->target.command_list, tag1, tag2);
1694 context->drawing_state.tag1 = tag1;
1695 context->drawing_state.tag2 = tag2;
1698 static void STDMETHODCALLTYPE d2d_device_context_GetTags(ID2D1DeviceContext1 *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
1700 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1702 TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2);
1704 *tag1 = render_target->drawing_state.tag1;
1705 *tag2 = render_target->drawing_state.tag2;
1708 static void STDMETHODCALLTYPE d2d_device_context_PushLayer(ID2D1DeviceContext1 *iface,
1709 const D2D1_LAYER_PARAMETERS *layer_parameters, ID2D1Layer *layer)
1711 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1713 FIXME("iface %p, layer_parameters %p, layer %p stub!\n", iface, layer_parameters, layer);
1715 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1717 D2D1_LAYER_PARAMETERS1 parameters;
1719 memcpy(&parameters, layer_parameters, sizeof(*layer_parameters));
1720 parameters.layerOptions = D2D1_LAYER_OPTIONS1_NONE;
1721 d2d_command_list_push_layer(context->target.command_list, context, &parameters, layer);
1725 static void STDMETHODCALLTYPE d2d_device_context_PopLayer(ID2D1DeviceContext1 *iface)
1727 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1729 FIXME("iface %p stub!\n", iface);
1731 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1732 d2d_command_list_pop_layer(context->target.command_list);
1735 static HRESULT STDMETHODCALLTYPE d2d_device_context_Flush(ID2D1DeviceContext1 *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
1737 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1739 FIXME("iface %p, tag1 %p, tag2 %p stub!\n", iface, tag1, tag2);
1741 if (context->ops && context->ops->device_context_present)
1742 context->ops->device_context_present(context->outer_unknown);
1744 return E_NOTIMPL;
1747 static void STDMETHODCALLTYPE d2d_device_context_SaveDrawingState(ID2D1DeviceContext1 *iface,
1748 ID2D1DrawingStateBlock *state_block)
1750 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1751 struct d2d_state_block *state_block_impl;
1753 TRACE("iface %p, state_block %p.\n", iface, state_block);
1755 if (!(state_block_impl = unsafe_impl_from_ID2D1DrawingStateBlock(state_block))) return;
1756 state_block_impl->drawing_state = render_target->drawing_state;
1757 if (render_target->text_rendering_params)
1758 IDWriteRenderingParams_AddRef(render_target->text_rendering_params);
1759 if (state_block_impl->text_rendering_params)
1760 IDWriteRenderingParams_Release(state_block_impl->text_rendering_params);
1761 state_block_impl->text_rendering_params = render_target->text_rendering_params;
1764 static void STDMETHODCALLTYPE d2d_device_context_RestoreDrawingState(ID2D1DeviceContext1 *iface,
1765 ID2D1DrawingStateBlock *state_block)
1767 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1768 struct d2d_state_block *state_block_impl;
1770 TRACE("iface %p, state_block %p.\n", iface, state_block);
1772 if (!(state_block_impl = unsafe_impl_from_ID2D1DrawingStateBlock(state_block))) return;
1773 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1775 struct d2d_command_list *command_list = context->target.command_list;
1777 if (context->drawing_state.antialiasMode != state_block_impl->drawing_state.antialiasMode)
1778 d2d_command_list_set_antialias_mode(command_list, state_block_impl->drawing_state.antialiasMode);
1779 d2d_command_list_set_text_antialias_mode(command_list, state_block_impl->drawing_state.textAntialiasMode);
1780 d2d_command_list_set_tags(command_list, state_block_impl->drawing_state.tag1, state_block_impl->drawing_state.tag2);
1781 d2d_command_list_set_transform(command_list, &state_block_impl->drawing_state.transform);
1782 d2d_command_list_set_primitive_blend(command_list, state_block_impl->drawing_state.primitiveBlend);
1783 d2d_command_list_set_unit_mode(command_list, state_block_impl->drawing_state.unitMode);
1784 d2d_command_list_set_text_rendering_params(command_list, state_block_impl->text_rendering_params);
1787 context->drawing_state = state_block_impl->drawing_state;
1788 if (state_block_impl->text_rendering_params)
1789 IDWriteRenderingParams_AddRef(state_block_impl->text_rendering_params);
1790 if (context->text_rendering_params)
1791 IDWriteRenderingParams_Release(context->text_rendering_params);
1792 context->text_rendering_params = state_block_impl->text_rendering_params;
1795 static void STDMETHODCALLTYPE d2d_device_context_PushAxisAlignedClip(ID2D1DeviceContext1 *iface,
1796 const D2D1_RECT_F *clip_rect, D2D1_ANTIALIAS_MODE antialias_mode)
1798 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1799 D2D1_RECT_F transformed_rect;
1800 float x_scale, y_scale;
1801 D2D1_POINT_2F point;
1803 TRACE("iface %p, clip_rect %s, antialias_mode %#x.\n", iface, debug_d2d_rect_f(clip_rect), antialias_mode);
1805 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1806 d2d_command_list_push_clip(context->target.command_list, clip_rect, antialias_mode);
1808 if (antialias_mode != D2D1_ANTIALIAS_MODE_ALIASED)
1809 FIXME("Ignoring antialias_mode %#x.\n", antialias_mode);
1811 x_scale = context->desc.dpiX / 96.0f;
1812 y_scale = context->desc.dpiY / 96.0f;
1813 d2d_point_transform(&point, &context->drawing_state.transform,
1814 clip_rect->left * x_scale, clip_rect->top * y_scale);
1815 d2d_rect_set(&transformed_rect, point.x, point.y, point.x, point.y);
1816 d2d_point_transform(&point, &context->drawing_state.transform,
1817 clip_rect->left * x_scale, clip_rect->bottom * y_scale);
1818 d2d_rect_expand(&transformed_rect, &point);
1819 d2d_point_transform(&point, &context->drawing_state.transform,
1820 clip_rect->right * x_scale, clip_rect->top * y_scale);
1821 d2d_rect_expand(&transformed_rect, &point);
1822 d2d_point_transform(&point, &context->drawing_state.transform,
1823 clip_rect->right * x_scale, clip_rect->bottom * y_scale);
1824 d2d_rect_expand(&transformed_rect, &point);
1826 if (!d2d_clip_stack_push(&context->clip_stack, &transformed_rect))
1827 WARN("Failed to push clip rect.\n");
1830 static void STDMETHODCALLTYPE d2d_device_context_PopAxisAlignedClip(ID2D1DeviceContext1 *iface)
1832 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1834 TRACE("iface %p.\n", iface);
1836 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1837 d2d_command_list_pop_clip(context->target.command_list);
1839 d2d_clip_stack_pop(&context->clip_stack);
1842 static void STDMETHODCALLTYPE d2d_device_context_Clear(ID2D1DeviceContext1 *iface, const D2D1_COLOR_F *colour)
1844 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1845 D3D11_MAPPED_SUBRESOURCE map_desc;
1846 ID3D11DeviceContext *d3d_context;
1847 struct d2d_ps_cb *ps_cb_data;
1848 struct d2d_vs_cb *vs_cb_data;
1849 D2D1_COLOR_F *c;
1850 HRESULT hr;
1852 TRACE("iface %p, colour %p.\n", iface, colour);
1854 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1856 d2d_command_list_clear(context->target.command_list, colour);
1857 return;
1860 ID3D11Device1_GetImmediateContext(context->d3d_device, &d3d_context);
1862 if (FAILED(hr = ID3D11DeviceContext_Map(d3d_context, (ID3D11Resource *)context->vs_cb,
1863 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc)))
1865 WARN("Failed to map vs constant buffer, hr %#lx.\n", hr);
1866 ID3D11DeviceContext_Release(d3d_context);
1867 return;
1870 vs_cb_data = map_desc.pData;
1871 vs_cb_data->transform_geometry._11 = 1.0f;
1872 vs_cb_data->transform_geometry._21 = 0.0f;
1873 vs_cb_data->transform_geometry._31 = 0.0f;
1874 vs_cb_data->transform_geometry.pad0 = 0.0f;
1875 vs_cb_data->transform_geometry._12 = 0.0f;
1876 vs_cb_data->transform_geometry._22 = 1.0f;
1877 vs_cb_data->transform_geometry._32 = 0.0f;
1878 vs_cb_data->transform_geometry.stroke_width = 0.0f;
1879 vs_cb_data->transform_rtx.x = 1.0f;
1880 vs_cb_data->transform_rtx.y = 0.0f;
1881 vs_cb_data->transform_rtx.z = 1.0f;
1882 vs_cb_data->transform_rtx.w = 1.0f;
1883 vs_cb_data->transform_rty.x = 0.0f;
1884 vs_cb_data->transform_rty.y = 1.0f;
1885 vs_cb_data->transform_rty.z = 1.0f;
1886 vs_cb_data->transform_rty.w = -1.0f;
1888 ID3D11DeviceContext_Unmap(d3d_context, (ID3D11Resource *)context->vs_cb, 0);
1890 if (FAILED(hr = ID3D11DeviceContext_Map(d3d_context, (ID3D11Resource *)context->ps_cb,
1891 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc)))
1893 WARN("Failed to map ps constant buffer, hr %#lx.\n", hr);
1894 ID3D11DeviceContext_Release(d3d_context);
1895 return;
1898 ps_cb_data = map_desc.pData;
1899 memset(ps_cb_data, 0, sizeof(*ps_cb_data));
1900 ps_cb_data->colour_brush.type = D2D_BRUSH_TYPE_SOLID;
1901 ps_cb_data->colour_brush.opacity = 1.0f;
1902 ps_cb_data->opacity_brush.type = D2D_BRUSH_TYPE_COUNT;
1903 c = &ps_cb_data->colour_brush.u.solid.colour;
1904 if (colour)
1905 *c = *colour;
1906 if (context->desc.pixelFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE)
1907 c->a = 1.0f;
1908 c->r *= c->a;
1909 c->g *= c->a;
1910 c->b *= c->a;
1912 ID3D11DeviceContext_Unmap(d3d_context, (ID3D11Resource *)context->ps_cb, 0);
1913 ID3D11DeviceContext_Release(d3d_context);
1915 d2d_device_context_draw(context, D2D_SHAPE_TYPE_TRIANGLE, context->ib, 6,
1916 context->vb, context->vb_stride, NULL, NULL);
1919 static void STDMETHODCALLTYPE d2d_device_context_BeginDraw(ID2D1DeviceContext1 *iface)
1921 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1923 TRACE("iface %p.\n", iface);
1925 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1926 d2d_command_list_begin_draw(context->target.command_list, context);
1928 memset(&context->error, 0, sizeof(context->error));
1931 static HRESULT STDMETHODCALLTYPE d2d_device_context_EndDraw(ID2D1DeviceContext1 *iface,
1932 D2D1_TAG *tag1, D2D1_TAG *tag2)
1934 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1935 HRESULT hr;
1937 TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2);
1939 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1941 FIXME("Unimplemented for command list target.\n");
1942 return E_NOTIMPL;
1945 if (tag1)
1946 *tag1 = context->error.tag1;
1947 if (tag2)
1948 *tag2 = context->error.tag2;
1950 if (context->ops && context->ops->device_context_present)
1952 if (FAILED(hr = context->ops->device_context_present(context->outer_unknown)))
1953 context->error.code = hr;
1956 return context->error.code;
1959 static D2D1_PIXEL_FORMAT * STDMETHODCALLTYPE d2d_device_context_GetPixelFormat(ID2D1DeviceContext1 *iface,
1960 D2D1_PIXEL_FORMAT *format)
1962 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1964 TRACE("iface %p, format %p.\n", iface, format);
1966 *format = render_target->desc.pixelFormat;
1967 return format;
1970 static void STDMETHODCALLTYPE d2d_device_context_SetDpi(ID2D1DeviceContext1 *iface, float dpi_x, float dpi_y)
1972 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1974 TRACE("iface %p, dpi_x %.8e, dpi_y %.8e.\n", iface, dpi_x, dpi_y);
1976 if (dpi_x == 0.0f && dpi_y == 0.0f)
1978 dpi_x = 96.0f;
1979 dpi_y = 96.0f;
1981 else if (dpi_x <= 0.0f || dpi_y <= 0.0f)
1982 return;
1984 render_target->desc.dpiX = dpi_x;
1985 render_target->desc.dpiY = dpi_y;
1988 static void STDMETHODCALLTYPE d2d_device_context_GetDpi(ID2D1DeviceContext1 *iface, float *dpi_x, float *dpi_y)
1990 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1992 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
1994 *dpi_x = render_target->desc.dpiX;
1995 *dpi_y = render_target->desc.dpiY;
1998 static D2D1_SIZE_F * STDMETHODCALLTYPE d2d_device_context_GetSize(ID2D1DeviceContext1 *iface, D2D1_SIZE_F *size)
2000 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
2002 TRACE("iface %p, size %p.\n", iface, size);
2004 size->width = render_target->pixel_size.width / (render_target->desc.dpiX / 96.0f);
2005 size->height = render_target->pixel_size.height / (render_target->desc.dpiY / 96.0f);
2006 return size;
2009 static D2D1_SIZE_U * STDMETHODCALLTYPE d2d_device_context_GetPixelSize(ID2D1DeviceContext1 *iface,
2010 D2D1_SIZE_U *pixel_size)
2012 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
2014 TRACE("iface %p, pixel_size %p.\n", iface, pixel_size);
2016 *pixel_size = render_target->pixel_size;
2017 return pixel_size;
2020 static UINT32 STDMETHODCALLTYPE d2d_device_context_GetMaximumBitmapSize(ID2D1DeviceContext1 *iface)
2022 TRACE("iface %p.\n", iface);
2024 return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
2027 static BOOL STDMETHODCALLTYPE d2d_device_context_IsSupported(ID2D1DeviceContext1 *iface,
2028 const D2D1_RENDER_TARGET_PROPERTIES *desc)
2030 FIXME("iface %p, desc %p stub!\n", iface, desc);
2032 return FALSE;
2035 static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateBitmap(ID2D1DeviceContext1 *iface,
2036 D2D1_SIZE_U size, const void *src_data, UINT32 pitch,
2037 const D2D1_BITMAP_PROPERTIES1 *desc, ID2D1Bitmap1 **bitmap)
2039 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2040 struct d2d_bitmap *object;
2041 HRESULT hr;
2043 TRACE("iface %p, size {%u, %u}, src_data %p, pitch %u, desc %p, bitmap %p.\n",
2044 iface, size.width, size.height, src_data, pitch, desc, bitmap);
2046 if (SUCCEEDED(hr = d2d_bitmap_create(context, size, src_data, pitch, desc, &object)))
2047 *bitmap = &object->ID2D1Bitmap1_iface;
2049 return hr;
2052 static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateBitmapFromWicBitmap(
2053 ID2D1DeviceContext1 *iface, IWICBitmapSource *bitmap_source,
2054 const D2D1_BITMAP_PROPERTIES1 *desc, ID2D1Bitmap1 **bitmap)
2056 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2057 struct d2d_bitmap *object;
2058 HRESULT hr;
2060 TRACE("iface %p, bitmap_source %p, desc %p, bitmap %p.\n", iface, bitmap_source, desc, bitmap);
2062 if (SUCCEEDED(hr = d2d_bitmap_create_from_wic_bitmap(context, bitmap_source, desc, &object)))
2063 *bitmap = &object->ID2D1Bitmap1_iface;
2065 return hr;
2068 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateColorContext(ID2D1DeviceContext1 *iface,
2069 D2D1_COLOR_SPACE space, const BYTE *profile, UINT32 profile_size, ID2D1ColorContext **color_context)
2071 FIXME("iface %p, space %#x, profile %p, profile_size %u, color_context %p stub!\n",
2072 iface, space, profile, profile_size, color_context);
2074 return E_NOTIMPL;
2077 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateColorContextFromFilename(ID2D1DeviceContext1 *iface,
2078 const WCHAR *filename, ID2D1ColorContext **color_context)
2080 FIXME("iface %p, filename %s, color_context %p stub!\n", iface, debugstr_w(filename), color_context);
2082 return E_NOTIMPL;
2085 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateColorContextFromWicColorContext(ID2D1DeviceContext1 *iface,
2086 IWICColorContext *wic_color_context, ID2D1ColorContext **color_context)
2088 FIXME("iface %p, wic_color_context %p, color_context %p stub!\n", iface, wic_color_context, color_context);
2090 return E_NOTIMPL;
2093 static BOOL d2d_bitmap_check_options_with_surface(unsigned int options, unsigned int surface_options)
2095 switch (options)
2097 case D2D1_BITMAP_OPTIONS_NONE:
2098 case D2D1_BITMAP_OPTIONS_TARGET:
2099 case D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW:
2100 case D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE:
2101 case D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE:
2102 case D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ:
2103 case D2D1_BITMAP_OPTIONS_CANNOT_DRAW:
2104 break;
2105 default:
2106 WARN("Invalid bitmap options %#x.\n", options);
2107 return FALSE;
2110 if (options && (options & D2D1_BITMAP_OPTIONS_TARGET) != (surface_options & D2D1_BITMAP_OPTIONS_TARGET))
2111 return FALSE;
2112 if (!(options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW) && (surface_options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW))
2113 return FALSE;
2114 if (options & D2D1_BITMAP_OPTIONS_TARGET)
2116 if (options & D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE && !(surface_options & D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE))
2117 return FALSE;
2118 return TRUE;
2121 if (options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW)
2123 if (!(surface_options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW))
2124 return FALSE;
2126 if (options & D2D1_BITMAP_OPTIONS_CPU_READ && !(surface_options & D2D1_BITMAP_OPTIONS_CPU_READ))
2127 return FALSE;
2130 return TRUE;
2133 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmapFromDxgiSurface(ID2D1DeviceContext1 *iface,
2134 IDXGISurface *surface, const D2D1_BITMAP_PROPERTIES1 *desc, ID2D1Bitmap1 **bitmap)
2136 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2137 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
2138 unsigned int surface_options;
2139 struct d2d_bitmap *object;
2140 HRESULT hr;
2142 TRACE("iface %p, surface %p, desc %p, bitmap %p.\n", iface, surface, desc, bitmap);
2144 surface_options = d2d_get_bitmap_options_for_surface(surface);
2146 if (desc)
2148 if (!d2d_bitmap_check_options_with_surface(desc->bitmapOptions, surface_options))
2150 WARN("Incompatible bitmap options %#x, surface options %#x.\n",
2151 desc->bitmapOptions, surface_options);
2152 return E_INVALIDARG;
2155 else
2157 DXGI_SURFACE_DESC surface_desc;
2159 if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc)))
2161 WARN("Failed to get surface desc, hr %#lx.\n", hr);
2162 return hr;
2165 memset(&bitmap_desc, 0, sizeof(bitmap_desc));
2166 bitmap_desc.pixelFormat.format = surface_desc.Format;
2167 bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
2168 bitmap_desc.bitmapOptions = surface_options;
2169 desc = &bitmap_desc;
2172 if (SUCCEEDED(hr = d2d_bitmap_create_shared(context, &IID_IDXGISurface, surface, desc, &object)))
2173 *bitmap = &object->ID2D1Bitmap1_iface;
2175 return hr;
2178 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateEffect(ID2D1DeviceContext1 *iface,
2179 REFCLSID effect_id, ID2D1Effect **effect)
2181 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2183 TRACE("iface %p, effect_id %s, effect %p.\n", iface, debugstr_guid(effect_id), effect);
2185 return d2d_effect_create(context, effect_id, effect);
2188 static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateGradientStopCollection(
2189 ID2D1DeviceContext1 *iface, const D2D1_GRADIENT_STOP *stops, UINT32 stop_count,
2190 D2D1_COLOR_SPACE preinterpolation_space, D2D1_COLOR_SPACE postinterpolation_space,
2191 D2D1_BUFFER_PRECISION buffer_precision, D2D1_EXTEND_MODE extend_mode,
2192 D2D1_COLOR_INTERPOLATION_MODE color_interpolation_mode, ID2D1GradientStopCollection1 **gradient)
2194 FIXME("iface %p, stops %p, stop_count %u, preinterpolation_space %#x, postinterpolation_space %#x, "
2195 "buffer_precision %#x, extend_mode %#x, color_interpolation_mode %#x, gradient %p stub!\n",
2196 iface, stops, stop_count, preinterpolation_space, postinterpolation_space,
2197 buffer_precision, extend_mode, color_interpolation_mode, gradient);
2199 return E_NOTIMPL;
2202 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateImageBrush(ID2D1DeviceContext1 *iface,
2203 ID2D1Image *image, const D2D1_IMAGE_BRUSH_PROPERTIES *image_brush_desc,
2204 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1ImageBrush **brush)
2206 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2207 struct d2d_brush *object;
2208 HRESULT hr;
2210 TRACE("iface %p, image %p, image_brush_desc %p, brush_desc %p, brush %p.\n", iface, image, image_brush_desc,
2211 brush_desc, brush);
2213 if (SUCCEEDED(hr = d2d_image_brush_create(context->factory, image, image_brush_desc,
2214 brush_desc, &object)))
2215 *brush = (ID2D1ImageBrush *)&object->ID2D1Brush_iface;
2217 return hr;
2220 static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateBitmapBrush(ID2D1DeviceContext1 *iface,
2221 ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES1 *bitmap_brush_desc,
2222 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1BitmapBrush1 **brush)
2224 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2225 struct d2d_brush *object;
2226 HRESULT hr;
2228 TRACE("iface %p, bitmap %p, bitmap_brush_desc %p, brush_desc %p, brush %p.\n", iface, bitmap, bitmap_brush_desc,
2229 brush_desc, brush);
2231 if (SUCCEEDED(hr = d2d_bitmap_brush_create(context->factory, bitmap, bitmap_brush_desc, brush_desc, &object)))
2232 *brush = (ID2D1BitmapBrush1 *)&object->ID2D1Brush_iface;
2234 return hr;
2237 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateCommandList(ID2D1DeviceContext1 *iface,
2238 ID2D1CommandList **command_list)
2240 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2241 struct d2d_command_list *object;
2242 HRESULT hr;
2244 TRACE("iface %p, command_list %p.\n", iface, command_list);
2246 if (SUCCEEDED(hr = d2d_command_list_create(context->factory, &object)))
2247 *command_list = &object->ID2D1CommandList_iface;
2249 return hr;
2252 static BOOL STDMETHODCALLTYPE d2d_device_context_IsDxgiFormatSupported(ID2D1DeviceContext1 *iface, DXGI_FORMAT format)
2254 FIXME("iface %p, format %#x stub!\n", iface, format);
2256 return FALSE;
2259 static BOOL STDMETHODCALLTYPE d2d_device_context_IsBufferPrecisionSupported(ID2D1DeviceContext1 *iface,
2260 D2D1_BUFFER_PRECISION buffer_precision)
2262 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2263 DXGI_FORMAT format;
2264 UINT support = 0;
2265 HRESULT hr;
2267 TRACE("iface %p, buffer_precision %u.\n", iface, buffer_precision);
2269 switch (buffer_precision)
2271 case D2D1_BUFFER_PRECISION_8BPC_UNORM: format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
2272 case D2D1_BUFFER_PRECISION_8BPC_UNORM_SRGB: format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; break;
2273 case D2D1_BUFFER_PRECISION_16BPC_UNORM: format = DXGI_FORMAT_R16G16B16A16_UNORM; break;
2274 case D2D1_BUFFER_PRECISION_16BPC_FLOAT: format = DXGI_FORMAT_R16G16B16A16_FLOAT; break;
2275 case D2D1_BUFFER_PRECISION_32BPC_FLOAT: format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
2276 default:
2277 WARN("Unexpected precision %u.\n", buffer_precision);
2278 return FALSE;
2281 if (FAILED(hr = ID3D11Device1_CheckFormatSupport(context->d3d_device, format, &support)))
2283 WARN("Format support check failed, hr %#lx.\n", hr);
2286 return !!(support & D3D11_FORMAT_SUPPORT_BUFFER);
2289 static void STDMETHODCALLTYPE d2d_device_context_GetImageLocalBounds(ID2D1DeviceContext1 *iface,
2290 ID2D1Image *image, D2D1_RECT_F *local_bounds)
2292 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2293 D2D_SIZE_U pixel_size;
2294 ID2D1Bitmap *bitmap;
2295 D2D_SIZE_F size;
2297 TRACE("iface %p, image %p, local_bounds %p.\n", iface, image, local_bounds);
2299 if (SUCCEEDED(ID2D1Image_QueryInterface(image, &IID_ID2D1Bitmap, (void **)&bitmap)))
2301 local_bounds->left = 0.0f;
2302 local_bounds->top = 0.0f;
2303 switch (context->drawing_state.unitMode)
2305 case D2D1_UNIT_MODE_DIPS:
2306 size = ID2D1Bitmap_GetSize(bitmap);
2307 local_bounds->right = size.width;
2308 local_bounds->bottom = size.height;
2309 break;
2311 case D2D1_UNIT_MODE_PIXELS:
2312 pixel_size = ID2D1Bitmap_GetPixelSize(bitmap);
2313 local_bounds->right = pixel_size.width;
2314 local_bounds->bottom = pixel_size.height;
2315 break;
2317 default:
2318 WARN("Unknown unit mode %#x.\n", context->drawing_state.unitMode);
2319 break;
2321 ID2D1Bitmap_Release(bitmap);
2323 else
2325 FIXME("Unable to get local bounds of image %p.\n", image);
2329 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetImageWorldBounds(ID2D1DeviceContext1 *iface,
2330 ID2D1Image *image, D2D1_RECT_F *world_bounds)
2332 FIXME("iface %p, image %p, world_bounds %p stub!\n", iface, image, world_bounds);
2334 return E_NOTIMPL;
2337 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetGlyphRunWorldBounds(ID2D1DeviceContext1 *iface,
2338 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run,
2339 DWRITE_MEASURING_MODE measuring_mode, D2D1_RECT_F *bounds)
2341 FIXME("iface %p, baseline_origin %s, glyph_run %p, measuring_mode %#x, bounds %p stub!\n",
2342 iface, debug_d2d_point_2f(&baseline_origin), glyph_run, measuring_mode, bounds);
2344 return E_NOTIMPL;
2347 static void STDMETHODCALLTYPE d2d_device_context_GetDevice(ID2D1DeviceContext1 *iface, ID2D1Device **device)
2349 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2351 TRACE("iface %p, device %p.\n", iface, device);
2353 *device = (ID2D1Device *)&context->device->ID2D1Device1_iface;
2354 ID2D1Device_AddRef(*device);
2357 static void d2d_device_context_reset_target(struct d2d_device_context *context)
2359 if (!context->target.object)
2360 return;
2362 IUnknown_Release(context->target.object);
2363 memset(&context->target, 0, sizeof(context->target));
2365 /* Note that DPI settings are kept. */
2366 memset(&context->desc.pixelFormat, 0, sizeof(context->desc.pixelFormat));
2367 memset(&context->pixel_size, 0, sizeof(context->pixel_size));
2369 if (context->bs)
2370 ID3D11BlendState_Release(context->bs);
2371 context->bs = NULL;
2374 static void STDMETHODCALLTYPE d2d_device_context_SetTarget(ID2D1DeviceContext1 *iface, ID2D1Image *target)
2376 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2377 struct d2d_command_list *command_list_impl;
2378 struct d2d_bitmap *bitmap_impl;
2379 ID2D1CommandList *command_list;
2380 D3D11_BLEND_DESC blend_desc;
2381 ID2D1Bitmap *bitmap;
2382 HRESULT hr;
2384 TRACE("iface %p, target %p.\n", iface, target);
2386 if (!target)
2388 d2d_device_context_reset_target(context);
2389 return;
2392 if (SUCCEEDED(ID2D1Image_QueryInterface(target, &IID_ID2D1Bitmap, (void **)&bitmap)))
2394 bitmap_impl = unsafe_impl_from_ID2D1Bitmap(bitmap);
2396 if (!(bitmap_impl->options & D2D1_BITMAP_OPTIONS_TARGET))
2398 ID2D1Bitmap_Release(bitmap);
2399 d2d_device_context_set_error(context, D2DERR_INVALID_TARGET);
2400 return;
2403 d2d_device_context_reset_target(context);
2405 /* Set sizes and pixel format. */
2406 context->pixel_size = bitmap_impl->pixel_size;
2407 context->desc.pixelFormat = bitmap_impl->format;
2408 context->target.bitmap = bitmap_impl;
2409 context->target.object = target;
2410 context->target.type = D2D_TARGET_BITMAP;
2412 memset(&blend_desc, 0, sizeof(blend_desc));
2413 blend_desc.IndependentBlendEnable = FALSE;
2414 blend_desc.RenderTarget[0].BlendEnable = TRUE;
2415 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
2416 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
2417 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
2418 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
2419 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
2420 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
2421 blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
2422 if (FAILED(hr = ID3D11Device1_CreateBlendState(context->d3d_device, &blend_desc, &context->bs)))
2423 WARN("Failed to create blend state, hr %#lx.\n", hr);
2425 else if (SUCCEEDED(ID2D1Image_QueryInterface(target, &IID_ID2D1CommandList, (void **)&command_list)))
2427 command_list_impl = unsafe_impl_from_ID2D1CommandList(command_list);
2429 d2d_device_context_reset_target(context);
2431 context->target.command_list = command_list_impl;
2432 context->target.object = target;
2433 context->target.type = D2D_TARGET_COMMAND_LIST;
2435 else
2437 WARN("Unsupported target type.\n");
2441 static void STDMETHODCALLTYPE d2d_device_context_GetTarget(ID2D1DeviceContext1 *iface, ID2D1Image **target)
2443 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2445 TRACE("iface %p, target %p.\n", iface, target);
2447 *target = context->target.object ? context->target.object : NULL;
2448 if (*target)
2449 ID2D1Image_AddRef(*target);
2452 static void STDMETHODCALLTYPE d2d_device_context_SetRenderingControls(ID2D1DeviceContext1 *iface,
2453 const D2D1_RENDERING_CONTROLS *rendering_controls)
2455 FIXME("iface %p, rendering_controls %p stub!\n", iface, rendering_controls);
2458 static void STDMETHODCALLTYPE d2d_device_context_GetRenderingControls(ID2D1DeviceContext1 *iface,
2459 D2D1_RENDERING_CONTROLS *rendering_controls)
2461 FIXME("iface %p, rendering_controls %p stub!\n", iface, rendering_controls);
2464 static void STDMETHODCALLTYPE d2d_device_context_SetPrimitiveBlend(ID2D1DeviceContext1 *iface,
2465 D2D1_PRIMITIVE_BLEND primitive_blend)
2467 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2469 TRACE("iface %p, primitive_blend %u.\n", iface, primitive_blend);
2471 if (primitive_blend > D2D1_PRIMITIVE_BLEND_MAX)
2473 WARN("Unknown blend mode %u.\n", primitive_blend);
2474 return;
2477 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2478 d2d_command_list_set_primitive_blend(context->target.command_list, primitive_blend);
2480 context->drawing_state.primitiveBlend = primitive_blend;
2483 static D2D1_PRIMITIVE_BLEND STDMETHODCALLTYPE d2d_device_context_GetPrimitiveBlend(ID2D1DeviceContext1 *iface)
2485 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2487 TRACE("iface %p.\n", iface);
2489 return context->drawing_state.primitiveBlend;
2492 static void STDMETHODCALLTYPE d2d_device_context_SetUnitMode(ID2D1DeviceContext1 *iface, D2D1_UNIT_MODE unit_mode)
2494 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2496 TRACE("iface %p, unit_mode %#x.\n", iface, unit_mode);
2498 if (unit_mode != D2D1_UNIT_MODE_DIPS && unit_mode != D2D1_UNIT_MODE_PIXELS)
2500 WARN("Unknown unit mode %#x.\n", unit_mode);
2501 return;
2504 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2505 d2d_command_list_set_unit_mode(context->target.command_list, unit_mode);
2507 context->drawing_state.unitMode = unit_mode;
2510 static D2D1_UNIT_MODE STDMETHODCALLTYPE d2d_device_context_GetUnitMode(ID2D1DeviceContext1 *iface)
2512 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2514 TRACE("iface %p.\n", iface);
2516 return context->drawing_state.unitMode;
2519 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_DrawGlyphRun(ID2D1DeviceContext1 *iface,
2520 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run,
2521 const DWRITE_GLYPH_RUN_DESCRIPTION *glyph_run_desc, ID2D1Brush *brush, DWRITE_MEASURING_MODE measuring_mode)
2523 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2525 TRACE("iface %p, baseline_origin %s, glyph_run %p, glyph_run_desc %p, brush %p, measuring_mode %#x.\n",
2526 iface, debug_d2d_point_2f(&baseline_origin), glyph_run, glyph_run_desc, brush, measuring_mode);
2528 d2d_device_context_draw_glyph_run(context, baseline_origin, glyph_run, glyph_run_desc, brush, measuring_mode);
2531 static void STDMETHODCALLTYPE d2d_device_context_DrawImage(ID2D1DeviceContext1 *iface, ID2D1Image *image,
2532 const D2D1_POINT_2F *target_offset, const D2D1_RECT_F *image_rect, D2D1_INTERPOLATION_MODE interpolation_mode,
2533 D2D1_COMPOSITE_MODE composite_mode)
2535 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2536 ID2D1Bitmap *bitmap;
2538 TRACE("iface %p, image %p, target_offset %s, image_rect %s, interpolation_mode %#x, composite_mode %#x.\n",
2539 iface, image, debug_d2d_point_2f(target_offset), debug_d2d_rect_f(image_rect),
2540 interpolation_mode, composite_mode);
2542 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2544 d2d_command_list_draw_image(context->target.command_list, image, target_offset, image_rect,
2545 interpolation_mode, composite_mode);
2546 return;
2549 if (composite_mode != D2D1_COMPOSITE_MODE_SOURCE_OVER)
2550 FIXME("Unhandled composite mode %#x.\n", composite_mode);
2552 if (SUCCEEDED(ID2D1Image_QueryInterface(image, &IID_ID2D1Bitmap, (void **)&bitmap)))
2554 d2d_device_context_draw_bitmap(context, bitmap, NULL, 1.0f, interpolation_mode, image_rect, target_offset, NULL);
2556 ID2D1Bitmap_Release(bitmap);
2557 return;
2560 FIXME("Unhandled image %p.\n", image);
2563 static void STDMETHODCALLTYPE d2d_device_context_DrawGdiMetafile(ID2D1DeviceContext1 *iface,
2564 ID2D1GdiMetafile *metafile, const D2D1_POINT_2F *target_offset)
2566 FIXME("iface %p, metafile %p, target_offset %s stub!\n",
2567 iface, metafile, debug_d2d_point_2f(target_offset));
2570 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_DrawBitmap(ID2D1DeviceContext1 *iface,
2571 ID2D1Bitmap *bitmap, const D2D1_RECT_F *dst_rect, float opacity, D2D1_INTERPOLATION_MODE interpolation_mode,
2572 const D2D1_RECT_F *src_rect, const D2D1_MATRIX_4X4_F *perspective_transform)
2574 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2576 TRACE("iface %p, bitmap %p, dst_rect %s, opacity %.8e, interpolation_mode %#x, "
2577 "src_rect %s, perspective_transform %p.\n",
2578 iface, bitmap, debug_d2d_rect_f(dst_rect), opacity, interpolation_mode,
2579 debug_d2d_rect_f(src_rect), perspective_transform);
2581 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2583 d2d_command_list_draw_bitmap(context->target.command_list, bitmap, dst_rect, opacity, interpolation_mode,
2584 src_rect, perspective_transform);
2586 else
2588 d2d_device_context_draw_bitmap(context, bitmap, dst_rect, opacity, interpolation_mode, src_rect,
2589 NULL, perspective_transform);
2593 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_PushLayer(ID2D1DeviceContext1 *iface,
2594 const D2D1_LAYER_PARAMETERS1 *layer_parameters, ID2D1Layer *layer)
2596 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2598 FIXME("iface %p, layer_parameters %p, layer %p stub!\n", iface, layer_parameters, layer);
2600 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2601 d2d_command_list_push_layer(context->target.command_list, context, layer_parameters, layer);
2604 static HRESULT STDMETHODCALLTYPE d2d_device_context_InvalidateEffectInputRectangle(ID2D1DeviceContext1 *iface,
2605 ID2D1Effect *effect, UINT32 input, const D2D1_RECT_F *input_rect)
2607 FIXME("iface %p, effect %p, input %u, input_rect %s stub!\n",
2608 iface, effect, input, debug_d2d_rect_f(input_rect));
2610 return E_NOTIMPL;
2613 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetEffectInvalidRectangleCount(ID2D1DeviceContext1 *iface,
2614 ID2D1Effect *effect, UINT32 *rect_count)
2616 FIXME("iface %p, effect %p, rect_count %p stub!\n", iface, effect, rect_count);
2618 return E_NOTIMPL;
2621 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetEffectInvalidRectangles(ID2D1DeviceContext1 *iface,
2622 ID2D1Effect *effect, D2D1_RECT_F *rectangles, UINT32 rect_count)
2624 FIXME("iface %p, effect %p, rectangles %p, rect_count %u stub!\n", iface, effect, rectangles, rect_count);
2626 return E_NOTIMPL;
2629 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetEffectRequiredInputRectangles(ID2D1DeviceContext1 *iface,
2630 ID2D1Effect *effect, const D2D1_RECT_F *image_rect, const D2D1_EFFECT_INPUT_DESCRIPTION *desc,
2631 D2D1_RECT_F *input_rect, UINT32 input_count)
2633 FIXME("iface %p, effect %p, image_rect %s, desc %p, input_rect %p, input_count %u stub!\n",
2634 iface, effect, debug_d2d_rect_f(image_rect), desc, input_rect, input_count);
2636 return E_NOTIMPL;
2639 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_FillOpacityMask(ID2D1DeviceContext1 *iface,
2640 ID2D1Bitmap *mask, ID2D1Brush *brush, const D2D1_RECT_F *dst_rect, const D2D1_RECT_F *src_rect)
2642 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2644 FIXME("iface %p, mask %p, brush %p, dst_rect %s, src_rect %s stub!\n",
2645 iface, mask, brush, debug_d2d_rect_f(dst_rect), debug_d2d_rect_f(src_rect));
2647 if (FAILED(context->error.code))
2648 return;
2650 if (context->drawing_state.antialiasMode != D2D1_ANTIALIAS_MODE_ALIASED)
2652 d2d_device_context_set_error(context, D2DERR_WRONG_STATE);
2653 return;
2656 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2657 d2d_command_list_fill_opacity_mask(context->target.command_list, context, mask, brush, dst_rect, src_rect);
2660 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateFilledGeometryRealization(ID2D1DeviceContext1 *iface,
2661 ID2D1Geometry *geometry, float tolerance, ID2D1GeometryRealization **realization)
2663 FIXME("iface %p, geometry %p, tolerance %.8e, realization %p stub!\n", iface, geometry, tolerance,
2664 realization);
2666 return E_NOTIMPL;
2669 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateStrokedGeometryRealization(ID2D1DeviceContext1 *iface,
2670 ID2D1Geometry *geometry, float tolerance, float stroke_width, ID2D1StrokeStyle *stroke_style,
2671 ID2D1GeometryRealization **realization)
2673 FIXME("iface %p, geometry %p, tolerance %.8e, stroke_width %.8e, stroke_style %p, realization %p stub!\n",
2674 iface, geometry, tolerance, stroke_width, stroke_style, realization);
2676 return E_NOTIMPL;
2679 static void STDMETHODCALLTYPE d2d_device_context_DrawGeometryRealization(ID2D1DeviceContext1 *iface,
2680 ID2D1GeometryRealization *realization, ID2D1Brush *brush)
2682 FIXME("iface %p, realization %p, brush %p stub!\n", iface, realization, brush);
2685 static const struct ID2D1DeviceContext1Vtbl d2d_device_context_vtbl =
2687 d2d_device_context_QueryInterface,
2688 d2d_device_context_AddRef,
2689 d2d_device_context_Release,
2690 d2d_device_context_GetFactory,
2691 d2d_device_context_CreateBitmap,
2692 d2d_device_context_CreateBitmapFromWicBitmap,
2693 d2d_device_context_CreateSharedBitmap,
2694 d2d_device_context_CreateBitmapBrush,
2695 d2d_device_context_CreateSolidColorBrush,
2696 d2d_device_context_CreateGradientStopCollection,
2697 d2d_device_context_CreateLinearGradientBrush,
2698 d2d_device_context_CreateRadialGradientBrush,
2699 d2d_device_context_CreateCompatibleRenderTarget,
2700 d2d_device_context_CreateLayer,
2701 d2d_device_context_CreateMesh,
2702 d2d_device_context_DrawLine,
2703 d2d_device_context_DrawRectangle,
2704 d2d_device_context_FillRectangle,
2705 d2d_device_context_DrawRoundedRectangle,
2706 d2d_device_context_FillRoundedRectangle,
2707 d2d_device_context_DrawEllipse,
2708 d2d_device_context_FillEllipse,
2709 d2d_device_context_DrawGeometry,
2710 d2d_device_context_FillGeometry,
2711 d2d_device_context_FillMesh,
2712 d2d_device_context_FillOpacityMask,
2713 d2d_device_context_DrawBitmap,
2714 d2d_device_context_DrawText,
2715 d2d_device_context_DrawTextLayout,
2716 d2d_device_context_DrawGlyphRun,
2717 d2d_device_context_SetTransform,
2718 d2d_device_context_GetTransform,
2719 d2d_device_context_SetAntialiasMode,
2720 d2d_device_context_GetAntialiasMode,
2721 d2d_device_context_SetTextAntialiasMode,
2722 d2d_device_context_GetTextAntialiasMode,
2723 d2d_device_context_SetTextRenderingParams,
2724 d2d_device_context_GetTextRenderingParams,
2725 d2d_device_context_SetTags,
2726 d2d_device_context_GetTags,
2727 d2d_device_context_PushLayer,
2728 d2d_device_context_PopLayer,
2729 d2d_device_context_Flush,
2730 d2d_device_context_SaveDrawingState,
2731 d2d_device_context_RestoreDrawingState,
2732 d2d_device_context_PushAxisAlignedClip,
2733 d2d_device_context_PopAxisAlignedClip,
2734 d2d_device_context_Clear,
2735 d2d_device_context_BeginDraw,
2736 d2d_device_context_EndDraw,
2737 d2d_device_context_GetPixelFormat,
2738 d2d_device_context_SetDpi,
2739 d2d_device_context_GetDpi,
2740 d2d_device_context_GetSize,
2741 d2d_device_context_GetPixelSize,
2742 d2d_device_context_GetMaximumBitmapSize,
2743 d2d_device_context_IsSupported,
2744 d2d_device_context_ID2D1DeviceContext_CreateBitmap,
2745 d2d_device_context_ID2D1DeviceContext_CreateBitmapFromWicBitmap,
2746 d2d_device_context_CreateColorContext,
2747 d2d_device_context_CreateColorContextFromFilename,
2748 d2d_device_context_CreateColorContextFromWicColorContext,
2749 d2d_device_context_CreateBitmapFromDxgiSurface,
2750 d2d_device_context_CreateEffect,
2751 d2d_device_context_ID2D1DeviceContext_CreateGradientStopCollection,
2752 d2d_device_context_CreateImageBrush,
2753 d2d_device_context_ID2D1DeviceContext_CreateBitmapBrush,
2754 d2d_device_context_CreateCommandList,
2755 d2d_device_context_IsDxgiFormatSupported,
2756 d2d_device_context_IsBufferPrecisionSupported,
2757 d2d_device_context_GetImageLocalBounds,
2758 d2d_device_context_GetImageWorldBounds,
2759 d2d_device_context_GetGlyphRunWorldBounds,
2760 d2d_device_context_GetDevice,
2761 d2d_device_context_SetTarget,
2762 d2d_device_context_GetTarget,
2763 d2d_device_context_SetRenderingControls,
2764 d2d_device_context_GetRenderingControls,
2765 d2d_device_context_SetPrimitiveBlend,
2766 d2d_device_context_GetPrimitiveBlend,
2767 d2d_device_context_SetUnitMode,
2768 d2d_device_context_GetUnitMode,
2769 d2d_device_context_ID2D1DeviceContext_DrawGlyphRun,
2770 d2d_device_context_DrawImage,
2771 d2d_device_context_DrawGdiMetafile,
2772 d2d_device_context_ID2D1DeviceContext_DrawBitmap,
2773 d2d_device_context_ID2D1DeviceContext_PushLayer,
2774 d2d_device_context_InvalidateEffectInputRectangle,
2775 d2d_device_context_GetEffectInvalidRectangleCount,
2776 d2d_device_context_GetEffectInvalidRectangles,
2777 d2d_device_context_GetEffectRequiredInputRectangles,
2778 d2d_device_context_ID2D1DeviceContext_FillOpacityMask,
2779 d2d_device_context_CreateFilledGeometryRealization,
2780 d2d_device_context_CreateStrokedGeometryRealization,
2781 d2d_device_context_DrawGeometryRealization,
2784 static inline struct d2d_device_context *impl_from_IDWriteTextRenderer(IDWriteTextRenderer *iface)
2786 return CONTAINING_RECORD(iface, struct d2d_device_context, IDWriteTextRenderer_iface);
2789 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_QueryInterface(IDWriteTextRenderer *iface, REFIID iid, void **out)
2791 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
2793 if (IsEqualGUID(iid, &IID_IDWriteTextRenderer)
2794 || IsEqualGUID(iid, &IID_IDWritePixelSnapping)
2795 || IsEqualGUID(iid, &IID_IUnknown))
2797 IDWriteTextRenderer_AddRef(iface);
2798 *out = iface;
2799 return S_OK;
2802 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2804 *out = NULL;
2805 return E_NOINTERFACE;
2808 static ULONG STDMETHODCALLTYPE d2d_text_renderer_AddRef(IDWriteTextRenderer *iface)
2810 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
2812 TRACE("iface %p.\n", iface);
2814 return d2d_device_context_AddRef(&render_target->ID2D1DeviceContext1_iface);
2817 static ULONG STDMETHODCALLTYPE d2d_text_renderer_Release(IDWriteTextRenderer *iface)
2819 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
2821 TRACE("iface %p.\n", iface);
2823 return d2d_device_context_Release(&render_target->ID2D1DeviceContext1_iface);
2826 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
2827 void *ctx, BOOL *disabled)
2829 struct d2d_draw_text_layout_ctx *context = ctx;
2831 TRACE("iface %p, ctx %p, disabled %p.\n", iface, ctx, disabled);
2833 *disabled = context->options & D2D1_DRAW_TEXT_OPTIONS_NO_SNAP;
2835 return S_OK;
2838 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetCurrentTransform(IDWriteTextRenderer *iface,
2839 void *ctx, DWRITE_MATRIX *transform)
2841 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
2843 TRACE("iface %p, ctx %p, transform %p.\n", iface, ctx, transform);
2845 d2d_device_context_GetTransform(&render_target->ID2D1DeviceContext1_iface, (D2D1_MATRIX_3X2_F *)transform);
2847 return S_OK;
2850 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetPixelsPerDip(IDWriteTextRenderer *iface, void *ctx, float *ppd)
2852 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
2854 TRACE("iface %p, ctx %p, ppd %p.\n", iface, ctx, ppd);
2856 *ppd = render_target->desc.dpiY / 96.0f;
2858 return S_OK;
2861 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawGlyphRun(IDWriteTextRenderer *iface, void *ctx,
2862 float baseline_origin_x, float baseline_origin_y, DWRITE_MEASURING_MODE measuring_mode,
2863 const DWRITE_GLYPH_RUN *glyph_run, const DWRITE_GLYPH_RUN_DESCRIPTION *glyph_run_desc, IUnknown *effect)
2865 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
2866 D2D1_POINT_2F baseline_origin = {baseline_origin_x, baseline_origin_y};
2867 struct d2d_draw_text_layout_ctx *context = ctx;
2868 BOOL color_font = FALSE;
2869 ID2D1Brush *brush;
2871 TRACE("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, "
2872 "measuring_mode %#x, glyph_run %p, glyph_run_desc %p, effect %p.\n",
2873 iface, ctx, baseline_origin_x, baseline_origin_y,
2874 measuring_mode, glyph_run, glyph_run_desc, effect);
2876 if (context->options & ~(D2D1_DRAW_TEXT_OPTIONS_NO_SNAP | D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT))
2877 FIXME("Ignoring options %#x.\n", context->options);
2879 brush = d2d_draw_get_text_brush(context, effect);
2881 TRACE("%s\n", debugstr_wn(glyph_run_desc->string, glyph_run_desc->stringLength));
2883 if (context->options & D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT)
2885 IDWriteFontFace2 *fontface;
2887 if (SUCCEEDED(IDWriteFontFace_QueryInterface(glyph_run->fontFace,
2888 &IID_IDWriteFontFace2, (void **)&fontface)))
2890 color_font = IDWriteFontFace2_IsColorFont(fontface);
2891 IDWriteFontFace2_Release(fontface);
2895 if (color_font)
2897 IDWriteColorGlyphRunEnumerator *layers;
2898 IDWriteFactory2 *dwrite_factory;
2899 HRESULT hr;
2901 if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory2,
2902 (IUnknown **)&dwrite_factory)))
2904 ERR("Failed to create dwrite factory, hr %#lx.\n", hr);
2905 ID2D1Brush_Release(brush);
2906 return hr;
2909 hr = IDWriteFactory2_TranslateColorGlyphRun(dwrite_factory, baseline_origin_x, baseline_origin_y,
2910 glyph_run, glyph_run_desc, measuring_mode, (DWRITE_MATRIX *)&render_target->drawing_state.transform, 0, &layers);
2911 IDWriteFactory2_Release(dwrite_factory);
2912 if (FAILED(hr))
2914 ERR("Failed to create colour glyph run enumerator, hr %#lx.\n", hr);
2915 ID2D1Brush_Release(brush);
2916 return hr;
2919 for (;;)
2921 const DWRITE_COLOR_GLYPH_RUN *color_run;
2922 ID2D1Brush *color_brush;
2923 D2D1_POINT_2F origin;
2924 BOOL has_run = FALSE;
2926 if (FAILED(hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &has_run)))
2928 ERR("Failed to switch colour glyph layer, hr %#lx.\n", hr);
2929 break;
2932 if (!has_run)
2933 break;
2935 if (FAILED(hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &color_run)))
2937 ERR("Failed to get current colour run, hr %#lx.\n", hr);
2938 break;
2941 if (color_run->paletteIndex == 0xffff)
2942 color_brush = brush;
2943 else
2945 if (FAILED(hr = d2d_device_context_CreateSolidColorBrush(&render_target->ID2D1DeviceContext1_iface,
2946 &color_run->runColor, NULL, (ID2D1SolidColorBrush **)&color_brush)))
2948 ERR("Failed to create solid colour brush, hr %#lx.\n", hr);
2949 break;
2953 origin.x = color_run->baselineOriginX;
2954 origin.y = color_run->baselineOriginY;
2955 d2d_device_context_draw_glyph_run(render_target, origin, &color_run->glyphRun,
2956 color_run->glyphRunDescription, color_brush, measuring_mode);
2958 if (color_brush != brush)
2959 ID2D1Brush_Release(color_brush);
2962 IDWriteColorGlyphRunEnumerator_Release(layers);
2964 else
2965 d2d_device_context_draw_glyph_run(render_target, baseline_origin, glyph_run, glyph_run_desc,
2966 brush, measuring_mode);
2968 ID2D1Brush_Release(brush);
2970 return S_OK;
2973 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawUnderline(IDWriteTextRenderer *iface, void *ctx,
2974 float baseline_origin_x, float baseline_origin_y, const DWRITE_UNDERLINE *underline, IUnknown *effect)
2976 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
2977 const D2D1_MATRIX_3X2_F *m = &render_target->drawing_state.transform;
2978 struct d2d_draw_text_layout_ctx *context = ctx;
2979 D2D1_ANTIALIAS_MODE prev_antialias_mode;
2980 D2D1_POINT_2F start, end;
2981 ID2D1Brush *brush;
2982 float thickness;
2984 TRACE("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, underline %p, effect %p\n",
2985 iface, ctx, baseline_origin_x, baseline_origin_y, underline, effect);
2987 /* minimal thickness in DIPs that will result in at least 1 pixel thick line */
2988 thickness = max(96.0f / (render_target->desc.dpiY * sqrtf(m->_21 * m->_21 + m->_22 * m->_22)),
2989 underline->thickness);
2991 brush = d2d_draw_get_text_brush(context, effect);
2993 start.x = baseline_origin_x;
2994 start.y = baseline_origin_y + underline->offset + thickness / 2.0f;
2995 end.x = start.x + underline->width;
2996 end.y = start.y;
2997 prev_antialias_mode = d2d_device_context_set_aa_mode_from_text_aa_mode(render_target);
2998 d2d_device_context_DrawLine(&render_target->ID2D1DeviceContext1_iface, start, end, brush, thickness, NULL);
2999 render_target->drawing_state.antialiasMode = prev_antialias_mode;
3001 ID2D1Brush_Release(brush);
3003 return S_OK;
3006 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawStrikethrough(IDWriteTextRenderer *iface, void *ctx,
3007 float baseline_origin_x, float baseline_origin_y, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *effect)
3009 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
3010 const D2D1_MATRIX_3X2_F *m = &render_target->drawing_state.transform;
3011 struct d2d_draw_text_layout_ctx *context = ctx;
3012 D2D1_ANTIALIAS_MODE prev_antialias_mode;
3013 D2D1_POINT_2F start, end;
3014 ID2D1Brush *brush;
3015 float thickness;
3017 TRACE("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, strikethrough %p, effect %p.\n",
3018 iface, ctx, baseline_origin_x, baseline_origin_y, strikethrough, effect);
3020 /* minimal thickness in DIPs that will result in at least 1 pixel thick line */
3021 thickness = max(96.0f / (render_target->desc.dpiY * sqrtf(m->_21 * m->_21 + m->_22 * m->_22)),
3022 strikethrough->thickness);
3024 brush = d2d_draw_get_text_brush(context, effect);
3026 start.x = baseline_origin_x;
3027 start.y = baseline_origin_y + strikethrough->offset + thickness / 2.0f;
3028 end.x = start.x + strikethrough->width;
3029 end.y = start.y;
3030 prev_antialias_mode = d2d_device_context_set_aa_mode_from_text_aa_mode(render_target);
3031 d2d_device_context_DrawLine(&render_target->ID2D1DeviceContext1_iface, start, end, brush, thickness, NULL);
3032 render_target->drawing_state.antialiasMode = prev_antialias_mode;
3034 ID2D1Brush_Release(brush);
3036 return S_OK;
3039 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawInlineObject(IDWriteTextRenderer *iface, void *ctx,
3040 float origin_x, float origin_y, IDWriteInlineObject *object, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
3042 struct d2d_draw_text_layout_ctx *context = ctx;
3043 ID2D1Brush *brush;
3044 HRESULT hr;
3046 TRACE("iface %p, ctx %p, origin_x %.8e, origin_y %.8e, object %p, is_sideways %#x, is_rtl %#x, effect %p.\n",
3047 iface, ctx, origin_x, origin_y, object, is_sideways, is_rtl, effect);
3049 /* Inline objects may not pass effects all the way down, when using layout object internally for example.
3050 This is how default trimming sign object in DirectWrite works - it does not use effect passed to Draw(),
3051 and resulting DrawGlyphRun() is always called with NULL effect, however original effect is used and correct
3052 brush is selected at Direct2D level. */
3053 brush = context->brush;
3054 context->brush = d2d_draw_get_text_brush(context, effect);
3056 hr = IDWriteInlineObject_Draw(object, ctx, iface, origin_x, origin_y, is_sideways, is_rtl, effect);
3058 ID2D1Brush_Release(context->brush);
3059 context->brush = brush;
3061 return hr;
3064 static const struct IDWriteTextRendererVtbl d2d_text_renderer_vtbl =
3066 d2d_text_renderer_QueryInterface,
3067 d2d_text_renderer_AddRef,
3068 d2d_text_renderer_Release,
3069 d2d_text_renderer_IsPixelSnappingDisabled,
3070 d2d_text_renderer_GetCurrentTransform,
3071 d2d_text_renderer_GetPixelsPerDip,
3072 d2d_text_renderer_DrawGlyphRun,
3073 d2d_text_renderer_DrawUnderline,
3074 d2d_text_renderer_DrawStrikethrough,
3075 d2d_text_renderer_DrawInlineObject,
3078 static inline struct d2d_device_context *impl_from_ID2D1GdiInteropRenderTarget(ID2D1GdiInteropRenderTarget *iface)
3080 return CONTAINING_RECORD(iface, struct d2d_device_context, ID2D1GdiInteropRenderTarget_iface);
3083 static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_QueryInterface(ID2D1GdiInteropRenderTarget *iface,
3084 REFIID iid, void **out)
3086 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3088 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3090 return IUnknown_QueryInterface(render_target->outer_unknown, iid, out);
3093 static ULONG STDMETHODCALLTYPE d2d_gdi_interop_render_target_AddRef(ID2D1GdiInteropRenderTarget *iface)
3095 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3097 TRACE("iface %p.\n", iface);
3099 return IUnknown_AddRef(render_target->outer_unknown);
3102 static ULONG STDMETHODCALLTYPE d2d_gdi_interop_render_target_Release(ID2D1GdiInteropRenderTarget *iface)
3104 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3106 TRACE("iface %p.\n", iface);
3108 return IUnknown_Release(render_target->outer_unknown);
3111 static HRESULT d2d_gdi_interop_get_surface(struct d2d_device_context *context, IDXGISurface1 **surface)
3113 ID3D11Resource *resource;
3114 HRESULT hr;
3116 if (context->target.type != D2D_TARGET_BITMAP)
3118 FIXME("Unimplemented for target type %u.\n", context->target.type);
3119 return E_NOTIMPL;
3122 if (!(context->target.bitmap->options & D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE))
3123 return D2DERR_TARGET_NOT_GDI_COMPATIBLE;
3125 ID3D11RenderTargetView_GetResource(context->target.bitmap->rtv, &resource);
3126 hr = ID3D11Resource_QueryInterface(resource, &IID_IDXGISurface1, (void **)surface);
3127 ID3D11Resource_Release(resource);
3128 if (FAILED(hr))
3130 *surface = NULL;
3131 WARN("Failed to get DXGI surface, %#lx.\n", hr);
3132 return hr;
3135 return hr;
3138 static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_GetDC(ID2D1GdiInteropRenderTarget *iface,
3139 D2D1_DC_INITIALIZE_MODE mode, HDC *dc)
3141 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3142 IDXGISurface1 *surface;
3143 HRESULT hr;
3145 TRACE("iface %p, mode %d, dc %p.\n", iface, mode, dc);
3147 *dc = NULL;
3149 if (render_target->target.hdc)
3150 return D2DERR_WRONG_STATE;
3152 if (FAILED(hr = d2d_gdi_interop_get_surface(render_target, &surface)))
3153 return hr;
3155 hr = IDXGISurface1_GetDC(surface, mode != D2D1_DC_INITIALIZE_MODE_COPY, &render_target->target.hdc);
3156 IDXGISurface1_Release(surface);
3158 if (SUCCEEDED(hr))
3159 *dc = render_target->target.hdc;
3161 return hr;
3164 static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_ReleaseDC(ID2D1GdiInteropRenderTarget *iface,
3165 const RECT *update)
3167 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3168 IDXGISurface1 *surface;
3169 RECT update_rect;
3170 HRESULT hr;
3172 TRACE("iface %p, update rect %s.\n", iface, wine_dbgstr_rect(update));
3174 if (!render_target->target.hdc)
3175 return D2DERR_WRONG_STATE;
3177 if (FAILED(hr = d2d_gdi_interop_get_surface(render_target, &surface)))
3178 return hr;
3180 render_target->target.hdc = NULL;
3181 if (update)
3182 update_rect = *update;
3183 hr = IDXGISurface1_ReleaseDC(surface, update ? &update_rect : NULL);
3184 IDXGISurface1_Release(surface);
3186 return hr;
3189 static const struct ID2D1GdiInteropRenderTargetVtbl d2d_gdi_interop_render_target_vtbl =
3191 d2d_gdi_interop_render_target_QueryInterface,
3192 d2d_gdi_interop_render_target_AddRef,
3193 d2d_gdi_interop_render_target_Release,
3194 d2d_gdi_interop_render_target_GetDC,
3195 d2d_gdi_interop_render_target_ReleaseDC,
3198 static HRESULT d2d_device_context_init(struct d2d_device_context *render_target,
3199 struct d2d_device *device, IUnknown *outer_unknown, const struct d2d_device_context_ops *ops)
3201 D3D11_SUBRESOURCE_DATA buffer_data;
3202 struct d2d_device *device_impl;
3203 IDWriteFactory *dwrite_factory;
3204 D3D11_RASTERIZER_DESC rs_desc;
3205 D3D11_BUFFER_DESC buffer_desc;
3206 struct d2d_factory *factory;
3207 ID3D10Blob *compiled;
3208 unsigned int i;
3209 HRESULT hr;
3211 static const D3D11_INPUT_ELEMENT_DESC il_desc_outline[] =
3213 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
3214 {"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
3215 {"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0},
3217 static const D3D11_INPUT_ELEMENT_DESC il_desc_curve_outline[] =
3219 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
3220 {"P", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
3221 {"P", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0},
3222 {"P", 2, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
3223 {"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0},
3224 {"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 40, D3D11_INPUT_PER_VERTEX_DATA, 0},
3226 static const D3D11_INPUT_ELEMENT_DESC il_desc_triangle[] =
3228 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
3230 static const D3D11_INPUT_ELEMENT_DESC il_desc_curve[] =
3232 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
3233 {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
3235 static const char vs_code_outline[] =
3236 "float3x2 transform_geometry;\n"
3237 "float stroke_width;\n"
3238 "float4 transform_rtx;\n"
3239 "float4 transform_rty;\n"
3240 "\n"
3241 "struct output\n"
3242 "{\n"
3243 " float2 p : WORLD_POSITION;\n"
3244 " float4 b : BEZIER;\n"
3245 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3246 " float4 position : SV_POSITION;\n"
3247 "};\n"
3248 "\n"
3249 "/* The lines PₚᵣₑᵥP₀ and P₀Pₙₑₓₜ, both offset by ±½w, intersect each other at:\n"
3250 " *\n"
3251 " * Pᵢ = P₀ ± w · ½q⃑ᵢ.\n"
3252 " *\n"
3253 " * Where:\n"
3254 " *\n"
3255 " * q⃑ᵢ = q̂ₚᵣₑᵥ⊥ + tan(½θ) · -q̂ₚᵣₑᵥ\n"
3256 " * θ = ∠PₚᵣₑᵥP₀Pₙₑₓₜ\n"
3257 " * q⃑ₚᵣₑᵥ = P₀ - Pₚᵣₑᵥ */\n"
3258 "void main(float2 position : POSITION, float2 prev : PREV, float2 next : NEXT, out struct output o)\n"
3259 "{\n"
3260 " float2 q_prev, q_next, v_p, q_i;\n"
3261 " float2x2 geom;\n"
3262 " float l;\n"
3263 "\n"
3264 " o.stroke_transform = float2x2(transform_rtx.xy, transform_rty.xy) * stroke_width * 0.5f;\n"
3265 "\n"
3266 " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n"
3267 " q_prev = normalize(mul(geom, prev));\n"
3268 " q_next = normalize(mul(geom, next));\n"
3269 "\n"
3270 " /* tan(½θ) = sin(θ) / (1 + cos(θ))\n"
3271 " * = (q̂ₚᵣₑᵥ⊥ · q̂ₙₑₓₜ) / (1 + (q̂ₚᵣₑᵥ · q̂ₙₑₓₜ)) */\n"
3272 " v_p = float2(-q_prev.y, q_prev.x);\n"
3273 " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n"
3274 " q_i = l * q_prev + v_p;\n"
3275 "\n"
3276 " o.b = float4(0.0, 0.0, 0.0, 0.0);\n"
3277 "\n"
3278 " o.p = mul(float3(position, 1.0f), transform_geometry) + stroke_width * 0.5f * q_i;\n"
3279 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3280 " * float2(transform_rtx.w, transform_rty.w);\n"
3281 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3282 "}\n";
3283 /* ⎡p0.x p0.y 1⎤
3284 * A = ⎢p1.x p1.y 1⎥
3285 * ⎣p2.x p2.y 1⎦
3287 * ⎡0 0⎤
3288 * B = ⎢½ 0⎥
3289 * ⎣1 1⎦
3291 * A' = ⎡p1.x-p0.x p1.y-p0.y⎤
3292 * ⎣p2.x-p0.x p2.y-p0.y⎦
3294 * B' = ⎡½ 0⎤
3295 * ⎣1 1⎦
3297 * A'T = B'
3298 * T = A'⁻¹B'
3300 static const char vs_code_bezier_outline[] =
3301 "float3x2 transform_geometry;\n"
3302 "float stroke_width;\n"
3303 "float4 transform_rtx;\n"
3304 "float4 transform_rty;\n"
3305 "\n"
3306 "struct output\n"
3307 "{\n"
3308 " float2 p : WORLD_POSITION;\n"
3309 " float4 b : BEZIER;\n"
3310 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3311 " float4 position : SV_POSITION;\n"
3312 "};\n"
3313 "\n"
3314 "void main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,\n"
3315 " float2 prev : PREV, float2 next : NEXT, out struct output o)\n"
3316 "{\n"
3317 " float2 q_prev, q_next, v_p, q_i, p;\n"
3318 " float2x2 geom, rt;\n"
3319 " float l;\n"
3320 "\n"
3321 " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n"
3322 " rt = float2x2(transform_rtx.xy, transform_rty.xy);\n"
3323 " o.stroke_transform = rt * stroke_width * 0.5f;\n"
3324 "\n"
3325 " p = mul(geom, position);\n"
3326 " p0 = mul(geom, p0);\n"
3327 " p1 = mul(geom, p1);\n"
3328 " p2 = mul(geom, p2);\n"
3329 "\n"
3330 " p -= p0;\n"
3331 " p1 -= p0;\n"
3332 " p2 -= p0;\n"
3333 "\n"
3334 " q_prev = normalize(mul(geom, prev));\n"
3335 " q_next = normalize(mul(geom, next));\n"
3336 "\n"
3337 " v_p = float2(-q_prev.y, q_prev.x);\n"
3338 " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n"
3339 " q_i = l * q_prev + v_p;\n"
3340 " p += 0.5f * stroke_width * q_i;\n"
3341 "\n"
3342 " v_p = mul(rt, p2);\n"
3343 " v_p = normalize(float2(-v_p.y, v_p.x));\n"
3344 " if (abs(dot(mul(rt, p1), v_p)) < 1.0f)\n"
3345 " {\n"
3346 " o.b.xzw = float3(0.0f, 0.0f, 0.0f);\n"
3347 " o.b.y = dot(mul(rt, p), v_p);\n"
3348 " }\n"
3349 " else\n"
3350 " {\n"
3351 " o.b.zw = sign(dot(mul(rt, p1), v_p)) * v_p;\n"
3352 " v_p = -float2(-p.y, p.x) / dot(float2(-p1.y, p1.x), p2);\n"
3353 " o.b.x = dot(v_p, p1 - 0.5f * p2);\n"
3354 " o.b.y = dot(v_p, p1);\n"
3355 " }\n"
3356 "\n"
3357 " o.p = mul(float3(position, 1.0f), transform_geometry) + 0.5f * stroke_width * q_i;\n"
3358 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3359 " * float2(transform_rtx.w, transform_rty.w);\n"
3360 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3361 "}\n";
3362 /* ⎡p0.x p0.y 1⎤
3363 * A = ⎢p1.x p1.y 1⎥
3364 * ⎣p2.x p2.y 1⎦
3366 * ⎡1 0⎤
3367 * B = ⎢1 1⎥
3368 * ⎣0 1⎦
3370 * A' = ⎡p1.x-p0.x p1.y-p0.y⎤
3371 * ⎣p2.x-p0.x p2.y-p0.y⎦
3373 * B' = ⎡ 0 1⎤
3374 * ⎣-1 1⎦
3376 * A'T = B'
3377 * T = A'⁻¹B' = (B'⁻¹A')⁻¹
3379 static const char vs_code_arc_outline[] =
3380 "float3x2 transform_geometry;\n"
3381 "float stroke_width;\n"
3382 "float4 transform_rtx;\n"
3383 "float4 transform_rty;\n"
3384 "\n"
3385 "struct output\n"
3386 "{\n"
3387 " float2 p : WORLD_POSITION;\n"
3388 " float4 b : BEZIER;\n"
3389 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3390 " float4 position : SV_POSITION;\n"
3391 "};\n"
3392 "\n"
3393 "void main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,\n"
3394 " float2 prev : PREV, float2 next : NEXT, out struct output o)\n"
3395 "{\n"
3396 " float2 q_prev, q_next, v_p, q_i, p;\n"
3397 " float2x2 geom, rt, p_inv;\n"
3398 " float l;\n"
3399 " float a;\n"
3400 " float2 bc;\n"
3401 "\n"
3402 " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n"
3403 " rt = float2x2(transform_rtx.xy, transform_rty.xy);\n"
3404 " o.stroke_transform = rt * stroke_width * 0.5f;\n"
3405 "\n"
3406 " p = mul(geom, position);\n"
3407 " p0 = mul(geom, p0);\n"
3408 " p1 = mul(geom, p1);\n"
3409 " p2 = mul(geom, p2);\n"
3410 "\n"
3411 " p -= p0;\n"
3412 " p1 -= p0;\n"
3413 " p2 -= p0;\n"
3414 "\n"
3415 " q_prev = normalize(mul(geom, prev));\n"
3416 " q_next = normalize(mul(geom, next));\n"
3417 "\n"
3418 " v_p = float2(-q_prev.y, q_prev.x);\n"
3419 " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n"
3420 " q_i = l * q_prev + v_p;\n"
3421 " p += 0.5f * stroke_width * q_i;\n"
3422 "\n"
3423 " p_inv = float2x2(p1.y, -p1.x, p2.y - p1.y, p1.x - p2.x) / (p1.x * p2.y - p2.x * p1.y);\n"
3424 " o.b.xy = mul(p_inv, p) + float2(1.0f, 0.0f);\n"
3425 " o.b.zw = 0.0f;\n"
3426 "\n"
3427 " o.p = mul(float3(position, 1.0f), transform_geometry) + 0.5f * stroke_width * q_i;\n"
3428 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3429 " * float2(transform_rtx.w, transform_rty.w);\n"
3430 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3431 "}\n";
3432 static const char vs_code_triangle[] =
3433 "float3x2 transform_geometry;\n"
3434 "float4 transform_rtx;\n"
3435 "float4 transform_rty;\n"
3436 "\n"
3437 "struct output\n"
3438 "{\n"
3439 " float2 p : WORLD_POSITION;\n"
3440 " float4 b : BEZIER;\n"
3441 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3442 " float4 position : SV_POSITION;\n"
3443 "};\n"
3444 "\n"
3445 "void main(float2 position : POSITION, out struct output o)\n"
3446 "{\n"
3447 " o.p = mul(float3(position, 1.0f), transform_geometry);\n"
3448 " o.b = float4(1.0, 0.0, 1.0, 1.0);\n"
3449 " o.stroke_transform = float2x2(1.0, 0.0, 0.0, 1.0);\n"
3450 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3451 " * float2(transform_rtx.w, transform_rty.w);\n"
3452 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3453 "}\n";
3454 static const char vs_code_curve[] =
3455 "float3x2 transform_geometry;\n"
3456 "float4 transform_rtx;\n"
3457 "float4 transform_rty;\n"
3458 "\n"
3459 "struct output\n"
3460 "{\n"
3461 " float2 p : WORLD_POSITION;\n"
3462 " float4 b : BEZIER;\n"
3463 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3464 " float4 position : SV_POSITION;\n"
3465 "};\n"
3466 "\n"
3467 "void main(float2 position : POSITION, float3 texcoord : TEXCOORD0, out struct output o)\n"
3468 "{\n"
3469 " o.p = mul(float3(position, 1.0f), transform_geometry);\n"
3470 " o.b = float4(texcoord, 1.0);\n"
3471 " o.stroke_transform = float2x2(1.0, 0.0, 0.0, 1.0);\n"
3472 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3473 " * float2(transform_rtx.w, transform_rty.w);\n"
3474 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3475 "}\n";
3476 static const char ps_code[] =
3477 "#define BRUSH_TYPE_SOLID 0\n"
3478 "#define BRUSH_TYPE_LINEAR 1\n"
3479 "#define BRUSH_TYPE_RADIAL 2\n"
3480 "#define BRUSH_TYPE_BITMAP 3\n"
3481 "#define BRUSH_TYPE_COUNT 4\n"
3482 "\n"
3483 "bool outline;\n"
3484 "bool is_arc;\n"
3485 "struct brush\n"
3486 "{\n"
3487 " uint type;\n"
3488 " float opacity;\n"
3489 " float4 data[3];\n"
3490 "} colour_brush, opacity_brush;\n"
3491 "\n"
3492 "SamplerState s0, s1;\n"
3493 "Texture2D t0, t1;\n"
3494 "Buffer<float4> b0, b1;\n"
3495 "\n"
3496 "struct input\n"
3497 "{\n"
3498 " float2 p : WORLD_POSITION;\n"
3499 " float4 b : BEZIER;\n"
3500 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3501 "};\n"
3502 "\n"
3503 "float4 sample_gradient(Buffer<float4> gradient, uint stop_count, float position)\n"
3504 "{\n"
3505 " float4 c_low, c_high;\n"
3506 " float p_low, p_high;\n"
3507 " uint i;\n"
3508 "\n"
3509 " p_low = gradient.Load(0).x;\n"
3510 " c_low = gradient.Load(1);\n"
3511 " c_high = c_low;\n"
3512 "\n"
3513 " if (position < p_low)\n"
3514 " return c_low;\n"
3515 "\n"
3516 " for (i = 1; i < stop_count; ++i)\n"
3517 " {\n"
3518 " p_high = gradient.Load(i * 2).x;\n"
3519 " c_high = gradient.Load(i * 2 + 1);\n"
3520 "\n"
3521 " if (position >= p_low && position <= p_high)\n"
3522 " return lerp(c_low, c_high, (position - p_low) / (p_high - p_low));\n"
3523 "\n"
3524 " p_low = p_high;\n"
3525 " c_low = c_high;\n"
3526 " }\n"
3527 "\n"
3528 " return c_high;\n"
3529 "}\n"
3530 "\n"
3531 "float4 brush_linear(struct brush brush, Buffer<float4> gradient, float2 position)\n"
3532 "{\n"
3533 " float2 start, end, v_p, v_q;\n"
3534 " uint stop_count;\n"
3535 " float p;\n"
3536 "\n"
3537 " start = brush.data[0].xy;\n"
3538 " end = brush.data[0].zw;\n"
3539 " stop_count = asuint(brush.data[1].x);\n"
3540 "\n"
3541 " v_p = position - start;\n"
3542 " v_q = end - start;\n"
3543 " p = dot(v_q, v_p) / dot(v_q, v_q);\n"
3544 "\n"
3545 " return sample_gradient(gradient, stop_count, p);\n"
3546 "}\n"
3547 "\n"
3548 "float4 brush_radial(struct brush brush, Buffer<float4> gradient, float2 position)\n"
3549 "{\n"
3550 " float2 centre, offset, ra, rb, v_p, v_q, r;\n"
3551 " float b, c, l, t;\n"
3552 " uint stop_count;\n"
3553 "\n"
3554 " centre = brush.data[0].xy;\n"
3555 " offset = brush.data[0].zw;\n"
3556 " ra = brush.data[1].xy;\n"
3557 " rb = brush.data[1].zw;\n"
3558 " stop_count = asuint(brush.data[2].x);\n"
3559 "\n"
3560 " /* Project onto ra, rb. */\n"
3561 " r = float2(dot(ra, ra), dot(rb, rb));\n"
3562 " v_p = position - (centre + offset);\n"
3563 " v_p = float2(dot(v_p, ra), dot(v_p, rb)) / r;\n"
3564 " v_q = float2(dot(offset, ra), dot(offset, rb)) / r;\n"
3565 "\n"
3566 " /* ‖t·p̂ + q⃑‖ = 1\n"
3567 " * (t·p̂ + q⃑) · (t·p̂ + q⃑) = 1\n"
3568 " * t² + 2·(p̂·q⃑)·t + (q⃑·q⃑) = 1\n"
3569 " *\n"
3570 " * b = p̂·q⃑\n"
3571 " * c = q⃑·q⃑ - 1\n"
3572 " * t = -b + √(b² - c) */\n"
3573 " l = length(v_p);\n"
3574 " b = dot(v_p, v_q) / l;\n"
3575 " c = dot(v_q, v_q) - 1.0;\n"
3576 " t = -b + sqrt(b * b - c);\n"
3577 "\n"
3578 " return sample_gradient(gradient, stop_count, l / t);\n"
3579 "}\n"
3580 "\n"
3581 "float4 brush_bitmap(struct brush brush, Texture2D t, SamplerState s, float2 position)\n"
3582 "{\n"
3583 " float3 transform[2];\n"
3584 " bool ignore_alpha;\n"
3585 " float2 texcoord;\n"
3586 " float4 colour;\n"
3587 "\n"
3588 " transform[0] = brush.data[0].xyz;\n"
3589 " transform[1] = brush.data[1].xyz;\n"
3590 " ignore_alpha = asuint(brush.data[1].w);\n"
3591 "\n"
3592 " texcoord.x = dot(position.xy, transform[0].xy) + transform[0].z;\n"
3593 " texcoord.y = dot(position.xy, transform[1].xy) + transform[1].z;\n"
3594 " colour = t.Sample(s, texcoord);\n"
3595 " if (ignore_alpha)\n"
3596 " colour.a = 1.0;\n"
3597 " return colour;\n"
3598 "}\n"
3599 "\n"
3600 "float4 sample_brush(struct brush brush, Texture2D t, SamplerState s, Buffer<float4> b, float2 position)\n"
3601 "{\n"
3602 " if (brush.type == BRUSH_TYPE_SOLID)\n"
3603 " return brush.data[0] * brush.opacity;\n"
3604 " if (brush.type == BRUSH_TYPE_LINEAR)\n"
3605 " return brush_linear(brush, b, position) * brush.opacity;\n"
3606 " if (brush.type == BRUSH_TYPE_RADIAL)\n"
3607 " return brush_radial(brush, b, position) * brush.opacity;\n"
3608 " if (brush.type == BRUSH_TYPE_BITMAP)\n"
3609 " return brush_bitmap(brush, t, s, position) * brush.opacity;\n"
3610 " return float4(0.0, 0.0, 0.0, brush.opacity);\n"
3611 "}\n"
3612 "\n"
3613 "float4 main(struct input i) : SV_Target\n"
3614 "{\n"
3615 " float4 colour;\n"
3616 "\n"
3617 " colour = sample_brush(colour_brush, t0, s0, b0, i.p);\n"
3618 " if (opacity_brush.type < BRUSH_TYPE_COUNT)\n"
3619 " colour *= sample_brush(opacity_brush, t1, s1, b1, i.p).a;\n"
3620 "\n"
3621 " if (outline)\n"
3622 " {\n"
3623 " float2 du, dv, df;\n"
3624 " float4 uv;\n"
3625 "\n"
3626 " /* Evaluate the implicit form of the curve (u² - v = 0\n"
3627 " * for Béziers, u² + v² - 1 = 0 for arcs) in texture\n"
3628 " * space, using the screen-space partial derivatives\n"
3629 " * to convert the calculated distance to object space.\n"
3630 " *\n"
3631 " * d(x, y) = |f(x, y)| / ‖∇f(x, y)‖\n"
3632 " * = |f(x, y)| / √((∂f/∂x)² + (∂f/∂y)²)\n"
3633 " *\n"
3634 " * For Béziers:\n"
3635 " * f(x, y) = u(x, y)² - v(x, y)\n"
3636 " * ∂f/∂x = 2u · ∂u/∂x - ∂v/∂x\n"
3637 " * ∂f/∂y = 2u · ∂u/∂y - ∂v/∂y\n"
3638 " *\n"
3639 " * For arcs:\n"
3640 " * f(x, y) = u(x, y)² + v(x, y)² - 1\n"
3641 " * ∂f/∂x = 2u · ∂u/∂x + 2v · ∂v/∂x\n"
3642 " * ∂f/∂y = 2u · ∂u/∂y + 2v · ∂v/∂y */\n"
3643 " uv = i.b;\n"
3644 " du = float2(ddx(uv.x), ddy(uv.x));\n"
3645 " dv = float2(ddx(uv.y), ddy(uv.y));\n"
3646 "\n"
3647 " if (!is_arc)\n"
3648 " {\n"
3649 " df = 2.0f * uv.x * du - dv;\n"
3650 "\n"
3651 " clip(dot(df, uv.zw));\n"
3652 " clip(length(mul(i.stroke_transform, df)) - abs(uv.x * uv.x - uv.y));\n"
3653 " }\n"
3654 " else\n"
3655 " {\n"
3656 " df = 2.0f * uv.x * du + 2.0f * uv.y * dv;\n"
3657 "\n"
3658 " clip(dot(df, uv.zw));\n"
3659 " clip(length(mul(i.stroke_transform, df)) - abs(uv.x * uv.x + uv.y * uv.y - 1.0f));\n"
3660 " }\n"
3661 " }\n"
3662 " else\n"
3663 " {\n"
3664 " /* Evaluate the implicit form of the curve in texture space.\n"
3665 " * \"i.b.z\" determines which side of the curve is shaded. */\n"
3666 " if (!is_arc)\n"
3667 " {\n"
3668 " clip((i.b.x * i.b.x - i.b.y) * i.b.z);\n"
3669 " }\n"
3670 " else\n"
3671 " {\n"
3672 " clip((i.b.x * i.b.x + i.b.y * i.b.y - 1.0) * i.b.z);\n"
3673 " }\n"
3674 " }\n"
3675 "\n"
3676 " return colour;\n"
3677 "}\n";
3678 static const struct shape_info
3680 enum d2d_shape_type shape_type;
3681 const D3D11_INPUT_ELEMENT_DESC *il_desc;
3682 unsigned int il_element_count;
3683 const char *name;
3684 const char *vs_code;
3685 size_t vs_code_size;
3687 shape_info[] =
3689 {D2D_SHAPE_TYPE_OUTLINE, il_desc_outline, ARRAY_SIZE(il_desc_outline),
3690 "outline", vs_code_outline, sizeof(vs_code_outline) - 1},
3691 {D2D_SHAPE_TYPE_BEZIER_OUTLINE, il_desc_curve_outline, ARRAY_SIZE(il_desc_curve_outline),
3692 "bezier_outline", vs_code_bezier_outline, sizeof(vs_code_bezier_outline) - 1},
3693 {D2D_SHAPE_TYPE_ARC_OUTLINE, il_desc_curve_outline, ARRAY_SIZE(il_desc_curve_outline),
3694 "arc_outline", vs_code_arc_outline, sizeof(vs_code_arc_outline) - 1},
3695 {D2D_SHAPE_TYPE_TRIANGLE, il_desc_triangle, ARRAY_SIZE(il_desc_triangle),
3696 "triangle", vs_code_triangle, sizeof(vs_code_triangle) - 1},
3697 {D2D_SHAPE_TYPE_CURVE, il_desc_curve, ARRAY_SIZE(il_desc_curve),
3698 "curve", vs_code_curve, sizeof(vs_code_curve) - 1},
3700 static const struct
3702 float x, y;
3704 quad[] =
3706 {-1.0f, 1.0f},
3707 {-1.0f, -1.0f},
3708 { 1.0f, 1.0f},
3709 { 1.0f, -1.0f},
3711 static const UINT16 indices[] = {0, 1, 2, 2, 1, 3};
3712 static const D3D_FEATURE_LEVEL feature_levels = D3D_FEATURE_LEVEL_10_0;
3714 render_target->ID2D1DeviceContext1_iface.lpVtbl = &d2d_device_context_vtbl;
3715 render_target->ID2D1GdiInteropRenderTarget_iface.lpVtbl = &d2d_gdi_interop_render_target_vtbl;
3716 render_target->IDWriteTextRenderer_iface.lpVtbl = &d2d_text_renderer_vtbl;
3717 render_target->IUnknown_iface.lpVtbl = &d2d_device_context_inner_unknown_vtbl;
3718 render_target->refcount = 1;
3719 ID2D1Device1_GetFactory(&device->ID2D1Device1_iface, &render_target->factory);
3720 render_target->device = device;
3721 ID2D1Device1_AddRef(&render_target->device->ID2D1Device1_iface);
3723 factory = unsafe_impl_from_ID2D1Factory(render_target->factory);
3724 if (factory->factory_type == D2D1_FACTORY_TYPE_MULTI_THREADED)
3725 render_target->cs = &factory->cs;
3727 render_target->outer_unknown = outer_unknown ? outer_unknown : &render_target->IUnknown_iface;
3728 render_target->ops = ops;
3730 device_impl = unsafe_impl_from_ID2D1Device((ID2D1Device1 *)device);
3731 if (FAILED(hr = IDXGIDevice_QueryInterface(device_impl->dxgi_device,
3732 &IID_ID3D11Device1, (void **)&render_target->d3d_device)))
3734 WARN("Failed to query ID3D11Device1 interface, hr %#lx.\n", hr);
3735 goto err;
3738 if (FAILED(hr = ID3D11Device1_CreateDeviceContextState(render_target->d3d_device,
3739 0, &feature_levels, 1, D3D11_SDK_VERSION, &IID_ID3D11Device1, NULL,
3740 &render_target->d3d_state)))
3742 WARN("Failed to create device context state, hr %#lx.\n", hr);
3743 goto err;
3746 for (i = 0; i < ARRAY_SIZE(shape_info); ++i)
3748 const struct shape_info *si = &shape_info[i];
3750 if (FAILED(hr = D3DCompile(si->vs_code, si->vs_code_size, si->name, NULL, NULL,
3751 "main", "vs_4_0", 0, 0, &compiled, NULL)))
3753 WARN("Failed to compile shader for shape type %#x, hr %#lx.\n", si->shape_type, hr);
3754 goto err;
3757 if (FAILED(hr = ID3D11Device1_CreateInputLayout(render_target->d3d_device, si->il_desc, si->il_element_count,
3758 ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled),
3759 &render_target->shape_resources[si->shape_type].il)))
3761 WARN("Failed to create input layout for shape type %#x, hr %#lx.\n", si->shape_type, hr);
3762 ID3D10Blob_Release(compiled);
3763 goto err;
3766 if (FAILED(hr = ID3D11Device1_CreateVertexShader(render_target->d3d_device,
3767 ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled),
3768 NULL, &render_target->shape_resources[si->shape_type].vs)))
3770 WARN("Failed to create vertex shader for shape type %#x, hr %#lx.\n", si->shape_type, hr);
3771 ID3D10Blob_Release(compiled);
3772 goto err;
3775 ID3D10Blob_Release(compiled);
3778 buffer_desc.ByteWidth = sizeof(struct d2d_vs_cb);
3779 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
3780 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
3781 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
3782 buffer_desc.MiscFlags = 0;
3784 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, NULL,
3785 &render_target->vs_cb)))
3787 WARN("Failed to create constant buffer, hr %#lx.\n", hr);
3788 goto err;
3791 if (FAILED(hr = D3DCompile(ps_code, sizeof(ps_code) - 1, "ps", NULL, NULL, "main", "ps_4_0", 0, 0, &compiled, NULL)))
3793 WARN("Failed to compile the pixel shader, hr %#lx.\n", hr);
3794 goto err;
3797 if (FAILED(hr = ID3D11Device1_CreatePixelShader(render_target->d3d_device,
3798 ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled),
3799 NULL, &render_target->ps)))
3801 WARN("Failed to create pixel shader, hr %#lx.\n", hr);
3802 ID3D10Blob_Release(compiled);
3803 goto err;
3806 ID3D10Blob_Release(compiled);
3808 buffer_desc.ByteWidth = sizeof(struct d2d_ps_cb);
3809 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
3810 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
3811 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
3812 buffer_desc.MiscFlags = 0;
3814 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, NULL,
3815 &render_target->ps_cb)))
3817 WARN("Failed to create constant buffer, hr %#lx.\n", hr);
3818 goto err;
3821 buffer_desc.ByteWidth = sizeof(indices);
3822 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
3823 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
3824 buffer_desc.CPUAccessFlags = 0;
3825 buffer_desc.MiscFlags = 0;
3827 buffer_data.pSysMem = indices;
3828 buffer_data.SysMemPitch = 0;
3829 buffer_data.SysMemSlicePitch = 0;
3831 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device,
3832 &buffer_desc, &buffer_data, &render_target->ib)))
3834 WARN("Failed to create clear index buffer, hr %#lx.\n", hr);
3835 goto err;
3838 buffer_desc.ByteWidth = sizeof(quad);
3839 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
3840 buffer_data.pSysMem = quad;
3842 render_target->vb_stride = sizeof(*quad);
3843 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device,
3844 &buffer_desc, &buffer_data, &render_target->vb)))
3846 WARN("Failed to create clear vertex buffer, hr %#lx.\n", hr);
3847 goto err;
3850 rs_desc.FillMode = D3D11_FILL_SOLID;
3851 rs_desc.CullMode = D3D11_CULL_NONE;
3852 rs_desc.FrontCounterClockwise = FALSE;
3853 rs_desc.DepthBias = 0;
3854 rs_desc.DepthBiasClamp = 0.0f;
3855 rs_desc.SlopeScaledDepthBias = 0.0f;
3856 rs_desc.DepthClipEnable = TRUE;
3857 rs_desc.ScissorEnable = TRUE;
3858 rs_desc.MultisampleEnable = FALSE;
3859 rs_desc.AntialiasedLineEnable = FALSE;
3860 if (FAILED(hr = ID3D11Device1_CreateRasterizerState(render_target->d3d_device, &rs_desc, &render_target->rs)))
3862 WARN("Failed to create clear rasteriser state, hr %#lx.\n", hr);
3863 goto err;
3866 if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
3867 &IID_IDWriteFactory, (IUnknown **)&dwrite_factory)))
3869 ERR("Failed to create dwrite factory, hr %#lx.\n", hr);
3870 goto err;
3873 hr = IDWriteFactory_CreateRenderingParams(dwrite_factory, &render_target->default_text_rendering_params);
3874 IDWriteFactory_Release(dwrite_factory);
3875 if (FAILED(hr))
3877 ERR("Failed to create default text rendering parameters, hr %#lx.\n", hr);
3878 goto err;
3881 render_target->drawing_state.transform = identity;
3883 if (!d2d_clip_stack_init(&render_target->clip_stack))
3885 WARN("Failed to initialize clip stack.\n");
3886 hr = E_FAIL;
3887 goto err;
3890 render_target->desc.dpiX = 96.0f;
3891 render_target->desc.dpiY = 96.0f;
3893 return S_OK;
3895 err:
3896 if (render_target->default_text_rendering_params)
3897 IDWriteRenderingParams_Release(render_target->default_text_rendering_params);
3898 if (render_target->rs)
3899 ID3D11RasterizerState_Release(render_target->rs);
3900 if (render_target->vb)
3901 ID3D11Buffer_Release(render_target->vb);
3902 if (render_target->ib)
3903 ID3D11Buffer_Release(render_target->ib);
3904 if (render_target->ps_cb)
3905 ID3D11Buffer_Release(render_target->ps_cb);
3906 if (render_target->ps)
3907 ID3D11PixelShader_Release(render_target->ps);
3908 if (render_target->vs_cb)
3909 ID3D11Buffer_Release(render_target->vs_cb);
3910 for (i = 0; i < D2D_SHAPE_TYPE_COUNT; ++i)
3912 if (render_target->shape_resources[i].vs)
3913 ID3D11VertexShader_Release(render_target->shape_resources[i].vs);
3914 if (render_target->shape_resources[i].il)
3915 ID3D11InputLayout_Release(render_target->shape_resources[i].il);
3917 if (render_target->d3d_state)
3918 ID3DDeviceContextState_Release(render_target->d3d_state);
3919 if (render_target->d3d_device)
3920 ID3D11Device1_Release(render_target->d3d_device);
3921 ID2D1Device1_Release(&render_target->device->ID2D1Device1_iface);
3922 ID2D1Factory_Release(render_target->factory);
3923 return hr;
3926 HRESULT d2d_d3d_create_render_target(struct d2d_device *device, IDXGISurface *surface, IUnknown *outer_unknown,
3927 const struct d2d_device_context_ops *ops, const D2D1_RENDER_TARGET_PROPERTIES *desc, void **render_target)
3929 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
3930 struct d2d_device_context *object;
3931 ID2D1Bitmap1 *bitmap;
3932 HRESULT hr;
3934 if (desc->type != D2D1_RENDER_TARGET_TYPE_DEFAULT && desc->type != D2D1_RENDER_TARGET_TYPE_HARDWARE)
3935 WARN("Ignoring render target type %#x.\n", desc->type);
3936 if (desc->usage != D2D1_RENDER_TARGET_USAGE_NONE)
3937 FIXME("Ignoring render target usage %#x.\n", desc->usage);
3938 if (desc->minLevel != D2D1_FEATURE_LEVEL_DEFAULT)
3939 WARN("Ignoring feature level %#x.\n", desc->minLevel);
3941 bitmap_desc.dpiX = desc->dpiX;
3942 bitmap_desc.dpiY = desc->dpiY;
3944 if (bitmap_desc.dpiX == 0.0f && bitmap_desc.dpiY == 0.0f)
3946 bitmap_desc.dpiX = 96.0f;
3947 bitmap_desc.dpiY = 96.0f;
3949 else if (bitmap_desc.dpiX <= 0.0f || bitmap_desc.dpiY <= 0.0f)
3950 return E_INVALIDARG;
3952 if (!(object = calloc(1, sizeof(*object))))
3953 return E_OUTOFMEMORY;
3955 if (FAILED(hr = d2d_device_context_init(object, device, outer_unknown, ops)))
3957 WARN("Failed to initialise render target, hr %#lx.\n", hr);
3958 free(object);
3959 return hr;
3962 ID2D1DeviceContext1_SetDpi(&object->ID2D1DeviceContext1_iface, bitmap_desc.dpiX, bitmap_desc.dpiY);
3964 if (surface)
3966 bitmap_desc.pixelFormat = desc->pixelFormat;
3967 bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
3968 if (desc->usage & D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE)
3969 bitmap_desc.bitmapOptions |= D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE;
3970 bitmap_desc.colorContext = NULL;
3972 if (FAILED(hr = ID2D1DeviceContext1_CreateBitmapFromDxgiSurface(&object->ID2D1DeviceContext1_iface,
3973 surface, &bitmap_desc, &bitmap)))
3975 WARN("Failed to create target bitmap, hr %#lx.\n", hr);
3976 IUnknown_Release(&object->IUnknown_iface);
3977 return hr;
3980 ID2D1DeviceContext1_SetTarget(&object->ID2D1DeviceContext1_iface, (ID2D1Image *)bitmap);
3981 ID2D1Bitmap1_Release(bitmap);
3983 else
3984 object->desc.pixelFormat = desc->pixelFormat;
3986 TRACE("Created render target %p.\n", object);
3987 *render_target = outer_unknown ? &object->IUnknown_iface : (IUnknown *)&object->ID2D1DeviceContext1_iface;
3989 return S_OK;
3992 static HRESULT WINAPI d2d_device_QueryInterface(ID2D1Device1 *iface, REFIID iid, void **out)
3994 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3996 if (IsEqualGUID(iid, &IID_ID2D1Device1)
3997 || IsEqualGUID(iid, &IID_ID2D1Device)
3998 || IsEqualGUID(iid, &IID_ID2D1Resource)
3999 || IsEqualGUID(iid, &IID_IUnknown))
4001 ID2D1Device1_AddRef(iface);
4002 *out = iface;
4003 return S_OK;
4006 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4008 *out = NULL;
4009 return E_NOINTERFACE;
4012 static ULONG WINAPI d2d_device_AddRef(ID2D1Device1 *iface)
4014 struct d2d_device *device = impl_from_ID2D1Device(iface);
4015 ULONG refcount = InterlockedIncrement(&device->refcount);
4017 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4019 return refcount;
4022 static ULONG WINAPI d2d_device_Release(ID2D1Device1 *iface)
4024 struct d2d_device *device = impl_from_ID2D1Device(iface);
4025 ULONG refcount = InterlockedDecrement(&device->refcount);
4026 size_t i;
4028 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4030 if (!refcount)
4032 IDXGIDevice_Release(device->dxgi_device);
4033 ID2D1Factory1_Release(device->factory);
4034 for (i = 0; i < device->shaders.count; ++i)
4035 IUnknown_Release(device->shaders.objects[i].shader);
4036 free(device->shaders.objects);
4037 free(device);
4040 return refcount;
4043 static void WINAPI d2d_device_GetFactory(ID2D1Device1 *iface, ID2D1Factory **factory)
4045 struct d2d_device *device = impl_from_ID2D1Device(iface);
4047 TRACE("iface %p, factory %p.\n", iface, factory);
4049 *factory = (ID2D1Factory *)device->factory;
4050 ID2D1Factory1_AddRef(device->factory);
4053 static HRESULT d2d_device_create_device_context(struct d2d_device *device,
4054 D2D1_DEVICE_CONTEXT_OPTIONS options, ID2D1DeviceContext1 **context)
4056 struct d2d_device_context *object;
4057 HRESULT hr;
4059 if (options)
4060 FIXME("Options are ignored %#x.\n", options);
4062 if (!(object = calloc(1, sizeof(*object))))
4063 return E_OUTOFMEMORY;
4065 if (FAILED(hr = d2d_device_context_init(object, device, NULL, NULL)))
4067 WARN("Failed to initialise device context, hr %#lx.\n", hr);
4068 free(object);
4069 return hr;
4072 TRACE("Created device context %p.\n", object);
4073 *context = &object->ID2D1DeviceContext1_iface;
4075 return S_OK;
4078 static HRESULT WINAPI d2d_device_CreateDeviceContext(ID2D1Device1 *iface, D2D1_DEVICE_CONTEXT_OPTIONS options,
4079 ID2D1DeviceContext **context)
4081 struct d2d_device *device = impl_from_ID2D1Device(iface);
4083 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4085 return d2d_device_create_device_context(device, options, (ID2D1DeviceContext1 **)context);
4088 static HRESULT WINAPI d2d_device_CreatePrintControl(ID2D1Device1 *iface, IWICImagingFactory *wic_factory,
4089 IPrintDocumentPackageTarget *document_target, const D2D1_PRINT_CONTROL_PROPERTIES *desc,
4090 ID2D1PrintControl **print_control)
4092 FIXME("iface %p, wic_factory %p, document_target %p, desc %p, print_control %p stub!\n", iface, wic_factory,
4093 document_target, desc, print_control);
4095 return E_NOTIMPL;
4098 static void WINAPI d2d_device_SetMaximumTextureMemory(ID2D1Device1 *iface, UINT64 max_texture_memory)
4100 FIXME("iface %p, max_texture_memory %s stub!\n", iface, wine_dbgstr_longlong(max_texture_memory));
4103 static UINT64 WINAPI d2d_device_GetMaximumTextureMemory(ID2D1Device1 *iface)
4105 FIXME("iface %p stub!\n", iface);
4107 return 0;
4110 static HRESULT WINAPI d2d_device_ClearResources(ID2D1Device1 *iface, UINT msec_since_use)
4112 FIXME("iface %p, msec_since_use %u stub!\n", iface, msec_since_use);
4114 return E_NOTIMPL;
4117 static D2D1_RENDERING_PRIORITY WINAPI d2d_device_GetRenderingPriority(ID2D1Device1 *iface)
4119 FIXME("iface %p stub!\n", iface);
4121 return D2D1_RENDERING_PRIORITY_NORMAL;
4124 static void WINAPI d2d_device_SetRenderingPriority(ID2D1Device1 *iface, D2D1_RENDERING_PRIORITY priority)
4126 FIXME("iface %p, priority %#x stub!\n", iface, priority);
4129 static HRESULT WINAPI d2d_device_CreateDeviceContext1(ID2D1Device1 *iface, D2D1_DEVICE_CONTEXT_OPTIONS options,
4130 ID2D1DeviceContext1 **context)
4132 struct d2d_device *device = impl_from_ID2D1Device(iface);
4134 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4136 return d2d_device_create_device_context(device, options, context);
4139 static const struct ID2D1Device1Vtbl d2d_device_vtbl =
4141 d2d_device_QueryInterface,
4142 d2d_device_AddRef,
4143 d2d_device_Release,
4144 d2d_device_GetFactory,
4145 d2d_device_CreateDeviceContext,
4146 d2d_device_CreatePrintControl,
4147 d2d_device_SetMaximumTextureMemory,
4148 d2d_device_GetMaximumTextureMemory,
4149 d2d_device_ClearResources,
4150 d2d_device_GetRenderingPriority,
4151 d2d_device_SetRenderingPriority,
4152 d2d_device_CreateDeviceContext1,
4155 struct d2d_device *unsafe_impl_from_ID2D1Device(ID2D1Device1 *iface)
4157 if (!iface)
4158 return NULL;
4159 assert(iface->lpVtbl == &d2d_device_vtbl);
4160 return CONTAINING_RECORD(iface, struct d2d_device, ID2D1Device1_iface);
4163 void d2d_device_init(struct d2d_device *device, ID2D1Factory1 *iface, IDXGIDevice *dxgi_device)
4165 device->ID2D1Device1_iface.lpVtbl = &d2d_device_vtbl;
4166 device->refcount = 1;
4167 device->factory = iface;
4168 ID2D1Factory1_AddRef(device->factory);
4169 device->dxgi_device = dxgi_device;
4170 IDXGIDevice_AddRef(device->dxgi_device);
4173 HRESULT d2d_device_add_shader(struct d2d_device *device, REFGUID shader_id, IUnknown *shader)
4175 struct d2d_shader *entry;
4177 if (!d2d_array_reserve((void **)&device->shaders.objects, &device->shaders.size,
4178 device->shaders.count + 1, sizeof(*device->shaders.objects)))
4180 WARN("Failed to resize shaders array.\n");
4181 return E_OUTOFMEMORY;
4184 entry = &device->shaders.objects[device->shaders.count++];
4185 entry->id = *shader_id;
4186 entry->shader = shader;
4187 IUnknown_AddRef(entry->shader);
4189 return S_OK;
4192 BOOL d2d_device_is_shader_loaded(struct d2d_device *device, REFGUID shader_id)
4194 size_t i;
4196 for (i = 0; i < device->shaders.count; ++i)
4198 if (IsEqualGUID(shader_id, &device->shaders.objects[i].id))
4199 return TRUE;
4202 return FALSE;