d2d1: Implement d2d_d3d_render_target_SetAntialiasMode().
[wine/multimedia.git] / dlls / d2d1 / render_target.c
blobdd74a58d1d6c479dc2589d089b09758a9a518b09
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 "config.h"
20 #include "wine/port.h"
22 #include "d2d1_private.h"
23 #include "wincodec.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
27 #define INITIAL_CLIP_STACK_SIZE 4
29 struct d2d_draw_text_layout_ctx
31 ID2D1Brush *brush;
32 D2D1_DRAW_TEXT_OPTIONS options;
35 static void d2d_point_transform(D2D1_POINT_2F *dst, const D2D1_MATRIX_3X2_F *matrix, float x, float y)
37 dst->x = x * matrix->_11 + y * matrix->_21 + matrix->_31;
38 dst->y = x * matrix->_12 + y * matrix->_22 + matrix->_32;
41 static void d2d_rect_expand(D2D1_RECT_F *dst, const D2D1_POINT_2F *point)
43 if (point->x < dst->left)
44 dst->left = point->x;
45 if (point->y < dst->top)
46 dst->top = point->y;
47 if (point->x > dst->right)
48 dst->right = point->x;
49 if (point->y > dst->bottom)
50 dst->bottom = point->y;
53 static void d2d_rect_intersect(D2D1_RECT_F *dst, const D2D1_RECT_F *src)
55 if (src->left > dst->left)
56 dst->left = src->left;
57 if (src->top > dst->top)
58 dst->top = src->top;
59 if (src->right < dst->right)
60 dst->right = src->right;
61 if (src->bottom < dst->bottom)
62 dst->bottom = src->bottom;
65 static void d2d_rect_set(D2D1_RECT_F *dst, float left, float top, float right, float bottom)
67 dst->left = left;
68 dst->top = top;
69 dst->right = right;
70 dst->bottom = bottom;
73 static BOOL d2d_clip_stack_init(struct d2d_clip_stack *stack)
75 if (!(stack->stack = HeapAlloc(GetProcessHeap(), 0, INITIAL_CLIP_STACK_SIZE * sizeof(*stack->stack))))
76 return FALSE;
78 stack->size = INITIAL_CLIP_STACK_SIZE;
79 stack->count = 0;
81 return TRUE;
84 static void d2d_clip_stack_cleanup(struct d2d_clip_stack *stack)
86 HeapFree(GetProcessHeap(), 0, stack->stack);
89 static BOOL d2d_clip_stack_push(struct d2d_clip_stack *stack, const D2D1_RECT_F *rect)
91 D2D1_RECT_F r;
93 if (stack->count == stack->size)
95 D2D1_RECT_F *new_stack;
96 unsigned int new_size;
98 if (stack->size > UINT_MAX / 2)
99 return FALSE;
101 new_size = stack->size * 2;
102 if (!(new_stack = HeapReAlloc(GetProcessHeap(), 0, stack->stack, new_size * sizeof(*stack->stack))))
103 return FALSE;
105 stack->stack = new_stack;
106 stack->size = new_size;
109 r = *rect;
110 if (stack->count)
111 d2d_rect_intersect(&r, &stack->stack[stack->count - 1]);
112 stack->stack[stack->count++] = r;
114 return TRUE;
117 static void d2d_clip_stack_pop(struct d2d_clip_stack *stack)
119 if (!stack->count)
120 return;
121 --stack->count;
124 static void d2d_draw(struct d2d_d3d_render_target *render_target, ID3D10Buffer *vs_cb,
125 ID3D10PixelShader *ps, ID3D10Buffer *ps_cb, struct d2d_brush *brush)
127 ID3D10Device *device = render_target->device;
128 unsigned int offset;
129 D3D10_VIEWPORT vp;
130 HRESULT hr;
131 static const float blend_factor[] = {1.0f, 1.0f, 1.0f, 1.0f};
133 vp.TopLeftX = 0;
134 vp.TopLeftY = 0;
135 vp.Width = render_target->pixel_size.width;
136 vp.Height = render_target->pixel_size.height;
137 vp.MinDepth = 0.0f;
138 vp.MaxDepth = 1.0f;
140 if (FAILED(hr = render_target->stateblock->lpVtbl->Capture(render_target->stateblock)))
142 WARN("Failed to capture stateblock, hr %#x.\n", hr);
143 return;
146 ID3D10Device_ClearState(device);
148 ID3D10Device_IASetInputLayout(device, render_target->il);
149 ID3D10Device_IASetPrimitiveTopology(device, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
150 offset = 0;
151 ID3D10Device_IASetVertexBuffers(device, 0, 1, &render_target->vb,
152 &render_target->vb_stride, &offset);
153 ID3D10Device_VSSetConstantBuffers(device, 0, 1, &vs_cb);
154 ID3D10Device_VSSetShader(device, render_target->vs);
155 ID3D10Device_PSSetConstantBuffers(device, 0, 1, &ps_cb);
156 ID3D10Device_PSSetShader(device, ps);
157 ID3D10Device_RSSetViewports(device, 1, &vp);
158 if (render_target->clip_stack.count)
160 const D2D1_RECT_F *clip_rect;
161 D3D10_RECT scissor_rect;
163 clip_rect = &render_target->clip_stack.stack[render_target->clip_stack.count - 1];
164 scissor_rect.left = clip_rect->left + 0.5f;
165 scissor_rect.top = clip_rect->top + 0.5f;
166 scissor_rect.right = clip_rect->right + 0.5f;
167 scissor_rect.bottom = clip_rect->bottom + 0.5f;
168 ID3D10Device_RSSetScissorRects(device, 1, &scissor_rect);
169 ID3D10Device_RSSetState(device, render_target->rs);
171 ID3D10Device_OMSetRenderTargets(device, 1, &render_target->view, NULL);
172 if (brush)
174 ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK);
175 d2d_brush_bind_resources(brush, device);
178 ID3D10Device_Draw(device, 4, 0);
180 if (FAILED(hr = render_target->stateblock->lpVtbl->Apply(render_target->stateblock)))
181 WARN("Failed to apply stateblock, hr %#x.\n", hr);
184 static inline struct d2d_d3d_render_target *impl_from_ID2D1RenderTarget(ID2D1RenderTarget *iface)
186 return CONTAINING_RECORD(iface, struct d2d_d3d_render_target, ID2D1RenderTarget_iface);
189 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_QueryInterface(ID2D1RenderTarget *iface, REFIID iid, void **out)
191 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
193 if (IsEqualGUID(iid, &IID_ID2D1RenderTarget)
194 || IsEqualGUID(iid, &IID_ID2D1Resource)
195 || IsEqualGUID(iid, &IID_IUnknown))
197 ID2D1RenderTarget_AddRef(iface);
198 *out = iface;
199 return S_OK;
202 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
204 *out = NULL;
205 return E_NOINTERFACE;
208 static ULONG STDMETHODCALLTYPE d2d_d3d_render_target_AddRef(ID2D1RenderTarget *iface)
210 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
211 ULONG refcount = InterlockedIncrement(&render_target->refcount);
213 TRACE("%p increasing refcount to %u.\n", iface, refcount);
215 return refcount;
218 static ULONG STDMETHODCALLTYPE d2d_d3d_render_target_Release(ID2D1RenderTarget *iface)
220 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
221 ULONG refcount = InterlockedDecrement(&render_target->refcount);
223 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
225 if (!refcount)
227 d2d_clip_stack_cleanup(&render_target->clip_stack);
228 if (render_target->text_rendering_params)
229 IDWriteRenderingParams_Release(render_target->text_rendering_params);
230 ID3D10PixelShader_Release(render_target->rect_bitmap_ps);
231 ID3D10PixelShader_Release(render_target->rect_solid_ps);
232 ID3D10BlendState_Release(render_target->bs);
233 ID3D10RasterizerState_Release(render_target->rs);
234 ID3D10VertexShader_Release(render_target->vs);
235 ID3D10Buffer_Release(render_target->vb);
236 ID3D10InputLayout_Release(render_target->il);
237 render_target->stateblock->lpVtbl->Release(render_target->stateblock);
238 ID3D10RenderTargetView_Release(render_target->view);
239 ID3D10Device_Release(render_target->device);
240 ID2D1Factory_Release(render_target->factory);
241 HeapFree(GetProcessHeap(), 0, render_target);
244 return refcount;
247 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetFactory(ID2D1RenderTarget *iface, ID2D1Factory **factory)
249 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
251 TRACE("iface %p, factory %p.\n", iface, factory);
253 *factory = render_target->factory;
254 ID2D1Factory_AddRef(*factory);
257 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmap(ID2D1RenderTarget *iface,
258 D2D1_SIZE_U size, const void *src_data, UINT32 pitch, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
260 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
261 struct d2d_bitmap *object;
262 HRESULT hr;
264 TRACE("iface %p, size {%u, %u}, src_data %p, pitch %u, desc %p, bitmap %p.\n",
265 iface, size.width, size.height, src_data, pitch, desc, bitmap);
267 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
268 return E_OUTOFMEMORY;
270 if (FAILED(hr = d2d_bitmap_init(object, render_target, size, src_data, pitch, desc)))
272 WARN("Failed to initialize bitmap, hr %#x.\n", hr);
273 HeapFree(GetProcessHeap(), 0, object);
274 return hr;
277 TRACE("Created bitmap %p.\n", object);
278 *bitmap = &object->ID2D1Bitmap_iface;
280 return S_OK;
283 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmapFromWicBitmap(ID2D1RenderTarget *iface,
284 IWICBitmapSource *bitmap_source, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
286 D2D1_BITMAP_PROPERTIES bitmap_desc;
287 unsigned int bpp, data_size;
288 D2D1_SIZE_U size;
289 WICRect rect;
290 UINT32 pitch;
291 HRESULT hr;
292 void *data;
294 TRACE("iface %p, bitmap_source %p, desc %p, bitmap %p.\n",
295 iface, bitmap_source, desc, bitmap);
297 if (FAILED(hr = IWICBitmapSource_GetSize(bitmap_source, &size.width, &size.height)))
299 WARN("Failed to get bitmap size, hr %#x.\n", hr);
300 return hr;
303 if (!desc)
305 bitmap_desc.pixelFormat.format = DXGI_FORMAT_UNKNOWN;
306 bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
307 bitmap_desc.dpiX = 0.0f;
308 bitmap_desc.dpiY = 0.0f;
310 else
312 bitmap_desc = *desc;
315 if (bitmap_desc.pixelFormat.format == DXGI_FORMAT_UNKNOWN)
317 WICPixelFormatGUID wic_format;
319 if (FAILED(hr = IWICBitmapSource_GetPixelFormat(bitmap_source, &wic_format)))
321 WARN("Failed to get bitmap format, hr %#x.\n", hr);
322 return hr;
325 if (IsEqualGUID(&wic_format, &GUID_WICPixelFormat32bppPBGRA)
326 || IsEqualGUID(&wic_format, &GUID_WICPixelFormat32bppBGR))
328 bitmap_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
330 else
332 WARN("Unsupported WIC bitmap format %s.\n", debugstr_guid(&wic_format));
333 return D2DERR_UNSUPPORTED_PIXEL_FORMAT;
337 switch (bitmap_desc.pixelFormat.format)
339 case DXGI_FORMAT_B8G8R8A8_UNORM:
340 bpp = 4;
341 break;
343 default:
344 FIXME("Unhandled format %#x.\n", bitmap_desc.pixelFormat.format);
345 return D2DERR_UNSUPPORTED_PIXEL_FORMAT;
348 pitch = ((bpp * size.width) + 15) & ~15;
349 data_size = pitch * size.height;
350 if (!(data = HeapAlloc(GetProcessHeap(), 0, data_size)))
351 return E_OUTOFMEMORY;
353 rect.X = 0;
354 rect.Y = 0;
355 rect.Width = size.width;
356 rect.Height = size.height;
357 if (FAILED(hr = IWICBitmapSource_CopyPixels(bitmap_source, &rect, pitch, data_size, data)))
359 WARN("Failed to copy bitmap pixels, hr %#x.\n", hr);
360 HeapFree(GetProcessHeap(), 0, data);
361 return hr;
364 hr = d2d_d3d_render_target_CreateBitmap(iface, size, data, pitch, &bitmap_desc, bitmap);
366 HeapFree(GetProcessHeap(), 0, data);
368 return hr;
371 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateSharedBitmap(ID2D1RenderTarget *iface,
372 REFIID iid, void *data, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap)
374 FIXME("iface %p, iid %s, data %p, desc %p, bitmap %p stub!\n",
375 iface, debugstr_guid(iid), data, desc, bitmap);
377 return E_NOTIMPL;
380 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmapBrush(ID2D1RenderTarget *iface,
381 ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc,
382 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1BitmapBrush **brush)
384 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
385 struct d2d_brush *object;
386 HRESULT hr;
388 TRACE("iface %p, bitmap %p, bitmap_brush_desc %p, brush_desc %p, brush %p.\n",
389 iface, bitmap, bitmap_brush_desc, brush_desc, brush);
391 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
392 return E_OUTOFMEMORY;
394 if (FAILED(hr = d2d_bitmap_brush_init(object, render_target, bitmap, bitmap_brush_desc, brush_desc)))
396 WARN("Failed to initialize brush, hr %#x.\n", hr);
397 HeapFree(GetProcessHeap(), 0, object);
398 return hr;
401 TRACE("Created brush %p.\n", object);
402 *brush = (ID2D1BitmapBrush *)&object->ID2D1Brush_iface;
404 return S_OK;
407 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateSolidColorBrush(ID2D1RenderTarget *iface,
408 const D2D1_COLOR_F *color, const D2D1_BRUSH_PROPERTIES *desc, ID2D1SolidColorBrush **brush)
410 struct d2d_brush *object;
412 TRACE("iface %p, color %p, desc %p, brush %p.\n", iface, color, desc, brush);
414 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
415 return E_OUTOFMEMORY;
417 d2d_solid_color_brush_init(object, iface, color, desc);
419 TRACE("Created brush %p.\n", object);
420 *brush = (ID2D1SolidColorBrush *)&object->ID2D1Brush_iface;
422 return S_OK;
425 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateGradientStopCollection(ID2D1RenderTarget *iface,
426 const D2D1_GRADIENT_STOP *stops, UINT32 stop_count, D2D1_GAMMA gamma, D2D1_EXTEND_MODE extend_mode,
427 ID2D1GradientStopCollection **gradient)
429 struct d2d_gradient *object;
430 HRESULT hr;
432 TRACE("iface %p, stops %p, stop_count %u, gamma %#x, extend_mode %#x, gradient %p.\n",
433 iface, stops, stop_count, gamma, extend_mode, gradient);
435 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
436 return E_OUTOFMEMORY;
438 if (FAILED(hr = d2d_gradient_init(object, iface, stops, stop_count, gamma, extend_mode)))
440 WARN("Failed to initialize gradient, hr %#x.\n", hr);
441 HeapFree(GetProcessHeap(), 0, object);
442 return hr;
445 TRACE("Created gradient %p.\n", object);
446 *gradient = &object->ID2D1GradientStopCollection_iface;
448 return S_OK;
451 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateLinearGradientBrush(ID2D1RenderTarget *iface,
452 const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
453 ID2D1GradientStopCollection *gradient, ID2D1LinearGradientBrush **brush)
455 struct d2d_brush *object;
457 TRACE("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p.\n",
458 iface, gradient_brush_desc, brush_desc, gradient, brush);
460 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
461 return E_OUTOFMEMORY;
463 d2d_linear_gradient_brush_init(object, iface, gradient_brush_desc, brush_desc, gradient);
465 TRACE("Created brush %p.\n", object);
466 *brush = (ID2D1LinearGradientBrush *)&object->ID2D1Brush_iface;
468 return S_OK;
471 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateRadialGradientBrush(ID2D1RenderTarget *iface,
472 const D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
473 ID2D1GradientStopCollection *gradient, ID2D1RadialGradientBrush **brush)
475 FIXME("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p stub!\n",
476 iface, gradient_brush_desc, brush_desc, gradient, brush);
478 return E_NOTIMPL;
481 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateCompatibleRenderTarget(ID2D1RenderTarget *iface,
482 const D2D1_SIZE_F *size, const D2D1_SIZE_U *pixel_size, const D2D1_PIXEL_FORMAT *format,
483 D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS options, ID2D1BitmapRenderTarget **render_target)
485 FIXME("iface %p, size %p, pixel_size %p, format %p, options %#x, render_target %p stub!\n",
486 iface, size, pixel_size, format, options, render_target);
488 return E_NOTIMPL;
491 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateLayer(ID2D1RenderTarget *iface,
492 const D2D1_SIZE_F *size, ID2D1Layer **layer)
494 FIXME("iface %p, size %p, layer %p stub!\n", iface, size, layer);
496 return E_NOTIMPL;
499 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateMesh(ID2D1RenderTarget *iface, ID2D1Mesh **mesh)
501 struct d2d_mesh *object;
503 TRACE("iface %p, mesh %p.\n", iface, mesh);
505 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
506 return E_OUTOFMEMORY;
508 d2d_mesh_init(object);
510 TRACE("Created mesh %p.\n", object);
511 *mesh = &object->ID2D1Mesh_iface;
513 return S_OK;
516 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawLine(ID2D1RenderTarget *iface,
517 D2D1_POINT_2F p0, D2D1_POINT_2F p1, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
519 FIXME("iface %p, p0 {%.8e, %.8e}, p1 {%.8e, %.8e}, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
520 iface, p0.x, p0.y, p1.x, p1.y, brush, stroke_width, stroke_style);
523 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawRectangle(ID2D1RenderTarget *iface,
524 const D2D1_RECT_F *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
526 FIXME("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
527 iface, rect, brush, stroke_width, stroke_style);
530 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillRectangle(ID2D1RenderTarget *iface,
531 const D2D1_RECT_F *rect, ID2D1Brush *brush)
533 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
534 struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
535 D3D10_SUBRESOURCE_DATA buffer_data;
536 D3D10_BUFFER_DESC buffer_desc;
537 ID3D10Buffer *vs_cb, *ps_cb;
538 ID3D10PixelShader *ps;
539 D2D1_COLOR_F color;
540 float tmp_x, tmp_y;
541 HRESULT hr;
542 struct
544 float _11, _21, _31, pad0;
545 float _12, _22, _32, pad1;
546 } transform, transform_inverse;
548 TRACE("iface %p, rect %p, brush %p.\n", iface, rect, brush);
550 if (brush_impl->type != D2D_BRUSH_TYPE_SOLID
551 && brush_impl->type != D2D_BRUSH_TYPE_BITMAP)
553 FIXME("Unhandled brush type %#x.\n", brush_impl->type);
554 return;
557 /* Translate from clip space to world (D2D rendertarget) space, taking the
558 * dpi and rendertarget transform into account. */
559 tmp_x = (2.0f * render_target->dpi_x) / (96.0f * render_target->pixel_size.width);
560 tmp_y = -(2.0f * render_target->dpi_y) / (96.0f * render_target->pixel_size.height);
561 transform._11 = render_target->transform._11 * tmp_x;
562 transform._21 = render_target->transform._21 * tmp_x;
563 transform._31 = render_target->transform._31 * tmp_x - 1.0f;
564 transform.pad0 = 0.0f;
565 transform._12 = render_target->transform._12 * tmp_y;
566 transform._22 = render_target->transform._22 * tmp_y;
567 transform._32 = render_target->transform._32 * tmp_y + 1.0f;
568 transform.pad1 = 0.0f;
570 /* Translate from world space to object space. */
571 tmp_x = rect->left + (rect->right - rect->left) / 2.0f;
572 tmp_y = rect->top + (rect->bottom - rect->top) / 2.0f;
573 transform._31 += tmp_x * transform._11 + tmp_y * transform._21;
574 transform._32 += tmp_x * transform._12 + tmp_y * transform._22;
575 tmp_x = (rect->right - rect->left) / 2.0f;
576 tmp_y = (rect->bottom - rect->top) / 2.0f;
577 transform._11 *= tmp_x;
578 transform._12 *= tmp_x;
579 transform._21 *= tmp_y;
580 transform._22 *= tmp_y;
582 buffer_desc.ByteWidth = sizeof(transform);
583 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
584 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
585 buffer_desc.CPUAccessFlags = 0;
586 buffer_desc.MiscFlags = 0;
588 buffer_data.pSysMem = &transform;
589 buffer_data.SysMemPitch = 0;
590 buffer_data.SysMemSlicePitch = 0;
592 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vs_cb)))
594 WARN("Failed to create constant buffer, hr %#x.\n", hr);
595 return;
598 if (brush_impl->type == D2D_BRUSH_TYPE_BITMAP)
600 struct d2d_bitmap *bitmap = brush_impl->u.bitmap.bitmap;
601 float rt_scale, rt_bitmap_scale, d;
603 ps = render_target->rect_bitmap_ps;
605 /* Scale for bitmap size and dpi. */
606 rt_scale = render_target->dpi_x / 96.0f;
607 rt_bitmap_scale = bitmap->pixel_size.width * (bitmap->dpi_x / 96.0f) * rt_scale;
608 transform._11 = brush_impl->transform._11 * rt_bitmap_scale;
609 transform._21 = brush_impl->transform._21 * rt_bitmap_scale;
610 transform._31 = brush_impl->transform._31 * rt_scale;
611 rt_scale = render_target->dpi_y / 96.0f;
612 rt_bitmap_scale = bitmap->pixel_size.height * (bitmap->dpi_y / 96.0f) * rt_scale;
613 transform._12 = brush_impl->transform._12 * rt_bitmap_scale;
614 transform._22 = brush_impl->transform._22 * rt_bitmap_scale;
615 transform._32 = brush_impl->transform._32 * rt_scale;
617 /* Invert the matrix. (Because the matrix is applied to the sampling
618 * coordinates. I.e., to scale the bitmap by 2 we need to divide the
619 * coordinates by 2.) */
620 d = transform._11 * transform._22 - transform._21 * transform._22;
621 if (d != 0.0f)
623 transform_inverse._11 = transform._22 / d;
624 transform_inverse._21 = -transform._21 / d;
625 transform_inverse._31 = (transform._21 * transform._32 - transform._31 * transform._22) / d;
626 transform_inverse._12 = -transform._12 / d;
627 transform_inverse._22 = transform._11 / d;
628 transform_inverse._32 = -(transform._11 * transform._32 - transform._31 * transform._12) / d;
631 buffer_desc.ByteWidth = sizeof(transform_inverse);
632 buffer_data.pSysMem = &transform_inverse;
634 else
636 ps = render_target->rect_solid_ps;
638 color = brush_impl->u.solid.color;
639 color.r *= brush_impl->opacity;
640 color.g *= brush_impl->opacity;
641 color.b *= brush_impl->opacity;
642 color.a *= brush_impl->opacity;
644 buffer_desc.ByteWidth = sizeof(color);
645 buffer_data.pSysMem = &color;
648 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ps_cb)))
650 WARN("Failed to create constant buffer, hr %#x.\n", hr);
651 ID3D10Buffer_Release(vs_cb);
652 return;
655 d2d_draw(render_target, vs_cb, ps, ps_cb, brush_impl);
657 ID3D10Buffer_Release(ps_cb);
658 ID3D10Buffer_Release(vs_cb);
661 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawRoundedRectangle(ID2D1RenderTarget *iface,
662 const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
664 FIXME("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
665 iface, rect, brush, stroke_width, stroke_style);
668 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillRoundedRectangle(ID2D1RenderTarget *iface,
669 const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush)
671 FIXME("iface %p, rect %p, brush %p stub!\n", iface, rect, brush);
674 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawEllipse(ID2D1RenderTarget *iface,
675 const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
677 FIXME("iface %p, ellipse %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
678 iface, ellipse, brush, stroke_width, stroke_style);
681 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillEllipse(ID2D1RenderTarget *iface,
682 const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush)
684 FIXME("iface %p, ellipse %p, brush %p stub!\n", iface, ellipse, brush);
687 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGeometry(ID2D1RenderTarget *iface,
688 ID2D1Geometry *geometry, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
690 FIXME("iface %p, geometry %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
691 iface, geometry, brush, stroke_width, stroke_style);
694 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarget *iface,
695 ID2D1Geometry *geometry, ID2D1Brush *brush, ID2D1Brush *opacity_brush)
697 FIXME("iface %p, geometry %p, brush %p, opacity_brush %p stub!\n", iface, geometry, brush, opacity_brush);
700 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillMesh(ID2D1RenderTarget *iface,
701 ID2D1Mesh *mesh, ID2D1Brush *brush)
703 FIXME("iface %p, mesh %p, brush %p stub!\n", iface, mesh, brush);
706 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillOpacityMask(ID2D1RenderTarget *iface,
707 ID2D1Bitmap *mask, ID2D1Brush *brush, D2D1_OPACITY_MASK_CONTENT content,
708 const D2D1_RECT_F *dst_rect, const D2D1_RECT_F *src_rect)
710 FIXME("iface %p, mask %p, brush %p, content %#x, dst_rect %p, src_rect %p stub!\n",
711 iface, mask, brush, content, dst_rect, src_rect);
714 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawBitmap(ID2D1RenderTarget *iface,
715 ID2D1Bitmap *bitmap, const D2D1_RECT_F *dst_rect, float opacity,
716 D2D1_BITMAP_INTERPOLATION_MODE interpolation_mode, const D2D1_RECT_F *src_rect)
718 D2D1_BITMAP_BRUSH_PROPERTIES bitmap_brush_desc;
719 D2D1_BRUSH_PROPERTIES brush_desc;
720 ID2D1BitmapBrush *brush;
721 D2D1_RECT_F s, d;
722 HRESULT hr;
724 TRACE("iface %p, bitmap %p, dst_rect %p, opacity %.8e, interpolation_mode %#x, src_rect %p.\n",
725 iface, bitmap, dst_rect, opacity, interpolation_mode, src_rect);
727 if (src_rect)
729 s = *src_rect;
731 else
733 D2D1_SIZE_F size;
735 size = ID2D1Bitmap_GetSize(bitmap);
736 s.left = 0.0f;
737 s.top = 0.0f;
738 s.right = size.width;
739 s.bottom = size.height;
742 if (dst_rect)
744 d = *dst_rect;
746 else
748 d.left = 0.0f;
749 d.top = 0.0f;
750 d.right = s.right - s.left;
751 d.bottom = s.bottom - s.top;
754 bitmap_brush_desc.extendModeX = D2D1_EXTEND_MODE_CLAMP;
755 bitmap_brush_desc.extendModeY = D2D1_EXTEND_MODE_CLAMP;
756 bitmap_brush_desc.interpolationMode = interpolation_mode;
758 brush_desc.opacity = opacity;
759 brush_desc.transform._11 = (d.right - d.left) / (s.right - s.left);
760 brush_desc.transform._21 = 0.0f;
761 brush_desc.transform._31 = d.left - s.left;
762 brush_desc.transform._12 = 0.0f;
763 brush_desc.transform._22 = (d.bottom - d.top) / (s.bottom - s.top);
764 brush_desc.transform._32 = d.top - s.top;
766 if (FAILED(hr = ID2D1RenderTarget_CreateBitmapBrush(iface, bitmap, &bitmap_brush_desc, &brush_desc, &brush)))
768 ERR("Failed to create bitmap brush, hr %#x.\n", hr);
769 return;
772 ID2D1RenderTarget_FillRectangle(iface, &d, (ID2D1Brush *)brush);
773 ID2D1BitmapBrush_Release(brush);
776 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawText(ID2D1RenderTarget *iface,
777 const WCHAR *string, UINT32 string_len, IDWriteTextFormat *text_format, const D2D1_RECT_F *layout_rect,
778 ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options, DWRITE_MEASURING_MODE measuring_mode)
780 FIXME("iface %p, string %s, string_len %u, text_format %p, layout_rect %p, "
781 "brush %p, options %#x, measuring_mode %#x stub!\n",
782 iface, debugstr_wn(string, string_len), string_len, text_format, layout_rect,
783 brush, options, measuring_mode);
786 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawTextLayout(ID2D1RenderTarget *iface,
787 D2D1_POINT_2F origin, IDWriteTextLayout *layout, ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options)
789 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
790 struct d2d_draw_text_layout_ctx ctx;
791 HRESULT hr;
793 TRACE("iface %p, origin {%.8e, %.8e}, layout %p, brush %p, options %#x.\n",
794 iface, origin.x, origin.y, layout, brush, options);
796 ctx.brush = brush;
797 ctx.options = options;
799 if (FAILED(hr = IDWriteTextLayout_Draw(layout,
800 &ctx, &render_target->IDWriteTextRenderer_iface, origin.x, origin.y)))
801 FIXME("Failed to draw text layout, hr %#x.\n", hr);
804 static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGlyphRun(ID2D1RenderTarget *iface,
805 D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
806 DWRITE_MEASURING_MODE measuring_mode)
808 FIXME("iface %p, baseline_origin {%.8e, %.8e}, glyph_run %p, brush %p, measuring_mode %#x stub!\n",
809 iface, baseline_origin.x, baseline_origin.y, glyph_run, brush, measuring_mode);
812 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTransform(ID2D1RenderTarget *iface,
813 const D2D1_MATRIX_3X2_F *transform)
815 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
817 TRACE("iface %p, transform %p.\n", iface, transform);
819 render_target->transform = *transform;
822 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTransform(ID2D1RenderTarget *iface,
823 D2D1_MATRIX_3X2_F *transform)
825 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
827 TRACE("iface %p, transform %p.\n", iface, transform);
829 *transform = render_target->transform;
832 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetAntialiasMode(ID2D1RenderTarget *iface,
833 D2D1_ANTIALIAS_MODE antialias_mode)
835 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
837 TRACE("iface %p, antialias_mode %#x stub!\n", iface, antialias_mode);
839 render_target->antialias_mode = antialias_mode;
842 static D2D1_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_d3d_render_target_GetAntialiasMode(ID2D1RenderTarget *iface)
844 FIXME("iface %p stub!\n", iface);
846 return D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
849 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTextAntialiasMode(ID2D1RenderTarget *iface,
850 D2D1_TEXT_ANTIALIAS_MODE antialias_mode)
852 FIXME("iface %p, antialias_mode %#x stub!\n", iface, antialias_mode);
855 static D2D1_TEXT_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_d3d_render_target_GetTextAntialiasMode(ID2D1RenderTarget *iface)
857 FIXME("iface %p stub!\n", iface);
859 return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
862 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTextRenderingParams(ID2D1RenderTarget *iface,
863 IDWriteRenderingParams *text_rendering_params)
865 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
867 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
869 if (text_rendering_params)
870 IDWriteRenderingParams_AddRef(text_rendering_params);
871 if (render_target->text_rendering_params)
872 IDWriteRenderingParams_Release(render_target->text_rendering_params);
873 render_target->text_rendering_params = text_rendering_params;
876 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTextRenderingParams(ID2D1RenderTarget *iface,
877 IDWriteRenderingParams **text_rendering_params)
879 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
881 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
883 if ((*text_rendering_params = render_target->text_rendering_params))
884 IDWriteRenderingParams_AddRef(*text_rendering_params);
887 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTags(ID2D1RenderTarget *iface, D2D1_TAG tag1, D2D1_TAG tag2)
889 FIXME("iface %p, tag1 %s, tag2 %s stub!\n", iface, wine_dbgstr_longlong(tag1), wine_dbgstr_longlong(tag2));
892 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTags(ID2D1RenderTarget *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
894 FIXME("iface %p, tag1 %p, tag2 %p stub!\n", iface, tag1, tag2);
896 *tag1 = 0;
897 *tag2 = 0;
900 static void STDMETHODCALLTYPE d2d_d3d_render_target_PushLayer(ID2D1RenderTarget *iface,
901 const D2D1_LAYER_PARAMETERS *layer_parameters, ID2D1Layer *layer)
903 FIXME("iface %p, layer_parameters %p, layer %p stub!\n", iface, layer_parameters, layer);
906 static void STDMETHODCALLTYPE d2d_d3d_render_target_PopLayer(ID2D1RenderTarget *iface)
908 FIXME("iface %p stub!\n", iface);
911 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_Flush(ID2D1RenderTarget *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
913 FIXME("iface %p, tag1 %p, tag2 %p stub!\n", iface, tag1, tag2);
915 return E_NOTIMPL;
918 static void STDMETHODCALLTYPE d2d_d3d_render_target_SaveDrawingState(ID2D1RenderTarget *iface,
919 ID2D1DrawingStateBlock *state_block)
921 FIXME("iface %p, state_block %p stub!\n", iface, state_block);
924 static void STDMETHODCALLTYPE d2d_d3d_render_target_RestoreDrawingState(ID2D1RenderTarget *iface,
925 ID2D1DrawingStateBlock *state_block)
927 FIXME("iface %p, state_block %p stub!\n", iface, state_block);
930 static void STDMETHODCALLTYPE d2d_d3d_render_target_PushAxisAlignedClip(ID2D1RenderTarget *iface,
931 const D2D1_RECT_F *clip_rect, D2D1_ANTIALIAS_MODE antialias_mode)
933 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
934 D2D1_RECT_F transformed_rect;
935 float x_scale, y_scale;
936 D2D1_POINT_2F point;
938 TRACE("iface %p, clip_rect %p, antialias_mode %#x.\n", iface, clip_rect, antialias_mode);
940 if (antialias_mode != D2D1_ANTIALIAS_MODE_ALIASED)
941 FIXME("Ignoring antialias_mode %#x.\n", antialias_mode);
943 x_scale = render_target->dpi_x / 96.0f;
944 y_scale = render_target->dpi_y / 96.0f;
945 d2d_point_transform(&point, &render_target->transform, clip_rect->left * x_scale, clip_rect->top * y_scale);
946 d2d_rect_set(&transformed_rect, point.x, point.y, point.x, point.y);
947 d2d_point_transform(&point, &render_target->transform, clip_rect->left * x_scale, clip_rect->bottom * y_scale);
948 d2d_rect_expand(&transformed_rect, &point);
949 d2d_point_transform(&point, &render_target->transform, clip_rect->right * x_scale, clip_rect->top * y_scale);
950 d2d_rect_expand(&transformed_rect, &point);
951 d2d_point_transform(&point, &render_target->transform, clip_rect->right * x_scale, clip_rect->bottom * y_scale);
952 d2d_rect_expand(&transformed_rect, &point);
954 if (!d2d_clip_stack_push(&render_target->clip_stack, &transformed_rect))
955 WARN("Failed to push clip rect.\n");
958 static void STDMETHODCALLTYPE d2d_d3d_render_target_PopAxisAlignedClip(ID2D1RenderTarget *iface)
960 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
962 TRACE("iface %p.\n", iface);
964 d2d_clip_stack_pop(&render_target->clip_stack);
967 static void STDMETHODCALLTYPE d2d_d3d_render_target_Clear(ID2D1RenderTarget *iface, const D2D1_COLOR_F *color)
969 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
970 D3D10_SUBRESOURCE_DATA buffer_data;
971 D3D10_BUFFER_DESC buffer_desc;
972 ID3D10Buffer *vs_cb, *ps_cb;
973 HRESULT hr;
975 static const float transform[] =
977 1.0f, 0.0f, 0.0f, 0.0f,
978 0.0f, -1.0f, 0.0f, 0.0f,
981 TRACE("iface %p, color %p.\n", iface, color);
983 buffer_desc.ByteWidth = sizeof(transform);
984 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
985 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
986 buffer_desc.CPUAccessFlags = 0;
987 buffer_desc.MiscFlags = 0;
989 buffer_data.pSysMem = transform;
990 buffer_data.SysMemPitch = 0;
991 buffer_data.SysMemSlicePitch = 0;
993 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vs_cb)))
995 WARN("Failed to create constant buffer, hr %#x.\n", hr);
996 return;
999 buffer_desc.ByteWidth = sizeof(*color);
1000 buffer_data.pSysMem = color;
1002 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ps_cb)))
1004 WARN("Failed to create constant buffer, hr %#x.\n", hr);
1005 ID3D10Buffer_Release(vs_cb);
1006 return;
1009 d2d_draw(render_target, vs_cb, render_target->rect_solid_ps, ps_cb, NULL);
1011 ID3D10Buffer_Release(ps_cb);
1012 ID3D10Buffer_Release(vs_cb);
1015 static void STDMETHODCALLTYPE d2d_d3d_render_target_BeginDraw(ID2D1RenderTarget *iface)
1017 TRACE("iface %p.\n", iface);
1020 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_EndDraw(ID2D1RenderTarget *iface,
1021 D2D1_TAG *tag1, D2D1_TAG *tag2)
1023 TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2);
1025 if (tag1)
1026 *tag1 = 0;
1027 if (tag2)
1028 *tag2 = 0;
1030 return S_OK;
1033 static D2D1_PIXEL_FORMAT * STDMETHODCALLTYPE d2d_d3d_render_target_GetPixelFormat(ID2D1RenderTarget *iface,
1034 D2D1_PIXEL_FORMAT *format)
1036 FIXME("iface %p, format %p stub!\n", iface, format);
1038 format->format = DXGI_FORMAT_UNKNOWN;
1039 format->alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
1040 return format;
1043 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetDpi(ID2D1RenderTarget *iface, float dpi_x, float dpi_y)
1045 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1047 TRACE("iface %p, dpi_x %.8e, dpi_y %.8e.\n", iface, dpi_x, dpi_y);
1049 if (dpi_x == 0.0f && dpi_y == 0.0f)
1051 dpi_x = 96.0f;
1052 dpi_y = 96.0f;
1055 render_target->dpi_x = dpi_x;
1056 render_target->dpi_y = dpi_y;
1059 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetDpi(ID2D1RenderTarget *iface, float *dpi_x, float *dpi_y)
1061 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1063 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
1065 *dpi_x = render_target->dpi_x;
1066 *dpi_y = render_target->dpi_y;
1069 static D2D1_SIZE_F * STDMETHODCALLTYPE d2d_d3d_render_target_GetSize(ID2D1RenderTarget *iface, D2D1_SIZE_F *size)
1071 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1073 TRACE("iface %p, size %p.\n", iface, size);
1075 size->width = render_target->pixel_size.width / (render_target->dpi_x / 96.0f);
1076 size->height = render_target->pixel_size.height / (render_target->dpi_y / 96.0f);
1077 return size;
1080 static D2D1_SIZE_U * STDMETHODCALLTYPE d2d_d3d_render_target_GetPixelSize(ID2D1RenderTarget *iface,
1081 D2D1_SIZE_U *pixel_size)
1083 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1085 TRACE("iface %p, pixel_size %p.\n", iface, pixel_size);
1087 *pixel_size = render_target->pixel_size;
1088 return pixel_size;
1091 static UINT32 STDMETHODCALLTYPE d2d_d3d_render_target_GetMaximumBitmapSize(ID2D1RenderTarget *iface)
1093 FIXME("iface %p stub!\n", iface);
1095 return 0;
1098 static BOOL STDMETHODCALLTYPE d2d_d3d_render_target_IsSupported(ID2D1RenderTarget *iface,
1099 const D2D1_RENDER_TARGET_PROPERTIES *desc)
1101 FIXME("iface %p, desc %p stub!\n", iface, desc);
1103 return FALSE;
1106 static const struct ID2D1RenderTargetVtbl d2d_d3d_render_target_vtbl =
1108 d2d_d3d_render_target_QueryInterface,
1109 d2d_d3d_render_target_AddRef,
1110 d2d_d3d_render_target_Release,
1111 d2d_d3d_render_target_GetFactory,
1112 d2d_d3d_render_target_CreateBitmap,
1113 d2d_d3d_render_target_CreateBitmapFromWicBitmap,
1114 d2d_d3d_render_target_CreateSharedBitmap,
1115 d2d_d3d_render_target_CreateBitmapBrush,
1116 d2d_d3d_render_target_CreateSolidColorBrush,
1117 d2d_d3d_render_target_CreateGradientStopCollection,
1118 d2d_d3d_render_target_CreateLinearGradientBrush,
1119 d2d_d3d_render_target_CreateRadialGradientBrush,
1120 d2d_d3d_render_target_CreateCompatibleRenderTarget,
1121 d2d_d3d_render_target_CreateLayer,
1122 d2d_d3d_render_target_CreateMesh,
1123 d2d_d3d_render_target_DrawLine,
1124 d2d_d3d_render_target_DrawRectangle,
1125 d2d_d3d_render_target_FillRectangle,
1126 d2d_d3d_render_target_DrawRoundedRectangle,
1127 d2d_d3d_render_target_FillRoundedRectangle,
1128 d2d_d3d_render_target_DrawEllipse,
1129 d2d_d3d_render_target_FillEllipse,
1130 d2d_d3d_render_target_DrawGeometry,
1131 d2d_d3d_render_target_FillGeometry,
1132 d2d_d3d_render_target_FillMesh,
1133 d2d_d3d_render_target_FillOpacityMask,
1134 d2d_d3d_render_target_DrawBitmap,
1135 d2d_d3d_render_target_DrawText,
1136 d2d_d3d_render_target_DrawTextLayout,
1137 d2d_d3d_render_target_DrawGlyphRun,
1138 d2d_d3d_render_target_SetTransform,
1139 d2d_d3d_render_target_GetTransform,
1140 d2d_d3d_render_target_SetAntialiasMode,
1141 d2d_d3d_render_target_GetAntialiasMode,
1142 d2d_d3d_render_target_SetTextAntialiasMode,
1143 d2d_d3d_render_target_GetTextAntialiasMode,
1144 d2d_d3d_render_target_SetTextRenderingParams,
1145 d2d_d3d_render_target_GetTextRenderingParams,
1146 d2d_d3d_render_target_SetTags,
1147 d2d_d3d_render_target_GetTags,
1148 d2d_d3d_render_target_PushLayer,
1149 d2d_d3d_render_target_PopLayer,
1150 d2d_d3d_render_target_Flush,
1151 d2d_d3d_render_target_SaveDrawingState,
1152 d2d_d3d_render_target_RestoreDrawingState,
1153 d2d_d3d_render_target_PushAxisAlignedClip,
1154 d2d_d3d_render_target_PopAxisAlignedClip,
1155 d2d_d3d_render_target_Clear,
1156 d2d_d3d_render_target_BeginDraw,
1157 d2d_d3d_render_target_EndDraw,
1158 d2d_d3d_render_target_GetPixelFormat,
1159 d2d_d3d_render_target_SetDpi,
1160 d2d_d3d_render_target_GetDpi,
1161 d2d_d3d_render_target_GetSize,
1162 d2d_d3d_render_target_GetPixelSize,
1163 d2d_d3d_render_target_GetMaximumBitmapSize,
1164 d2d_d3d_render_target_IsSupported,
1167 static inline struct d2d_d3d_render_target *impl_from_IDWriteTextRenderer(IDWriteTextRenderer *iface)
1169 return CONTAINING_RECORD(iface, struct d2d_d3d_render_target, IDWriteTextRenderer_iface);
1172 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_QueryInterface(IDWriteTextRenderer *iface, REFIID iid, void **out)
1174 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1176 if (IsEqualGUID(iid, &IID_IDWriteTextRenderer)
1177 || IsEqualGUID(iid, &IID_IDWritePixelSnapping)
1178 || IsEqualGUID(iid, &IID_IUnknown))
1180 IDWriteTextRenderer_AddRef(iface);
1181 *out = iface;
1182 return S_OK;
1185 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1187 *out = NULL;
1188 return E_NOINTERFACE;
1191 static ULONG STDMETHODCALLTYPE d2d_text_renderer_AddRef(IDWriteTextRenderer *iface)
1193 struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface);
1195 TRACE("iface %p.\n", iface);
1197 return d2d_d3d_render_target_AddRef(&render_target->ID2D1RenderTarget_iface);
1200 static ULONG STDMETHODCALLTYPE d2d_text_renderer_Release(IDWriteTextRenderer *iface)
1202 struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface);
1204 TRACE("iface %p.\n", iface);
1206 return d2d_d3d_render_target_Release(&render_target->ID2D1RenderTarget_iface);
1209 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
1210 void *ctx, BOOL *disabled)
1212 FIXME("iface %p, ctx %p, disabled %p stub!\n", iface, ctx, disabled);
1214 return E_NOTIMPL;
1217 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetCurrentTransform(IDWriteTextRenderer *iface,
1218 void *ctx, DWRITE_MATRIX *transform)
1220 FIXME("iface %p, ctx %p, transform %p stub!\n", iface, ctx, transform);
1222 return E_NOTIMPL;
1225 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetPixelsPerDip(IDWriteTextRenderer *iface, void *ctx, float *ppd)
1227 FIXME("iface %p, ctx %p, ppd %p stub!\n", iface, ctx, ppd);
1229 return E_NOTIMPL;
1232 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawGlyphRun(IDWriteTextRenderer *iface, void *ctx,
1233 float baseline_origin_x, float baseline_origin_y, DWRITE_MEASURING_MODE measuring_mode,
1234 const DWRITE_GLYPH_RUN *glyph_run, const DWRITE_GLYPH_RUN_DESCRIPTION *desc, IUnknown *effect)
1236 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, "
1237 "measuring_mode %#x, glyph_run %p, desc %p, effect %p stub!\n",
1238 iface, ctx, baseline_origin_x, baseline_origin_y,
1239 measuring_mode, glyph_run, desc, effect);
1241 return E_NOTIMPL;
1244 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawUnderline(IDWriteTextRenderer *iface, void *ctx,
1245 float baseline_origin_x, float baseline_origin_y, const DWRITE_UNDERLINE *underline, IUnknown *effect)
1247 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, underline %p, effect %p stub!\n",
1248 iface, ctx, baseline_origin_x, baseline_origin_y, underline, effect);
1250 return E_NOTIMPL;
1253 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawStrikethrough(IDWriteTextRenderer *iface, void *ctx,
1254 float baseline_origin_x, float baseline_origin_y, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *effect)
1256 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, strikethrough %p, effect %p stub!\n",
1257 iface, ctx, baseline_origin_x, baseline_origin_y, strikethrough, effect);
1259 return E_NOTIMPL;
1262 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawInlineObject(IDWriteTextRenderer *iface, void *ctx,
1263 float origin_x, float origin_y, IDWriteInlineObject *object, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
1265 FIXME("iface %p, ctx %p, origin_x %.8e, origin_y %.8e, object %p, is_sideways %#x, is_rtl %#x, effect %p stub!\n",
1266 iface, ctx, origin_x, origin_y, object, is_sideways, is_rtl, effect);
1268 return E_NOTIMPL;
1271 static const struct IDWriteTextRendererVtbl d2d_text_renderer_vtbl =
1273 d2d_text_renderer_QueryInterface,
1274 d2d_text_renderer_AddRef,
1275 d2d_text_renderer_Release,
1276 d2d_text_renderer_IsPixelSnappingDisabled,
1277 d2d_text_renderer_GetCurrentTransform,
1278 d2d_text_renderer_GetPixelsPerDip,
1279 d2d_text_renderer_DrawGlyphRun,
1280 d2d_text_renderer_DrawUnderline,
1281 d2d_text_renderer_DrawStrikethrough,
1282 d2d_text_renderer_DrawInlineObject,
1285 HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target, ID2D1Factory *factory,
1286 IDXGISurface *surface, const D2D1_RENDER_TARGET_PROPERTIES *desc)
1288 D3D10_SUBRESOURCE_DATA buffer_data;
1289 D3D10_STATE_BLOCK_MASK state_mask;
1290 DXGI_SURFACE_DESC surface_desc;
1291 D3D10_RASTERIZER_DESC rs_desc;
1292 D3D10_BUFFER_DESC buffer_desc;
1293 D3D10_BLEND_DESC blend_desc;
1294 ID3D10Resource *resource;
1295 HRESULT hr;
1297 static const D3D10_INPUT_ELEMENT_DESC il_desc[] =
1299 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
1301 static const DWORD vs_code[] =
1303 /* float3x2 transform;
1305 * float4 main(float4 position : POSITION) : SV_POSITION
1307 * return float4(mul(position.xyw, transform), position.zw);
1308 * } */
1309 0x43425844, 0x0add3194, 0x205f74ec, 0xab527fe7, 0xbe6ad704, 0x00000001, 0x00000128, 0x00000003,
1310 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1311 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
1312 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
1313 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000008c, 0x00010040,
1314 0x00000023, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005f, 0x001010f2, 0x00000000,
1315 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x08000010, 0x00102012, 0x00000000, 0x00101346,
1316 0x00000000, 0x00208246, 0x00000000, 0x00000000, 0x08000010, 0x00102022, 0x00000000, 0x00101346,
1317 0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x05000036, 0x001020c2, 0x00000000, 0x00101ea6,
1318 0x00000000, 0x0100003e,
1320 static const DWORD rect_solid_ps_code[] =
1322 /* float4 color;
1324 * float4 main(float4 position : SV_POSITION) : SV_Target
1326 * return color;
1327 * } */
1328 0x43425844, 0x88eefcfd, 0x93d6fd47, 0x173c242f, 0x0106d07a, 0x00000001, 0x000000dc, 0x00000003,
1329 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1330 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49,
1331 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
1332 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x00000040, 0x00000040,
1333 0x00000010, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x03000065, 0x001020f2, 0x00000000,
1334 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x0100003e,
1336 static const DWORD rect_bitmap_ps_code[] =
1338 #if 0
1339 float3x2 transform;
1340 SamplerState s;
1341 Texture2D t;
1343 float4 main(float4 position : SV_POSITION) : SV_Target
1345 return t.Sample(s, mul(float3(position.xy, 1.0), transform));
1347 #endif
1348 0x43425844, 0x20fce5be, 0x138fa37f, 0x9554f03f, 0x3dbe9c02, 0x00000001, 0x00000184, 0x00000003,
1349 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1350 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
1351 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
1352 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x000000e8, 0x00000040,
1353 0x0000003a, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005a, 0x00106000, 0x00000000,
1354 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
1355 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x05000036, 0x00100032, 0x00000000,
1356 0x00101046, 0x00000000, 0x05000036, 0x00100042, 0x00000000, 0x00004001, 0x3f800000, 0x08000010,
1357 0x00100012, 0x00000001, 0x00100246, 0x00000000, 0x00208246, 0x00000000, 0x00000000, 0x08000010,
1358 0x00100022, 0x00000001, 0x00100246, 0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x09000045,
1359 0x001020f2, 0x00000000, 0x00100046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, 0x00000000,
1360 0x0100003e,
1362 static const struct
1364 float x, y;
1366 quad[] =
1368 {-1.0f, 1.0f},
1369 {-1.0f, -1.0f},
1370 { 1.0f, 1.0f},
1371 { 1.0f, -1.0f},
1373 static const D2D1_MATRIX_3X2_F identity =
1375 1.0f, 0.0f,
1376 0.0f, 1.0f,
1377 0.0f, 0.0f,
1380 FIXME("Ignoring render target properties.\n");
1382 render_target->ID2D1RenderTarget_iface.lpVtbl = &d2d_d3d_render_target_vtbl;
1383 render_target->IDWriteTextRenderer_iface.lpVtbl = &d2d_text_renderer_vtbl;
1384 render_target->refcount = 1;
1385 render_target->factory = factory;
1386 ID2D1Factory_AddRef(render_target->factory);
1388 if (FAILED(hr = IDXGISurface_GetDevice(surface, &IID_ID3D10Device, (void **)&render_target->device)))
1390 WARN("Failed to get device interface, hr %#x.\n", hr);
1391 ID2D1Factory_Release(render_target->factory);
1392 return hr;
1395 if (FAILED(hr = IDXGISurface_QueryInterface(surface, &IID_ID3D10Resource, (void **)&resource)))
1397 WARN("Failed to get ID3D10Resource interface, hr %#x.\n", hr);
1398 goto err;
1401 hr = ID3D10Device_CreateRenderTargetView(render_target->device, resource, NULL, &render_target->view);
1402 ID3D10Resource_Release(resource);
1403 if (FAILED(hr))
1405 WARN("Failed to create rendertarget view, hr %#x.\n", hr);
1406 goto err;
1409 if (FAILED(hr = D3D10StateBlockMaskEnableAll(&state_mask)))
1411 WARN("Failed to create stateblock mask, hr %#x.\n", hr);
1412 goto err;
1415 if (FAILED(hr = D3D10CreateStateBlock(render_target->device, &state_mask, &render_target->stateblock)))
1417 WARN("Failed to create stateblock, hr %#x.\n", hr);
1418 goto err;
1421 if (FAILED(hr = ID3D10Device_CreateInputLayout(render_target->device, il_desc,
1422 sizeof(il_desc) / sizeof(*il_desc), vs_code, sizeof(vs_code),
1423 &render_target->il)))
1425 WARN("Failed to create clear input layout, hr %#x.\n", hr);
1426 goto err;
1429 buffer_desc.ByteWidth = sizeof(quad);
1430 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
1431 buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
1432 buffer_desc.CPUAccessFlags = 0;
1433 buffer_desc.MiscFlags = 0;
1435 buffer_data.pSysMem = quad;
1436 buffer_data.SysMemPitch = 0;
1437 buffer_data.SysMemSlicePitch = 0;
1439 render_target->vb_stride = sizeof(*quad);
1440 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device,
1441 &buffer_desc, &buffer_data, &render_target->vb)))
1443 WARN("Failed to create clear vertex buffer, hr %#x.\n", hr);
1444 goto err;
1447 if (FAILED(hr = ID3D10Device_CreateVertexShader(render_target->device,
1448 vs_code, sizeof(vs_code), &render_target->vs)))
1450 WARN("Failed to create clear vertex shader, hr %#x.\n", hr);
1451 goto err;
1454 rs_desc.FillMode = D3D10_FILL_SOLID;
1455 rs_desc.CullMode = D3D10_CULL_BACK;
1456 rs_desc.FrontCounterClockwise = FALSE;
1457 rs_desc.DepthBias = 0;
1458 rs_desc.DepthBiasClamp = 0.0f;
1459 rs_desc.SlopeScaledDepthBias = 0.0f;
1460 rs_desc.DepthClipEnable = TRUE;
1461 rs_desc.ScissorEnable = TRUE;
1462 rs_desc.MultisampleEnable = FALSE;
1463 rs_desc.AntialiasedLineEnable = FALSE;
1464 if (FAILED(hr = ID3D10Device_CreateRasterizerState(render_target->device, &rs_desc, &render_target->rs)))
1466 WARN("Failed to create clear rasterizer state, hr %#x.\n", hr);
1467 goto err;
1470 memset(&blend_desc, 0, sizeof(blend_desc));
1471 blend_desc.BlendEnable[0] = TRUE;
1472 blend_desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
1473 blend_desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
1474 blend_desc.BlendOp = D3D10_BLEND_OP_ADD;
1475 blend_desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
1476 blend_desc.DestBlendAlpha = D3D10_BLEND_ONE;
1477 blend_desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
1478 blend_desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
1479 if (FAILED(hr = ID3D10Device_CreateBlendState(render_target->device, &blend_desc, &render_target->bs)))
1481 WARN("Failed to create blend state, hr %#x.\n", hr);
1482 goto err;
1485 if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
1486 rect_solid_ps_code, sizeof(rect_solid_ps_code), &render_target->rect_solid_ps)))
1488 WARN("Failed to create pixel shader, hr %#x.\n", hr);
1489 goto err;
1492 if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
1493 rect_bitmap_ps_code, sizeof(rect_bitmap_ps_code), &render_target->rect_bitmap_ps)))
1495 WARN("Failed to create pixel shader, hr %#x.\n", hr);
1496 goto err;
1499 if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc)))
1501 WARN("Failed to get surface desc, hr %#x.\n", hr);
1502 goto err;
1505 render_target->pixel_size.width = surface_desc.Width;
1506 render_target->pixel_size.height = surface_desc.Height;
1507 render_target->transform = identity;
1509 if (!d2d_clip_stack_init(&render_target->clip_stack))
1511 WARN("Failed to initialize clip stack.\n");
1512 hr = E_FAIL;
1513 goto err;
1516 render_target->dpi_x = desc->dpiX;
1517 render_target->dpi_y = desc->dpiY;
1519 if (render_target->dpi_x == 0.0f && render_target->dpi_y == 0.0f)
1521 render_target->dpi_x = 96.0f;
1522 render_target->dpi_y = 96.0f;
1525 return S_OK;
1527 err:
1528 if (render_target->rect_bitmap_ps)
1529 ID3D10PixelShader_Release(render_target->rect_bitmap_ps);
1530 if (render_target->rect_solid_ps)
1531 ID3D10PixelShader_Release(render_target->rect_solid_ps);
1532 if (render_target->bs)
1533 ID3D10BlendState_Release(render_target->bs);
1534 if (render_target->rs)
1535 ID3D10RasterizerState_Release(render_target->rs);
1536 if (render_target->vs)
1537 ID3D10VertexShader_Release(render_target->vs);
1538 if (render_target->vb)
1539 ID3D10Buffer_Release(render_target->vb);
1540 if (render_target->il)
1541 ID3D10InputLayout_Release(render_target->il);
1542 if (render_target->stateblock)
1543 render_target->stateblock->lpVtbl->Release(render_target->stateblock);
1544 if (render_target->view)
1545 ID3D10RenderTargetView_Release(render_target->view);
1546 if (render_target->device)
1547 ID3D10Device_Release(render_target->device);
1548 ID2D1Factory_Release(render_target->factory);
1549 return hr;