include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / d2d1 / device.c
blob75da15c99a560be2da6655e1a8a58c7c717e4ea5
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(ID2D1Device6 *iface)
41 return CONTAINING_RECORD(iface, struct d2d_device, ID2D1Device6_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(ID2D1DeviceContext6 *iface)
214 return CONTAINING_RECORD(iface, struct d2d_device_context, ID2D1DeviceContext6_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_ID2D1DeviceContext6)
224 || IsEqualGUID(iid, &IID_ID2D1DeviceContext5)
225 || IsEqualGUID(iid, &IID_ID2D1DeviceContext4)
226 || IsEqualGUID(iid, &IID_ID2D1DeviceContext3)
227 || IsEqualGUID(iid, &IID_ID2D1DeviceContext2)
228 || IsEqualGUID(iid, &IID_ID2D1DeviceContext1)
229 || IsEqualGUID(iid, &IID_ID2D1DeviceContext)
230 || IsEqualGUID(iid, &IID_ID2D1RenderTarget)
231 || IsEqualGUID(iid, &IID_ID2D1Resource)
232 || IsEqualGUID(iid, &IID_IUnknown))
234 ID2D1DeviceContext6_AddRef(&context->ID2D1DeviceContext6_iface);
235 *out = &context->ID2D1DeviceContext6_iface;
236 return S_OK;
238 else if (IsEqualGUID(iid, &IID_ID2D1GdiInteropRenderTarget))
240 ID2D1GdiInteropRenderTarget_AddRef(&context->ID2D1GdiInteropRenderTarget_iface);
241 *out = &context->ID2D1GdiInteropRenderTarget_iface;
242 return S_OK;
245 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
247 *out = NULL;
248 return E_NOINTERFACE;
251 static ULONG STDMETHODCALLTYPE d2d_device_context_inner_AddRef(IUnknown *iface)
253 struct d2d_device_context *context = impl_from_IUnknown(iface);
254 ULONG refcount = InterlockedIncrement(&context->refcount);
256 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
258 return refcount;
261 static ULONG STDMETHODCALLTYPE d2d_device_context_inner_Release(IUnknown *iface)
263 struct d2d_device_context *context = impl_from_IUnknown(iface);
264 ULONG refcount = InterlockedDecrement(&context->refcount);
266 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
268 if (!refcount)
270 unsigned int i, j, k;
272 d2d_clip_stack_cleanup(&context->clip_stack);
273 IDWriteRenderingParams_Release(context->default_text_rendering_params);
274 if (context->text_rendering_params)
275 IDWriteRenderingParams_Release(context->text_rendering_params);
276 if (context->bs)
277 ID3D11BlendState_Release(context->bs);
278 ID3D11RasterizerState_Release(context->rs);
279 ID3D11Buffer_Release(context->vb);
280 ID3D11Buffer_Release(context->ib);
281 ID3D11Buffer_Release(context->ps_cb);
282 ID3D11PixelShader_Release(context->ps);
283 ID3D11Buffer_Release(context->vs_cb);
284 for (i = 0; i < D2D_SHAPE_TYPE_COUNT; ++i)
286 ID3D11VertexShader_Release(context->shape_resources[i].vs);
287 ID3D11InputLayout_Release(context->shape_resources[i].il);
289 for (i = 0; i < D2D_SAMPLER_INTERPOLATION_MODE_COUNT; ++i)
291 for (j = 0; j < D2D_SAMPLER_EXTEND_MODE_COUNT; ++j)
293 for (k = 0; k < D2D_SAMPLER_EXTEND_MODE_COUNT; ++k)
295 if (context->sampler_states[i][j][k])
296 ID3D11SamplerState_Release(context->sampler_states[i][j][k]);
300 if (context->d3d_state)
301 ID3DDeviceContextState_Release(context->d3d_state);
302 if (context->target.object)
303 IUnknown_Release(context->target.object);
304 ID3D11Device1_Release(context->d3d_device);
305 ID2D1Factory_Release(context->factory);
306 ID2D1Device6_Release(&context->device->ID2D1Device6_iface);
307 d2d_device_indexed_objects_clear(&context->vertex_buffers);
308 free(context);
311 return refcount;
314 static const struct IUnknownVtbl d2d_device_context_inner_unknown_vtbl =
316 d2d_device_context_inner_QueryInterface,
317 d2d_device_context_inner_AddRef,
318 d2d_device_context_inner_Release,
321 static HRESULT STDMETHODCALLTYPE d2d_device_context_QueryInterface(ID2D1DeviceContext6 *iface,
322 REFIID iid, void **out)
324 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
326 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
328 return IUnknown_QueryInterface(context->outer_unknown, iid, out);
331 static ULONG STDMETHODCALLTYPE d2d_device_context_AddRef(ID2D1DeviceContext6 *iface)
333 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
335 TRACE("iface %p.\n", iface);
337 return IUnknown_AddRef(context->outer_unknown);
340 static ULONG STDMETHODCALLTYPE d2d_device_context_Release(ID2D1DeviceContext6 *iface)
342 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
344 TRACE("iface %p.\n", iface);
346 return IUnknown_Release(context->outer_unknown);
349 static void STDMETHODCALLTYPE d2d_device_context_GetFactory(ID2D1DeviceContext6 *iface, ID2D1Factory **factory)
351 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
353 TRACE("iface %p, factory %p.\n", iface, factory);
355 *factory = render_target->factory;
356 ID2D1Factory_AddRef(*factory);
359 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmap(ID2D1DeviceContext6 *iface,
360 D2D1_SIZE_U size, const void *src_data, UINT32 pitch, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
362 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
363 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
364 struct d2d_bitmap *object;
365 HRESULT hr;
367 TRACE("iface %p, size {%u, %u}, src_data %p, pitch %u, desc %p, bitmap %p.\n",
368 iface, size.width, size.height, src_data, pitch, desc, bitmap);
370 if (desc)
372 memcpy(&bitmap_desc, desc, sizeof(*desc));
373 bitmap_desc.bitmapOptions = 0;
374 bitmap_desc.colorContext = NULL;
377 if (SUCCEEDED(hr = d2d_bitmap_create(context, size, src_data, pitch, desc ? &bitmap_desc : NULL, &object)))
378 *bitmap = (ID2D1Bitmap *)&object->ID2D1Bitmap1_iface;
380 return hr;
383 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmapFromWicBitmap(ID2D1DeviceContext6 *iface,
384 IWICBitmapSource *bitmap_source, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
386 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
387 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
388 struct d2d_bitmap *object;
389 HRESULT hr;
391 TRACE("iface %p, bitmap_source %p, desc %p, bitmap %p.\n",
392 iface, bitmap_source, desc, bitmap);
394 if (desc)
396 memcpy(&bitmap_desc, desc, sizeof(*desc));
397 bitmap_desc.bitmapOptions = 0;
398 bitmap_desc.colorContext = NULL;
401 if (SUCCEEDED(hr = d2d_bitmap_create_from_wic_bitmap(context, bitmap_source, desc ? &bitmap_desc : NULL, &object)))
402 *bitmap = (ID2D1Bitmap *)&object->ID2D1Bitmap1_iface;
404 return hr;
407 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSharedBitmap(ID2D1DeviceContext6 *iface,
408 REFIID iid, void *data, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
410 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
411 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
412 struct d2d_bitmap *object;
413 HRESULT hr;
415 TRACE("iface %p, iid %s, data %p, desc %p, bitmap %p.\n",
416 iface, debugstr_guid(iid), data, desc, bitmap);
418 if (desc)
420 memcpy(&bitmap_desc, desc, sizeof(*desc));
421 if (IsEqualIID(iid, &IID_IDXGISurface) || IsEqualIID(iid, &IID_IDXGISurface1))
422 bitmap_desc.bitmapOptions = d2d_get_bitmap_options_for_surface(data);
423 else
424 bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
425 bitmap_desc.colorContext = NULL;
428 if (SUCCEEDED(hr = d2d_bitmap_create_shared(context, iid, data, desc ? &bitmap_desc : NULL, &object)))
429 *bitmap = (ID2D1Bitmap *)&object->ID2D1Bitmap1_iface;
431 return hr;
434 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmapBrush(ID2D1DeviceContext6 *iface,
435 ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc,
436 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1BitmapBrush **brush)
438 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
439 struct d2d_brush *object;
440 HRESULT hr;
442 TRACE("iface %p, bitmap %p, bitmap_brush_desc %p, brush_desc %p, brush %p.\n",
443 iface, bitmap, bitmap_brush_desc, brush_desc, brush);
445 if (SUCCEEDED(hr = d2d_bitmap_brush_create(context->factory, bitmap, (const D2D1_BITMAP_BRUSH_PROPERTIES1 *)bitmap_brush_desc,
446 brush_desc, &object)))
447 *brush = (ID2D1BitmapBrush *)&object->ID2D1Brush_iface;
449 return hr;
452 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSolidColorBrush(ID2D1DeviceContext6 *iface,
453 const D2D1_COLOR_F *color, const D2D1_BRUSH_PROPERTIES *desc, ID2D1SolidColorBrush **brush)
455 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
456 struct d2d_brush *object;
457 HRESULT hr;
459 TRACE("iface %p, color %p, desc %p, brush %p.\n", iface, color, desc, brush);
461 if (SUCCEEDED(hr = d2d_solid_color_brush_create(render_target->factory, color, desc, &object)))
462 *brush = (ID2D1SolidColorBrush *)&object->ID2D1Brush_iface;
464 return hr;
467 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateGradientStopCollection(ID2D1DeviceContext6 *iface,
468 const D2D1_GRADIENT_STOP *stops, UINT32 stop_count, D2D1_GAMMA gamma, D2D1_EXTEND_MODE extend_mode,
469 ID2D1GradientStopCollection **gradient)
471 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
472 struct d2d_gradient *object;
473 HRESULT hr;
475 TRACE("iface %p, stops %p, stop_count %u, gamma %#x, extend_mode %#x, gradient %p.\n",
476 iface, stops, stop_count, gamma, extend_mode, gradient);
478 if (SUCCEEDED(hr = d2d_gradient_create(render_target->factory, render_target->d3d_device,
479 stops, stop_count, gamma, extend_mode, &object)))
480 *gradient = &object->ID2D1GradientStopCollection_iface;
482 return hr;
485 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateLinearGradientBrush(ID2D1DeviceContext6 *iface,
486 const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
487 ID2D1GradientStopCollection *gradient, ID2D1LinearGradientBrush **brush)
489 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
490 struct d2d_brush *object;
491 HRESULT hr;
493 TRACE("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p.\n",
494 iface, gradient_brush_desc, brush_desc, gradient, brush);
496 if (SUCCEEDED(hr = d2d_linear_gradient_brush_create(render_target->factory, gradient_brush_desc, brush_desc,
497 gradient, &object)))
498 *brush = (ID2D1LinearGradientBrush *)&object->ID2D1Brush_iface;
500 return hr;
503 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateRadialGradientBrush(ID2D1DeviceContext6 *iface,
504 const D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
505 ID2D1GradientStopCollection *gradient, ID2D1RadialGradientBrush **brush)
507 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
508 struct d2d_brush *object;
509 HRESULT hr;
511 TRACE("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p.\n",
512 iface, gradient_brush_desc, brush_desc, gradient, brush);
514 if (SUCCEEDED(hr = d2d_radial_gradient_brush_create(render_target->factory,
515 gradient_brush_desc, brush_desc, gradient, &object)))
516 *brush = (ID2D1RadialGradientBrush *)&object->ID2D1Brush_iface;
518 return hr;
521 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateCompatibleRenderTarget(ID2D1DeviceContext6 *iface,
522 const D2D1_SIZE_F *size, const D2D1_SIZE_U *pixel_size, const D2D1_PIXEL_FORMAT *format,
523 D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS options, ID2D1BitmapRenderTarget **rt)
525 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
526 struct d2d_bitmap_render_target *object;
527 HRESULT hr;
529 TRACE("iface %p, size %p, pixel_size %p, format %p, options %#x, render_target %p.\n",
530 iface, size, pixel_size, format, options, rt);
532 if (!(object = calloc(1, sizeof(*object))))
533 return E_OUTOFMEMORY;
535 if (FAILED(hr = d2d_bitmap_render_target_init(object, render_target, size, pixel_size,
536 format, options)))
538 WARN("Failed to initialise render target, hr %#lx.\n", hr);
539 free(object);
540 return hr;
543 TRACE("Created render target %p.\n", object);
544 *rt = &object->ID2D1BitmapRenderTarget_iface;
546 return S_OK;
549 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateLayer(ID2D1DeviceContext6 *iface,
550 const D2D1_SIZE_F *size, ID2D1Layer **layer)
552 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
553 struct d2d_layer *object;
554 HRESULT hr;
556 TRACE("iface %p, size %p, layer %p.\n", iface, size, layer);
558 if (SUCCEEDED(hr = d2d_layer_create(render_target->factory, size, &object)))
559 *layer = &object->ID2D1Layer_iface;
561 return hr;
564 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateMesh(ID2D1DeviceContext6 *iface, ID2D1Mesh **mesh)
566 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
567 struct d2d_mesh *object;
568 HRESULT hr;
570 TRACE("iface %p, mesh %p.\n", iface, mesh);
572 if (SUCCEEDED(hr = d2d_mesh_create(render_target->factory, &object)))
573 *mesh = &object->ID2D1Mesh_iface;
575 return hr;
578 static void STDMETHODCALLTYPE d2d_device_context_DrawLine(ID2D1DeviceContext6 *iface,
579 D2D1_POINT_2F p0, D2D1_POINT_2F p1, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
581 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
582 ID2D1PathGeometry *geometry;
583 ID2D1GeometrySink *sink;
584 HRESULT hr;
586 TRACE("iface %p, p0 %s, p1 %s, brush %p, stroke_width %.8e, stroke_style %p.\n",
587 iface, debug_d2d_point_2f(&p0), debug_d2d_point_2f(&p1), brush, stroke_width, stroke_style);
589 if (context->target.type == D2D_TARGET_COMMAND_LIST)
591 d2d_command_list_draw_line(context->target.command_list, context, p0, p1, brush, stroke_width, stroke_style);
592 return;
595 if (FAILED(hr = ID2D1Factory_CreatePathGeometry(context->factory, &geometry)))
597 WARN("Failed to create path geometry, hr %#lx.\n", hr);
598 return;
601 if (FAILED(hr = ID2D1PathGeometry_Open(geometry, &sink)))
603 WARN("Failed to open geometry sink, hr %#lx.\n", hr);
604 ID2D1PathGeometry_Release(geometry);
605 return;
608 ID2D1GeometrySink_BeginFigure(sink, p0, D2D1_FIGURE_BEGIN_HOLLOW);
609 ID2D1GeometrySink_AddLine(sink, p1);
610 ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
611 if (FAILED(hr = ID2D1GeometrySink_Close(sink)))
612 WARN("Failed to close geometry sink, hr %#lx.\n", hr);
613 ID2D1GeometrySink_Release(sink);
615 ID2D1DeviceContext6_DrawGeometry(iface, (ID2D1Geometry *)geometry, brush, stroke_width, stroke_style);
616 ID2D1PathGeometry_Release(geometry);
619 static void STDMETHODCALLTYPE d2d_device_context_DrawRectangle(ID2D1DeviceContext6 *iface,
620 const D2D1_RECT_F *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
622 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
623 ID2D1RectangleGeometry *geometry;
624 HRESULT hr;
626 TRACE("iface %p, rect %s, brush %p, stroke_width %.8e, stroke_style %p.\n",
627 iface, debug_d2d_rect_f(rect), brush, stroke_width, stroke_style);
629 if (context->target.type == D2D_TARGET_COMMAND_LIST)
631 d2d_command_list_draw_rectangle(context->target.command_list, context, rect, brush, stroke_width, stroke_style);
632 return;
635 if (FAILED(hr = ID2D1Factory_CreateRectangleGeometry(context->factory, rect, &geometry)))
637 ERR("Failed to create geometry, hr %#lx.\n", hr);
638 return;
641 ID2D1DeviceContext6_DrawGeometry(iface, (ID2D1Geometry *)geometry, brush, stroke_width, stroke_style);
642 ID2D1RectangleGeometry_Release(geometry);
645 static void STDMETHODCALLTYPE d2d_device_context_FillRectangle(ID2D1DeviceContext6 *iface,
646 const D2D1_RECT_F *rect, ID2D1Brush *brush)
648 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
649 ID2D1RectangleGeometry *geometry;
650 HRESULT hr;
652 TRACE("iface %p, rect %s, brush %p.\n", iface, debug_d2d_rect_f(rect), brush);
654 if (context->target.type == D2D_TARGET_COMMAND_LIST)
656 d2d_command_list_fill_rectangle(context->target.command_list, context, rect, brush);
657 return;
660 if (FAILED(hr = ID2D1Factory_CreateRectangleGeometry(context->factory, rect, &geometry)))
662 ERR("Failed to create geometry, hr %#lx.\n", hr);
663 return;
666 ID2D1DeviceContext6_FillGeometry(iface, (ID2D1Geometry *)geometry, brush, NULL);
667 ID2D1RectangleGeometry_Release(geometry);
670 static void STDMETHODCALLTYPE d2d_device_context_DrawRoundedRectangle(ID2D1DeviceContext6 *iface,
671 const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
673 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
674 ID2D1RoundedRectangleGeometry *geometry;
675 HRESULT hr;
677 TRACE("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p.\n",
678 iface, rect, brush, stroke_width, stroke_style);
680 if (FAILED(hr = ID2D1Factory_CreateRoundedRectangleGeometry(render_target->factory, rect, &geometry)))
682 ERR("Failed to create geometry, hr %#lx.\n", hr);
683 return;
686 ID2D1DeviceContext6_DrawGeometry(iface, (ID2D1Geometry *)geometry, brush, stroke_width, stroke_style);
687 ID2D1RoundedRectangleGeometry_Release(geometry);
690 static void STDMETHODCALLTYPE d2d_device_context_FillRoundedRectangle(ID2D1DeviceContext6 *iface,
691 const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush)
693 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
694 ID2D1RoundedRectangleGeometry *geometry;
695 HRESULT hr;
697 TRACE("iface %p, rect %p, brush %p.\n", iface, rect, brush);
699 if (FAILED(hr = ID2D1Factory_CreateRoundedRectangleGeometry(render_target->factory, rect, &geometry)))
701 ERR("Failed to create geometry, hr %#lx.\n", hr);
702 return;
705 ID2D1DeviceContext6_FillGeometry(iface, (ID2D1Geometry *)geometry, brush, NULL);
706 ID2D1RoundedRectangleGeometry_Release(geometry);
709 static void STDMETHODCALLTYPE d2d_device_context_DrawEllipse(ID2D1DeviceContext6 *iface,
710 const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
712 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
713 ID2D1EllipseGeometry *geometry;
714 HRESULT hr;
716 TRACE("iface %p, ellipse %p, brush %p, stroke_width %.8e, stroke_style %p.\n",
717 iface, ellipse, brush, stroke_width, stroke_style);
719 if (FAILED(hr = ID2D1Factory_CreateEllipseGeometry(render_target->factory, ellipse, &geometry)))
721 ERR("Failed to create geometry, hr %#lx.\n", hr);
722 return;
725 ID2D1DeviceContext6_DrawGeometry(iface, (ID2D1Geometry *)geometry, brush, stroke_width, stroke_style);
726 ID2D1EllipseGeometry_Release(geometry);
729 static void STDMETHODCALLTYPE d2d_device_context_FillEllipse(ID2D1DeviceContext6 *iface,
730 const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush)
732 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
733 ID2D1EllipseGeometry *geometry;
734 HRESULT hr;
736 TRACE("iface %p, ellipse %p, brush %p.\n", iface, ellipse, brush);
738 if (FAILED(hr = ID2D1Factory_CreateEllipseGeometry(render_target->factory, ellipse, &geometry)))
740 ERR("Failed to create geometry, hr %#lx.\n", hr);
741 return;
744 ID2D1DeviceContext6_FillGeometry(iface, (ID2D1Geometry *)geometry, brush, NULL);
745 ID2D1EllipseGeometry_Release(geometry);
748 static HRESULT d2d_device_context_update_ps_cb(struct d2d_device_context *context,
749 struct d2d_brush *brush, struct d2d_brush *opacity_brush, BOOL outline, BOOL is_arc)
751 D3D11_MAPPED_SUBRESOURCE map_desc;
752 ID3D11DeviceContext *d3d_context;
753 struct d2d_ps_cb *cb_data;
754 HRESULT hr;
756 ID3D11Device1_GetImmediateContext(context->d3d_device, &d3d_context);
758 if (FAILED(hr = ID3D11DeviceContext_Map(d3d_context, (ID3D11Resource *)context->ps_cb,
759 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc)))
761 WARN("Failed to map constant buffer, hr %#lx.\n", hr);
762 ID3D11DeviceContext_Release(d3d_context);
763 return hr;
766 cb_data = map_desc.pData;
767 cb_data->outline = outline;
768 cb_data->is_arc = is_arc;
769 cb_data->pad[0] = 0;
770 cb_data->pad[1] = 0;
771 if (!d2d_brush_fill_cb(brush, &cb_data->colour_brush))
772 WARN("Failed to initialize colour brush buffer.\n");
773 if (!d2d_brush_fill_cb(opacity_brush, &cb_data->opacity_brush))
774 WARN("Failed to initialize opacity brush buffer.\n");
776 ID3D11DeviceContext_Unmap(d3d_context, (ID3D11Resource *)context->ps_cb, 0);
777 ID3D11DeviceContext_Release(d3d_context);
779 return hr;
782 static HRESULT d2d_device_context_update_vs_cb(struct d2d_device_context *context,
783 const D2D_MATRIX_3X2_F *geometry_transform, float stroke_width)
785 D3D11_MAPPED_SUBRESOURCE map_desc;
786 ID3D11DeviceContext *d3d_context;
787 const D2D1_MATRIX_3X2_F *w;
788 struct d2d_vs_cb *cb_data;
789 float tmp_x, tmp_y;
790 HRESULT hr;
792 ID3D11Device1_GetImmediateContext(context->d3d_device, &d3d_context);
794 if (FAILED(hr = ID3D11DeviceContext_Map(d3d_context, (ID3D11Resource *)context->vs_cb,
795 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc)))
797 WARN("Failed to map constant buffer, hr %#lx.\n", hr);
798 ID3D11DeviceContext_Release(d3d_context);
799 return hr;
802 cb_data = map_desc.pData;
803 cb_data->transform_geometry._11 = geometry_transform->_11;
804 cb_data->transform_geometry._21 = geometry_transform->_21;
805 cb_data->transform_geometry._31 = geometry_transform->_31;
806 cb_data->transform_geometry.pad0 = 0.0f;
807 cb_data->transform_geometry._12 = geometry_transform->_12;
808 cb_data->transform_geometry._22 = geometry_transform->_22;
809 cb_data->transform_geometry._32 = geometry_transform->_32;
810 cb_data->transform_geometry.stroke_width = stroke_width;
812 w = &context->drawing_state.transform;
814 tmp_x = context->desc.dpiX / 96.0f;
815 cb_data->transform_rtx.x = w->_11 * tmp_x;
816 cb_data->transform_rtx.y = w->_21 * tmp_x;
817 cb_data->transform_rtx.z = w->_31 * tmp_x;
818 cb_data->transform_rtx.w = 2.0f / context->pixel_size.width;
820 tmp_y = context->desc.dpiY / 96.0f;
821 cb_data->transform_rty.x = w->_12 * tmp_y;
822 cb_data->transform_rty.y = w->_22 * tmp_y;
823 cb_data->transform_rty.z = w->_32 * tmp_y;
824 cb_data->transform_rty.w = -2.0f / context->pixel_size.height;
826 ID3D11DeviceContext_Unmap(d3d_context, (ID3D11Resource *)context->vs_cb, 0);
827 ID3D11DeviceContext_Release(d3d_context);
829 return S_OK;
832 static void d2d_device_context_draw_geometry(struct d2d_device_context *render_target,
833 const struct d2d_geometry *geometry, struct d2d_brush *brush, float stroke_width)
835 D3D11_SUBRESOURCE_DATA buffer_data;
836 D3D11_BUFFER_DESC buffer_desc;
837 ID3D11Buffer *ib, *vb;
838 HRESULT hr;
840 if (FAILED(hr = d2d_device_context_update_vs_cb(render_target, &geometry->transform, stroke_width)))
842 WARN("Failed to update vs constant buffer, hr %#lx.\n", hr);
843 return;
846 if (FAILED(hr = d2d_device_context_update_ps_cb(render_target, brush, NULL, TRUE, FALSE)))
848 WARN("Failed to update ps constant buffer, hr %#lx.\n", hr);
849 return;
852 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
853 buffer_desc.CPUAccessFlags = 0;
854 buffer_desc.MiscFlags = 0;
856 buffer_data.SysMemPitch = 0;
857 buffer_data.SysMemSlicePitch = 0;
859 if (geometry->outline.face_count)
861 buffer_desc.ByteWidth = geometry->outline.face_count * sizeof(*geometry->outline.faces);
862 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
863 buffer_data.pSysMem = geometry->outline.faces;
865 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &ib)))
867 WARN("Failed to create index buffer, hr %#lx.\n", hr);
868 return;
871 buffer_desc.ByteWidth = geometry->outline.vertex_count * sizeof(*geometry->outline.vertices);
872 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
873 buffer_data.pSysMem = geometry->outline.vertices;
875 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
877 ERR("Failed to create vertex buffer, hr %#lx.\n", hr);
878 ID3D11Buffer_Release(ib);
879 return;
882 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_OUTLINE, ib, 3 * geometry->outline.face_count, vb,
883 sizeof(*geometry->outline.vertices), brush, NULL);
885 ID3D11Buffer_Release(vb);
886 ID3D11Buffer_Release(ib);
889 if (geometry->outline.bezier_face_count)
891 buffer_desc.ByteWidth = geometry->outline.bezier_face_count * sizeof(*geometry->outline.bezier_faces);
892 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
893 buffer_data.pSysMem = geometry->outline.bezier_faces;
895 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &ib)))
897 WARN("Failed to create curves index buffer, hr %#lx.\n", hr);
898 return;
901 buffer_desc.ByteWidth = geometry->outline.bezier_count * sizeof(*geometry->outline.beziers);
902 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
903 buffer_data.pSysMem = geometry->outline.beziers;
905 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
907 ERR("Failed to create curves vertex buffer, hr %#lx.\n", hr);
908 ID3D11Buffer_Release(ib);
909 return;
912 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_BEZIER_OUTLINE, ib,
913 3 * geometry->outline.bezier_face_count, vb,
914 sizeof(*geometry->outline.beziers), brush, NULL);
916 ID3D11Buffer_Release(vb);
917 ID3D11Buffer_Release(ib);
920 if (geometry->outline.arc_face_count)
922 buffer_desc.ByteWidth = geometry->outline.arc_face_count * sizeof(*geometry->outline.arc_faces);
923 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
924 buffer_data.pSysMem = geometry->outline.arc_faces;
926 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &ib)))
928 WARN("Failed to create arcs index buffer, hr %#lx.\n", hr);
929 return;
932 buffer_desc.ByteWidth = geometry->outline.arc_count * sizeof(*geometry->outline.arcs);
933 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
934 buffer_data.pSysMem = geometry->outline.arcs;
936 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
938 ERR("Failed to create arcs vertex buffer, hr %#lx.\n", hr);
939 ID3D11Buffer_Release(ib);
940 return;
943 if (SUCCEEDED(d2d_device_context_update_ps_cb(render_target, brush, NULL, TRUE, TRUE)))
944 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_ARC_OUTLINE, ib,
945 3 * geometry->outline.arc_face_count, vb,
946 sizeof(*geometry->outline.arcs), brush, NULL);
948 ID3D11Buffer_Release(vb);
949 ID3D11Buffer_Release(ib);
953 static void STDMETHODCALLTYPE d2d_device_context_DrawGeometry(ID2D1DeviceContext6 *iface,
954 ID2D1Geometry *geometry, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
956 const struct d2d_geometry *geometry_impl = unsafe_impl_from_ID2D1Geometry(geometry);
957 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
958 struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
959 struct d2d_stroke_style *stroke_style_impl = unsafe_impl_from_ID2D1StrokeStyle(stroke_style);
961 TRACE("iface %p, geometry %p, brush %p, stroke_width %.8e, stroke_style %p.\n",
962 iface, geometry, brush, stroke_width, stroke_style);
964 if (context->target.type == D2D_TARGET_COMMAND_LIST)
966 d2d_command_list_draw_geometry(context->target.command_list, context, geometry, brush,
967 stroke_width, stroke_style);
968 return;
971 if (stroke_style)
972 FIXME("Ignoring stroke style %p.\n", stroke_style);
974 if (stroke_style_impl)
976 if (stroke_style_impl->desc.transformType == D2D1_STROKE_TRANSFORM_TYPE_FIXED)
977 stroke_width /= context->drawing_state.transform.m11;
980 d2d_device_context_draw_geometry(context, geometry_impl, brush_impl, stroke_width);
983 static void d2d_device_context_fill_geometry(struct d2d_device_context *render_target,
984 const struct d2d_geometry *geometry, struct d2d_brush *brush, struct d2d_brush *opacity_brush)
986 D3D11_SUBRESOURCE_DATA buffer_data;
987 D3D11_BUFFER_DESC buffer_desc;
988 ID3D11Buffer *ib, *vb;
989 HRESULT hr;
991 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
992 buffer_desc.CPUAccessFlags = 0;
993 buffer_desc.MiscFlags = 0;
995 buffer_data.SysMemPitch = 0;
996 buffer_data.SysMemSlicePitch = 0;
998 if (FAILED(hr = d2d_device_context_update_vs_cb(render_target, &geometry->transform, 0.0f)))
1000 WARN("Failed to update vs constant buffer, hr %#lx.\n", hr);
1001 return;
1004 if (FAILED(hr = d2d_device_context_update_ps_cb(render_target, brush, opacity_brush, FALSE, FALSE)))
1006 WARN("Failed to update ps constant buffer, hr %#lx.\n", hr);
1007 return;
1010 if (geometry->fill.face_count)
1012 buffer_desc.ByteWidth = geometry->fill.face_count * sizeof(*geometry->fill.faces);
1013 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
1014 buffer_data.pSysMem = geometry->fill.faces;
1016 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &ib)))
1018 WARN("Failed to create index buffer, hr %#lx.\n", hr);
1019 return;
1022 buffer_desc.ByteWidth = geometry->fill.vertex_count * sizeof(*geometry->fill.vertices);
1023 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1024 buffer_data.pSysMem = geometry->fill.vertices;
1026 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
1028 ERR("Failed to create vertex buffer, hr %#lx.\n", hr);
1029 ID3D11Buffer_Release(ib);
1030 return;
1033 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_TRIANGLE, ib, 3 * geometry->fill.face_count, vb,
1034 sizeof(*geometry->fill.vertices), brush, opacity_brush);
1036 ID3D11Buffer_Release(vb);
1037 ID3D11Buffer_Release(ib);
1040 if (geometry->fill.bezier_vertex_count)
1042 buffer_desc.ByteWidth = geometry->fill.bezier_vertex_count * sizeof(*geometry->fill.bezier_vertices);
1043 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1044 buffer_data.pSysMem = geometry->fill.bezier_vertices;
1046 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
1048 ERR("Failed to create curves vertex buffer, hr %#lx.\n", hr);
1049 return;
1052 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_CURVE, NULL, geometry->fill.bezier_vertex_count, vb,
1053 sizeof(*geometry->fill.bezier_vertices), brush, opacity_brush);
1055 ID3D11Buffer_Release(vb);
1058 if (geometry->fill.arc_vertex_count)
1060 buffer_desc.ByteWidth = geometry->fill.arc_vertex_count * sizeof(*geometry->fill.arc_vertices);
1061 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1062 buffer_data.pSysMem = geometry->fill.arc_vertices;
1064 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, &buffer_data, &vb)))
1066 ERR("Failed to create arc vertex buffer, hr %#lx.\n", hr);
1067 return;
1070 if (SUCCEEDED(d2d_device_context_update_ps_cb(render_target, brush, opacity_brush, FALSE, TRUE)))
1071 d2d_device_context_draw(render_target, D2D_SHAPE_TYPE_CURVE, NULL, geometry->fill.arc_vertex_count, vb,
1072 sizeof(*geometry->fill.arc_vertices), brush, opacity_brush);
1074 ID3D11Buffer_Release(vb);
1078 static void STDMETHODCALLTYPE d2d_device_context_FillGeometry(ID2D1DeviceContext6 *iface,
1079 ID2D1Geometry *geometry, ID2D1Brush *brush, ID2D1Brush *opacity_brush)
1081 const struct d2d_geometry *geometry_impl = unsafe_impl_from_ID2D1Geometry(geometry);
1082 struct d2d_brush *opacity_brush_impl = unsafe_impl_from_ID2D1Brush(opacity_brush);
1083 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1084 struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
1086 TRACE("iface %p, geometry %p, brush %p, opacity_brush %p.\n", iface, geometry, brush, opacity_brush);
1088 if (FAILED(context->error.code))
1089 return;
1091 if (opacity_brush && brush_impl->type != D2D_BRUSH_TYPE_BITMAP)
1093 d2d_device_context_set_error(context, D2DERR_INCOMPATIBLE_BRUSH_TYPES);
1094 return;
1097 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1098 d2d_command_list_fill_geometry(context->target.command_list, context, geometry, brush, opacity_brush);
1099 else
1100 d2d_device_context_fill_geometry(context, geometry_impl, brush_impl, opacity_brush_impl);
1103 static void STDMETHODCALLTYPE d2d_device_context_FillMesh(ID2D1DeviceContext6 *iface,
1104 ID2D1Mesh *mesh, ID2D1Brush *brush)
1106 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1108 FIXME("iface %p, mesh %p, brush %p stub!\n", iface, mesh, brush);
1110 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1111 d2d_command_list_fill_mesh(context->target.command_list, context, mesh, brush);
1114 static void STDMETHODCALLTYPE d2d_device_context_FillOpacityMask(ID2D1DeviceContext6 *iface,
1115 ID2D1Bitmap *mask, ID2D1Brush *brush, D2D1_OPACITY_MASK_CONTENT content,
1116 const D2D1_RECT_F *dst_rect, const D2D1_RECT_F *src_rect)
1118 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1120 FIXME("iface %p, mask %p, brush %p, content %#x, dst_rect %s, src_rect %s stub!\n",
1121 iface, mask, brush, content, debug_d2d_rect_f(dst_rect), debug_d2d_rect_f(src_rect));
1123 if (FAILED(context->error.code))
1124 return;
1126 if (context->drawing_state.antialiasMode != D2D1_ANTIALIAS_MODE_ALIASED)
1128 d2d_device_context_set_error(context, D2DERR_WRONG_STATE);
1129 return;
1132 if ((unsigned int)content > D2D1_OPACITY_MASK_CONTENT_TEXT_GDI_COMPATIBLE)
1134 d2d_device_context_set_error(context, E_INVALIDARG);
1135 return;
1138 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1139 d2d_command_list_fill_opacity_mask(context->target.command_list, context, mask, brush, dst_rect, src_rect);
1142 static void d2d_device_context_draw_bitmap(struct d2d_device_context *context, ID2D1Bitmap *bitmap,
1143 const D2D1_RECT_F *dst_rect, float opacity, D2D1_INTERPOLATION_MODE interpolation_mode,
1144 const D2D1_RECT_F *src_rect, const D2D1_POINT_2F *offset,
1145 const D2D1_MATRIX_4X4_F *perspective_transform)
1147 D2D1_BITMAP_BRUSH_PROPERTIES1 bitmap_brush_desc;
1148 D2D1_BRUSH_PROPERTIES brush_desc;
1149 struct d2d_brush *brush;
1150 D2D1_SIZE_F size;
1151 D2D1_RECT_F s, d;
1152 HRESULT hr;
1154 if (perspective_transform)
1155 FIXME("Perspective transform is ignored.\n");
1157 size = ID2D1Bitmap_GetSize(bitmap);
1158 d2d_rect_set(&s, 0.0f, 0.0f, size.width, size.height);
1159 if (src_rect && src_rect->left <= src_rect->right
1160 && src_rect->top <= src_rect->bottom)
1162 d2d_rect_intersect(&s, src_rect);
1165 if (s.left == s.right || s.top == s.bottom)
1166 return;
1168 if (dst_rect)
1170 d = *dst_rect;
1172 else
1174 d.left = 0.0f;
1175 d.top = 0.0f;
1176 d.right = s.right - s.left;
1177 d.bottom = s.bottom - s.top;
1180 if (offset)
1182 d.left += offset->x;
1183 d.top += offset->y;
1184 d.right += offset->x;
1185 d.bottom += offset->y;
1188 bitmap_brush_desc.extendModeX = D2D1_EXTEND_MODE_CLAMP;
1189 bitmap_brush_desc.extendModeY = D2D1_EXTEND_MODE_CLAMP;
1190 bitmap_brush_desc.interpolationMode = interpolation_mode;
1192 brush_desc.opacity = opacity;
1193 brush_desc.transform._11 = fabsf((d.right - d.left) / (s.right - s.left));
1194 brush_desc.transform._21 = 0.0f;
1195 brush_desc.transform._31 = min(d.left, d.right) - min(s.left, s.right) * brush_desc.transform._11;
1196 brush_desc.transform._12 = 0.0f;
1197 brush_desc.transform._22 = fabsf((d.bottom - d.top) / (s.bottom - s.top));
1198 brush_desc.transform._32 = min(d.top, d.bottom) - min(s.top, s.bottom) * brush_desc.transform._22;
1200 if (FAILED(hr = d2d_bitmap_brush_create(context->factory, bitmap, &bitmap_brush_desc, &brush_desc, &brush)))
1202 ERR("Failed to create bitmap brush, hr %#lx.\n", hr);
1203 return;
1206 d2d_device_context_FillRectangle(&context->ID2D1DeviceContext6_iface, &d, &brush->ID2D1Brush_iface);
1207 ID2D1Brush_Release(&brush->ID2D1Brush_iface);
1210 static void STDMETHODCALLTYPE d2d_device_context_DrawBitmap(ID2D1DeviceContext6 *iface,
1211 ID2D1Bitmap *bitmap, const D2D1_RECT_F *dst_rect, float opacity,
1212 D2D1_BITMAP_INTERPOLATION_MODE interpolation_mode, const D2D1_RECT_F *src_rect)
1214 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1216 TRACE("iface %p, bitmap %p, dst_rect %s, opacity %.8e, interpolation_mode %#x, src_rect %s.\n",
1217 iface, bitmap, debug_d2d_rect_f(dst_rect), opacity, interpolation_mode, debug_d2d_rect_f(src_rect));
1219 if (interpolation_mode != D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
1220 && interpolation_mode != D2D1_BITMAP_INTERPOLATION_MODE_LINEAR)
1222 d2d_device_context_set_error(context, E_INVALIDARG);
1223 return;
1226 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1228 d2d_command_list_draw_bitmap(context->target.command_list, bitmap, dst_rect, opacity,
1229 d2d1_1_interp_mode_from_d2d1(interpolation_mode), src_rect, NULL);
1231 else
1233 d2d_device_context_draw_bitmap(context, bitmap, dst_rect, opacity,
1234 d2d1_1_interp_mode_from_d2d1(interpolation_mode), src_rect, NULL, NULL);
1238 static void STDMETHODCALLTYPE d2d_device_context_DrawText(ID2D1DeviceContext6 *iface,
1239 const WCHAR *string, UINT32 string_len, IDWriteTextFormat *text_format, const D2D1_RECT_F *layout_rect,
1240 ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options, DWRITE_MEASURING_MODE measuring_mode)
1242 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1243 IDWriteTextLayout *text_layout;
1244 IDWriteFactory *dwrite_factory;
1245 D2D1_POINT_2F origin;
1246 float width, height;
1247 HRESULT hr;
1249 TRACE("iface %p, string %s, string_len %u, text_format %p, layout_rect %s, "
1250 "brush %p, options %#x, measuring_mode %#x.\n",
1251 iface, debugstr_wn(string, string_len), string_len, text_format, debug_d2d_rect_f(layout_rect),
1252 brush, options, measuring_mode);
1254 if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
1255 &IID_IDWriteFactory, (IUnknown **)&dwrite_factory)))
1257 ERR("Failed to create dwrite factory, hr %#lx.\n", hr);
1258 return;
1261 width = max(0.0f, layout_rect->right - layout_rect->left);
1262 height = max(0.0f, layout_rect->bottom - layout_rect->top);
1263 if (measuring_mode == DWRITE_MEASURING_MODE_NATURAL)
1264 hr = IDWriteFactory_CreateTextLayout(dwrite_factory, string, string_len, text_format,
1265 width, height, &text_layout);
1266 else
1267 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(dwrite_factory, string, string_len, text_format,
1268 width, height, render_target->desc.dpiX / 96.0f, (DWRITE_MATRIX *)&render_target->drawing_state.transform,
1269 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, &text_layout);
1270 IDWriteFactory_Release(dwrite_factory);
1271 if (FAILED(hr))
1273 ERR("Failed to create text layout, hr %#lx.\n", hr);
1274 return;
1277 d2d_point_set(&origin, min(layout_rect->left, layout_rect->right), min(layout_rect->top, layout_rect->bottom));
1278 ID2D1DeviceContext1_DrawTextLayout((ID2D1DeviceContext1 *)iface, origin, text_layout, brush, options);
1279 IDWriteTextLayout_Release(text_layout);
1282 static void STDMETHODCALLTYPE d2d_device_context_DrawTextLayout(ID2D1DeviceContext6 *iface,
1283 D2D1_POINT_2F origin, IDWriteTextLayout *layout, ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options)
1285 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1286 struct d2d_draw_text_layout_ctx ctx;
1287 HRESULT hr;
1289 TRACE("iface %p, origin %s, layout %p, brush %p, options %#x.\n",
1290 iface, debug_d2d_point_2f(&origin), layout, brush, options);
1292 ctx.brush = brush;
1293 ctx.options = options;
1295 if (FAILED(hr = IDWriteTextLayout_Draw(layout,
1296 &ctx, &render_target->IDWriteTextRenderer_iface, origin.x, origin.y)))
1297 FIXME("Failed to draw text layout, hr %#lx.\n", hr);
1300 static D2D1_ANTIALIAS_MODE d2d_device_context_set_aa_mode_from_text_aa_mode(struct d2d_device_context *rt)
1302 D2D1_ANTIALIAS_MODE prev_antialias_mode = rt->drawing_state.antialiasMode;
1303 rt->drawing_state.antialiasMode = rt->drawing_state.textAntialiasMode == D2D1_TEXT_ANTIALIAS_MODE_ALIASED ?
1304 D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
1305 return prev_antialias_mode;
1308 static void d2d_device_context_draw_glyph_run_outline(struct d2d_device_context *render_target,
1309 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush)
1311 D2D1_MATRIX_3X2_F *transform, prev_transform;
1312 D2D1_ANTIALIAS_MODE prev_antialias_mode;
1313 ID2D1PathGeometry *geometry;
1314 ID2D1GeometrySink *sink;
1315 HRESULT hr;
1317 if (FAILED(hr = ID2D1Factory_CreatePathGeometry(render_target->factory, &geometry)))
1319 ERR("Failed to create geometry, hr %#lx.\n", hr);
1320 return;
1323 if (FAILED(hr = ID2D1PathGeometry_Open(geometry, &sink)))
1325 ERR("Failed to open geometry sink, hr %#lx.\n", hr);
1326 ID2D1PathGeometry_Release(geometry);
1327 return;
1330 if (FAILED(hr = IDWriteFontFace_GetGlyphRunOutline(glyph_run->fontFace, glyph_run->fontEmSize,
1331 glyph_run->glyphIndices, glyph_run->glyphAdvances, glyph_run->glyphOffsets, glyph_run->glyphCount,
1332 glyph_run->isSideways, glyph_run->bidiLevel & 1, (IDWriteGeometrySink *)sink)))
1334 ERR("Failed to get glyph run outline, hr %#lx.\n", hr);
1335 ID2D1GeometrySink_Release(sink);
1336 ID2D1PathGeometry_Release(geometry);
1337 return;
1340 if (FAILED(hr = ID2D1GeometrySink_Close(sink)))
1341 ERR("Failed to close geometry sink, hr %#lx.\n", hr);
1342 ID2D1GeometrySink_Release(sink);
1344 transform = &render_target->drawing_state.transform;
1345 prev_transform = *transform;
1346 transform->_31 += baseline_origin.x * transform->_11 + baseline_origin.y * transform->_21;
1347 transform->_32 += baseline_origin.x * transform->_12 + baseline_origin.y * transform->_22;
1348 prev_antialias_mode = d2d_device_context_set_aa_mode_from_text_aa_mode(render_target);
1349 d2d_device_context_fill_geometry(render_target, unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)geometry),
1350 unsafe_impl_from_ID2D1Brush(brush), NULL);
1351 render_target->drawing_state.antialiasMode = prev_antialias_mode;
1352 *transform = prev_transform;
1354 ID2D1PathGeometry_Release(geometry);
1357 static void d2d_device_context_draw_glyph_run_bitmap(struct d2d_device_context *context,
1358 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
1359 DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode,
1360 DWRITE_TEXT_ANTIALIAS_MODE antialias_mode)
1362 ID2D1RectangleGeometry *geometry = NULL;
1363 ID2D1BitmapBrush *opacity_brush = NULL;
1364 D2D1_BITMAP_PROPERTIES bitmap_desc;
1365 ID2D1Bitmap *opacity_bitmap = NULL;
1366 IDWriteGlyphRunAnalysis *analysis;
1367 DWRITE_TEXTURE_TYPE texture_type;
1368 D2D1_BRUSH_PROPERTIES brush_desc;
1369 IDWriteFactory2 *dwrite_factory;
1370 D2D1_MATRIX_3X2_F *transform, m;
1371 void *opacity_values = NULL;
1372 size_t opacity_values_size;
1373 D2D1_SIZE_U bitmap_size;
1374 float scale_x, scale_y;
1375 D2D1_RECT_F run_rect;
1376 RECT bounds;
1377 HRESULT hr;
1379 if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
1380 &IID_IDWriteFactory2, (IUnknown **)&dwrite_factory)))
1382 ERR("Failed to create dwrite factory, hr %#lx.\n", hr);
1383 return;
1386 transform = &context->drawing_state.transform;
1388 scale_x = context->desc.dpiX / 96.0f;
1389 m._11 = transform->_11 * scale_x;
1390 m._21 = transform->_21 * scale_x;
1391 m._31 = transform->_31 * scale_x;
1393 scale_y = context->desc.dpiY / 96.0f;
1394 m._12 = transform->_12 * scale_y;
1395 m._22 = transform->_22 * scale_y;
1396 m._32 = transform->_32 * scale_y;
1398 hr = IDWriteFactory2_CreateGlyphRunAnalysis(dwrite_factory, glyph_run, (DWRITE_MATRIX *)&m,
1399 rendering_mode, measuring_mode, DWRITE_GRID_FIT_MODE_DEFAULT, antialias_mode,
1400 baseline_origin.x, baseline_origin.y, &analysis);
1401 IDWriteFactory2_Release(dwrite_factory);
1402 if (FAILED(hr))
1404 ERR("Failed to create glyph run analysis, hr %#lx.\n", hr);
1405 return;
1408 if (rendering_mode == DWRITE_RENDERING_MODE_ALIASED || antialias_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
1409 texture_type = DWRITE_TEXTURE_ALIASED_1x1;
1410 else
1411 texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
1413 if (FAILED(hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, texture_type, &bounds)))
1415 ERR("Failed to get alpha texture bounds, hr %#lx.\n", hr);
1416 goto done;
1419 d2d_size_set(&bitmap_size, bounds.right - bounds.left, bounds.bottom - bounds.top);
1420 if (!bitmap_size.width || !bitmap_size.height)
1422 /* Empty run, nothing to do. */
1423 goto done;
1426 if (texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
1427 bitmap_size.width *= 3;
1428 if (!(opacity_values = calloc(bitmap_size.height, bitmap_size.width)))
1430 ERR("Failed to allocate opacity values.\n");
1431 goto done;
1433 opacity_values_size = bitmap_size.height * bitmap_size.width;
1435 if (FAILED(hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis,
1436 texture_type, &bounds, opacity_values, opacity_values_size)))
1438 ERR("Failed to create alpha texture, hr %#lx.\n", hr);
1439 goto done;
1442 bitmap_desc.pixelFormat.format = DXGI_FORMAT_A8_UNORM;
1443 bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
1444 bitmap_desc.dpiX = context->desc.dpiX;
1445 if (texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
1446 bitmap_desc.dpiX *= 3.0f;
1447 bitmap_desc.dpiY = context->desc.dpiY;
1448 if (FAILED(hr = d2d_device_context_CreateBitmap(&context->ID2D1DeviceContext6_iface,
1449 bitmap_size, opacity_values, bitmap_size.width, &bitmap_desc, &opacity_bitmap)))
1451 ERR("Failed to create opacity bitmap, hr %#lx.\n", hr);
1452 goto done;
1455 d2d_rect_set(&run_rect, bounds.left / scale_x, bounds.top / scale_y,
1456 bounds.right / scale_x, bounds.bottom / scale_y);
1458 brush_desc.opacity = 1.0f;
1459 brush_desc.transform._11 = 1.0f;
1460 brush_desc.transform._12 = 0.0f;
1461 brush_desc.transform._21 = 0.0f;
1462 brush_desc.transform._22 = 1.0f;
1463 brush_desc.transform._31 = run_rect.left;
1464 brush_desc.transform._32 = run_rect.top;
1465 if (FAILED(hr = d2d_device_context_CreateBitmapBrush(&context->ID2D1DeviceContext6_iface,
1466 opacity_bitmap, NULL, &brush_desc, &opacity_brush)))
1468 ERR("Failed to create opacity bitmap brush, hr %#lx.\n", hr);
1469 goto done;
1472 if (FAILED(hr = ID2D1Factory_CreateRectangleGeometry(context->factory, &run_rect, &geometry)))
1474 ERR("Failed to create geometry, hr %#lx.\n", hr);
1475 goto done;
1478 m = *transform;
1479 *transform = identity;
1480 d2d_device_context_fill_geometry(context, unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)geometry),
1481 unsafe_impl_from_ID2D1Brush(brush), unsafe_impl_from_ID2D1Brush((ID2D1Brush *)opacity_brush));
1482 *transform = m;
1484 done:
1485 if (geometry)
1486 ID2D1RectangleGeometry_Release(geometry);
1487 if (opacity_brush)
1488 ID2D1BitmapBrush_Release(opacity_brush);
1489 if (opacity_bitmap)
1490 ID2D1Bitmap_Release(opacity_bitmap);
1491 free(opacity_values);
1492 IDWriteGlyphRunAnalysis_Release(analysis);
1495 static void d2d_device_context_draw_glyph_run(struct d2d_device_context *context,
1496 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run,
1497 const DWRITE_GLYPH_RUN_DESCRIPTION *glyph_run_desc, ID2D1Brush *brush, DWRITE_MEASURING_MODE measuring_mode)
1499 DWRITE_TEXT_ANTIALIAS_MODE antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
1500 IDWriteRenderingParams *rendering_params;
1501 DWRITE_RENDERING_MODE rendering_mode;
1502 HRESULT hr;
1504 if (FAILED(context->error.code))
1505 return;
1507 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1509 d2d_command_list_draw_glyph_run(context->target.command_list, context, baseline_origin, glyph_run,
1510 glyph_run_desc, brush, measuring_mode);
1511 return;
1514 rendering_params = context->text_rendering_params ? context->text_rendering_params
1515 : context->default_text_rendering_params;
1517 rendering_mode = IDWriteRenderingParams_GetRenderingMode(rendering_params);
1519 switch (context->drawing_state.textAntialiasMode)
1521 case D2D1_TEXT_ANTIALIAS_MODE_ALIASED:
1522 if (rendering_mode == DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL
1523 || rendering_mode == DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC
1524 || rendering_mode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL
1525 || rendering_mode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC)
1526 d2d_device_context_set_error(context, E_INVALIDARG);
1527 break;
1529 case D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE:
1530 if (rendering_mode == DWRITE_RENDERING_MODE_ALIASED
1531 || rendering_mode == DWRITE_RENDERING_MODE_OUTLINE)
1532 d2d_device_context_set_error(context, E_INVALIDARG);
1533 break;
1535 case D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE:
1536 if (rendering_mode == DWRITE_RENDERING_MODE_ALIASED)
1537 d2d_device_context_set_error(context, E_INVALIDARG);
1538 break;
1540 default:
1541 break;
1544 if (FAILED(context->error.code))
1545 return;
1547 rendering_mode = DWRITE_RENDERING_MODE_DEFAULT;
1548 switch (context->drawing_state.textAntialiasMode)
1550 case D2D1_TEXT_ANTIALIAS_MODE_DEFAULT:
1551 if (IDWriteRenderingParams_GetClearTypeLevel(rendering_params) > 0.0f)
1552 antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
1553 break;
1555 case D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE:
1556 antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
1557 break;
1559 case D2D1_TEXT_ANTIALIAS_MODE_ALIASED:
1560 rendering_mode = DWRITE_RENDERING_MODE_ALIASED;
1561 break;
1563 default:
1564 break;
1567 if (rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
1569 if (FAILED(hr = IDWriteFontFace_GetRecommendedRenderingMode(glyph_run->fontFace, glyph_run->fontEmSize,
1570 max(context->desc.dpiX, context->desc.dpiY) / 96.0f,
1571 measuring_mode, rendering_params, &rendering_mode)))
1573 ERR("Failed to get recommended rendering mode, hr %#lx.\n", hr);
1574 rendering_mode = DWRITE_RENDERING_MODE_OUTLINE;
1578 if (rendering_mode == DWRITE_RENDERING_MODE_OUTLINE)
1579 d2d_device_context_draw_glyph_run_outline(context, baseline_origin, glyph_run, brush);
1580 else
1581 d2d_device_context_draw_glyph_run_bitmap(context, baseline_origin, glyph_run, brush,
1582 rendering_mode, measuring_mode, antialias_mode);
1585 static void STDMETHODCALLTYPE d2d_device_context_DrawGlyphRun(ID2D1DeviceContext6 *iface,
1586 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
1587 DWRITE_MEASURING_MODE measuring_mode)
1589 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1591 TRACE("iface %p, baseline_origin %s, glyph_run %p, brush %p, measuring_mode %#x.\n",
1592 iface, debug_d2d_point_2f(&baseline_origin), glyph_run, brush, measuring_mode);
1594 d2d_device_context_draw_glyph_run(context, baseline_origin, glyph_run, NULL, brush, measuring_mode);
1597 static void STDMETHODCALLTYPE d2d_device_context_SetTransform(ID2D1DeviceContext6 *iface,
1598 const D2D1_MATRIX_3X2_F *transform)
1600 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1602 TRACE("iface %p, transform %p.\n", iface, transform);
1604 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1605 d2d_command_list_set_transform(context->target.command_list, transform);
1607 context->drawing_state.transform = *transform;
1610 static void STDMETHODCALLTYPE d2d_device_context_GetTransform(ID2D1DeviceContext6 *iface,
1611 D2D1_MATRIX_3X2_F *transform)
1613 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1615 TRACE("iface %p, transform %p.\n", iface, transform);
1617 *transform = render_target->drawing_state.transform;
1620 static void STDMETHODCALLTYPE d2d_device_context_SetAntialiasMode(ID2D1DeviceContext6 *iface,
1621 D2D1_ANTIALIAS_MODE antialias_mode)
1623 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1625 TRACE("iface %p, antialias_mode %#x stub!\n", iface, antialias_mode);
1627 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1628 d2d_command_list_set_antialias_mode(context->target.command_list, antialias_mode);
1630 context->drawing_state.antialiasMode = antialias_mode;
1633 static D2D1_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_device_context_GetAntialiasMode(ID2D1DeviceContext6 *iface)
1635 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1637 TRACE("iface %p.\n", iface);
1639 return render_target->drawing_state.antialiasMode;
1642 static void STDMETHODCALLTYPE d2d_device_context_SetTextAntialiasMode(ID2D1DeviceContext6 *iface,
1643 D2D1_TEXT_ANTIALIAS_MODE antialias_mode)
1645 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1647 TRACE("iface %p, antialias_mode %#x.\n", iface, antialias_mode);
1649 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1650 d2d_command_list_set_text_antialias_mode(context->target.command_list, antialias_mode);
1652 context->drawing_state.textAntialiasMode = antialias_mode;
1655 static D2D1_TEXT_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_device_context_GetTextAntialiasMode(ID2D1DeviceContext6 *iface)
1657 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1659 TRACE("iface %p.\n", iface);
1661 return render_target->drawing_state.textAntialiasMode;
1664 static void STDMETHODCALLTYPE d2d_device_context_SetTextRenderingParams(ID2D1DeviceContext6 *iface,
1665 IDWriteRenderingParams *text_rendering_params)
1667 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1669 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
1671 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1672 d2d_command_list_set_text_rendering_params(context->target.command_list, text_rendering_params);
1674 if (text_rendering_params)
1675 IDWriteRenderingParams_AddRef(text_rendering_params);
1676 if (context->text_rendering_params)
1677 IDWriteRenderingParams_Release(context->text_rendering_params);
1678 context->text_rendering_params = text_rendering_params;
1681 static void STDMETHODCALLTYPE d2d_device_context_GetTextRenderingParams(ID2D1DeviceContext6 *iface,
1682 IDWriteRenderingParams **text_rendering_params)
1684 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1686 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
1688 if ((*text_rendering_params = render_target->text_rendering_params))
1689 IDWriteRenderingParams_AddRef(*text_rendering_params);
1692 static void STDMETHODCALLTYPE d2d_device_context_SetTags(ID2D1DeviceContext6 *iface, D2D1_TAG tag1, D2D1_TAG tag2)
1694 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1696 TRACE("iface %p, tag1 %s, tag2 %s.\n", iface, wine_dbgstr_longlong(tag1), wine_dbgstr_longlong(tag2));
1698 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1699 d2d_command_list_set_tags(context->target.command_list, tag1, tag2);
1701 context->drawing_state.tag1 = tag1;
1702 context->drawing_state.tag2 = tag2;
1705 static void STDMETHODCALLTYPE d2d_device_context_GetTags(ID2D1DeviceContext6 *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
1707 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1709 TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2);
1711 *tag1 = render_target->drawing_state.tag1;
1712 *tag2 = render_target->drawing_state.tag2;
1715 static void STDMETHODCALLTYPE d2d_device_context_PushLayer(ID2D1DeviceContext6 *iface,
1716 const D2D1_LAYER_PARAMETERS *layer_parameters, ID2D1Layer *layer)
1718 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1720 FIXME("iface %p, layer_parameters %p, layer %p stub!\n", iface, layer_parameters, layer);
1722 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1724 D2D1_LAYER_PARAMETERS1 parameters;
1726 memcpy(&parameters, layer_parameters, sizeof(*layer_parameters));
1727 parameters.layerOptions = D2D1_LAYER_OPTIONS1_NONE;
1728 d2d_command_list_push_layer(context->target.command_list, context, &parameters, layer);
1732 static void STDMETHODCALLTYPE d2d_device_context_PopLayer(ID2D1DeviceContext6 *iface)
1734 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1736 FIXME("iface %p stub!\n", iface);
1738 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1739 d2d_command_list_pop_layer(context->target.command_list);
1742 static HRESULT STDMETHODCALLTYPE d2d_device_context_Flush(ID2D1DeviceContext6 *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
1744 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1746 FIXME("iface %p, tag1 %p, tag2 %p stub!\n", iface, tag1, tag2);
1748 if (context->ops && context->ops->device_context_present)
1749 context->ops->device_context_present(context->outer_unknown);
1751 return E_NOTIMPL;
1754 static void STDMETHODCALLTYPE d2d_device_context_SaveDrawingState(ID2D1DeviceContext6 *iface,
1755 ID2D1DrawingStateBlock *state_block)
1757 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1758 struct d2d_state_block *state_block_impl;
1760 TRACE("iface %p, state_block %p.\n", iface, state_block);
1762 if (!(state_block_impl = unsafe_impl_from_ID2D1DrawingStateBlock(state_block))) return;
1763 state_block_impl->drawing_state = render_target->drawing_state;
1764 if (render_target->text_rendering_params)
1765 IDWriteRenderingParams_AddRef(render_target->text_rendering_params);
1766 if (state_block_impl->text_rendering_params)
1767 IDWriteRenderingParams_Release(state_block_impl->text_rendering_params);
1768 state_block_impl->text_rendering_params = render_target->text_rendering_params;
1771 static void STDMETHODCALLTYPE d2d_device_context_RestoreDrawingState(ID2D1DeviceContext6 *iface,
1772 ID2D1DrawingStateBlock *state_block)
1774 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1775 struct d2d_state_block *state_block_impl;
1777 TRACE("iface %p, state_block %p.\n", iface, state_block);
1779 if (!(state_block_impl = unsafe_impl_from_ID2D1DrawingStateBlock(state_block))) return;
1780 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1782 struct d2d_command_list *command_list = context->target.command_list;
1784 if (context->drawing_state.antialiasMode != state_block_impl->drawing_state.antialiasMode)
1785 d2d_command_list_set_antialias_mode(command_list, state_block_impl->drawing_state.antialiasMode);
1786 d2d_command_list_set_text_antialias_mode(command_list, state_block_impl->drawing_state.textAntialiasMode);
1787 d2d_command_list_set_tags(command_list, state_block_impl->drawing_state.tag1, state_block_impl->drawing_state.tag2);
1788 d2d_command_list_set_transform(command_list, &state_block_impl->drawing_state.transform);
1789 d2d_command_list_set_primitive_blend(command_list, state_block_impl->drawing_state.primitiveBlend);
1790 d2d_command_list_set_unit_mode(command_list, state_block_impl->drawing_state.unitMode);
1791 d2d_command_list_set_text_rendering_params(command_list, state_block_impl->text_rendering_params);
1794 context->drawing_state = state_block_impl->drawing_state;
1795 if (state_block_impl->text_rendering_params)
1796 IDWriteRenderingParams_AddRef(state_block_impl->text_rendering_params);
1797 if (context->text_rendering_params)
1798 IDWriteRenderingParams_Release(context->text_rendering_params);
1799 context->text_rendering_params = state_block_impl->text_rendering_params;
1802 static void STDMETHODCALLTYPE d2d_device_context_PushAxisAlignedClip(ID2D1DeviceContext6 *iface,
1803 const D2D1_RECT_F *clip_rect, D2D1_ANTIALIAS_MODE antialias_mode)
1805 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1806 D2D1_RECT_F transformed_rect;
1807 float x_scale, y_scale;
1808 D2D1_POINT_2F point;
1810 TRACE("iface %p, clip_rect %s, antialias_mode %#x.\n", iface, debug_d2d_rect_f(clip_rect), antialias_mode);
1812 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1813 d2d_command_list_push_clip(context->target.command_list, clip_rect, antialias_mode);
1815 if (antialias_mode != D2D1_ANTIALIAS_MODE_ALIASED)
1816 FIXME("Ignoring antialias_mode %#x.\n", antialias_mode);
1818 x_scale = context->desc.dpiX / 96.0f;
1819 y_scale = context->desc.dpiY / 96.0f;
1820 d2d_point_transform(&point, &context->drawing_state.transform,
1821 clip_rect->left * x_scale, clip_rect->top * y_scale);
1822 d2d_rect_set(&transformed_rect, point.x, point.y, point.x, point.y);
1823 d2d_point_transform(&point, &context->drawing_state.transform,
1824 clip_rect->left * x_scale, clip_rect->bottom * y_scale);
1825 d2d_rect_expand(&transformed_rect, &point);
1826 d2d_point_transform(&point, &context->drawing_state.transform,
1827 clip_rect->right * x_scale, clip_rect->top * y_scale);
1828 d2d_rect_expand(&transformed_rect, &point);
1829 d2d_point_transform(&point, &context->drawing_state.transform,
1830 clip_rect->right * x_scale, clip_rect->bottom * y_scale);
1831 d2d_rect_expand(&transformed_rect, &point);
1833 if (!d2d_clip_stack_push(&context->clip_stack, &transformed_rect))
1834 WARN("Failed to push clip rect.\n");
1837 static void STDMETHODCALLTYPE d2d_device_context_PopAxisAlignedClip(ID2D1DeviceContext6 *iface)
1839 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1841 TRACE("iface %p.\n", iface);
1843 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1844 d2d_command_list_pop_clip(context->target.command_list);
1846 d2d_clip_stack_pop(&context->clip_stack);
1849 static void STDMETHODCALLTYPE d2d_device_context_Clear(ID2D1DeviceContext6 *iface, const D2D1_COLOR_F *colour)
1851 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1852 D3D11_MAPPED_SUBRESOURCE map_desc;
1853 ID3D11DeviceContext *d3d_context;
1854 struct d2d_ps_cb *ps_cb_data;
1855 struct d2d_vs_cb *vs_cb_data;
1856 D2D1_COLOR_F *c;
1857 HRESULT hr;
1859 TRACE("iface %p, colour %p.\n", iface, colour);
1861 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1863 d2d_command_list_clear(context->target.command_list, colour);
1864 return;
1867 ID3D11Device1_GetImmediateContext(context->d3d_device, &d3d_context);
1869 if (FAILED(hr = ID3D11DeviceContext_Map(d3d_context, (ID3D11Resource *)context->vs_cb,
1870 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc)))
1872 WARN("Failed to map vs constant buffer, hr %#lx.\n", hr);
1873 ID3D11DeviceContext_Release(d3d_context);
1874 return;
1877 vs_cb_data = map_desc.pData;
1878 vs_cb_data->transform_geometry._11 = 1.0f;
1879 vs_cb_data->transform_geometry._21 = 0.0f;
1880 vs_cb_data->transform_geometry._31 = 0.0f;
1881 vs_cb_data->transform_geometry.pad0 = 0.0f;
1882 vs_cb_data->transform_geometry._12 = 0.0f;
1883 vs_cb_data->transform_geometry._22 = 1.0f;
1884 vs_cb_data->transform_geometry._32 = 0.0f;
1885 vs_cb_data->transform_geometry.stroke_width = 0.0f;
1886 vs_cb_data->transform_rtx.x = 1.0f;
1887 vs_cb_data->transform_rtx.y = 0.0f;
1888 vs_cb_data->transform_rtx.z = 1.0f;
1889 vs_cb_data->transform_rtx.w = 1.0f;
1890 vs_cb_data->transform_rty.x = 0.0f;
1891 vs_cb_data->transform_rty.y = 1.0f;
1892 vs_cb_data->transform_rty.z = 1.0f;
1893 vs_cb_data->transform_rty.w = -1.0f;
1895 ID3D11DeviceContext_Unmap(d3d_context, (ID3D11Resource *)context->vs_cb, 0);
1897 if (FAILED(hr = ID3D11DeviceContext_Map(d3d_context, (ID3D11Resource *)context->ps_cb,
1898 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc)))
1900 WARN("Failed to map ps constant buffer, hr %#lx.\n", hr);
1901 ID3D11DeviceContext_Release(d3d_context);
1902 return;
1905 ps_cb_data = map_desc.pData;
1906 memset(ps_cb_data, 0, sizeof(*ps_cb_data));
1907 ps_cb_data->colour_brush.type = D2D_BRUSH_TYPE_SOLID;
1908 ps_cb_data->colour_brush.opacity = 1.0f;
1909 ps_cb_data->opacity_brush.type = D2D_BRUSH_TYPE_COUNT;
1910 c = &ps_cb_data->colour_brush.u.solid.colour;
1911 if (colour)
1912 *c = *colour;
1913 if (context->desc.pixelFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE)
1914 c->a = 1.0f;
1915 c->r *= c->a;
1916 c->g *= c->a;
1917 c->b *= c->a;
1919 ID3D11DeviceContext_Unmap(d3d_context, (ID3D11Resource *)context->ps_cb, 0);
1920 ID3D11DeviceContext_Release(d3d_context);
1922 d2d_device_context_draw(context, D2D_SHAPE_TYPE_TRIANGLE, context->ib, 6,
1923 context->vb, context->vb_stride, NULL, NULL);
1926 static void STDMETHODCALLTYPE d2d_device_context_BeginDraw(ID2D1DeviceContext6 *iface)
1928 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1930 TRACE("iface %p.\n", iface);
1932 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1933 d2d_command_list_begin_draw(context->target.command_list, context);
1935 memset(&context->error, 0, sizeof(context->error));
1938 static HRESULT STDMETHODCALLTYPE d2d_device_context_EndDraw(ID2D1DeviceContext6 *iface,
1939 D2D1_TAG *tag1, D2D1_TAG *tag2)
1941 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
1942 HRESULT hr;
1944 TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2);
1946 if (context->target.type == D2D_TARGET_COMMAND_LIST)
1948 FIXME("Unimplemented for command list target.\n");
1949 return E_NOTIMPL;
1952 if (tag1)
1953 *tag1 = context->error.tag1;
1954 if (tag2)
1955 *tag2 = context->error.tag2;
1957 if (context->ops && context->ops->device_context_present)
1959 if (FAILED(hr = context->ops->device_context_present(context->outer_unknown)))
1960 context->error.code = hr;
1963 return context->error.code;
1966 static D2D1_PIXEL_FORMAT * STDMETHODCALLTYPE d2d_device_context_GetPixelFormat(ID2D1DeviceContext6 *iface,
1967 D2D1_PIXEL_FORMAT *format)
1969 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1971 TRACE("iface %p, format %p.\n", iface, format);
1973 *format = render_target->desc.pixelFormat;
1974 return format;
1977 static void STDMETHODCALLTYPE d2d_device_context_SetDpi(ID2D1DeviceContext6 *iface, float dpi_x, float dpi_y)
1979 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1981 TRACE("iface %p, dpi_x %.8e, dpi_y %.8e.\n", iface, dpi_x, dpi_y);
1983 if (dpi_x == 0.0f && dpi_y == 0.0f)
1985 dpi_x = 96.0f;
1986 dpi_y = 96.0f;
1988 else if (dpi_x <= 0.0f || dpi_y <= 0.0f)
1989 return;
1991 render_target->desc.dpiX = dpi_x;
1992 render_target->desc.dpiY = dpi_y;
1995 static void STDMETHODCALLTYPE d2d_device_context_GetDpi(ID2D1DeviceContext6 *iface, float *dpi_x, float *dpi_y)
1997 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
1999 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
2001 *dpi_x = render_target->desc.dpiX;
2002 *dpi_y = render_target->desc.dpiY;
2005 static D2D1_SIZE_F * STDMETHODCALLTYPE d2d_device_context_GetSize(ID2D1DeviceContext6 *iface, D2D1_SIZE_F *size)
2007 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
2009 TRACE("iface %p, size %p.\n", iface, size);
2011 size->width = render_target->pixel_size.width / (render_target->desc.dpiX / 96.0f);
2012 size->height = render_target->pixel_size.height / (render_target->desc.dpiY / 96.0f);
2013 return size;
2016 static D2D1_SIZE_U * STDMETHODCALLTYPE d2d_device_context_GetPixelSize(ID2D1DeviceContext6 *iface,
2017 D2D1_SIZE_U *pixel_size)
2019 struct d2d_device_context *render_target = impl_from_ID2D1DeviceContext(iface);
2021 TRACE("iface %p, pixel_size %p.\n", iface, pixel_size);
2023 *pixel_size = render_target->pixel_size;
2024 return pixel_size;
2027 static UINT32 STDMETHODCALLTYPE d2d_device_context_GetMaximumBitmapSize(ID2D1DeviceContext6 *iface)
2029 TRACE("iface %p.\n", iface);
2031 return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
2034 static BOOL STDMETHODCALLTYPE d2d_device_context_IsSupported(ID2D1DeviceContext6 *iface,
2035 const D2D1_RENDER_TARGET_PROPERTIES *desc)
2037 FIXME("iface %p, desc %p stub!\n", iface, desc);
2039 return FALSE;
2042 static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateBitmap(ID2D1DeviceContext6 *iface,
2043 D2D1_SIZE_U size, const void *src_data, UINT32 pitch,
2044 const D2D1_BITMAP_PROPERTIES1 *desc, ID2D1Bitmap1 **bitmap)
2046 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2047 struct d2d_bitmap *object;
2048 HRESULT hr;
2050 TRACE("iface %p, size {%u, %u}, src_data %p, pitch %u, desc %p, bitmap %p.\n",
2051 iface, size.width, size.height, src_data, pitch, desc, bitmap);
2053 if (SUCCEEDED(hr = d2d_bitmap_create(context, size, src_data, pitch, desc, &object)))
2054 *bitmap = &object->ID2D1Bitmap1_iface;
2056 return hr;
2059 static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateBitmapFromWicBitmap(
2060 ID2D1DeviceContext6 *iface, IWICBitmapSource *bitmap_source,
2061 const D2D1_BITMAP_PROPERTIES1 *desc, ID2D1Bitmap1 **bitmap)
2063 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2064 struct d2d_bitmap *object;
2065 HRESULT hr;
2067 TRACE("iface %p, bitmap_source %p, desc %p, bitmap %p.\n", iface, bitmap_source, desc, bitmap);
2069 if (SUCCEEDED(hr = d2d_bitmap_create_from_wic_bitmap(context, bitmap_source, desc, &object)))
2070 *bitmap = &object->ID2D1Bitmap1_iface;
2072 return hr;
2075 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateColorContext(ID2D1DeviceContext6 *iface,
2076 D2D1_COLOR_SPACE space, const BYTE *profile, UINT32 profile_size, ID2D1ColorContext **color_context)
2078 FIXME("iface %p, space %#x, profile %p, profile_size %u, color_context %p stub!\n",
2079 iface, space, profile, profile_size, color_context);
2081 return E_NOTIMPL;
2084 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateColorContextFromFilename(ID2D1DeviceContext6 *iface,
2085 const WCHAR *filename, ID2D1ColorContext **color_context)
2087 FIXME("iface %p, filename %s, color_context %p stub!\n", iface, debugstr_w(filename), color_context);
2089 return E_NOTIMPL;
2092 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateColorContextFromWicColorContext(ID2D1DeviceContext6 *iface,
2093 IWICColorContext *wic_color_context, ID2D1ColorContext **color_context)
2095 FIXME("iface %p, wic_color_context %p, color_context %p stub!\n", iface, wic_color_context, color_context);
2097 return E_NOTIMPL;
2100 static BOOL d2d_bitmap_check_options_with_surface(unsigned int options, unsigned int surface_options)
2102 switch (options)
2104 case D2D1_BITMAP_OPTIONS_NONE:
2105 case D2D1_BITMAP_OPTIONS_TARGET:
2106 case D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW:
2107 case D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE:
2108 case D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE:
2109 case D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ:
2110 case D2D1_BITMAP_OPTIONS_CANNOT_DRAW:
2111 break;
2112 default:
2113 WARN("Invalid bitmap options %#x.\n", options);
2114 return FALSE;
2117 if (options && (options & D2D1_BITMAP_OPTIONS_TARGET) != (surface_options & D2D1_BITMAP_OPTIONS_TARGET))
2118 return FALSE;
2119 if (!(options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW) && (surface_options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW))
2120 return FALSE;
2121 if (options & D2D1_BITMAP_OPTIONS_TARGET)
2123 if (options & D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE && !(surface_options & D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE))
2124 return FALSE;
2125 return TRUE;
2128 if (options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW)
2130 if (!(surface_options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW))
2131 return FALSE;
2133 if (options & D2D1_BITMAP_OPTIONS_CPU_READ && !(surface_options & D2D1_BITMAP_OPTIONS_CPU_READ))
2134 return FALSE;
2137 return TRUE;
2140 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmapFromDxgiSurface(ID2D1DeviceContext6 *iface,
2141 IDXGISurface *surface, const D2D1_BITMAP_PROPERTIES1 *desc, ID2D1Bitmap1 **bitmap)
2143 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2144 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
2145 unsigned int surface_options;
2146 struct d2d_bitmap *object;
2147 HRESULT hr;
2149 TRACE("iface %p, surface %p, desc %p, bitmap %p.\n", iface, surface, desc, bitmap);
2151 surface_options = d2d_get_bitmap_options_for_surface(surface);
2153 if (desc)
2155 if (!d2d_bitmap_check_options_with_surface(desc->bitmapOptions, surface_options))
2157 WARN("Incompatible bitmap options %#x, surface options %#x.\n",
2158 desc->bitmapOptions, surface_options);
2159 return E_INVALIDARG;
2162 else
2164 DXGI_SURFACE_DESC surface_desc;
2166 if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc)))
2168 WARN("Failed to get surface desc, hr %#lx.\n", hr);
2169 return hr;
2172 memset(&bitmap_desc, 0, sizeof(bitmap_desc));
2173 bitmap_desc.pixelFormat.format = surface_desc.Format;
2174 bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
2175 bitmap_desc.bitmapOptions = surface_options;
2176 desc = &bitmap_desc;
2179 if (SUCCEEDED(hr = d2d_bitmap_create_shared(context, &IID_IDXGISurface, surface, desc, &object)))
2180 *bitmap = &object->ID2D1Bitmap1_iface;
2182 return hr;
2185 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateEffect(ID2D1DeviceContext6 *iface,
2186 REFCLSID effect_id, ID2D1Effect **effect)
2188 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2190 TRACE("iface %p, effect_id %s, effect %p.\n", iface, debugstr_guid(effect_id), effect);
2192 return d2d_effect_create(context, effect_id, effect);
2195 static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateGradientStopCollection(
2196 ID2D1DeviceContext6 *iface, const D2D1_GRADIENT_STOP *stops, UINT32 stop_count,
2197 D2D1_COLOR_SPACE preinterpolation_space, D2D1_COLOR_SPACE postinterpolation_space,
2198 D2D1_BUFFER_PRECISION buffer_precision, D2D1_EXTEND_MODE extend_mode,
2199 D2D1_COLOR_INTERPOLATION_MODE color_interpolation_mode, ID2D1GradientStopCollection1 **gradient)
2201 FIXME("iface %p, stops %p, stop_count %u, preinterpolation_space %#x, postinterpolation_space %#x, "
2202 "buffer_precision %#x, extend_mode %#x, color_interpolation_mode %#x, gradient %p stub!\n",
2203 iface, stops, stop_count, preinterpolation_space, postinterpolation_space,
2204 buffer_precision, extend_mode, color_interpolation_mode, gradient);
2206 return E_NOTIMPL;
2209 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateImageBrush(ID2D1DeviceContext6 *iface,
2210 ID2D1Image *image, const D2D1_IMAGE_BRUSH_PROPERTIES *image_brush_desc,
2211 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1ImageBrush **brush)
2213 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2214 struct d2d_brush *object;
2215 HRESULT hr;
2217 TRACE("iface %p, image %p, image_brush_desc %p, brush_desc %p, brush %p.\n", iface, image, image_brush_desc,
2218 brush_desc, brush);
2220 if (SUCCEEDED(hr = d2d_image_brush_create(context->factory, image, image_brush_desc,
2221 brush_desc, &object)))
2222 *brush = (ID2D1ImageBrush *)&object->ID2D1Brush_iface;
2224 return hr;
2227 static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateBitmapBrush(ID2D1DeviceContext6 *iface,
2228 ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES1 *bitmap_brush_desc,
2229 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1BitmapBrush1 **brush)
2231 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2232 struct d2d_brush *object;
2233 HRESULT hr;
2235 TRACE("iface %p, bitmap %p, bitmap_brush_desc %p, brush_desc %p, brush %p.\n", iface, bitmap, bitmap_brush_desc,
2236 brush_desc, brush);
2238 if (SUCCEEDED(hr = d2d_bitmap_brush_create(context->factory, bitmap, bitmap_brush_desc, brush_desc, &object)))
2239 *brush = (ID2D1BitmapBrush1 *)&object->ID2D1Brush_iface;
2241 return hr;
2244 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateCommandList(ID2D1DeviceContext6 *iface,
2245 ID2D1CommandList **command_list)
2247 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2248 struct d2d_command_list *object;
2249 HRESULT hr;
2251 TRACE("iface %p, command_list %p.\n", iface, command_list);
2253 if (SUCCEEDED(hr = d2d_command_list_create(context->factory, &object)))
2254 *command_list = &object->ID2D1CommandList_iface;
2256 return hr;
2259 static BOOL STDMETHODCALLTYPE d2d_device_context_IsDxgiFormatSupported(ID2D1DeviceContext6 *iface, DXGI_FORMAT format)
2261 FIXME("iface %p, format %#x stub!\n", iface, format);
2263 return FALSE;
2266 static BOOL STDMETHODCALLTYPE d2d_device_context_IsBufferPrecisionSupported(ID2D1DeviceContext6 *iface,
2267 D2D1_BUFFER_PRECISION buffer_precision)
2269 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2270 DXGI_FORMAT format;
2271 UINT support = 0;
2272 HRESULT hr;
2274 TRACE("iface %p, buffer_precision %u.\n", iface, buffer_precision);
2276 switch (buffer_precision)
2278 case D2D1_BUFFER_PRECISION_8BPC_UNORM: format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
2279 case D2D1_BUFFER_PRECISION_8BPC_UNORM_SRGB: format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; break;
2280 case D2D1_BUFFER_PRECISION_16BPC_UNORM: format = DXGI_FORMAT_R16G16B16A16_UNORM; break;
2281 case D2D1_BUFFER_PRECISION_16BPC_FLOAT: format = DXGI_FORMAT_R16G16B16A16_FLOAT; break;
2282 case D2D1_BUFFER_PRECISION_32BPC_FLOAT: format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
2283 default:
2284 WARN("Unexpected precision %u.\n", buffer_precision);
2285 return FALSE;
2288 if (FAILED(hr = ID3D11Device1_CheckFormatSupport(context->d3d_device, format, &support)))
2290 WARN("Format support check failed, hr %#lx.\n", hr);
2293 return !!(support & D3D11_FORMAT_SUPPORT_BUFFER);
2296 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetImageLocalBounds(ID2D1DeviceContext6 *iface,
2297 ID2D1Image *image, D2D1_RECT_F *local_bounds)
2299 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2300 D2D_SIZE_U pixel_size;
2301 ID2D1Bitmap *bitmap;
2302 D2D_SIZE_F size;
2304 TRACE("iface %p, image %p, local_bounds %p.\n", iface, image, local_bounds);
2306 if (SUCCEEDED(ID2D1Image_QueryInterface(image, &IID_ID2D1Bitmap, (void **)&bitmap)))
2308 local_bounds->left = 0.0f;
2309 local_bounds->top = 0.0f;
2310 switch (context->drawing_state.unitMode)
2312 case D2D1_UNIT_MODE_DIPS:
2313 size = ID2D1Bitmap_GetSize(bitmap);
2314 local_bounds->right = size.width;
2315 local_bounds->bottom = size.height;
2316 break;
2318 case D2D1_UNIT_MODE_PIXELS:
2319 pixel_size = ID2D1Bitmap_GetPixelSize(bitmap);
2320 local_bounds->right = pixel_size.width;
2321 local_bounds->bottom = pixel_size.height;
2322 break;
2324 default:
2325 WARN("Unknown unit mode %#x.\n", context->drawing_state.unitMode);
2326 break;
2328 ID2D1Bitmap_Release(bitmap);
2330 return S_OK;
2332 else
2334 FIXME("Unable to get local bounds of image %p.\n", image);
2336 return E_NOTIMPL;
2340 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetImageWorldBounds(ID2D1DeviceContext6 *iface,
2341 ID2D1Image *image, D2D1_RECT_F *world_bounds)
2343 FIXME("iface %p, image %p, world_bounds %p stub!\n", iface, image, world_bounds);
2345 return E_NOTIMPL;
2348 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetGlyphRunWorldBounds(ID2D1DeviceContext6 *iface,
2349 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run,
2350 DWRITE_MEASURING_MODE measuring_mode, D2D1_RECT_F *bounds)
2352 FIXME("iface %p, baseline_origin %s, glyph_run %p, measuring_mode %#x, bounds %p stub!\n",
2353 iface, debug_d2d_point_2f(&baseline_origin), glyph_run, measuring_mode, bounds);
2355 return E_NOTIMPL;
2358 static void STDMETHODCALLTYPE d2d_device_context_GetDevice(ID2D1DeviceContext6 *iface, ID2D1Device **device)
2360 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2362 TRACE("iface %p, device %p.\n", iface, device);
2364 *device = (ID2D1Device *)&context->device->ID2D1Device6_iface;
2365 ID2D1Device_AddRef(*device);
2368 static void d2d_device_context_reset_target(struct d2d_device_context *context)
2370 if (!context->target.object)
2371 return;
2373 IUnknown_Release(context->target.object);
2374 memset(&context->target, 0, sizeof(context->target));
2376 /* Note that DPI settings are kept. */
2377 memset(&context->desc.pixelFormat, 0, sizeof(context->desc.pixelFormat));
2378 memset(&context->pixel_size, 0, sizeof(context->pixel_size));
2380 if (context->bs)
2381 ID3D11BlendState_Release(context->bs);
2382 context->bs = NULL;
2385 static void STDMETHODCALLTYPE d2d_device_context_SetTarget(ID2D1DeviceContext6 *iface, ID2D1Image *target)
2387 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2388 struct d2d_command_list *command_list_impl;
2389 struct d2d_bitmap *bitmap_impl;
2390 ID2D1CommandList *command_list;
2391 D3D11_BLEND_DESC blend_desc;
2392 ID2D1Bitmap *bitmap;
2393 HRESULT hr;
2395 TRACE("iface %p, target %p.\n", iface, target);
2397 if (!target)
2399 d2d_device_context_reset_target(context);
2400 return;
2403 if (SUCCEEDED(ID2D1Image_QueryInterface(target, &IID_ID2D1Bitmap, (void **)&bitmap)))
2405 bitmap_impl = unsafe_impl_from_ID2D1Bitmap(bitmap);
2407 if (!(bitmap_impl->options & D2D1_BITMAP_OPTIONS_TARGET))
2409 ID2D1Bitmap_Release(bitmap);
2410 d2d_device_context_set_error(context, D2DERR_INVALID_TARGET);
2411 return;
2414 d2d_device_context_reset_target(context);
2416 /* Set sizes and pixel format. */
2417 context->pixel_size = bitmap_impl->pixel_size;
2418 context->desc.pixelFormat = bitmap_impl->format;
2419 context->target.bitmap = bitmap_impl;
2420 context->target.object = target;
2421 context->target.type = D2D_TARGET_BITMAP;
2423 memset(&blend_desc, 0, sizeof(blend_desc));
2424 blend_desc.IndependentBlendEnable = FALSE;
2425 blend_desc.RenderTarget[0].BlendEnable = TRUE;
2426 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
2427 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
2428 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
2429 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
2430 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
2431 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
2432 blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
2433 if (FAILED(hr = ID3D11Device1_CreateBlendState(context->d3d_device, &blend_desc, &context->bs)))
2434 WARN("Failed to create blend state, hr %#lx.\n", hr);
2436 else if (SUCCEEDED(ID2D1Image_QueryInterface(target, &IID_ID2D1CommandList, (void **)&command_list)))
2438 command_list_impl = unsafe_impl_from_ID2D1CommandList(command_list);
2440 d2d_device_context_reset_target(context);
2442 context->target.command_list = command_list_impl;
2443 context->target.object = target;
2444 context->target.type = D2D_TARGET_COMMAND_LIST;
2446 else
2448 WARN("Unsupported target type.\n");
2452 static void STDMETHODCALLTYPE d2d_device_context_GetTarget(ID2D1DeviceContext6 *iface, ID2D1Image **target)
2454 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2456 TRACE("iface %p, target %p.\n", iface, target);
2458 *target = context->target.object ? context->target.object : NULL;
2459 if (*target)
2460 ID2D1Image_AddRef(*target);
2463 static void STDMETHODCALLTYPE d2d_device_context_SetRenderingControls(ID2D1DeviceContext6 *iface,
2464 const D2D1_RENDERING_CONTROLS *rendering_controls)
2466 FIXME("iface %p, rendering_controls %p stub!\n", iface, rendering_controls);
2469 static void STDMETHODCALLTYPE d2d_device_context_GetRenderingControls(ID2D1DeviceContext6 *iface,
2470 D2D1_RENDERING_CONTROLS *rendering_controls)
2472 FIXME("iface %p, rendering_controls %p stub!\n", iface, rendering_controls);
2475 static void STDMETHODCALLTYPE d2d_device_context_SetPrimitiveBlend(ID2D1DeviceContext6 *iface,
2476 D2D1_PRIMITIVE_BLEND primitive_blend)
2478 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2480 TRACE("iface %p, primitive_blend %u.\n", iface, primitive_blend);
2482 if (primitive_blend > D2D1_PRIMITIVE_BLEND_MAX)
2484 WARN("Unknown blend mode %u.\n", primitive_blend);
2485 return;
2488 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2489 d2d_command_list_set_primitive_blend(context->target.command_list, primitive_blend);
2491 context->drawing_state.primitiveBlend = primitive_blend;
2494 static D2D1_PRIMITIVE_BLEND STDMETHODCALLTYPE d2d_device_context_GetPrimitiveBlend(ID2D1DeviceContext6 *iface)
2496 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2498 TRACE("iface %p.\n", iface);
2500 return context->drawing_state.primitiveBlend;
2503 static void STDMETHODCALLTYPE d2d_device_context_SetUnitMode(ID2D1DeviceContext6 *iface, D2D1_UNIT_MODE unit_mode)
2505 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2507 TRACE("iface %p, unit_mode %#x.\n", iface, unit_mode);
2509 if (unit_mode != D2D1_UNIT_MODE_DIPS && unit_mode != D2D1_UNIT_MODE_PIXELS)
2511 WARN("Unknown unit mode %#x.\n", unit_mode);
2512 return;
2515 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2516 d2d_command_list_set_unit_mode(context->target.command_list, unit_mode);
2518 context->drawing_state.unitMode = unit_mode;
2521 static D2D1_UNIT_MODE STDMETHODCALLTYPE d2d_device_context_GetUnitMode(ID2D1DeviceContext6 *iface)
2523 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2525 TRACE("iface %p.\n", iface);
2527 return context->drawing_state.unitMode;
2530 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_DrawGlyphRun(ID2D1DeviceContext6 *iface,
2531 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run,
2532 const DWRITE_GLYPH_RUN_DESCRIPTION *glyph_run_desc, ID2D1Brush *brush, DWRITE_MEASURING_MODE measuring_mode)
2534 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2536 TRACE("iface %p, baseline_origin %s, glyph_run %p, glyph_run_desc %p, brush %p, measuring_mode %#x.\n",
2537 iface, debug_d2d_point_2f(&baseline_origin), glyph_run, glyph_run_desc, brush, measuring_mode);
2539 d2d_device_context_draw_glyph_run(context, baseline_origin, glyph_run, glyph_run_desc, brush, measuring_mode);
2542 static void STDMETHODCALLTYPE d2d_device_context_DrawImage(ID2D1DeviceContext6 *iface, ID2D1Image *image,
2543 const D2D1_POINT_2F *target_offset, const D2D1_RECT_F *image_rect, D2D1_INTERPOLATION_MODE interpolation_mode,
2544 D2D1_COMPOSITE_MODE composite_mode)
2546 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2547 ID2D1Bitmap *bitmap;
2549 TRACE("iface %p, image %p, target_offset %s, image_rect %s, interpolation_mode %#x, composite_mode %#x.\n",
2550 iface, image, debug_d2d_point_2f(target_offset), debug_d2d_rect_f(image_rect),
2551 interpolation_mode, composite_mode);
2553 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2555 d2d_command_list_draw_image(context->target.command_list, image, target_offset, image_rect,
2556 interpolation_mode, composite_mode);
2557 return;
2560 if (composite_mode != D2D1_COMPOSITE_MODE_SOURCE_OVER)
2561 FIXME("Unhandled composite mode %#x.\n", composite_mode);
2563 if (SUCCEEDED(ID2D1Image_QueryInterface(image, &IID_ID2D1Bitmap, (void **)&bitmap)))
2565 d2d_device_context_draw_bitmap(context, bitmap, NULL, 1.0f, interpolation_mode, image_rect, target_offset, NULL);
2567 ID2D1Bitmap_Release(bitmap);
2568 return;
2571 FIXME("Unhandled image %p.\n", image);
2574 static void STDMETHODCALLTYPE d2d_device_context_DrawGdiMetafile(ID2D1DeviceContext6 *iface,
2575 ID2D1GdiMetafile *metafile, const D2D1_POINT_2F *target_offset)
2577 FIXME("iface %p, metafile %p, target_offset %s stub!\n",
2578 iface, metafile, debug_d2d_point_2f(target_offset));
2581 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_DrawBitmap(ID2D1DeviceContext6 *iface,
2582 ID2D1Bitmap *bitmap, const D2D1_RECT_F *dst_rect, float opacity, D2D1_INTERPOLATION_MODE interpolation_mode,
2583 const D2D1_RECT_F *src_rect, const D2D1_MATRIX_4X4_F *perspective_transform)
2585 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2587 TRACE("iface %p, bitmap %p, dst_rect %s, opacity %.8e, interpolation_mode %#x, "
2588 "src_rect %s, perspective_transform %p.\n",
2589 iface, bitmap, debug_d2d_rect_f(dst_rect), opacity, interpolation_mode,
2590 debug_d2d_rect_f(src_rect), perspective_transform);
2592 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2594 d2d_command_list_draw_bitmap(context->target.command_list, bitmap, dst_rect, opacity, interpolation_mode,
2595 src_rect, perspective_transform);
2597 else
2599 d2d_device_context_draw_bitmap(context, bitmap, dst_rect, opacity, interpolation_mode, src_rect,
2600 NULL, perspective_transform);
2604 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_PushLayer(ID2D1DeviceContext6 *iface,
2605 const D2D1_LAYER_PARAMETERS1 *layer_parameters, ID2D1Layer *layer)
2607 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2609 FIXME("iface %p, layer_parameters %p, layer %p stub!\n", iface, layer_parameters, layer);
2611 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2612 d2d_command_list_push_layer(context->target.command_list, context, layer_parameters, layer);
2615 static HRESULT STDMETHODCALLTYPE d2d_device_context_InvalidateEffectInputRectangle(ID2D1DeviceContext6 *iface,
2616 ID2D1Effect *effect, UINT32 input, const D2D1_RECT_F *input_rect)
2618 FIXME("iface %p, effect %p, input %u, input_rect %s stub!\n",
2619 iface, effect, input, debug_d2d_rect_f(input_rect));
2621 return E_NOTIMPL;
2624 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetEffectInvalidRectangleCount(ID2D1DeviceContext6 *iface,
2625 ID2D1Effect *effect, UINT32 *rect_count)
2627 FIXME("iface %p, effect %p, rect_count %p stub!\n", iface, effect, rect_count);
2629 return E_NOTIMPL;
2632 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetEffectInvalidRectangles(ID2D1DeviceContext6 *iface,
2633 ID2D1Effect *effect, D2D1_RECT_F *rectangles, UINT32 rect_count)
2635 FIXME("iface %p, effect %p, rectangles %p, rect_count %u stub!\n", iface, effect, rectangles, rect_count);
2637 return E_NOTIMPL;
2640 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetEffectRequiredInputRectangles(ID2D1DeviceContext6 *iface,
2641 ID2D1Effect *effect, const D2D1_RECT_F *image_rect, const D2D1_EFFECT_INPUT_DESCRIPTION *desc,
2642 D2D1_RECT_F *input_rect, UINT32 input_count)
2644 FIXME("iface %p, effect %p, image_rect %s, desc %p, input_rect %p, input_count %u stub!\n",
2645 iface, effect, debug_d2d_rect_f(image_rect), desc, input_rect, input_count);
2647 return E_NOTIMPL;
2650 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_FillOpacityMask(ID2D1DeviceContext6 *iface,
2651 ID2D1Bitmap *mask, ID2D1Brush *brush, const D2D1_RECT_F *dst_rect, const D2D1_RECT_F *src_rect)
2653 struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
2655 FIXME("iface %p, mask %p, brush %p, dst_rect %s, src_rect %s stub!\n",
2656 iface, mask, brush, debug_d2d_rect_f(dst_rect), debug_d2d_rect_f(src_rect));
2658 if (FAILED(context->error.code))
2659 return;
2661 if (context->drawing_state.antialiasMode != D2D1_ANTIALIAS_MODE_ALIASED)
2663 d2d_device_context_set_error(context, D2DERR_WRONG_STATE);
2664 return;
2667 if (context->target.type == D2D_TARGET_COMMAND_LIST)
2668 d2d_command_list_fill_opacity_mask(context->target.command_list, context, mask, brush, dst_rect, src_rect);
2671 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateFilledGeometryRealization(ID2D1DeviceContext6 *iface,
2672 ID2D1Geometry *geometry, float tolerance, ID2D1GeometryRealization **realization)
2674 FIXME("iface %p, geometry %p, tolerance %.8e, realization %p stub!\n", iface, geometry, tolerance,
2675 realization);
2677 return E_NOTIMPL;
2680 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateStrokedGeometryRealization(
2681 ID2D1DeviceContext6 *iface, ID2D1Geometry *geometry, float tolerance, float stroke_width,
2682 ID2D1StrokeStyle *stroke_style, ID2D1GeometryRealization **realization)
2684 FIXME("iface %p, geometry %p, tolerance %.8e, stroke_width %.8e, stroke_style %p, realization %p stub!\n",
2685 iface, geometry, tolerance, stroke_width, stroke_style, realization);
2687 return E_NOTIMPL;
2690 static void STDMETHODCALLTYPE d2d_device_context_DrawGeometryRealization(ID2D1DeviceContext6 *iface,
2691 ID2D1GeometryRealization *realization, ID2D1Brush *brush)
2693 FIXME("iface %p, realization %p, brush %p stub!\n", iface, realization, brush);
2696 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateInk(ID2D1DeviceContext6 *iface,
2697 const D2D1_INK_POINT *start_point, ID2D1Ink **ink)
2699 FIXME("iface %p, start_point %p, ink %p stub!\n", iface, start_point, ink);
2701 return E_NOTIMPL;
2704 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateInkStyle(ID2D1DeviceContext6 *iface,
2705 const D2D1_INK_STYLE_PROPERTIES *ink_style_properties, ID2D1InkStyle **ink_style)
2707 FIXME("iface %p, ink_style_properties %p, ink_style %p stub!\n", iface, ink_style_properties, ink_style);
2709 return E_NOTIMPL;
2712 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateGradientMesh(ID2D1DeviceContext6 *iface,
2713 const D2D1_GRADIENT_MESH_PATCH *patches, UINT32 patches_count,
2714 ID2D1GradientMesh **gradient_mesh)
2716 FIXME("iface %p, patches %p, patches_count %u, gradient_mesh %p stub!\n", iface, patches,
2717 patches_count, gradient_mesh);
2719 return E_NOTIMPL;
2722 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateImageSourceFromWic(ID2D1DeviceContext6 *iface,
2723 IWICBitmapSource *wic_bitmap_source, D2D1_IMAGE_SOURCE_LOADING_OPTIONS loading_options,
2724 D2D1_ALPHA_MODE alpha_mode, ID2D1ImageSourceFromWic **image_source)
2726 FIXME("iface %p, wic_bitmap_source %p, loading_options %#x, alpha_mode %u, image_source %p stub!\n",
2727 iface, wic_bitmap_source, loading_options, alpha_mode, image_source);
2729 return E_NOTIMPL;
2732 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateLookupTable3D(ID2D1DeviceContext6 *iface,
2733 D2D1_BUFFER_PRECISION precision, const UINT32 *extents, const BYTE *data,
2734 UINT32 data_count, const UINT32 *strides, ID2D1LookupTable3D **lookup_table)
2736 FIXME("iface %p, precision %u, extents %p, data %p, data_count %u, strides %p, lookup_table %p stub!\n",
2737 iface, precision, extents, data, data_count, strides, lookup_table);
2739 return E_NOTIMPL;
2742 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateImageSourceFromDxgi(ID2D1DeviceContext6 *iface,
2743 IDXGISurface **surfaces, UINT32 surface_count, DXGI_COLOR_SPACE_TYPE color_space,
2744 D2D1_IMAGE_SOURCE_FROM_DXGI_OPTIONS options, ID2D1ImageSource **image_source)
2746 FIXME("iface %p, surfaces %p, surface_count %u, color_space %u, options %#x, image_source %p stub!\n",
2747 iface, surfaces, surface_count, color_space, options, image_source);
2749 return E_NOTIMPL;
2752 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetGradientMeshWorldBounds(ID2D1DeviceContext6 *iface,
2753 ID2D1GradientMesh *gradient_mesh, D2D1_RECT_F *bounds)
2755 FIXME("iface %p, gradient_mesh %p, bounds %p stub!\n", iface, gradient_mesh, bounds);
2757 return E_NOTIMPL;
2760 static void STDMETHODCALLTYPE d2d_device_context_DrawInk(ID2D1DeviceContext6 *iface, ID2D1Ink *ink,
2761 ID2D1Brush *brush, ID2D1InkStyle *ink_style)
2763 FIXME("iface %p, ink %p, brush %p, ink_style %p stub!\n", iface, ink, brush, ink_style);
2766 static void STDMETHODCALLTYPE d2d_device_context_DrawGradientMesh(ID2D1DeviceContext6 *iface,
2767 ID2D1GradientMesh *gradient_mesh)
2769 FIXME("iface %p, gradient_mesh %p stub!\n", iface, gradient_mesh);
2772 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext2_DrawGdiMetafile(
2773 ID2D1DeviceContext6 *iface, ID2D1GdiMetafile *gdi_metafile, const D2D1_RECT_F *dst_rect,
2774 const D2D1_RECT_F *src_rect)
2776 FIXME("iface %p, gdi_metafile %p, dst_rect %s, src_rect %s stub!\n", iface, gdi_metafile,
2777 debug_d2d_rect_f(dst_rect), debug_d2d_rect_f(src_rect));
2780 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateTransformedImageSource(ID2D1DeviceContext6 *iface,
2781 ID2D1ImageSource *source, const D2D1_TRANSFORMED_IMAGE_SOURCE_PROPERTIES *props,
2782 ID2D1TransformedImageSource **transformed)
2784 FIXME("iface %p, source %p, props %p, transformed %p stub!\n", iface, source, props, transformed);
2786 return E_NOTIMPL;
2789 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSpriteBatch(ID2D1DeviceContext6 *iface,
2790 ID2D1SpriteBatch **sprite_batch)
2792 FIXME("iface %p, sprite_batch %p stub!\n", iface, sprite_batch);
2794 return E_NOTIMPL;
2797 static void STDMETHODCALLTYPE d2d_device_context_DrawSpriteBatch(ID2D1DeviceContext6 *iface,
2798 ID2D1SpriteBatch *sprite_batch, UINT32 start_index, UINT32 sprite_count, ID2D1Bitmap *bitmap,
2799 D2D1_BITMAP_INTERPOLATION_MODE interpolation_mode, D2D1_SPRITE_OPTIONS sprite_options)
2801 FIXME("iface %p, sprite_batch %p, start_index %u, sprite_count %u, bitmap %p, interpolation_mode %u,"
2802 "sprite_options %u stub!\n", iface, sprite_batch, start_index, sprite_count, bitmap,
2803 interpolation_mode, sprite_options);
2806 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSvgGlyphStyle(ID2D1DeviceContext6 *iface,
2807 ID2D1SvgGlyphStyle **svg_glyph_style)
2809 FIXME("iface %p, svg_glyph_style %p stub!\n", iface, svg_glyph_style);
2811 return E_NOTIMPL;
2814 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext4_DrawText(ID2D1DeviceContext6 *iface,
2815 const WCHAR *string, UINT32 string_length, IDWriteTextFormat *text_format, const D2D1_RECT_F *layout_rect,
2816 ID2D1Brush *default_fill_brush, ID2D1SvgGlyphStyle *svg_glyph_style, UINT32 color_palette_index,
2817 D2D1_DRAW_TEXT_OPTIONS options, DWRITE_MEASURING_MODE measuring_mode)
2819 FIXME("iface %p, string %s, string_length %u, text_format %p, layout_rect %s, default_fill_brush %p,"
2820 "svg_glyph_style %p, color_palette_index %u, options %#x, measuring_mode %u stub!\n",
2821 iface, debugstr_wn(string, string_length), string_length, text_format, debug_d2d_rect_f(layout_rect),
2822 default_fill_brush, svg_glyph_style, color_palette_index, options, measuring_mode);
2825 static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext4_DrawTextLayout(ID2D1DeviceContext6 *iface,
2826 D2D1_POINT_2F origin, IDWriteTextLayout *text_layout, ID2D1Brush *default_fill_brush,
2827 ID2D1SvgGlyphStyle *svg_glyph_style, UINT32 color_palette_index, D2D1_DRAW_TEXT_OPTIONS options)
2829 FIXME("iface %p, origin %s, text_layout %p, default_fill_brush %p, svg_glyph_style %p, color_palette_index %u,"
2830 "options %#x stub!\n", iface, debug_d2d_point_2f(&origin), text_layout, default_fill_brush,
2831 svg_glyph_style, color_palette_index, options);
2834 static void STDMETHODCALLTYPE d2d_device_context_DrawColorBitmapGlyphRun(ID2D1DeviceContext6 *iface,
2835 DWRITE_GLYPH_IMAGE_FORMATS glyph_image_format, D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run,
2836 DWRITE_MEASURING_MODE measuring_mode, D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION bitmap_snap_option)
2838 FIXME("iface %p, glyph_image_format %#x, baseline_origin %s, glyph_run %p, measuring_mode %u, bitmap_snap_option %#x stub!\n",
2839 iface, glyph_image_format, debug_d2d_point_2f(&baseline_origin), glyph_run, measuring_mode, bitmap_snap_option);
2842 static void STDMETHODCALLTYPE d2d_device_context_DrawSvgGlyphRun(ID2D1DeviceContext6 *iface,
2843 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *default_fill_brush,
2844 ID2D1SvgGlyphStyle *svg_glyph_style, UINT32 color_palette_index, DWRITE_MEASURING_MODE measuring_mode)
2846 FIXME("iface %p, baseline_origin %s, glyph_run %p, default_fill_brush %p, svg_glyph_style %p,"
2847 "color_palette_index %u, measuring_mode %u stub!\n", iface, debug_d2d_point_2f(&baseline_origin),
2848 glyph_run, default_fill_brush, svg_glyph_style, color_palette_index, measuring_mode);
2851 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetColorBitmapGlyphImage(ID2D1DeviceContext6 *iface,
2852 DWRITE_GLYPH_IMAGE_FORMATS glyph_image_format, D2D1_POINT_2F glyph_origin, IDWriteFontFace *font_face,
2853 FLOAT font_em_size, UINT16 glyph_index, BOOL is_sideways, const D2D1_MATRIX_3X2_F *world_transform,
2854 FLOAT dpi_x, FLOAT dpi_y, D2D1_MATRIX_3X2_F *glyph_transform, ID2D1Image **glyph_image)
2856 FIXME("iface %p, glyph_image_format %u, glyph_origin %s, font_face %p, font_em_size %f, glyph_index %u,"
2857 "is_sideways %d, world_transform %p, dpi_x %f, dpi_y %f, glyph_transform %p, glyph_image %p stub!\n",
2858 iface, glyph_image_format, debug_d2d_point_2f(&glyph_origin), font_face, font_em_size, glyph_index,
2859 is_sideways, world_transform, dpi_x, dpi_y, glyph_transform, glyph_image);
2861 return E_NOTIMPL;
2864 static HRESULT STDMETHODCALLTYPE d2d_device_context_GetSvgGlyphImage(ID2D1DeviceContext6 *iface,
2865 D2D1_POINT_2F glyph_origin, IDWriteFontFace *font_face, FLOAT font_em_size, UINT16 glyph_index,
2866 BOOL is_sideways, const D2D1_MATRIX_3X2_F *world_transform, ID2D1Brush *default_fill_brush,
2867 ID2D1SvgGlyphStyle *svg_glyph_style, UINT32 color_palette_index, D2D1_MATRIX_3X2_F *glyph_transform,
2868 ID2D1CommandList **glyph_image)
2870 FIXME("iface %p, glyph_origin %s, font_face %p, font_em_size %f, glyph_index %u, is_sideways %d,"
2871 "world_transform %p, default_fill_brush %p, svg_glyph_style %p, color_palette_index %u,"
2872 "glyph_transform %p, glyph_image %p stub!\n", iface, debug_d2d_point_2f(&glyph_origin),
2873 font_face, font_em_size, glyph_index, is_sideways, world_transform, default_fill_brush,
2874 svg_glyph_style, color_palette_index, glyph_transform, glyph_image);
2876 return E_NOTIMPL;
2879 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSvgDocument(ID2D1DeviceContext6 *iface,
2880 IStream *input_xml_stream, D2D1_SIZE_F viewport_size, ID2D1SvgDocument **svg_document)
2882 FIXME("iface %p, input_xml_stream %p, svg_document %p stub!\n", iface, input_xml_stream,
2883 svg_document);
2885 return E_NOTIMPL;
2888 static void STDMETHODCALLTYPE d2d_device_context_DrawSvgDocument(ID2D1DeviceContext6 *iface,
2889 ID2D1SvgDocument *svg_document)
2891 FIXME("iface %p, svg_document %p stub!\n", iface, svg_document);
2894 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateColorContextFromDxgiColorSpace(
2895 ID2D1DeviceContext6 *iface, DXGI_COLOR_SPACE_TYPE color_space, ID2D1ColorContext1 **color_context)
2897 FIXME("iface %p, color_space %u, color_context %p stub!\n", iface, color_space, color_context);
2899 return E_NOTIMPL;
2902 static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateColorContextFromSimpleColorProfile(
2903 ID2D1DeviceContext6 *iface, const D2D1_SIMPLE_COLOR_PROFILE *simple_profile, ID2D1ColorContext1 **color_context)
2905 FIXME("iface %p, simple_profile %p, color_context %p stub!\n", iface, simple_profile, color_context);
2907 return E_NOTIMPL;
2910 static void STDMETHODCALLTYPE d2d_device_context_BlendImage(ID2D1DeviceContext6 *iface, ID2D1Image *image,
2911 D2D1_BLEND_MODE blend_mode, const D2D1_POINT_2F *target_offset, const D2D1_RECT_F *image_rect,
2912 D2D1_INTERPOLATION_MODE interpolation_mode)
2914 FIXME("iface %p, image %p, blend_mode %u, target_offset %s, image_rect %s, interpolation_mode %u stub!\n",
2915 iface, image, blend_mode, debug_d2d_point_2f(target_offset), debug_d2d_rect_f(image_rect),
2916 interpolation_mode);
2919 static const struct ID2D1DeviceContext6Vtbl d2d_device_context_vtbl =
2921 d2d_device_context_QueryInterface,
2922 d2d_device_context_AddRef,
2923 d2d_device_context_Release,
2924 d2d_device_context_GetFactory,
2925 d2d_device_context_CreateBitmap,
2926 d2d_device_context_CreateBitmapFromWicBitmap,
2927 d2d_device_context_CreateSharedBitmap,
2928 d2d_device_context_CreateBitmapBrush,
2929 d2d_device_context_CreateSolidColorBrush,
2930 d2d_device_context_CreateGradientStopCollection,
2931 d2d_device_context_CreateLinearGradientBrush,
2932 d2d_device_context_CreateRadialGradientBrush,
2933 d2d_device_context_CreateCompatibleRenderTarget,
2934 d2d_device_context_CreateLayer,
2935 d2d_device_context_CreateMesh,
2936 d2d_device_context_DrawLine,
2937 d2d_device_context_DrawRectangle,
2938 d2d_device_context_FillRectangle,
2939 d2d_device_context_DrawRoundedRectangle,
2940 d2d_device_context_FillRoundedRectangle,
2941 d2d_device_context_DrawEllipse,
2942 d2d_device_context_FillEllipse,
2943 d2d_device_context_DrawGeometry,
2944 d2d_device_context_FillGeometry,
2945 d2d_device_context_FillMesh,
2946 d2d_device_context_FillOpacityMask,
2947 d2d_device_context_DrawBitmap,
2948 d2d_device_context_DrawText,
2949 d2d_device_context_DrawTextLayout,
2950 d2d_device_context_DrawGlyphRun,
2951 d2d_device_context_SetTransform,
2952 d2d_device_context_GetTransform,
2953 d2d_device_context_SetAntialiasMode,
2954 d2d_device_context_GetAntialiasMode,
2955 d2d_device_context_SetTextAntialiasMode,
2956 d2d_device_context_GetTextAntialiasMode,
2957 d2d_device_context_SetTextRenderingParams,
2958 d2d_device_context_GetTextRenderingParams,
2959 d2d_device_context_SetTags,
2960 d2d_device_context_GetTags,
2961 d2d_device_context_PushLayer,
2962 d2d_device_context_PopLayer,
2963 d2d_device_context_Flush,
2964 d2d_device_context_SaveDrawingState,
2965 d2d_device_context_RestoreDrawingState,
2966 d2d_device_context_PushAxisAlignedClip,
2967 d2d_device_context_PopAxisAlignedClip,
2968 d2d_device_context_Clear,
2969 d2d_device_context_BeginDraw,
2970 d2d_device_context_EndDraw,
2971 d2d_device_context_GetPixelFormat,
2972 d2d_device_context_SetDpi,
2973 d2d_device_context_GetDpi,
2974 d2d_device_context_GetSize,
2975 d2d_device_context_GetPixelSize,
2976 d2d_device_context_GetMaximumBitmapSize,
2977 d2d_device_context_IsSupported,
2978 d2d_device_context_ID2D1DeviceContext_CreateBitmap,
2979 d2d_device_context_ID2D1DeviceContext_CreateBitmapFromWicBitmap,
2980 d2d_device_context_CreateColorContext,
2981 d2d_device_context_CreateColorContextFromFilename,
2982 d2d_device_context_CreateColorContextFromWicColorContext,
2983 d2d_device_context_CreateBitmapFromDxgiSurface,
2984 d2d_device_context_CreateEffect,
2985 d2d_device_context_ID2D1DeviceContext_CreateGradientStopCollection,
2986 d2d_device_context_CreateImageBrush,
2987 d2d_device_context_ID2D1DeviceContext_CreateBitmapBrush,
2988 d2d_device_context_CreateCommandList,
2989 d2d_device_context_IsDxgiFormatSupported,
2990 d2d_device_context_IsBufferPrecisionSupported,
2991 d2d_device_context_GetImageLocalBounds,
2992 d2d_device_context_GetImageWorldBounds,
2993 d2d_device_context_GetGlyphRunWorldBounds,
2994 d2d_device_context_GetDevice,
2995 d2d_device_context_SetTarget,
2996 d2d_device_context_GetTarget,
2997 d2d_device_context_SetRenderingControls,
2998 d2d_device_context_GetRenderingControls,
2999 d2d_device_context_SetPrimitiveBlend,
3000 d2d_device_context_GetPrimitiveBlend,
3001 d2d_device_context_SetUnitMode,
3002 d2d_device_context_GetUnitMode,
3003 d2d_device_context_ID2D1DeviceContext_DrawGlyphRun,
3004 d2d_device_context_DrawImage,
3005 d2d_device_context_DrawGdiMetafile,
3006 d2d_device_context_ID2D1DeviceContext_DrawBitmap,
3007 d2d_device_context_ID2D1DeviceContext_PushLayer,
3008 d2d_device_context_InvalidateEffectInputRectangle,
3009 d2d_device_context_GetEffectInvalidRectangleCount,
3010 d2d_device_context_GetEffectInvalidRectangles,
3011 d2d_device_context_GetEffectRequiredInputRectangles,
3012 d2d_device_context_ID2D1DeviceContext_FillOpacityMask,
3013 d2d_device_context_CreateFilledGeometryRealization,
3014 d2d_device_context_CreateStrokedGeometryRealization,
3015 d2d_device_context_DrawGeometryRealization,
3016 d2d_device_context_CreateInk,
3017 d2d_device_context_CreateInkStyle,
3018 d2d_device_context_CreateGradientMesh,
3019 d2d_device_context_CreateImageSourceFromWic,
3020 d2d_device_context_CreateLookupTable3D,
3021 d2d_device_context_CreateImageSourceFromDxgi,
3022 d2d_device_context_GetGradientMeshWorldBounds,
3023 d2d_device_context_DrawInk,
3024 d2d_device_context_DrawGradientMesh,
3025 d2d_device_context_ID2D1DeviceContext2_DrawGdiMetafile,
3026 d2d_device_context_CreateTransformedImageSource,
3027 d2d_device_context_CreateSpriteBatch,
3028 d2d_device_context_DrawSpriteBatch,
3029 d2d_device_context_CreateSvgGlyphStyle,
3030 d2d_device_context_ID2D1DeviceContext4_DrawText,
3031 d2d_device_context_ID2D1DeviceContext4_DrawTextLayout,
3032 d2d_device_context_DrawColorBitmapGlyphRun,
3033 d2d_device_context_DrawSvgGlyphRun,
3034 d2d_device_context_GetColorBitmapGlyphImage,
3035 d2d_device_context_GetSvgGlyphImage,
3036 d2d_device_context_CreateSvgDocument,
3037 d2d_device_context_DrawSvgDocument,
3038 d2d_device_context_CreateColorContextFromDxgiColorSpace,
3039 d2d_device_context_CreateColorContextFromSimpleColorProfile,
3040 d2d_device_context_BlendImage,
3043 static inline struct d2d_device_context *impl_from_IDWriteTextRenderer(IDWriteTextRenderer *iface)
3045 return CONTAINING_RECORD(iface, struct d2d_device_context, IDWriteTextRenderer_iface);
3048 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_QueryInterface(IDWriteTextRenderer *iface, REFIID iid, void **out)
3050 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3052 if (IsEqualGUID(iid, &IID_IDWriteTextRenderer)
3053 || IsEqualGUID(iid, &IID_IDWritePixelSnapping)
3054 || IsEqualGUID(iid, &IID_IUnknown))
3056 IDWriteTextRenderer_AddRef(iface);
3057 *out = iface;
3058 return S_OK;
3061 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
3063 *out = NULL;
3064 return E_NOINTERFACE;
3067 static ULONG STDMETHODCALLTYPE d2d_text_renderer_AddRef(IDWriteTextRenderer *iface)
3069 struct d2d_device_context *context = impl_from_IDWriteTextRenderer(iface);
3071 TRACE("iface %p.\n", iface);
3073 return d2d_device_context_AddRef(&context->ID2D1DeviceContext6_iface);
3076 static ULONG STDMETHODCALLTYPE d2d_text_renderer_Release(IDWriteTextRenderer *iface)
3078 struct d2d_device_context *context = impl_from_IDWriteTextRenderer(iface);
3080 TRACE("iface %p.\n", iface);
3082 return d2d_device_context_Release(&context->ID2D1DeviceContext6_iface);
3085 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
3086 void *ctx, BOOL *disabled)
3088 struct d2d_draw_text_layout_ctx *context = ctx;
3090 TRACE("iface %p, ctx %p, disabled %p.\n", iface, ctx, disabled);
3092 *disabled = context->options & D2D1_DRAW_TEXT_OPTIONS_NO_SNAP;
3094 return S_OK;
3097 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetCurrentTransform(IDWriteTextRenderer *iface,
3098 void *ctx, DWRITE_MATRIX *transform)
3100 struct d2d_device_context *context = impl_from_IDWriteTextRenderer(iface);
3102 TRACE("iface %p, ctx %p, transform %p.\n", iface, ctx, transform);
3104 d2d_device_context_GetTransform(&context->ID2D1DeviceContext6_iface, (D2D1_MATRIX_3X2_F *)transform);
3106 return S_OK;
3109 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetPixelsPerDip(IDWriteTextRenderer *iface, void *ctx, float *ppd)
3111 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
3113 TRACE("iface %p, ctx %p, ppd %p.\n", iface, ctx, ppd);
3115 *ppd = render_target->desc.dpiY / 96.0f;
3117 return S_OK;
3120 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawGlyphRun(IDWriteTextRenderer *iface, void *ctx,
3121 float baseline_origin_x, float baseline_origin_y, DWRITE_MEASURING_MODE measuring_mode,
3122 const DWRITE_GLYPH_RUN *glyph_run, const DWRITE_GLYPH_RUN_DESCRIPTION *glyph_run_desc, IUnknown *effect)
3124 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
3125 D2D1_POINT_2F baseline_origin = {baseline_origin_x, baseline_origin_y};
3126 struct d2d_draw_text_layout_ctx *context = ctx;
3127 BOOL color_font = FALSE;
3128 ID2D1Brush *brush;
3130 TRACE("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, "
3131 "measuring_mode %#x, glyph_run %p, glyph_run_desc %p, effect %p.\n",
3132 iface, ctx, baseline_origin_x, baseline_origin_y,
3133 measuring_mode, glyph_run, glyph_run_desc, effect);
3135 if (context->options & ~(D2D1_DRAW_TEXT_OPTIONS_NO_SNAP | D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT))
3136 FIXME("Ignoring options %#x.\n", context->options);
3138 brush = d2d_draw_get_text_brush(context, effect);
3140 TRACE("%s\n", debugstr_wn(glyph_run_desc->string, glyph_run_desc->stringLength));
3142 if (context->options & D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT)
3144 IDWriteFontFace2 *fontface;
3146 if (SUCCEEDED(IDWriteFontFace_QueryInterface(glyph_run->fontFace,
3147 &IID_IDWriteFontFace2, (void **)&fontface)))
3149 color_font = IDWriteFontFace2_IsColorFont(fontface);
3150 IDWriteFontFace2_Release(fontface);
3154 if (color_font)
3156 IDWriteColorGlyphRunEnumerator *layers;
3157 IDWriteFactory2 *dwrite_factory;
3158 HRESULT hr;
3160 if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory2,
3161 (IUnknown **)&dwrite_factory)))
3163 ERR("Failed to create dwrite factory, hr %#lx.\n", hr);
3164 ID2D1Brush_Release(brush);
3165 return hr;
3168 hr = IDWriteFactory2_TranslateColorGlyphRun(dwrite_factory, baseline_origin_x, baseline_origin_y,
3169 glyph_run, glyph_run_desc, measuring_mode, (DWRITE_MATRIX *)&render_target->drawing_state.transform, 0, &layers);
3170 IDWriteFactory2_Release(dwrite_factory);
3171 if (FAILED(hr))
3173 ERR("Failed to create colour glyph run enumerator, hr %#lx.\n", hr);
3174 ID2D1Brush_Release(brush);
3175 return hr;
3178 for (;;)
3180 const DWRITE_COLOR_GLYPH_RUN *color_run;
3181 ID2D1Brush *color_brush;
3182 D2D1_POINT_2F origin;
3183 BOOL has_run = FALSE;
3185 if (FAILED(hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &has_run)))
3187 ERR("Failed to switch colour glyph layer, hr %#lx.\n", hr);
3188 break;
3191 if (!has_run)
3192 break;
3194 if (FAILED(hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &color_run)))
3196 ERR("Failed to get current colour run, hr %#lx.\n", hr);
3197 break;
3200 if (color_run->paletteIndex == 0xffff)
3201 color_brush = brush;
3202 else
3204 if (FAILED(hr = d2d_device_context_CreateSolidColorBrush(&render_target->ID2D1DeviceContext6_iface,
3205 &color_run->runColor, NULL, (ID2D1SolidColorBrush **)&color_brush)))
3207 ERR("Failed to create solid colour brush, hr %#lx.\n", hr);
3208 break;
3212 origin.x = color_run->baselineOriginX;
3213 origin.y = color_run->baselineOriginY;
3214 d2d_device_context_draw_glyph_run(render_target, origin, &color_run->glyphRun,
3215 color_run->glyphRunDescription, color_brush, measuring_mode);
3217 if (color_brush != brush)
3218 ID2D1Brush_Release(color_brush);
3221 IDWriteColorGlyphRunEnumerator_Release(layers);
3223 else
3224 d2d_device_context_draw_glyph_run(render_target, baseline_origin, glyph_run, glyph_run_desc,
3225 brush, measuring_mode);
3227 ID2D1Brush_Release(brush);
3229 return S_OK;
3232 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawUnderline(IDWriteTextRenderer *iface, void *ctx,
3233 float baseline_origin_x, float baseline_origin_y, const DWRITE_UNDERLINE *underline, IUnknown *effect)
3235 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
3236 const D2D1_MATRIX_3X2_F *m = &render_target->drawing_state.transform;
3237 struct d2d_draw_text_layout_ctx *context = ctx;
3238 D2D1_ANTIALIAS_MODE prev_antialias_mode;
3239 D2D1_POINT_2F start, end;
3240 ID2D1Brush *brush;
3241 float thickness;
3243 TRACE("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, underline %p, effect %p\n",
3244 iface, ctx, baseline_origin_x, baseline_origin_y, underline, effect);
3246 /* minimal thickness in DIPs that will result in at least 1 pixel thick line */
3247 thickness = max(96.0f / (render_target->desc.dpiY * sqrtf(m->_21 * m->_21 + m->_22 * m->_22)),
3248 underline->thickness);
3250 brush = d2d_draw_get_text_brush(context, effect);
3252 start.x = baseline_origin_x;
3253 start.y = baseline_origin_y + underline->offset + thickness / 2.0f;
3254 end.x = start.x + underline->width;
3255 end.y = start.y;
3256 prev_antialias_mode = d2d_device_context_set_aa_mode_from_text_aa_mode(render_target);
3257 d2d_device_context_DrawLine(&render_target->ID2D1DeviceContext6_iface, start, end, brush, thickness, NULL);
3258 render_target->drawing_state.antialiasMode = prev_antialias_mode;
3260 ID2D1Brush_Release(brush);
3262 return S_OK;
3265 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawStrikethrough(IDWriteTextRenderer *iface, void *ctx,
3266 float baseline_origin_x, float baseline_origin_y, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *effect)
3268 struct d2d_device_context *render_target = impl_from_IDWriteTextRenderer(iface);
3269 const D2D1_MATRIX_3X2_F *m = &render_target->drawing_state.transform;
3270 struct d2d_draw_text_layout_ctx *context = ctx;
3271 D2D1_ANTIALIAS_MODE prev_antialias_mode;
3272 D2D1_POINT_2F start, end;
3273 ID2D1Brush *brush;
3274 float thickness;
3276 TRACE("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, strikethrough %p, effect %p.\n",
3277 iface, ctx, baseline_origin_x, baseline_origin_y, strikethrough, effect);
3279 /* minimal thickness in DIPs that will result in at least 1 pixel thick line */
3280 thickness = max(96.0f / (render_target->desc.dpiY * sqrtf(m->_21 * m->_21 + m->_22 * m->_22)),
3281 strikethrough->thickness);
3283 brush = d2d_draw_get_text_brush(context, effect);
3285 start.x = baseline_origin_x;
3286 start.y = baseline_origin_y + strikethrough->offset + thickness / 2.0f;
3287 end.x = start.x + strikethrough->width;
3288 end.y = start.y;
3289 prev_antialias_mode = d2d_device_context_set_aa_mode_from_text_aa_mode(render_target);
3290 d2d_device_context_DrawLine(&render_target->ID2D1DeviceContext6_iface, start, end, brush, thickness, NULL);
3291 render_target->drawing_state.antialiasMode = prev_antialias_mode;
3293 ID2D1Brush_Release(brush);
3295 return S_OK;
3298 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawInlineObject(IDWriteTextRenderer *iface, void *ctx,
3299 float origin_x, float origin_y, IDWriteInlineObject *object, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
3301 struct d2d_draw_text_layout_ctx *context = ctx;
3302 ID2D1Brush *brush;
3303 HRESULT hr;
3305 TRACE("iface %p, ctx %p, origin_x %.8e, origin_y %.8e, object %p, is_sideways %#x, is_rtl %#x, effect %p.\n",
3306 iface, ctx, origin_x, origin_y, object, is_sideways, is_rtl, effect);
3308 /* Inline objects may not pass effects all the way down, when using layout object internally for example.
3309 This is how default trimming sign object in DirectWrite works - it does not use effect passed to Draw(),
3310 and resulting DrawGlyphRun() is always called with NULL effect, however original effect is used and correct
3311 brush is selected at Direct2D level. */
3312 brush = context->brush;
3313 context->brush = d2d_draw_get_text_brush(context, effect);
3315 hr = IDWriteInlineObject_Draw(object, ctx, iface, origin_x, origin_y, is_sideways, is_rtl, effect);
3317 ID2D1Brush_Release(context->brush);
3318 context->brush = brush;
3320 return hr;
3323 static const struct IDWriteTextRendererVtbl d2d_text_renderer_vtbl =
3325 d2d_text_renderer_QueryInterface,
3326 d2d_text_renderer_AddRef,
3327 d2d_text_renderer_Release,
3328 d2d_text_renderer_IsPixelSnappingDisabled,
3329 d2d_text_renderer_GetCurrentTransform,
3330 d2d_text_renderer_GetPixelsPerDip,
3331 d2d_text_renderer_DrawGlyphRun,
3332 d2d_text_renderer_DrawUnderline,
3333 d2d_text_renderer_DrawStrikethrough,
3334 d2d_text_renderer_DrawInlineObject,
3337 static inline struct d2d_device_context *impl_from_ID2D1GdiInteropRenderTarget(ID2D1GdiInteropRenderTarget *iface)
3339 return CONTAINING_RECORD(iface, struct d2d_device_context, ID2D1GdiInteropRenderTarget_iface);
3342 static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_QueryInterface(ID2D1GdiInteropRenderTarget *iface,
3343 REFIID iid, void **out)
3345 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3347 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
3349 return IUnknown_QueryInterface(render_target->outer_unknown, iid, out);
3352 static ULONG STDMETHODCALLTYPE d2d_gdi_interop_render_target_AddRef(ID2D1GdiInteropRenderTarget *iface)
3354 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3356 TRACE("iface %p.\n", iface);
3358 return IUnknown_AddRef(render_target->outer_unknown);
3361 static ULONG STDMETHODCALLTYPE d2d_gdi_interop_render_target_Release(ID2D1GdiInteropRenderTarget *iface)
3363 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3365 TRACE("iface %p.\n", iface);
3367 return IUnknown_Release(render_target->outer_unknown);
3370 static HRESULT d2d_gdi_interop_get_surface(struct d2d_device_context *context, IDXGISurface1 **surface)
3372 ID3D11Resource *resource;
3373 HRESULT hr;
3375 if (context->target.type != D2D_TARGET_BITMAP)
3377 FIXME("Unimplemented for target type %u.\n", context->target.type);
3378 return E_NOTIMPL;
3381 if (!(context->target.bitmap->options & D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE))
3382 return D2DERR_TARGET_NOT_GDI_COMPATIBLE;
3384 ID3D11RenderTargetView_GetResource(context->target.bitmap->rtv, &resource);
3385 hr = ID3D11Resource_QueryInterface(resource, &IID_IDXGISurface1, (void **)surface);
3386 ID3D11Resource_Release(resource);
3387 if (FAILED(hr))
3389 *surface = NULL;
3390 WARN("Failed to get DXGI surface, %#lx.\n", hr);
3391 return hr;
3394 return hr;
3397 static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_GetDC(ID2D1GdiInteropRenderTarget *iface,
3398 D2D1_DC_INITIALIZE_MODE mode, HDC *dc)
3400 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3401 IDXGISurface1 *surface;
3402 HRESULT hr;
3404 TRACE("iface %p, mode %d, dc %p.\n", iface, mode, dc);
3406 *dc = NULL;
3408 if (render_target->target.hdc)
3409 return D2DERR_WRONG_STATE;
3411 if (FAILED(hr = d2d_gdi_interop_get_surface(render_target, &surface)))
3412 return hr;
3414 hr = IDXGISurface1_GetDC(surface, mode != D2D1_DC_INITIALIZE_MODE_COPY, &render_target->target.hdc);
3415 IDXGISurface1_Release(surface);
3417 if (SUCCEEDED(hr))
3418 *dc = render_target->target.hdc;
3420 return hr;
3423 static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_ReleaseDC(ID2D1GdiInteropRenderTarget *iface,
3424 const RECT *update)
3426 struct d2d_device_context *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
3427 IDXGISurface1 *surface;
3428 RECT update_rect;
3429 HRESULT hr;
3431 TRACE("iface %p, update rect %s.\n", iface, wine_dbgstr_rect(update));
3433 if (!render_target->target.hdc)
3434 return D2DERR_WRONG_STATE;
3436 if (FAILED(hr = d2d_gdi_interop_get_surface(render_target, &surface)))
3437 return hr;
3439 render_target->target.hdc = NULL;
3440 if (update)
3441 update_rect = *update;
3442 hr = IDXGISurface1_ReleaseDC(surface, update ? &update_rect : NULL);
3443 IDXGISurface1_Release(surface);
3445 return hr;
3448 static const struct ID2D1GdiInteropRenderTargetVtbl d2d_gdi_interop_render_target_vtbl =
3450 d2d_gdi_interop_render_target_QueryInterface,
3451 d2d_gdi_interop_render_target_AddRef,
3452 d2d_gdi_interop_render_target_Release,
3453 d2d_gdi_interop_render_target_GetDC,
3454 d2d_gdi_interop_render_target_ReleaseDC,
3457 static HRESULT d2d_device_context_init(struct d2d_device_context *render_target,
3458 struct d2d_device *device, IUnknown *outer_unknown, const struct d2d_device_context_ops *ops)
3460 D3D11_SUBRESOURCE_DATA buffer_data;
3461 struct d2d_device *device_impl;
3462 IDWriteFactory *dwrite_factory;
3463 D3D11_RASTERIZER_DESC rs_desc;
3464 D3D11_BUFFER_DESC buffer_desc;
3465 struct d2d_factory *factory;
3466 ID3D10Blob *compiled;
3467 unsigned int i;
3468 HRESULT hr;
3470 static const D3D11_INPUT_ELEMENT_DESC il_desc_outline[] =
3472 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
3473 {"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
3474 {"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0},
3476 static const D3D11_INPUT_ELEMENT_DESC il_desc_curve_outline[] =
3478 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
3479 {"P", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
3480 {"P", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0},
3481 {"P", 2, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
3482 {"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0},
3483 {"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 40, D3D11_INPUT_PER_VERTEX_DATA, 0},
3485 static const D3D11_INPUT_ELEMENT_DESC il_desc_triangle[] =
3487 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
3489 static const D3D11_INPUT_ELEMENT_DESC il_desc_curve[] =
3491 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
3492 {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
3494 static const char vs_code_outline[] =
3495 "float3x2 transform_geometry;\n"
3496 "float stroke_width;\n"
3497 "float4 transform_rtx;\n"
3498 "float4 transform_rty;\n"
3499 "\n"
3500 "struct output\n"
3501 "{\n"
3502 " float2 p : WORLD_POSITION;\n"
3503 " float4 b : BEZIER;\n"
3504 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3505 " float4 position : SV_POSITION;\n"
3506 "};\n"
3507 "\n"
3508 "/* The lines PₚᵣₑᵥP₀ and P₀Pₙₑₓₜ, both offset by ±½w, intersect each other at:\n"
3509 " *\n"
3510 " * Pᵢ = P₀ ± w · ½q⃑ᵢ.\n"
3511 " *\n"
3512 " * Where:\n"
3513 " *\n"
3514 " * q⃑ᵢ = q̂ₚᵣₑᵥ⊥ + tan(½θ) · -q̂ₚᵣₑᵥ\n"
3515 " * θ = ∠PₚᵣₑᵥP₀Pₙₑₓₜ\n"
3516 " * q⃑ₚᵣₑᵥ = P₀ - Pₚᵣₑᵥ */\n"
3517 "void main(float2 position : POSITION, float2 prev : PREV, float2 next : NEXT, out struct output o)\n"
3518 "{\n"
3519 " float2 q_prev, q_next, v_p, q_i;\n"
3520 " float2x2 geom;\n"
3521 " float l;\n"
3522 "\n"
3523 " o.stroke_transform = float2x2(transform_rtx.xy, transform_rty.xy) * stroke_width * 0.5f;\n"
3524 "\n"
3525 " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n"
3526 " q_prev = normalize(mul(geom, prev));\n"
3527 " q_next = normalize(mul(geom, next));\n"
3528 "\n"
3529 " /* tan(½θ) = sin(θ) / (1 + cos(θ))\n"
3530 " * = (q̂ₚᵣₑᵥ⊥ · q̂ₙₑₓₜ) / (1 + (q̂ₚᵣₑᵥ · q̂ₙₑₓₜ)) */\n"
3531 " v_p = float2(-q_prev.y, q_prev.x);\n"
3532 " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n"
3533 " q_i = l * q_prev + v_p;\n"
3534 "\n"
3535 " o.b = float4(0.0, 0.0, 0.0, 0.0);\n"
3536 "\n"
3537 " o.p = mul(float3(position, 1.0f), transform_geometry) + stroke_width * 0.5f * q_i;\n"
3538 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3539 " * float2(transform_rtx.w, transform_rty.w);\n"
3540 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3541 "}\n";
3542 /* ⎡p0.x p0.y 1⎤
3543 * A = ⎢p1.x p1.y 1⎥
3544 * ⎣p2.x p2.y 1⎦
3546 * ⎡0 0⎤
3547 * B = ⎢½ 0⎥
3548 * ⎣1 1⎦
3550 * A' = ⎡p1.x-p0.x p1.y-p0.y⎤
3551 * ⎣p2.x-p0.x p2.y-p0.y⎦
3553 * B' = ⎡½ 0⎤
3554 * ⎣1 1⎦
3556 * A'T = B'
3557 * T = A'⁻¹B'
3559 static const char vs_code_bezier_outline[] =
3560 "float3x2 transform_geometry;\n"
3561 "float stroke_width;\n"
3562 "float4 transform_rtx;\n"
3563 "float4 transform_rty;\n"
3564 "\n"
3565 "struct output\n"
3566 "{\n"
3567 " float2 p : WORLD_POSITION;\n"
3568 " float4 b : BEZIER;\n"
3569 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3570 " float4 position : SV_POSITION;\n"
3571 "};\n"
3572 "\n"
3573 "void main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,\n"
3574 " float2 prev : PREV, float2 next : NEXT, out struct output o)\n"
3575 "{\n"
3576 " float2 q_prev, q_next, v_p, q_i, p;\n"
3577 " float2x2 geom, rt;\n"
3578 " float l;\n"
3579 "\n"
3580 " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n"
3581 " rt = float2x2(transform_rtx.xy, transform_rty.xy);\n"
3582 " o.stroke_transform = rt * stroke_width * 0.5f;\n"
3583 "\n"
3584 " p = mul(geom, position);\n"
3585 " p0 = mul(geom, p0);\n"
3586 " p1 = mul(geom, p1);\n"
3587 " p2 = mul(geom, p2);\n"
3588 "\n"
3589 " p -= p0;\n"
3590 " p1 -= p0;\n"
3591 " p2 -= p0;\n"
3592 "\n"
3593 " q_prev = normalize(mul(geom, prev));\n"
3594 " q_next = normalize(mul(geom, next));\n"
3595 "\n"
3596 " v_p = float2(-q_prev.y, q_prev.x);\n"
3597 " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n"
3598 " q_i = l * q_prev + v_p;\n"
3599 " p += 0.5f * stroke_width * q_i;\n"
3600 "\n"
3601 " v_p = mul(rt, p2);\n"
3602 " v_p = normalize(float2(-v_p.y, v_p.x));\n"
3603 " if (abs(dot(mul(rt, p1), v_p)) < 1.0f)\n"
3604 " {\n"
3605 " o.b.xzw = float3(0.0f, 0.0f, 0.0f);\n"
3606 " o.b.y = dot(mul(rt, p), v_p);\n"
3607 " }\n"
3608 " else\n"
3609 " {\n"
3610 " o.b.zw = sign(dot(mul(rt, p1), v_p)) * v_p;\n"
3611 " v_p = -float2(-p.y, p.x) / dot(float2(-p1.y, p1.x), p2);\n"
3612 " o.b.x = dot(v_p, p1 - 0.5f * p2);\n"
3613 " o.b.y = dot(v_p, p1);\n"
3614 " }\n"
3615 "\n"
3616 " o.p = mul(float3(position, 1.0f), transform_geometry) + 0.5f * stroke_width * q_i;\n"
3617 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3618 " * float2(transform_rtx.w, transform_rty.w);\n"
3619 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3620 "}\n";
3621 /* ⎡p0.x p0.y 1⎤
3622 * A = ⎢p1.x p1.y 1⎥
3623 * ⎣p2.x p2.y 1⎦
3625 * ⎡1 0⎤
3626 * B = ⎢1 1⎥
3627 * ⎣0 1⎦
3629 * A' = ⎡p1.x-p0.x p1.y-p0.y⎤
3630 * ⎣p2.x-p0.x p2.y-p0.y⎦
3632 * B' = ⎡ 0 1⎤
3633 * ⎣-1 1⎦
3635 * A'T = B'
3636 * T = A'⁻¹B' = (B'⁻¹A')⁻¹
3638 static const char vs_code_arc_outline[] =
3639 "float3x2 transform_geometry;\n"
3640 "float stroke_width;\n"
3641 "float4 transform_rtx;\n"
3642 "float4 transform_rty;\n"
3643 "\n"
3644 "struct output\n"
3645 "{\n"
3646 " float2 p : WORLD_POSITION;\n"
3647 " float4 b : BEZIER;\n"
3648 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3649 " float4 position : SV_POSITION;\n"
3650 "};\n"
3651 "\n"
3652 "void main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,\n"
3653 " float2 prev : PREV, float2 next : NEXT, out struct output o)\n"
3654 "{\n"
3655 " float2 q_prev, q_next, v_p, q_i, p;\n"
3656 " float2x2 geom, rt, p_inv;\n"
3657 " float l;\n"
3658 " float a;\n"
3659 " float2 bc;\n"
3660 "\n"
3661 " geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);\n"
3662 " rt = float2x2(transform_rtx.xy, transform_rty.xy);\n"
3663 " o.stroke_transform = rt * stroke_width * 0.5f;\n"
3664 "\n"
3665 " p = mul(geom, position);\n"
3666 " p0 = mul(geom, p0);\n"
3667 " p1 = mul(geom, p1);\n"
3668 " p2 = mul(geom, p2);\n"
3669 "\n"
3670 " p -= p0;\n"
3671 " p1 -= p0;\n"
3672 " p2 -= p0;\n"
3673 "\n"
3674 " q_prev = normalize(mul(geom, prev));\n"
3675 " q_next = normalize(mul(geom, next));\n"
3676 "\n"
3677 " v_p = float2(-q_prev.y, q_prev.x);\n"
3678 " l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));\n"
3679 " q_i = l * q_prev + v_p;\n"
3680 " p += 0.5f * stroke_width * q_i;\n"
3681 "\n"
3682 " p_inv = float2x2(p1.y, -p1.x, p2.y - p1.y, p1.x - p2.x) / (p1.x * p2.y - p2.x * p1.y);\n"
3683 " o.b.xy = mul(p_inv, p) + float2(1.0f, 0.0f);\n"
3684 " o.b.zw = 0.0f;\n"
3685 "\n"
3686 " o.p = mul(float3(position, 1.0f), transform_geometry) + 0.5f * stroke_width * q_i;\n"
3687 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3688 " * float2(transform_rtx.w, transform_rty.w);\n"
3689 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3690 "}\n";
3691 static const char vs_code_triangle[] =
3692 "float3x2 transform_geometry;\n"
3693 "float4 transform_rtx;\n"
3694 "float4 transform_rty;\n"
3695 "\n"
3696 "struct output\n"
3697 "{\n"
3698 " float2 p : WORLD_POSITION;\n"
3699 " float4 b : BEZIER;\n"
3700 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3701 " float4 position : SV_POSITION;\n"
3702 "};\n"
3703 "\n"
3704 "void main(float2 position : POSITION, out struct output o)\n"
3705 "{\n"
3706 " o.p = mul(float3(position, 1.0f), transform_geometry);\n"
3707 " o.b = float4(1.0, 0.0, 1.0, 1.0);\n"
3708 " o.stroke_transform = float2x2(1.0, 0.0, 0.0, 1.0);\n"
3709 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3710 " * float2(transform_rtx.w, transform_rty.w);\n"
3711 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3712 "}\n";
3713 static const char vs_code_curve[] =
3714 "float3x2 transform_geometry;\n"
3715 "float4 transform_rtx;\n"
3716 "float4 transform_rty;\n"
3717 "\n"
3718 "struct output\n"
3719 "{\n"
3720 " float2 p : WORLD_POSITION;\n"
3721 " float4 b : BEZIER;\n"
3722 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3723 " float4 position : SV_POSITION;\n"
3724 "};\n"
3725 "\n"
3726 "void main(float2 position : POSITION, float3 texcoord : TEXCOORD0, out struct output o)\n"
3727 "{\n"
3728 " o.p = mul(float3(position, 1.0f), transform_geometry);\n"
3729 " o.b = float4(texcoord, 1.0);\n"
3730 " o.stroke_transform = float2x2(1.0, 0.0, 0.0, 1.0);\n"
3731 " position = mul(float2x3(transform_rtx.xyz, transform_rty.xyz), float3(o.p, 1.0f))\n"
3732 " * float2(transform_rtx.w, transform_rty.w);\n"
3733 " o.position = float4(position + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
3734 "}\n";
3735 static const char ps_code[] =
3736 "#define BRUSH_TYPE_SOLID 0\n"
3737 "#define BRUSH_TYPE_LINEAR 1\n"
3738 "#define BRUSH_TYPE_RADIAL 2\n"
3739 "#define BRUSH_TYPE_BITMAP 3\n"
3740 "#define BRUSH_TYPE_COUNT 4\n"
3741 "\n"
3742 "bool outline;\n"
3743 "bool is_arc;\n"
3744 "struct brush\n"
3745 "{\n"
3746 " uint type;\n"
3747 " float opacity;\n"
3748 " float4 data[3];\n"
3749 "} colour_brush, opacity_brush;\n"
3750 "\n"
3751 "SamplerState s0, s1;\n"
3752 "Texture2D t0, t1;\n"
3753 "Buffer<float4> b0, b1;\n"
3754 "\n"
3755 "struct input\n"
3756 "{\n"
3757 " float2 p : WORLD_POSITION;\n"
3758 " float4 b : BEZIER;\n"
3759 " nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM;\n"
3760 "};\n"
3761 "\n"
3762 "float4 sample_gradient(Buffer<float4> gradient, uint stop_count, float position)\n"
3763 "{\n"
3764 " float4 c_low, c_high;\n"
3765 " float p_low, p_high;\n"
3766 " uint i;\n"
3767 "\n"
3768 " p_low = gradient.Load(0).x;\n"
3769 " c_low = gradient.Load(1);\n"
3770 " c_high = c_low;\n"
3771 "\n"
3772 " if (position < p_low)\n"
3773 " return c_low;\n"
3774 "\n"
3775 " for (i = 1; i < stop_count; ++i)\n"
3776 " {\n"
3777 " p_high = gradient.Load(i * 2).x;\n"
3778 " c_high = gradient.Load(i * 2 + 1);\n"
3779 "\n"
3780 " if (position >= p_low && position <= p_high)\n"
3781 " return lerp(c_low, c_high, (position - p_low) / (p_high - p_low));\n"
3782 "\n"
3783 " p_low = p_high;\n"
3784 " c_low = c_high;\n"
3785 " }\n"
3786 "\n"
3787 " return c_high;\n"
3788 "}\n"
3789 "\n"
3790 "float4 brush_linear(struct brush brush, Buffer<float4> gradient, float2 position)\n"
3791 "{\n"
3792 " float2 start, end, v_p, v_q;\n"
3793 " uint stop_count;\n"
3794 " float p;\n"
3795 "\n"
3796 " start = brush.data[0].xy;\n"
3797 " end = brush.data[0].zw;\n"
3798 " stop_count = asuint(brush.data[1].x);\n"
3799 "\n"
3800 " v_p = position - start;\n"
3801 " v_q = end - start;\n"
3802 " p = dot(v_q, v_p) / dot(v_q, v_q);\n"
3803 "\n"
3804 " return sample_gradient(gradient, stop_count, p);\n"
3805 "}\n"
3806 "\n"
3807 "float4 brush_radial(struct brush brush, Buffer<float4> gradient, float2 position)\n"
3808 "{\n"
3809 " float2 centre, offset, ra, rb, v_p, v_q, r;\n"
3810 " float b, c, l, t;\n"
3811 " uint stop_count;\n"
3812 "\n"
3813 " centre = brush.data[0].xy;\n"
3814 " offset = brush.data[0].zw;\n"
3815 " ra = brush.data[1].xy;\n"
3816 " rb = brush.data[1].zw;\n"
3817 " stop_count = asuint(brush.data[2].x);\n"
3818 "\n"
3819 " /* Project onto ra, rb. */\n"
3820 " r = float2(dot(ra, ra), dot(rb, rb));\n"
3821 " v_p = position - (centre + offset);\n"
3822 " v_p = float2(dot(v_p, ra), dot(v_p, rb)) / r;\n"
3823 " v_q = float2(dot(offset, ra), dot(offset, rb)) / r;\n"
3824 "\n"
3825 " /* ‖t·p̂ + q⃑‖ = 1\n"
3826 " * (t·p̂ + q⃑) · (t·p̂ + q⃑) = 1\n"
3827 " * t² + 2·(p̂·q⃑)·t + (q⃑·q⃑) = 1\n"
3828 " *\n"
3829 " * b = p̂·q⃑\n"
3830 " * c = q⃑·q⃑ - 1\n"
3831 " * t = -b + √(b² - c) */\n"
3832 " l = length(v_p);\n"
3833 " b = dot(v_p, v_q) / l;\n"
3834 " c = dot(v_q, v_q) - 1.0;\n"
3835 " t = -b + sqrt(b * b - c);\n"
3836 "\n"
3837 " return sample_gradient(gradient, stop_count, l / t);\n"
3838 "}\n"
3839 "\n"
3840 "float4 brush_bitmap(struct brush brush, Texture2D t, SamplerState s, float2 position)\n"
3841 "{\n"
3842 " float3 transform[2];\n"
3843 " bool ignore_alpha;\n"
3844 " float2 texcoord;\n"
3845 " float4 colour;\n"
3846 "\n"
3847 " transform[0] = brush.data[0].xyz;\n"
3848 " transform[1] = brush.data[1].xyz;\n"
3849 " ignore_alpha = asuint(brush.data[1].w);\n"
3850 "\n"
3851 " texcoord.x = dot(position.xy, transform[0].xy) + transform[0].z;\n"
3852 " texcoord.y = dot(position.xy, transform[1].xy) + transform[1].z;\n"
3853 " colour = t.Sample(s, texcoord);\n"
3854 " if (ignore_alpha)\n"
3855 " colour.a = 1.0;\n"
3856 " return colour;\n"
3857 "}\n"
3858 "\n"
3859 "float4 sample_brush(struct brush brush, Texture2D t, SamplerState s, Buffer<float4> b, float2 position)\n"
3860 "{\n"
3861 " if (brush.type == BRUSH_TYPE_SOLID)\n"
3862 " return brush.data[0] * brush.opacity;\n"
3863 " if (brush.type == BRUSH_TYPE_LINEAR)\n"
3864 " return brush_linear(brush, b, position) * brush.opacity;\n"
3865 " if (brush.type == BRUSH_TYPE_RADIAL)\n"
3866 " return brush_radial(brush, b, position) * brush.opacity;\n"
3867 " if (brush.type == BRUSH_TYPE_BITMAP)\n"
3868 " return brush_bitmap(brush, t, s, position) * brush.opacity;\n"
3869 " return float4(0.0, 0.0, 0.0, brush.opacity);\n"
3870 "}\n"
3871 "\n"
3872 "float4 main(struct input i) : SV_Target\n"
3873 "{\n"
3874 " float4 colour;\n"
3875 "\n"
3876 " colour = sample_brush(colour_brush, t0, s0, b0, i.p);\n"
3877 " if (opacity_brush.type < BRUSH_TYPE_COUNT)\n"
3878 " colour *= sample_brush(opacity_brush, t1, s1, b1, i.p).a;\n"
3879 "\n"
3880 " if (outline)\n"
3881 " {\n"
3882 " float2 du, dv, df;\n"
3883 " float4 uv;\n"
3884 "\n"
3885 " /* Evaluate the implicit form of the curve (u² - v = 0\n"
3886 " * for Béziers, u² + v² - 1 = 0 for arcs) in texture\n"
3887 " * space, using the screen-space partial derivatives\n"
3888 " * to convert the calculated distance to object space.\n"
3889 " *\n"
3890 " * d(x, y) = |f(x, y)| / ‖∇f(x, y)‖\n"
3891 " * = |f(x, y)| / √((∂f/∂x)² + (∂f/∂y)²)\n"
3892 " *\n"
3893 " * For Béziers:\n"
3894 " * f(x, y) = u(x, y)² - v(x, y)\n"
3895 " * ∂f/∂x = 2u · ∂u/∂x - ∂v/∂x\n"
3896 " * ∂f/∂y = 2u · ∂u/∂y - ∂v/∂y\n"
3897 " *\n"
3898 " * For arcs:\n"
3899 " * f(x, y) = u(x, y)² + v(x, y)² - 1\n"
3900 " * ∂f/∂x = 2u · ∂u/∂x + 2v · ∂v/∂x\n"
3901 " * ∂f/∂y = 2u · ∂u/∂y + 2v · ∂v/∂y */\n"
3902 " uv = i.b;\n"
3903 " du = float2(ddx(uv.x), ddy(uv.x));\n"
3904 " dv = float2(ddx(uv.y), ddy(uv.y));\n"
3905 "\n"
3906 " if (!is_arc)\n"
3907 " {\n"
3908 " df = 2.0f * uv.x * du - dv;\n"
3909 "\n"
3910 " clip(dot(df, uv.zw));\n"
3911 " clip(length(mul(i.stroke_transform, df)) - abs(uv.x * uv.x - uv.y));\n"
3912 " }\n"
3913 " else\n"
3914 " {\n"
3915 " df = 2.0f * uv.x * du + 2.0f * uv.y * dv;\n"
3916 "\n"
3917 " clip(dot(df, uv.zw));\n"
3918 " clip(length(mul(i.stroke_transform, df)) - abs(uv.x * uv.x + uv.y * uv.y - 1.0f));\n"
3919 " }\n"
3920 " }\n"
3921 " else\n"
3922 " {\n"
3923 " /* Evaluate the implicit form of the curve in texture space.\n"
3924 " * \"i.b.z\" determines which side of the curve is shaded. */\n"
3925 " if (!is_arc)\n"
3926 " {\n"
3927 " clip((i.b.x * i.b.x - i.b.y) * i.b.z);\n"
3928 " }\n"
3929 " else\n"
3930 " {\n"
3931 " clip((i.b.x * i.b.x + i.b.y * i.b.y - 1.0) * i.b.z);\n"
3932 " }\n"
3933 " }\n"
3934 "\n"
3935 " return colour;\n"
3936 "}\n";
3937 static const struct shape_info
3939 enum d2d_shape_type shape_type;
3940 const D3D11_INPUT_ELEMENT_DESC *il_desc;
3941 unsigned int il_element_count;
3942 const char *name;
3943 const char *vs_code;
3944 size_t vs_code_size;
3946 shape_info[] =
3948 {D2D_SHAPE_TYPE_OUTLINE, il_desc_outline, ARRAY_SIZE(il_desc_outline),
3949 "outline", vs_code_outline, sizeof(vs_code_outline) - 1},
3950 {D2D_SHAPE_TYPE_BEZIER_OUTLINE, il_desc_curve_outline, ARRAY_SIZE(il_desc_curve_outline),
3951 "bezier_outline", vs_code_bezier_outline, sizeof(vs_code_bezier_outline) - 1},
3952 {D2D_SHAPE_TYPE_ARC_OUTLINE, il_desc_curve_outline, ARRAY_SIZE(il_desc_curve_outline),
3953 "arc_outline", vs_code_arc_outline, sizeof(vs_code_arc_outline) - 1},
3954 {D2D_SHAPE_TYPE_TRIANGLE, il_desc_triangle, ARRAY_SIZE(il_desc_triangle),
3955 "triangle", vs_code_triangle, sizeof(vs_code_triangle) - 1},
3956 {D2D_SHAPE_TYPE_CURVE, il_desc_curve, ARRAY_SIZE(il_desc_curve),
3957 "curve", vs_code_curve, sizeof(vs_code_curve) - 1},
3959 static const struct
3961 float x, y;
3963 quad[] =
3965 {-1.0f, 1.0f},
3966 {-1.0f, -1.0f},
3967 { 1.0f, 1.0f},
3968 { 1.0f, -1.0f},
3970 static const UINT16 indices[] = {0, 1, 2, 2, 1, 3};
3971 static const D3D_FEATURE_LEVEL feature_levels = D3D_FEATURE_LEVEL_10_0;
3973 render_target->ID2D1DeviceContext6_iface.lpVtbl = &d2d_device_context_vtbl;
3974 render_target->ID2D1GdiInteropRenderTarget_iface.lpVtbl = &d2d_gdi_interop_render_target_vtbl;
3975 render_target->IDWriteTextRenderer_iface.lpVtbl = &d2d_text_renderer_vtbl;
3976 render_target->IUnknown_iface.lpVtbl = &d2d_device_context_inner_unknown_vtbl;
3977 render_target->refcount = 1;
3978 ID2D1Device1_GetFactory((ID2D1Device1 *)&device->ID2D1Device6_iface, &render_target->factory);
3979 render_target->device = device;
3980 ID2D1Device6_AddRef(&render_target->device->ID2D1Device6_iface);
3982 factory = unsafe_impl_from_ID2D1Factory(render_target->factory);
3983 if (factory->factory_type == D2D1_FACTORY_TYPE_MULTI_THREADED)
3984 render_target->cs = &factory->cs;
3986 render_target->outer_unknown = outer_unknown ? outer_unknown : &render_target->IUnknown_iface;
3987 render_target->ops = ops;
3989 device_impl = unsafe_impl_from_ID2D1Device((ID2D1Device1 *)device);
3990 if (FAILED(hr = IDXGIDevice_QueryInterface(device_impl->dxgi_device,
3991 &IID_ID3D11Device1, (void **)&render_target->d3d_device)))
3993 WARN("Failed to query ID3D11Device1 interface, hr %#lx.\n", hr);
3994 goto err;
3997 if (FAILED(hr = ID3D11Device1_CreateDeviceContextState(render_target->d3d_device,
3998 0, &feature_levels, 1, D3D11_SDK_VERSION, &IID_ID3D11Device1, NULL,
3999 &render_target->d3d_state)))
4001 WARN("Failed to create device context state, hr %#lx.\n", hr);
4002 goto err;
4005 for (i = 0; i < ARRAY_SIZE(shape_info); ++i)
4007 const struct shape_info *si = &shape_info[i];
4009 if (FAILED(hr = D3DCompile(si->vs_code, si->vs_code_size, si->name, NULL, NULL,
4010 "main", "vs_4_0", 0, 0, &compiled, NULL)))
4012 WARN("Failed to compile shader for shape type %#x, hr %#lx.\n", si->shape_type, hr);
4013 goto err;
4016 if (FAILED(hr = ID3D11Device1_CreateInputLayout(render_target->d3d_device, si->il_desc, si->il_element_count,
4017 ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled),
4018 &render_target->shape_resources[si->shape_type].il)))
4020 WARN("Failed to create input layout for shape type %#x, hr %#lx.\n", si->shape_type, hr);
4021 ID3D10Blob_Release(compiled);
4022 goto err;
4025 if (FAILED(hr = ID3D11Device1_CreateVertexShader(render_target->d3d_device,
4026 ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled),
4027 NULL, &render_target->shape_resources[si->shape_type].vs)))
4029 WARN("Failed to create vertex shader for shape type %#x, hr %#lx.\n", si->shape_type, hr);
4030 ID3D10Blob_Release(compiled);
4031 goto err;
4034 ID3D10Blob_Release(compiled);
4037 buffer_desc.ByteWidth = sizeof(struct d2d_vs_cb);
4038 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
4039 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
4040 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
4041 buffer_desc.MiscFlags = 0;
4043 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, NULL,
4044 &render_target->vs_cb)))
4046 WARN("Failed to create constant buffer, hr %#lx.\n", hr);
4047 goto err;
4050 if (FAILED(hr = D3DCompile(ps_code, sizeof(ps_code) - 1, "ps", NULL, NULL, "main", "ps_4_0", 0, 0, &compiled, NULL)))
4052 WARN("Failed to compile the pixel shader, hr %#lx.\n", hr);
4053 goto err;
4056 if (FAILED(hr = ID3D11Device1_CreatePixelShader(render_target->d3d_device,
4057 ID3D10Blob_GetBufferPointer(compiled), ID3D10Blob_GetBufferSize(compiled),
4058 NULL, &render_target->ps)))
4060 WARN("Failed to create pixel shader, hr %#lx.\n", hr);
4061 ID3D10Blob_Release(compiled);
4062 goto err;
4065 ID3D10Blob_Release(compiled);
4067 buffer_desc.ByteWidth = sizeof(struct d2d_ps_cb);
4068 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
4069 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
4070 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
4071 buffer_desc.MiscFlags = 0;
4073 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device, &buffer_desc, NULL,
4074 &render_target->ps_cb)))
4076 WARN("Failed to create constant buffer, hr %#lx.\n", hr);
4077 goto err;
4080 buffer_desc.ByteWidth = sizeof(indices);
4081 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
4082 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
4083 buffer_desc.CPUAccessFlags = 0;
4084 buffer_desc.MiscFlags = 0;
4086 buffer_data.pSysMem = indices;
4087 buffer_data.SysMemPitch = 0;
4088 buffer_data.SysMemSlicePitch = 0;
4090 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device,
4091 &buffer_desc, &buffer_data, &render_target->ib)))
4093 WARN("Failed to create clear index buffer, hr %#lx.\n", hr);
4094 goto err;
4097 buffer_desc.ByteWidth = sizeof(quad);
4098 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
4099 buffer_data.pSysMem = quad;
4101 render_target->vb_stride = sizeof(*quad);
4102 if (FAILED(hr = ID3D11Device1_CreateBuffer(render_target->d3d_device,
4103 &buffer_desc, &buffer_data, &render_target->vb)))
4105 WARN("Failed to create clear vertex buffer, hr %#lx.\n", hr);
4106 goto err;
4109 rs_desc.FillMode = D3D11_FILL_SOLID;
4110 rs_desc.CullMode = D3D11_CULL_NONE;
4111 rs_desc.FrontCounterClockwise = FALSE;
4112 rs_desc.DepthBias = 0;
4113 rs_desc.DepthBiasClamp = 0.0f;
4114 rs_desc.SlopeScaledDepthBias = 0.0f;
4115 rs_desc.DepthClipEnable = TRUE;
4116 rs_desc.ScissorEnable = TRUE;
4117 rs_desc.MultisampleEnable = FALSE;
4118 rs_desc.AntialiasedLineEnable = FALSE;
4119 if (FAILED(hr = ID3D11Device1_CreateRasterizerState(render_target->d3d_device, &rs_desc, &render_target->rs)))
4121 WARN("Failed to create clear rasteriser state, hr %#lx.\n", hr);
4122 goto err;
4125 if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
4126 &IID_IDWriteFactory, (IUnknown **)&dwrite_factory)))
4128 ERR("Failed to create dwrite factory, hr %#lx.\n", hr);
4129 goto err;
4132 hr = IDWriteFactory_CreateRenderingParams(dwrite_factory, &render_target->default_text_rendering_params);
4133 IDWriteFactory_Release(dwrite_factory);
4134 if (FAILED(hr))
4136 ERR("Failed to create default text rendering parameters, hr %#lx.\n", hr);
4137 goto err;
4140 render_target->drawing_state.transform = identity;
4142 if (!d2d_clip_stack_init(&render_target->clip_stack))
4144 WARN("Failed to initialize clip stack.\n");
4145 hr = E_FAIL;
4146 goto err;
4149 render_target->desc.dpiX = 96.0f;
4150 render_target->desc.dpiY = 96.0f;
4152 return S_OK;
4154 err:
4155 if (render_target->default_text_rendering_params)
4156 IDWriteRenderingParams_Release(render_target->default_text_rendering_params);
4157 if (render_target->rs)
4158 ID3D11RasterizerState_Release(render_target->rs);
4159 if (render_target->vb)
4160 ID3D11Buffer_Release(render_target->vb);
4161 if (render_target->ib)
4162 ID3D11Buffer_Release(render_target->ib);
4163 if (render_target->ps_cb)
4164 ID3D11Buffer_Release(render_target->ps_cb);
4165 if (render_target->ps)
4166 ID3D11PixelShader_Release(render_target->ps);
4167 if (render_target->vs_cb)
4168 ID3D11Buffer_Release(render_target->vs_cb);
4169 for (i = 0; i < D2D_SHAPE_TYPE_COUNT; ++i)
4171 if (render_target->shape_resources[i].vs)
4172 ID3D11VertexShader_Release(render_target->shape_resources[i].vs);
4173 if (render_target->shape_resources[i].il)
4174 ID3D11InputLayout_Release(render_target->shape_resources[i].il);
4176 if (render_target->d3d_state)
4177 ID3DDeviceContextState_Release(render_target->d3d_state);
4178 if (render_target->d3d_device)
4179 ID3D11Device1_Release(render_target->d3d_device);
4180 ID2D1Device6_Release(&render_target->device->ID2D1Device6_iface);
4181 ID2D1Factory_Release(render_target->factory);
4182 return hr;
4185 HRESULT d2d_d3d_create_render_target(struct d2d_device *device, IDXGISurface *surface, IUnknown *outer_unknown,
4186 const struct d2d_device_context_ops *ops, const D2D1_RENDER_TARGET_PROPERTIES *desc, void **render_target)
4188 D2D1_BITMAP_PROPERTIES1 bitmap_desc;
4189 struct d2d_device_context *object;
4190 ID2D1Bitmap1 *bitmap;
4191 HRESULT hr;
4193 if (desc->type != D2D1_RENDER_TARGET_TYPE_DEFAULT && desc->type != D2D1_RENDER_TARGET_TYPE_HARDWARE)
4194 WARN("Ignoring render target type %#x.\n", desc->type);
4195 if (desc->usage != D2D1_RENDER_TARGET_USAGE_NONE)
4196 FIXME("Ignoring render target usage %#x.\n", desc->usage);
4197 if (desc->minLevel != D2D1_FEATURE_LEVEL_DEFAULT)
4198 WARN("Ignoring feature level %#x.\n", desc->minLevel);
4200 bitmap_desc.dpiX = desc->dpiX;
4201 bitmap_desc.dpiY = desc->dpiY;
4203 if (bitmap_desc.dpiX == 0.0f && bitmap_desc.dpiY == 0.0f)
4205 bitmap_desc.dpiX = 96.0f;
4206 bitmap_desc.dpiY = 96.0f;
4208 else if (bitmap_desc.dpiX <= 0.0f || bitmap_desc.dpiY <= 0.0f)
4209 return E_INVALIDARG;
4211 if (!(object = calloc(1, sizeof(*object))))
4212 return E_OUTOFMEMORY;
4214 if (FAILED(hr = d2d_device_context_init(object, device, outer_unknown, ops)))
4216 WARN("Failed to initialise render target, hr %#lx.\n", hr);
4217 free(object);
4218 return hr;
4221 ID2D1DeviceContext6_SetDpi(&object->ID2D1DeviceContext6_iface, bitmap_desc.dpiX, bitmap_desc.dpiY);
4223 if (surface)
4225 bitmap_desc.pixelFormat = desc->pixelFormat;
4226 bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
4227 if (desc->usage & D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE)
4228 bitmap_desc.bitmapOptions |= D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE;
4229 bitmap_desc.colorContext = NULL;
4231 if (FAILED(hr = ID2D1DeviceContext6_CreateBitmapFromDxgiSurface(&object->ID2D1DeviceContext6_iface,
4232 surface, &bitmap_desc, &bitmap)))
4234 WARN("Failed to create target bitmap, hr %#lx.\n", hr);
4235 IUnknown_Release(&object->IUnknown_iface);
4236 return hr;
4239 ID2D1DeviceContext6_SetTarget(&object->ID2D1DeviceContext6_iface, (ID2D1Image *)bitmap);
4240 ID2D1Bitmap1_Release(bitmap);
4242 else
4243 object->desc.pixelFormat = desc->pixelFormat;
4245 TRACE("Created render target %p.\n", object);
4246 *render_target = outer_unknown ? &object->IUnknown_iface : (IUnknown *)&object->ID2D1DeviceContext6_iface;
4248 return S_OK;
4251 static HRESULT WINAPI d2d_device_QueryInterface(ID2D1Device6 *iface, REFIID iid, void **out)
4253 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
4255 if (IsEqualGUID(iid, &IID_ID2D1Device6)
4256 || IsEqualGUID(iid, &IID_ID2D1Device5)
4257 || IsEqualGUID(iid, &IID_ID2D1Device4)
4258 || IsEqualGUID(iid, &IID_ID2D1Device3)
4259 || IsEqualGUID(iid, &IID_ID2D1Device2)
4260 || IsEqualGUID(iid, &IID_ID2D1Device1)
4261 || IsEqualGUID(iid, &IID_ID2D1Device)
4262 || IsEqualGUID(iid, &IID_ID2D1Resource)
4263 || IsEqualGUID(iid, &IID_IUnknown))
4265 ID2D1Device6_AddRef(iface);
4266 *out = iface;
4267 return S_OK;
4270 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
4272 *out = NULL;
4273 return E_NOINTERFACE;
4276 static ULONG WINAPI d2d_device_AddRef(ID2D1Device6 *iface)
4278 struct d2d_device *device = impl_from_ID2D1Device(iface);
4279 ULONG refcount = InterlockedIncrement(&device->refcount);
4281 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
4283 return refcount;
4286 void d2d_device_indexed_objects_clear(struct d2d_indexed_objects *objects)
4288 size_t i;
4290 for (i = 0; i < objects->count; ++i)
4291 IUnknown_Release(objects->elements[i].object);
4292 free(objects->elements);
4293 objects->elements = NULL;
4296 static ULONG WINAPI d2d_device_Release(ID2D1Device6 *iface)
4298 struct d2d_device *device = impl_from_ID2D1Device(iface);
4299 ULONG refcount = InterlockedDecrement(&device->refcount);
4301 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
4303 if (!refcount)
4305 IDXGIDevice_Release(device->dxgi_device);
4306 ID2D1Factory1_Release(device->factory);
4307 d2d_device_indexed_objects_clear(&device->shaders);
4308 free(device);
4311 return refcount;
4314 static void WINAPI d2d_device_GetFactory(ID2D1Device6 *iface, ID2D1Factory **factory)
4316 struct d2d_device *device = impl_from_ID2D1Device(iface);
4318 TRACE("iface %p, factory %p.\n", iface, factory);
4320 *factory = (ID2D1Factory *)device->factory;
4321 ID2D1Factory1_AddRef(device->factory);
4324 static HRESULT d2d_device_create_device_context(struct d2d_device *device,
4325 D2D1_DEVICE_CONTEXT_OPTIONS options, REFIID iid, void **context)
4327 struct d2d_device_context *object;
4328 HRESULT hr;
4330 if (options)
4331 FIXME("Options are ignored %#x.\n", options);
4333 if (!(object = calloc(1, sizeof(*object))))
4334 return E_OUTOFMEMORY;
4336 if (FAILED(hr = d2d_device_context_init(object, device, NULL, NULL)))
4338 WARN("Failed to initialise device context, hr %#lx.\n", hr);
4339 free(object);
4340 return hr;
4343 TRACE("Created device context %p.\n", object);
4345 hr = ID2D1DeviceContext6_QueryInterface(&object->ID2D1DeviceContext6_iface, iid, context);
4346 ID2D1DeviceContext6_Release(&object->ID2D1DeviceContext6_iface);
4348 return hr;
4351 static HRESULT WINAPI d2d_device_CreateDeviceContext(ID2D1Device6 *iface, D2D1_DEVICE_CONTEXT_OPTIONS options,
4352 ID2D1DeviceContext **context)
4354 struct d2d_device *device = impl_from_ID2D1Device(iface);
4356 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4358 return d2d_device_create_device_context(device, options, &IID_ID2D1DeviceContext, (void **)context);
4361 static HRESULT WINAPI d2d_device_CreatePrintControl(ID2D1Device6 *iface, IWICImagingFactory *wic_factory,
4362 IPrintDocumentPackageTarget *document_target, const D2D1_PRINT_CONTROL_PROPERTIES *desc,
4363 ID2D1PrintControl **print_control)
4365 FIXME("iface %p, wic_factory %p, document_target %p, desc %p, print_control %p stub!\n", iface, wic_factory,
4366 document_target, desc, print_control);
4368 return E_NOTIMPL;
4371 static void WINAPI d2d_device_SetMaximumTextureMemory(ID2D1Device6 *iface, UINT64 max_texture_memory)
4373 FIXME("iface %p, max_texture_memory %s stub!\n", iface, wine_dbgstr_longlong(max_texture_memory));
4376 static UINT64 WINAPI d2d_device_GetMaximumTextureMemory(ID2D1Device6 *iface)
4378 FIXME("iface %p stub!\n", iface);
4380 return 0;
4383 static HRESULT WINAPI d2d_device_ClearResources(ID2D1Device6 *iface, UINT msec_since_use)
4385 FIXME("iface %p, msec_since_use %u stub!\n", iface, msec_since_use);
4387 return E_NOTIMPL;
4390 static D2D1_RENDERING_PRIORITY WINAPI d2d_device_GetRenderingPriority(ID2D1Device6 *iface)
4392 FIXME("iface %p stub!\n", iface);
4394 return D2D1_RENDERING_PRIORITY_NORMAL;
4397 static void WINAPI d2d_device_SetRenderingPriority(ID2D1Device6 *iface, D2D1_RENDERING_PRIORITY priority)
4399 FIXME("iface %p, priority %#x stub!\n", iface, priority);
4402 static HRESULT WINAPI d2d_device_CreateDeviceContext1(ID2D1Device6 *iface, D2D1_DEVICE_CONTEXT_OPTIONS options,
4403 ID2D1DeviceContext1 **context)
4405 struct d2d_device *device = impl_from_ID2D1Device(iface);
4407 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4409 return d2d_device_create_device_context(device, options, &IID_ID2D1DeviceContext1, (void **)context);
4412 static HRESULT STDMETHODCALLTYPE d2d_device_ID2D1Device2_CreateDeviceContext(ID2D1Device6 *iface,
4413 D2D1_DEVICE_CONTEXT_OPTIONS options, ID2D1DeviceContext2 **context)
4415 struct d2d_device *device = impl_from_ID2D1Device(iface);
4417 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4419 return d2d_device_create_device_context(device, options, &IID_ID2D1DeviceContext2, (void **)context);
4422 static void STDMETHODCALLTYPE d2d_device_FlushDeviceContexts(ID2D1Device6 *iface,
4423 ID2D1Bitmap *bitmap)
4425 FIXME("iface %p, bitmap %p stub!\n", iface, bitmap);
4428 static HRESULT STDMETHODCALLTYPE d2d_device_GetDxgiDevice(ID2D1Device6 *iface,
4429 IDXGIDevice **dxgi_device)
4431 FIXME("iface %p, dxgi_device %p stub!\n", iface, dxgi_device);
4433 return E_NOTIMPL;
4436 static HRESULT STDMETHODCALLTYPE d2d_device_ID2D1Device3_CreateDeviceContext(ID2D1Device6 *iface,
4437 D2D1_DEVICE_CONTEXT_OPTIONS options, ID2D1DeviceContext3 **context)
4439 struct d2d_device *device = impl_from_ID2D1Device(iface);
4441 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4443 return d2d_device_create_device_context(device, options, &IID_ID2D1DeviceContext3, (void **)context);
4446 static HRESULT STDMETHODCALLTYPE d2d_device_ID2D1Device4_CreateDeviceContext(ID2D1Device6 *iface,
4447 D2D1_DEVICE_CONTEXT_OPTIONS options, ID2D1DeviceContext4 **context)
4449 struct d2d_device *device = impl_from_ID2D1Device(iface);
4451 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4453 return d2d_device_create_device_context(device, options, &IID_ID2D1DeviceContext4, (void **)context);
4456 static void STDMETHODCALLTYPE d2d_device_SetMaximumColorGlyphCacheMemory(ID2D1Device6 *iface,
4457 UINT64 size)
4459 FIXME("iface %p, size %s stub!\n", iface, wine_dbgstr_longlong(size));
4462 static UINT64 STDMETHODCALLTYPE d2d_device_GetMaximumColorGlyphCacheMemory(ID2D1Device6 *iface)
4464 FIXME("iface %p stub!\n", iface);
4466 return 0;
4469 static HRESULT STDMETHODCALLTYPE d2d_device_ID2D1Device5_CreateDeviceContext(ID2D1Device6 *iface,
4470 D2D1_DEVICE_CONTEXT_OPTIONS options, ID2D1DeviceContext5 **context)
4472 struct d2d_device *device = impl_from_ID2D1Device(iface);
4474 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4476 return d2d_device_create_device_context(device, options, &IID_ID2D1DeviceContext5, (void **)context);
4479 static HRESULT STDMETHODCALLTYPE d2d_device_ID2D1Device6_CreateDeviceContext(ID2D1Device6 *iface,
4480 D2D1_DEVICE_CONTEXT_OPTIONS options, ID2D1DeviceContext6 **context)
4482 struct d2d_device *device = impl_from_ID2D1Device(iface);
4484 TRACE("iface %p, options %#x, context %p.\n", iface, options, context);
4486 return d2d_device_create_device_context(device, options, &IID_ID2D1DeviceContext6, (void **)context);
4489 static const struct ID2D1Device6Vtbl d2d_device_vtbl =
4491 d2d_device_QueryInterface,
4492 d2d_device_AddRef,
4493 d2d_device_Release,
4494 d2d_device_GetFactory,
4495 d2d_device_CreateDeviceContext,
4496 d2d_device_CreatePrintControl,
4497 d2d_device_SetMaximumTextureMemory,
4498 d2d_device_GetMaximumTextureMemory,
4499 d2d_device_ClearResources,
4500 d2d_device_GetRenderingPriority,
4501 d2d_device_SetRenderingPriority,
4502 d2d_device_CreateDeviceContext1,
4503 d2d_device_ID2D1Device2_CreateDeviceContext,
4504 d2d_device_FlushDeviceContexts,
4505 d2d_device_GetDxgiDevice,
4506 d2d_device_ID2D1Device3_CreateDeviceContext,
4507 d2d_device_ID2D1Device4_CreateDeviceContext,
4508 d2d_device_SetMaximumColorGlyphCacheMemory,
4509 d2d_device_GetMaximumColorGlyphCacheMemory,
4510 d2d_device_ID2D1Device5_CreateDeviceContext,
4511 d2d_device_ID2D1Device6_CreateDeviceContext,
4514 struct d2d_device *unsafe_impl_from_ID2D1Device(ID2D1Device1 *iface)
4516 if (!iface)
4517 return NULL;
4518 assert(iface->lpVtbl == (ID2D1Device1Vtbl *)&d2d_device_vtbl);
4519 return CONTAINING_RECORD(iface, struct d2d_device, ID2D1Device6_iface);
4522 void d2d_device_init(struct d2d_device *device, struct d2d_factory *factory, IDXGIDevice *dxgi_device)
4524 device->ID2D1Device6_iface.lpVtbl = &d2d_device_vtbl;
4525 device->refcount = 1;
4526 device->factory = (ID2D1Factory1 *)&factory->ID2D1Factory7_iface;
4527 ID2D1Factory1_AddRef(device->factory);
4528 device->dxgi_device = dxgi_device;
4529 IDXGIDevice_AddRef(device->dxgi_device);
4532 HRESULT d2d_device_add_indexed_object(struct d2d_indexed_objects *objects,
4533 const GUID *id, IUnknown *object)
4535 if (!d2d_array_reserve((void **)&objects->elements, &objects->size, objects->count + 1,
4536 sizeof(*objects->elements)))
4538 WARN("Failed to resize elements array.\n");
4539 return E_OUTOFMEMORY;
4542 objects->elements[objects->count].id = *id;
4543 objects->elements[objects->count].object = object;
4544 IUnknown_AddRef(object);
4545 objects->count++;
4547 return S_OK;
4550 BOOL d2d_device_get_indexed_object(struct d2d_indexed_objects *objects, const GUID *id,
4551 IUnknown **object)
4553 size_t i;
4555 for (i = 0; i < objects->count; ++i)
4557 if (IsEqualGUID(id, &objects->elements[i].id))
4559 if (object)
4561 *object = objects->elements[i].object;
4562 IUnknown_AddRef(*object);
4564 return TRUE;
4568 if (object) *object = NULL;
4569 return FALSE;