d2d1: Implement d2d_d3d_render_target_SetTextAntialiasMode().
[wine/multimedia.git] / dlls / d2d1 / render_target.c
blob4b7896783f714f51c56dc901ea9fd06282cc983e
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 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
846 TRACE("iface %p.\n", iface);
848 return render_target->antialias_mode;
851 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTextAntialiasMode(ID2D1RenderTarget *iface,
852 D2D1_TEXT_ANTIALIAS_MODE antialias_mode)
854 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
856 TRACE("iface %p, antialias_mode %#x.\n", iface, antialias_mode);
858 render_target->text_antialias_mode = antialias_mode;
861 static D2D1_TEXT_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_d3d_render_target_GetTextAntialiasMode(ID2D1RenderTarget *iface)
863 FIXME("iface %p stub!\n", iface);
865 return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
868 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTextRenderingParams(ID2D1RenderTarget *iface,
869 IDWriteRenderingParams *text_rendering_params)
871 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
873 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
875 if (text_rendering_params)
876 IDWriteRenderingParams_AddRef(text_rendering_params);
877 if (render_target->text_rendering_params)
878 IDWriteRenderingParams_Release(render_target->text_rendering_params);
879 render_target->text_rendering_params = text_rendering_params;
882 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTextRenderingParams(ID2D1RenderTarget *iface,
883 IDWriteRenderingParams **text_rendering_params)
885 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
887 TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params);
889 if ((*text_rendering_params = render_target->text_rendering_params))
890 IDWriteRenderingParams_AddRef(*text_rendering_params);
893 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTags(ID2D1RenderTarget *iface, D2D1_TAG tag1, D2D1_TAG tag2)
895 FIXME("iface %p, tag1 %s, tag2 %s stub!\n", iface, wine_dbgstr_longlong(tag1), wine_dbgstr_longlong(tag2));
898 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTags(ID2D1RenderTarget *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
900 FIXME("iface %p, tag1 %p, tag2 %p stub!\n", iface, tag1, tag2);
902 *tag1 = 0;
903 *tag2 = 0;
906 static void STDMETHODCALLTYPE d2d_d3d_render_target_PushLayer(ID2D1RenderTarget *iface,
907 const D2D1_LAYER_PARAMETERS *layer_parameters, ID2D1Layer *layer)
909 FIXME("iface %p, layer_parameters %p, layer %p stub!\n", iface, layer_parameters, layer);
912 static void STDMETHODCALLTYPE d2d_d3d_render_target_PopLayer(ID2D1RenderTarget *iface)
914 FIXME("iface %p stub!\n", iface);
917 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_Flush(ID2D1RenderTarget *iface, D2D1_TAG *tag1, D2D1_TAG *tag2)
919 FIXME("iface %p, tag1 %p, tag2 %p stub!\n", iface, tag1, tag2);
921 return E_NOTIMPL;
924 static void STDMETHODCALLTYPE d2d_d3d_render_target_SaveDrawingState(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_RestoreDrawingState(ID2D1RenderTarget *iface,
931 ID2D1DrawingStateBlock *state_block)
933 FIXME("iface %p, state_block %p stub!\n", iface, state_block);
936 static void STDMETHODCALLTYPE d2d_d3d_render_target_PushAxisAlignedClip(ID2D1RenderTarget *iface,
937 const D2D1_RECT_F *clip_rect, D2D1_ANTIALIAS_MODE antialias_mode)
939 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
940 D2D1_RECT_F transformed_rect;
941 float x_scale, y_scale;
942 D2D1_POINT_2F point;
944 TRACE("iface %p, clip_rect %p, antialias_mode %#x.\n", iface, clip_rect, antialias_mode);
946 if (antialias_mode != D2D1_ANTIALIAS_MODE_ALIASED)
947 FIXME("Ignoring antialias_mode %#x.\n", antialias_mode);
949 x_scale = render_target->dpi_x / 96.0f;
950 y_scale = render_target->dpi_y / 96.0f;
951 d2d_point_transform(&point, &render_target->transform, clip_rect->left * x_scale, clip_rect->top * y_scale);
952 d2d_rect_set(&transformed_rect, point.x, point.y, point.x, point.y);
953 d2d_point_transform(&point, &render_target->transform, clip_rect->left * x_scale, clip_rect->bottom * y_scale);
954 d2d_rect_expand(&transformed_rect, &point);
955 d2d_point_transform(&point, &render_target->transform, clip_rect->right * x_scale, clip_rect->top * y_scale);
956 d2d_rect_expand(&transformed_rect, &point);
957 d2d_point_transform(&point, &render_target->transform, clip_rect->right * x_scale, clip_rect->bottom * y_scale);
958 d2d_rect_expand(&transformed_rect, &point);
960 if (!d2d_clip_stack_push(&render_target->clip_stack, &transformed_rect))
961 WARN("Failed to push clip rect.\n");
964 static void STDMETHODCALLTYPE d2d_d3d_render_target_PopAxisAlignedClip(ID2D1RenderTarget *iface)
966 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
968 TRACE("iface %p.\n", iface);
970 d2d_clip_stack_pop(&render_target->clip_stack);
973 static void STDMETHODCALLTYPE d2d_d3d_render_target_Clear(ID2D1RenderTarget *iface, const D2D1_COLOR_F *color)
975 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
976 D3D10_SUBRESOURCE_DATA buffer_data;
977 D3D10_BUFFER_DESC buffer_desc;
978 ID3D10Buffer *vs_cb, *ps_cb;
979 HRESULT hr;
981 static const float transform[] =
983 1.0f, 0.0f, 0.0f, 0.0f,
984 0.0f, -1.0f, 0.0f, 0.0f,
987 TRACE("iface %p, color %p.\n", iface, color);
989 buffer_desc.ByteWidth = sizeof(transform);
990 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
991 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
992 buffer_desc.CPUAccessFlags = 0;
993 buffer_desc.MiscFlags = 0;
995 buffer_data.pSysMem = transform;
996 buffer_data.SysMemPitch = 0;
997 buffer_data.SysMemSlicePitch = 0;
999 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vs_cb)))
1001 WARN("Failed to create constant buffer, hr %#x.\n", hr);
1002 return;
1005 buffer_desc.ByteWidth = sizeof(*color);
1006 buffer_data.pSysMem = color;
1008 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ps_cb)))
1010 WARN("Failed to create constant buffer, hr %#x.\n", hr);
1011 ID3D10Buffer_Release(vs_cb);
1012 return;
1015 d2d_draw(render_target, vs_cb, render_target->rect_solid_ps, ps_cb, NULL);
1017 ID3D10Buffer_Release(ps_cb);
1018 ID3D10Buffer_Release(vs_cb);
1021 static void STDMETHODCALLTYPE d2d_d3d_render_target_BeginDraw(ID2D1RenderTarget *iface)
1023 TRACE("iface %p.\n", iface);
1026 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_EndDraw(ID2D1RenderTarget *iface,
1027 D2D1_TAG *tag1, D2D1_TAG *tag2)
1029 TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2);
1031 if (tag1)
1032 *tag1 = 0;
1033 if (tag2)
1034 *tag2 = 0;
1036 return S_OK;
1039 static D2D1_PIXEL_FORMAT * STDMETHODCALLTYPE d2d_d3d_render_target_GetPixelFormat(ID2D1RenderTarget *iface,
1040 D2D1_PIXEL_FORMAT *format)
1042 FIXME("iface %p, format %p stub!\n", iface, format);
1044 format->format = DXGI_FORMAT_UNKNOWN;
1045 format->alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
1046 return format;
1049 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetDpi(ID2D1RenderTarget *iface, float dpi_x, float dpi_y)
1051 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1053 TRACE("iface %p, dpi_x %.8e, dpi_y %.8e.\n", iface, dpi_x, dpi_y);
1055 if (dpi_x == 0.0f && dpi_y == 0.0f)
1057 dpi_x = 96.0f;
1058 dpi_y = 96.0f;
1061 render_target->dpi_x = dpi_x;
1062 render_target->dpi_y = dpi_y;
1065 static void STDMETHODCALLTYPE d2d_d3d_render_target_GetDpi(ID2D1RenderTarget *iface, float *dpi_x, float *dpi_y)
1067 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1069 TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
1071 *dpi_x = render_target->dpi_x;
1072 *dpi_y = render_target->dpi_y;
1075 static D2D1_SIZE_F * STDMETHODCALLTYPE d2d_d3d_render_target_GetSize(ID2D1RenderTarget *iface, D2D1_SIZE_F *size)
1077 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1079 TRACE("iface %p, size %p.\n", iface, size);
1081 size->width = render_target->pixel_size.width / (render_target->dpi_x / 96.0f);
1082 size->height = render_target->pixel_size.height / (render_target->dpi_y / 96.0f);
1083 return size;
1086 static D2D1_SIZE_U * STDMETHODCALLTYPE d2d_d3d_render_target_GetPixelSize(ID2D1RenderTarget *iface,
1087 D2D1_SIZE_U *pixel_size)
1089 struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
1091 TRACE("iface %p, pixel_size %p.\n", iface, pixel_size);
1093 *pixel_size = render_target->pixel_size;
1094 return pixel_size;
1097 static UINT32 STDMETHODCALLTYPE d2d_d3d_render_target_GetMaximumBitmapSize(ID2D1RenderTarget *iface)
1099 FIXME("iface %p stub!\n", iface);
1101 return 0;
1104 static BOOL STDMETHODCALLTYPE d2d_d3d_render_target_IsSupported(ID2D1RenderTarget *iface,
1105 const D2D1_RENDER_TARGET_PROPERTIES *desc)
1107 FIXME("iface %p, desc %p stub!\n", iface, desc);
1109 return FALSE;
1112 static const struct ID2D1RenderTargetVtbl d2d_d3d_render_target_vtbl =
1114 d2d_d3d_render_target_QueryInterface,
1115 d2d_d3d_render_target_AddRef,
1116 d2d_d3d_render_target_Release,
1117 d2d_d3d_render_target_GetFactory,
1118 d2d_d3d_render_target_CreateBitmap,
1119 d2d_d3d_render_target_CreateBitmapFromWicBitmap,
1120 d2d_d3d_render_target_CreateSharedBitmap,
1121 d2d_d3d_render_target_CreateBitmapBrush,
1122 d2d_d3d_render_target_CreateSolidColorBrush,
1123 d2d_d3d_render_target_CreateGradientStopCollection,
1124 d2d_d3d_render_target_CreateLinearGradientBrush,
1125 d2d_d3d_render_target_CreateRadialGradientBrush,
1126 d2d_d3d_render_target_CreateCompatibleRenderTarget,
1127 d2d_d3d_render_target_CreateLayer,
1128 d2d_d3d_render_target_CreateMesh,
1129 d2d_d3d_render_target_DrawLine,
1130 d2d_d3d_render_target_DrawRectangle,
1131 d2d_d3d_render_target_FillRectangle,
1132 d2d_d3d_render_target_DrawRoundedRectangle,
1133 d2d_d3d_render_target_FillRoundedRectangle,
1134 d2d_d3d_render_target_DrawEllipse,
1135 d2d_d3d_render_target_FillEllipse,
1136 d2d_d3d_render_target_DrawGeometry,
1137 d2d_d3d_render_target_FillGeometry,
1138 d2d_d3d_render_target_FillMesh,
1139 d2d_d3d_render_target_FillOpacityMask,
1140 d2d_d3d_render_target_DrawBitmap,
1141 d2d_d3d_render_target_DrawText,
1142 d2d_d3d_render_target_DrawTextLayout,
1143 d2d_d3d_render_target_DrawGlyphRun,
1144 d2d_d3d_render_target_SetTransform,
1145 d2d_d3d_render_target_GetTransform,
1146 d2d_d3d_render_target_SetAntialiasMode,
1147 d2d_d3d_render_target_GetAntialiasMode,
1148 d2d_d3d_render_target_SetTextAntialiasMode,
1149 d2d_d3d_render_target_GetTextAntialiasMode,
1150 d2d_d3d_render_target_SetTextRenderingParams,
1151 d2d_d3d_render_target_GetTextRenderingParams,
1152 d2d_d3d_render_target_SetTags,
1153 d2d_d3d_render_target_GetTags,
1154 d2d_d3d_render_target_PushLayer,
1155 d2d_d3d_render_target_PopLayer,
1156 d2d_d3d_render_target_Flush,
1157 d2d_d3d_render_target_SaveDrawingState,
1158 d2d_d3d_render_target_RestoreDrawingState,
1159 d2d_d3d_render_target_PushAxisAlignedClip,
1160 d2d_d3d_render_target_PopAxisAlignedClip,
1161 d2d_d3d_render_target_Clear,
1162 d2d_d3d_render_target_BeginDraw,
1163 d2d_d3d_render_target_EndDraw,
1164 d2d_d3d_render_target_GetPixelFormat,
1165 d2d_d3d_render_target_SetDpi,
1166 d2d_d3d_render_target_GetDpi,
1167 d2d_d3d_render_target_GetSize,
1168 d2d_d3d_render_target_GetPixelSize,
1169 d2d_d3d_render_target_GetMaximumBitmapSize,
1170 d2d_d3d_render_target_IsSupported,
1173 static inline struct d2d_d3d_render_target *impl_from_IDWriteTextRenderer(IDWriteTextRenderer *iface)
1175 return CONTAINING_RECORD(iface, struct d2d_d3d_render_target, IDWriteTextRenderer_iface);
1178 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_QueryInterface(IDWriteTextRenderer *iface, REFIID iid, void **out)
1180 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1182 if (IsEqualGUID(iid, &IID_IDWriteTextRenderer)
1183 || IsEqualGUID(iid, &IID_IDWritePixelSnapping)
1184 || IsEqualGUID(iid, &IID_IUnknown))
1186 IDWriteTextRenderer_AddRef(iface);
1187 *out = iface;
1188 return S_OK;
1191 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1193 *out = NULL;
1194 return E_NOINTERFACE;
1197 static ULONG STDMETHODCALLTYPE d2d_text_renderer_AddRef(IDWriteTextRenderer *iface)
1199 struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface);
1201 TRACE("iface %p.\n", iface);
1203 return d2d_d3d_render_target_AddRef(&render_target->ID2D1RenderTarget_iface);
1206 static ULONG STDMETHODCALLTYPE d2d_text_renderer_Release(IDWriteTextRenderer *iface)
1208 struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface);
1210 TRACE("iface %p.\n", iface);
1212 return d2d_d3d_render_target_Release(&render_target->ID2D1RenderTarget_iface);
1215 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
1216 void *ctx, BOOL *disabled)
1218 FIXME("iface %p, ctx %p, disabled %p stub!\n", iface, ctx, disabled);
1220 return E_NOTIMPL;
1223 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetCurrentTransform(IDWriteTextRenderer *iface,
1224 void *ctx, DWRITE_MATRIX *transform)
1226 FIXME("iface %p, ctx %p, transform %p stub!\n", iface, ctx, transform);
1228 return E_NOTIMPL;
1231 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetPixelsPerDip(IDWriteTextRenderer *iface, void *ctx, float *ppd)
1233 FIXME("iface %p, ctx %p, ppd %p stub!\n", iface, ctx, ppd);
1235 return E_NOTIMPL;
1238 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawGlyphRun(IDWriteTextRenderer *iface, void *ctx,
1239 float baseline_origin_x, float baseline_origin_y, DWRITE_MEASURING_MODE measuring_mode,
1240 const DWRITE_GLYPH_RUN *glyph_run, const DWRITE_GLYPH_RUN_DESCRIPTION *desc, IUnknown *effect)
1242 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, "
1243 "measuring_mode %#x, glyph_run %p, desc %p, effect %p stub!\n",
1244 iface, ctx, baseline_origin_x, baseline_origin_y,
1245 measuring_mode, glyph_run, desc, effect);
1247 return E_NOTIMPL;
1250 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawUnderline(IDWriteTextRenderer *iface, void *ctx,
1251 float baseline_origin_x, float baseline_origin_y, const DWRITE_UNDERLINE *underline, IUnknown *effect)
1253 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, underline %p, effect %p stub!\n",
1254 iface, ctx, baseline_origin_x, baseline_origin_y, underline, effect);
1256 return E_NOTIMPL;
1259 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawStrikethrough(IDWriteTextRenderer *iface, void *ctx,
1260 float baseline_origin_x, float baseline_origin_y, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *effect)
1262 FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, strikethrough %p, effect %p stub!\n",
1263 iface, ctx, baseline_origin_x, baseline_origin_y, strikethrough, effect);
1265 return E_NOTIMPL;
1268 static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawInlineObject(IDWriteTextRenderer *iface, void *ctx,
1269 float origin_x, float origin_y, IDWriteInlineObject *object, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
1271 FIXME("iface %p, ctx %p, origin_x %.8e, origin_y %.8e, object %p, is_sideways %#x, is_rtl %#x, effect %p stub!\n",
1272 iface, ctx, origin_x, origin_y, object, is_sideways, is_rtl, effect);
1274 return E_NOTIMPL;
1277 static const struct IDWriteTextRendererVtbl d2d_text_renderer_vtbl =
1279 d2d_text_renderer_QueryInterface,
1280 d2d_text_renderer_AddRef,
1281 d2d_text_renderer_Release,
1282 d2d_text_renderer_IsPixelSnappingDisabled,
1283 d2d_text_renderer_GetCurrentTransform,
1284 d2d_text_renderer_GetPixelsPerDip,
1285 d2d_text_renderer_DrawGlyphRun,
1286 d2d_text_renderer_DrawUnderline,
1287 d2d_text_renderer_DrawStrikethrough,
1288 d2d_text_renderer_DrawInlineObject,
1291 HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target, ID2D1Factory *factory,
1292 IDXGISurface *surface, const D2D1_RENDER_TARGET_PROPERTIES *desc)
1294 D3D10_SUBRESOURCE_DATA buffer_data;
1295 D3D10_STATE_BLOCK_MASK state_mask;
1296 DXGI_SURFACE_DESC surface_desc;
1297 D3D10_RASTERIZER_DESC rs_desc;
1298 D3D10_BUFFER_DESC buffer_desc;
1299 D3D10_BLEND_DESC blend_desc;
1300 ID3D10Resource *resource;
1301 HRESULT hr;
1303 static const D3D10_INPUT_ELEMENT_DESC il_desc[] =
1305 {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
1307 static const DWORD vs_code[] =
1309 /* float3x2 transform;
1311 * float4 main(float4 position : POSITION) : SV_POSITION
1313 * return float4(mul(position.xyw, transform), position.zw);
1314 * } */
1315 0x43425844, 0x0add3194, 0x205f74ec, 0xab527fe7, 0xbe6ad704, 0x00000001, 0x00000128, 0x00000003,
1316 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1317 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
1318 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
1319 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000008c, 0x00010040,
1320 0x00000023, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005f, 0x001010f2, 0x00000000,
1321 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x08000010, 0x00102012, 0x00000000, 0x00101346,
1322 0x00000000, 0x00208246, 0x00000000, 0x00000000, 0x08000010, 0x00102022, 0x00000000, 0x00101346,
1323 0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x05000036, 0x001020c2, 0x00000000, 0x00101ea6,
1324 0x00000000, 0x0100003e,
1326 static const DWORD rect_solid_ps_code[] =
1328 /* float4 color;
1330 * float4 main(float4 position : SV_POSITION) : SV_Target
1332 * return color;
1333 * } */
1334 0x43425844, 0x88eefcfd, 0x93d6fd47, 0x173c242f, 0x0106d07a, 0x00000001, 0x000000dc, 0x00000003,
1335 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1336 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49,
1337 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
1338 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x00000040, 0x00000040,
1339 0x00000010, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x03000065, 0x001020f2, 0x00000000,
1340 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x0100003e,
1342 static const DWORD rect_bitmap_ps_code[] =
1344 #if 0
1345 float3x2 transform;
1346 SamplerState s;
1347 Texture2D t;
1349 float4 main(float4 position : SV_POSITION) : SV_Target
1351 return t.Sample(s, mul(float3(position.xy, 1.0), transform));
1353 #endif
1354 0x43425844, 0x20fce5be, 0x138fa37f, 0x9554f03f, 0x3dbe9c02, 0x00000001, 0x00000184, 0x00000003,
1355 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
1356 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
1357 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
1358 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x000000e8, 0x00000040,
1359 0x0000003a, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005a, 0x00106000, 0x00000000,
1360 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
1361 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x05000036, 0x00100032, 0x00000000,
1362 0x00101046, 0x00000000, 0x05000036, 0x00100042, 0x00000000, 0x00004001, 0x3f800000, 0x08000010,
1363 0x00100012, 0x00000001, 0x00100246, 0x00000000, 0x00208246, 0x00000000, 0x00000000, 0x08000010,
1364 0x00100022, 0x00000001, 0x00100246, 0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x09000045,
1365 0x001020f2, 0x00000000, 0x00100046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, 0x00000000,
1366 0x0100003e,
1368 static const struct
1370 float x, y;
1372 quad[] =
1374 {-1.0f, 1.0f},
1375 {-1.0f, -1.0f},
1376 { 1.0f, 1.0f},
1377 { 1.0f, -1.0f},
1379 static const D2D1_MATRIX_3X2_F identity =
1381 1.0f, 0.0f,
1382 0.0f, 1.0f,
1383 0.0f, 0.0f,
1386 FIXME("Ignoring render target properties.\n");
1388 render_target->ID2D1RenderTarget_iface.lpVtbl = &d2d_d3d_render_target_vtbl;
1389 render_target->IDWriteTextRenderer_iface.lpVtbl = &d2d_text_renderer_vtbl;
1390 render_target->refcount = 1;
1391 render_target->factory = factory;
1392 ID2D1Factory_AddRef(render_target->factory);
1394 if (FAILED(hr = IDXGISurface_GetDevice(surface, &IID_ID3D10Device, (void **)&render_target->device)))
1396 WARN("Failed to get device interface, hr %#x.\n", hr);
1397 ID2D1Factory_Release(render_target->factory);
1398 return hr;
1401 if (FAILED(hr = IDXGISurface_QueryInterface(surface, &IID_ID3D10Resource, (void **)&resource)))
1403 WARN("Failed to get ID3D10Resource interface, hr %#x.\n", hr);
1404 goto err;
1407 hr = ID3D10Device_CreateRenderTargetView(render_target->device, resource, NULL, &render_target->view);
1408 ID3D10Resource_Release(resource);
1409 if (FAILED(hr))
1411 WARN("Failed to create rendertarget view, hr %#x.\n", hr);
1412 goto err;
1415 if (FAILED(hr = D3D10StateBlockMaskEnableAll(&state_mask)))
1417 WARN("Failed to create stateblock mask, hr %#x.\n", hr);
1418 goto err;
1421 if (FAILED(hr = D3D10CreateStateBlock(render_target->device, &state_mask, &render_target->stateblock)))
1423 WARN("Failed to create stateblock, hr %#x.\n", hr);
1424 goto err;
1427 if (FAILED(hr = ID3D10Device_CreateInputLayout(render_target->device, il_desc,
1428 sizeof(il_desc) / sizeof(*il_desc), vs_code, sizeof(vs_code),
1429 &render_target->il)))
1431 WARN("Failed to create clear input layout, hr %#x.\n", hr);
1432 goto err;
1435 buffer_desc.ByteWidth = sizeof(quad);
1436 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
1437 buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
1438 buffer_desc.CPUAccessFlags = 0;
1439 buffer_desc.MiscFlags = 0;
1441 buffer_data.pSysMem = quad;
1442 buffer_data.SysMemPitch = 0;
1443 buffer_data.SysMemSlicePitch = 0;
1445 render_target->vb_stride = sizeof(*quad);
1446 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device,
1447 &buffer_desc, &buffer_data, &render_target->vb)))
1449 WARN("Failed to create clear vertex buffer, hr %#x.\n", hr);
1450 goto err;
1453 if (FAILED(hr = ID3D10Device_CreateVertexShader(render_target->device,
1454 vs_code, sizeof(vs_code), &render_target->vs)))
1456 WARN("Failed to create clear vertex shader, hr %#x.\n", hr);
1457 goto err;
1460 rs_desc.FillMode = D3D10_FILL_SOLID;
1461 rs_desc.CullMode = D3D10_CULL_BACK;
1462 rs_desc.FrontCounterClockwise = FALSE;
1463 rs_desc.DepthBias = 0;
1464 rs_desc.DepthBiasClamp = 0.0f;
1465 rs_desc.SlopeScaledDepthBias = 0.0f;
1466 rs_desc.DepthClipEnable = TRUE;
1467 rs_desc.ScissorEnable = TRUE;
1468 rs_desc.MultisampleEnable = FALSE;
1469 rs_desc.AntialiasedLineEnable = FALSE;
1470 if (FAILED(hr = ID3D10Device_CreateRasterizerState(render_target->device, &rs_desc, &render_target->rs)))
1472 WARN("Failed to create clear rasterizer state, hr %#x.\n", hr);
1473 goto err;
1476 memset(&blend_desc, 0, sizeof(blend_desc));
1477 blend_desc.BlendEnable[0] = TRUE;
1478 blend_desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
1479 blend_desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
1480 blend_desc.BlendOp = D3D10_BLEND_OP_ADD;
1481 blend_desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
1482 blend_desc.DestBlendAlpha = D3D10_BLEND_ONE;
1483 blend_desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
1484 blend_desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
1485 if (FAILED(hr = ID3D10Device_CreateBlendState(render_target->device, &blend_desc, &render_target->bs)))
1487 WARN("Failed to create blend state, hr %#x.\n", hr);
1488 goto err;
1491 if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
1492 rect_solid_ps_code, sizeof(rect_solid_ps_code), &render_target->rect_solid_ps)))
1494 WARN("Failed to create pixel shader, hr %#x.\n", hr);
1495 goto err;
1498 if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
1499 rect_bitmap_ps_code, sizeof(rect_bitmap_ps_code), &render_target->rect_bitmap_ps)))
1501 WARN("Failed to create pixel shader, hr %#x.\n", hr);
1502 goto err;
1505 if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc)))
1507 WARN("Failed to get surface desc, hr %#x.\n", hr);
1508 goto err;
1511 render_target->pixel_size.width = surface_desc.Width;
1512 render_target->pixel_size.height = surface_desc.Height;
1513 render_target->transform = identity;
1515 if (!d2d_clip_stack_init(&render_target->clip_stack))
1517 WARN("Failed to initialize clip stack.\n");
1518 hr = E_FAIL;
1519 goto err;
1522 render_target->dpi_x = desc->dpiX;
1523 render_target->dpi_y = desc->dpiY;
1525 if (render_target->dpi_x == 0.0f && render_target->dpi_y == 0.0f)
1527 render_target->dpi_x = 96.0f;
1528 render_target->dpi_y = 96.0f;
1531 return S_OK;
1533 err:
1534 if (render_target->rect_bitmap_ps)
1535 ID3D10PixelShader_Release(render_target->rect_bitmap_ps);
1536 if (render_target->rect_solid_ps)
1537 ID3D10PixelShader_Release(render_target->rect_solid_ps);
1538 if (render_target->bs)
1539 ID3D10BlendState_Release(render_target->bs);
1540 if (render_target->rs)
1541 ID3D10RasterizerState_Release(render_target->rs);
1542 if (render_target->vs)
1543 ID3D10VertexShader_Release(render_target->vs);
1544 if (render_target->vb)
1545 ID3D10Buffer_Release(render_target->vb);
1546 if (render_target->il)
1547 ID3D10InputLayout_Release(render_target->il);
1548 if (render_target->stateblock)
1549 render_target->stateblock->lpVtbl->Release(render_target->stateblock);
1550 if (render_target->view)
1551 ID3D10RenderTargetView_Release(render_target->view);
1552 if (render_target->device)
1553 ID3D10Device_Release(render_target->device);
1554 ID2D1Factory_Release(render_target->factory);
1555 return hr;