advapi32/tests: Improve RegDeleteTree tests.
[wine.git] / dlls / d2d1 / brush.c
blobaa92318c7711b60e49b7e9431ffabb06865f031c
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"
24 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
26 struct d2d_bitmap_brush_cb
28 float _11, _21, _31, pad0;
29 float _12, _22, _32, opacity;
30 BOOL ignore_alpha, pad1, pad2, pad3;
33 static inline struct d2d_gradient *impl_from_ID2D1GradientStopCollection(ID2D1GradientStopCollection *iface)
35 return CONTAINING_RECORD(iface, struct d2d_gradient, ID2D1GradientStopCollection_iface);
38 static HRESULT STDMETHODCALLTYPE d2d_gradient_QueryInterface(ID2D1GradientStopCollection *iface,
39 REFIID iid, void **out)
41 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
43 if (IsEqualGUID(iid, &IID_ID2D1GradientStopCollection)
44 || IsEqualGUID(iid, &IID_ID2D1Resource)
45 || IsEqualGUID(iid, &IID_IUnknown))
47 ID2D1GradientStopCollection_AddRef(iface);
48 *out = iface;
49 return S_OK;
52 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
54 *out = NULL;
55 return E_NOINTERFACE;
58 static ULONG STDMETHODCALLTYPE d2d_gradient_AddRef(ID2D1GradientStopCollection *iface)
60 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
61 ULONG refcount = InterlockedIncrement(&gradient->refcount);
63 TRACE("%p increasing refcount to %u.\n", iface, refcount);
65 return refcount;
68 static ULONG STDMETHODCALLTYPE d2d_gradient_Release(ID2D1GradientStopCollection *iface)
70 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
71 ULONG refcount = InterlockedDecrement(&gradient->refcount);
73 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
75 if (!refcount)
77 HeapFree(GetProcessHeap(), 0, gradient->stops);
78 ID2D1Factory_Release(gradient->factory);
79 HeapFree(GetProcessHeap(), 0, gradient);
82 return refcount;
85 static void STDMETHODCALLTYPE d2d_gradient_GetFactory(ID2D1GradientStopCollection *iface, ID2D1Factory **factory)
87 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
89 TRACE("iface %p, factory %p.\n", iface, factory);
91 ID2D1Factory_AddRef(*factory = gradient->factory);
94 static UINT32 STDMETHODCALLTYPE d2d_gradient_GetGradientStopCount(ID2D1GradientStopCollection *iface)
96 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
98 TRACE("iface %p.\n", iface);
100 return gradient->stop_count;
103 static void STDMETHODCALLTYPE d2d_gradient_GetGradientStops(ID2D1GradientStopCollection *iface,
104 D2D1_GRADIENT_STOP *stops, UINT32 stop_count)
106 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
108 TRACE("iface %p, stops %p, stop_count %u.\n", iface, stops, stop_count);
110 memcpy(stops, gradient->stops, min(gradient->stop_count, stop_count) * sizeof(*stops));
111 if (stop_count > gradient->stop_count)
112 memset(stops, 0, (stop_count - gradient->stop_count) * sizeof(*stops));
115 static D2D1_GAMMA STDMETHODCALLTYPE d2d_gradient_GetColorInterpolationGamma(ID2D1GradientStopCollection *iface)
117 FIXME("iface %p stub!\n", iface);
119 return D2D1_GAMMA_1_0;
122 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_gradient_GetExtendMode(ID2D1GradientStopCollection *iface)
124 FIXME("iface %p stub!\n", iface);
126 return D2D1_EXTEND_MODE_CLAMP;
129 static const struct ID2D1GradientStopCollectionVtbl d2d_gradient_vtbl =
131 d2d_gradient_QueryInterface,
132 d2d_gradient_AddRef,
133 d2d_gradient_Release,
134 d2d_gradient_GetFactory,
135 d2d_gradient_GetGradientStopCount,
136 d2d_gradient_GetGradientStops,
137 d2d_gradient_GetColorInterpolationGamma,
138 d2d_gradient_GetExtendMode,
141 HRESULT d2d_gradient_init(struct d2d_gradient *gradient, ID2D1Factory *factory,
142 const D2D1_GRADIENT_STOP *stops, UINT32 stop_count, D2D1_GAMMA gamma, D2D1_EXTEND_MODE extend_mode)
144 FIXME("Ignoring gradient properties.\n");
146 gradient->ID2D1GradientStopCollection_iface.lpVtbl = &d2d_gradient_vtbl;
147 gradient->refcount = 1;
148 ID2D1Factory_AddRef(gradient->factory = factory);
150 gradient->stop_count = stop_count;
151 if (!(gradient->stops = HeapAlloc(GetProcessHeap(), 0, stop_count * sizeof(*stops))))
152 return E_OUTOFMEMORY;
153 memcpy(gradient->stops, stops, stop_count * sizeof(*stops));
155 return S_OK;
158 static void d2d_brush_destroy(struct d2d_brush *brush)
160 ID2D1Factory_Release(brush->factory);
161 HeapFree(GetProcessHeap(), 0, brush);
164 static void d2d_brush_init(struct d2d_brush *brush, ID2D1Factory *factory,
165 enum d2d_brush_type type, const D2D1_BRUSH_PROPERTIES *desc, const struct ID2D1BrushVtbl *vtbl)
167 static const D2D1_MATRIX_3X2_F identity =
169 1.0f, 0.0f,
170 0.0f, 1.0f,
171 0.0f, 0.0f,
174 brush->ID2D1Brush_iface.lpVtbl = vtbl;
175 brush->refcount = 1;
176 ID2D1Factory_AddRef(brush->factory = factory);
177 brush->opacity = desc ? desc->opacity : 1.0f;
178 brush->transform = desc ? desc->transform : identity;
179 brush->type = type;
182 static inline struct d2d_brush *impl_from_ID2D1SolidColorBrush(ID2D1SolidColorBrush *iface)
184 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
187 static HRESULT STDMETHODCALLTYPE d2d_solid_color_brush_QueryInterface(ID2D1SolidColorBrush *iface,
188 REFIID iid, void **out)
190 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
192 if (IsEqualGUID(iid, &IID_ID2D1SolidColorBrush)
193 || IsEqualGUID(iid, &IID_ID2D1Brush)
194 || IsEqualGUID(iid, &IID_ID2D1Resource)
195 || IsEqualGUID(iid, &IID_IUnknown))
197 ID2D1SolidColorBrush_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_solid_color_brush_AddRef(ID2D1SolidColorBrush *iface)
210 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
211 ULONG refcount = InterlockedIncrement(&brush->refcount);
213 TRACE("%p increasing refcount to %u.\n", iface, refcount);
215 return refcount;
218 static ULONG STDMETHODCALLTYPE d2d_solid_color_brush_Release(ID2D1SolidColorBrush *iface)
220 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
221 ULONG refcount = InterlockedDecrement(&brush->refcount);
223 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
225 if (!refcount)
226 d2d_brush_destroy(brush);
228 return refcount;
231 static void STDMETHODCALLTYPE d2d_solid_color_brush_GetFactory(ID2D1SolidColorBrush *iface, ID2D1Factory **factory)
233 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
235 TRACE("iface %p, factory %p.\n", iface, factory);
237 ID2D1Factory_AddRef(*factory = brush->factory);
240 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetOpacity(ID2D1SolidColorBrush *iface, float opacity)
242 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
244 TRACE("iface %p, opacity %.8e.\n", iface, opacity);
246 brush->opacity = opacity;
249 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetTransform(ID2D1SolidColorBrush *iface,
250 const D2D1_MATRIX_3X2_F *transform)
252 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
254 TRACE("iface %p, transform %p.\n", iface, transform);
256 brush->transform = *transform;
259 static float STDMETHODCALLTYPE d2d_solid_color_brush_GetOpacity(ID2D1SolidColorBrush *iface)
261 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
263 TRACE("iface %p.\n", iface);
265 return brush->opacity;
268 static void STDMETHODCALLTYPE d2d_solid_color_brush_GetTransform(ID2D1SolidColorBrush *iface,
269 D2D1_MATRIX_3X2_F *transform)
271 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
273 TRACE("iface %p, transform %p.\n", iface, transform);
275 *transform = brush->transform;
278 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetColor(ID2D1SolidColorBrush *iface, const D2D1_COLOR_F *color)
280 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
282 TRACE("iface %p, color %p.\n", iface, color);
284 brush->u.solid.color = *color;
287 static D2D1_COLOR_F * STDMETHODCALLTYPE d2d_solid_color_brush_GetColor(ID2D1SolidColorBrush *iface, D2D1_COLOR_F *color)
289 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
291 TRACE("iface %p, color %p.\n", iface, color);
293 *color = brush->u.solid.color;
294 return color;
297 static const struct ID2D1SolidColorBrushVtbl d2d_solid_color_brush_vtbl =
299 d2d_solid_color_brush_QueryInterface,
300 d2d_solid_color_brush_AddRef,
301 d2d_solid_color_brush_Release,
302 d2d_solid_color_brush_GetFactory,
303 d2d_solid_color_brush_SetOpacity,
304 d2d_solid_color_brush_SetTransform,
305 d2d_solid_color_brush_GetOpacity,
306 d2d_solid_color_brush_GetTransform,
307 d2d_solid_color_brush_SetColor,
308 d2d_solid_color_brush_GetColor,
311 void d2d_solid_color_brush_init(struct d2d_brush *brush, ID2D1Factory *factory,
312 const D2D1_COLOR_F *color, const D2D1_BRUSH_PROPERTIES *desc)
314 d2d_brush_init(brush, factory, D2D_BRUSH_TYPE_SOLID, desc,
315 (ID2D1BrushVtbl *)&d2d_solid_color_brush_vtbl);
316 brush->u.solid.color = *color;
319 static inline struct d2d_brush *impl_from_ID2D1LinearGradientBrush(ID2D1LinearGradientBrush *iface)
321 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
324 static HRESULT STDMETHODCALLTYPE d2d_linear_gradient_brush_QueryInterface(ID2D1LinearGradientBrush *iface,
325 REFIID iid, void **out)
327 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
329 if (IsEqualGUID(iid, &IID_ID2D1LinearGradientBrush)
330 || IsEqualGUID(iid, &IID_ID2D1Brush)
331 || IsEqualGUID(iid, &IID_ID2D1Resource)
332 || IsEqualGUID(iid, &IID_IUnknown))
334 ID2D1LinearGradientBrush_AddRef(iface);
335 *out = iface;
336 return S_OK;
339 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
341 *out = NULL;
342 return E_NOINTERFACE;
345 static ULONG STDMETHODCALLTYPE d2d_linear_gradient_brush_AddRef(ID2D1LinearGradientBrush *iface)
347 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
348 ULONG refcount = InterlockedIncrement(&brush->refcount);
350 TRACE("%p increasing refcount to %u.\n", iface, refcount);
352 return refcount;
355 static ULONG STDMETHODCALLTYPE d2d_linear_gradient_brush_Release(ID2D1LinearGradientBrush *iface)
357 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
358 ULONG refcount = InterlockedDecrement(&brush->refcount);
360 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
362 if (!refcount)
363 d2d_brush_destroy(brush);
365 return refcount;
368 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetFactory(ID2D1LinearGradientBrush *iface,
369 ID2D1Factory **factory)
371 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
373 TRACE("iface %p, factory %p.\n", iface, factory);
375 ID2D1Factory_AddRef(*factory = brush->factory);
378 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetOpacity(ID2D1LinearGradientBrush *iface, float opacity)
380 FIXME("iface %p, opacity %.8e stub!\n", iface, opacity);
383 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetTransform(ID2D1LinearGradientBrush *iface,
384 const D2D1_MATRIX_3X2_F *transform)
386 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
388 TRACE("iface %p, transform %p.\n", iface, transform);
390 brush->transform = *transform;
393 static float STDMETHODCALLTYPE d2d_linear_gradient_brush_GetOpacity(ID2D1LinearGradientBrush *iface)
395 FIXME("iface %p stub!\n", iface);
397 return 0.0f;
400 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetTransform(ID2D1LinearGradientBrush *iface,
401 D2D1_MATRIX_3X2_F *transform)
403 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
405 TRACE("iface %p, transform %p.\n", iface, transform);
407 *transform = brush->transform;
410 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetStartPoint(ID2D1LinearGradientBrush *iface,
411 D2D1_POINT_2F start_point)
413 FIXME("iface %p, start_point {%.8e, %.8e} stub!\n", iface, start_point.x, start_point.y);
416 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetEndPoint(ID2D1LinearGradientBrush *iface,
417 D2D1_POINT_2F end_point)
419 FIXME("iface %p, end_point {%.8e, %.8e} stub!\n", iface, end_point.x, end_point.y);
422 static D2D1_POINT_2F * STDMETHODCALLTYPE d2d_linear_gradient_brush_GetStartPoint(ID2D1LinearGradientBrush *iface,
423 D2D1_POINT_2F *point)
425 FIXME("iface %p, point %p stub!\n", iface, point);
427 point->x = 0.0f;
428 point->y = 0.0f;
429 return point;
432 static D2D1_POINT_2F * STDMETHODCALLTYPE d2d_linear_gradient_brush_GetEndPoint(ID2D1LinearGradientBrush *iface,
433 D2D1_POINT_2F *point)
435 FIXME("iface %p, point %p stub!\n", iface, point);
437 point->x = 0.0f;
438 point->y = 0.0f;
439 return point;
442 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetGradientStopCollection(ID2D1LinearGradientBrush *iface,
443 ID2D1GradientStopCollection **gradient)
445 FIXME("iface %p, gradient %p stub!\n", iface, gradient);
447 *gradient = NULL;
450 static const struct ID2D1LinearGradientBrushVtbl d2d_linear_gradient_brush_vtbl =
452 d2d_linear_gradient_brush_QueryInterface,
453 d2d_linear_gradient_brush_AddRef,
454 d2d_linear_gradient_brush_Release,
455 d2d_linear_gradient_brush_GetFactory,
456 d2d_linear_gradient_brush_SetOpacity,
457 d2d_linear_gradient_brush_SetTransform,
458 d2d_linear_gradient_brush_GetOpacity,
459 d2d_linear_gradient_brush_GetTransform,
460 d2d_linear_gradient_brush_SetStartPoint,
461 d2d_linear_gradient_brush_SetEndPoint,
462 d2d_linear_gradient_brush_GetStartPoint,
463 d2d_linear_gradient_brush_GetEndPoint,
464 d2d_linear_gradient_brush_GetGradientStopCollection,
467 void d2d_linear_gradient_brush_init(struct d2d_brush *brush, ID2D1Factory *factory,
468 const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
469 ID2D1GradientStopCollection *gradient)
471 FIXME("Ignoring brush properties.\n");
473 d2d_brush_init(brush, factory, D2D_BRUSH_TYPE_LINEAR, brush_desc,
474 (ID2D1BrushVtbl *)&d2d_linear_gradient_brush_vtbl);
477 static inline struct d2d_brush *impl_from_ID2D1BitmapBrush(ID2D1BitmapBrush *iface)
479 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
482 static HRESULT STDMETHODCALLTYPE d2d_bitmap_brush_QueryInterface(ID2D1BitmapBrush *iface,
483 REFIID iid, void **out)
485 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
487 if (IsEqualGUID(iid, &IID_ID2D1BitmapBrush)
488 || IsEqualGUID(iid, &IID_ID2D1Brush)
489 || IsEqualGUID(iid, &IID_ID2D1Resource)
490 || IsEqualGUID(iid, &IID_IUnknown))
492 ID2D1BitmapBrush_AddRef(iface);
493 *out = iface;
494 return S_OK;
497 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
499 *out = NULL;
500 return E_NOINTERFACE;
503 static ULONG STDMETHODCALLTYPE d2d_bitmap_brush_AddRef(ID2D1BitmapBrush *iface)
505 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
506 ULONG refcount = InterlockedIncrement(&brush->refcount);
508 TRACE("%p increasing refcount to %u.\n", iface, refcount);
510 return refcount;
513 static ULONG STDMETHODCALLTYPE d2d_bitmap_brush_Release(ID2D1BitmapBrush *iface)
515 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
516 ULONG refcount = InterlockedDecrement(&brush->refcount);
518 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
520 if (!refcount)
522 if (brush->u.bitmap.sampler_state)
523 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
524 if (brush->u.bitmap.bitmap)
525 ID2D1Bitmap_Release(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
526 d2d_brush_destroy(brush);
529 return refcount;
532 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetFactory(ID2D1BitmapBrush *iface,
533 ID2D1Factory **factory)
535 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
537 TRACE("iface %p, factory %p.\n", iface, factory);
539 ID2D1Factory_AddRef(*factory = brush->factory);
542 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetOpacity(ID2D1BitmapBrush *iface, float opacity)
544 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
546 TRACE("iface %p, opacity %.8e.\n", iface, opacity);
548 brush->opacity = opacity;
551 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetTransform(ID2D1BitmapBrush *iface,
552 const D2D1_MATRIX_3X2_F *transform)
554 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
556 TRACE("iface %p, transform %p.\n", iface, transform);
558 brush->transform = *transform;
561 static float STDMETHODCALLTYPE d2d_bitmap_brush_GetOpacity(ID2D1BitmapBrush *iface)
563 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
565 TRACE("iface %p.\n", iface);
567 return brush->opacity;
570 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetTransform(ID2D1BitmapBrush *iface,
571 D2D1_MATRIX_3X2_F *transform)
573 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
575 TRACE("iface %p, transform %p.\n", iface, transform);
577 *transform = brush->transform;
580 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetExtendModeX(ID2D1BitmapBrush *iface, D2D1_EXTEND_MODE mode)
582 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
584 TRACE("iface %p, mode %#x.\n", iface, mode);
586 brush->u.bitmap.extend_mode_x = mode;
587 if (brush->u.bitmap.sampler_state)
589 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
590 brush->u.bitmap.sampler_state = NULL;
594 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetExtendModeY(ID2D1BitmapBrush *iface, D2D1_EXTEND_MODE mode)
596 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
598 TRACE("iface %p, mode %#x.\n", iface, mode);
600 brush->u.bitmap.extend_mode_y = mode;
601 if (brush->u.bitmap.sampler_state)
603 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
604 brush->u.bitmap.sampler_state = NULL;
608 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetInterpolationMode(ID2D1BitmapBrush *iface,
609 D2D1_BITMAP_INTERPOLATION_MODE mode)
611 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
613 TRACE("iface %p, mode %#x.\n", iface, mode);
615 brush->u.bitmap.interpolation_mode = mode;
616 if (brush->u.bitmap.sampler_state)
618 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
619 brush->u.bitmap.sampler_state = NULL;
623 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetBitmap(ID2D1BitmapBrush *iface, ID2D1Bitmap *bitmap)
625 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
627 TRACE("iface %p, bitmap %p.\n", iface, bitmap);
629 if (bitmap)
630 ID2D1Bitmap_AddRef(bitmap);
631 if (brush->u.bitmap.bitmap)
632 ID2D1Bitmap_Release(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
633 brush->u.bitmap.bitmap = unsafe_impl_from_ID2D1Bitmap(bitmap);
636 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetExtendModeX(ID2D1BitmapBrush *iface)
638 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
640 TRACE("iface %p.\n", iface);
642 return brush->u.bitmap.extend_mode_x;
645 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetExtendModeY(ID2D1BitmapBrush *iface)
647 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
649 TRACE("iface %p.\n", iface);
651 return brush->u.bitmap.extend_mode_y;
654 static D2D1_BITMAP_INTERPOLATION_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetInterpolationMode(ID2D1BitmapBrush *iface)
656 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
658 TRACE("iface %p.\n", iface);
660 return brush->u.bitmap.interpolation_mode;
663 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetBitmap(ID2D1BitmapBrush *iface, ID2D1Bitmap **bitmap)
665 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
667 TRACE("iface %p, bitmap %p.\n", iface, bitmap);
669 if ((*bitmap = &brush->u.bitmap.bitmap->ID2D1Bitmap_iface))
670 ID2D1Bitmap_AddRef(*bitmap);
673 static const struct ID2D1BitmapBrushVtbl d2d_bitmap_brush_vtbl =
675 d2d_bitmap_brush_QueryInterface,
676 d2d_bitmap_brush_AddRef,
677 d2d_bitmap_brush_Release,
678 d2d_bitmap_brush_GetFactory,
679 d2d_bitmap_brush_SetOpacity,
680 d2d_bitmap_brush_SetTransform,
681 d2d_bitmap_brush_GetOpacity,
682 d2d_bitmap_brush_GetTransform,
683 d2d_bitmap_brush_SetExtendModeX,
684 d2d_bitmap_brush_SetExtendModeY,
685 d2d_bitmap_brush_SetInterpolationMode,
686 d2d_bitmap_brush_SetBitmap,
687 d2d_bitmap_brush_GetExtendModeX,
688 d2d_bitmap_brush_GetExtendModeY,
689 d2d_bitmap_brush_GetInterpolationMode,
690 d2d_bitmap_brush_GetBitmap,
693 void d2d_bitmap_brush_init(struct d2d_brush *brush, ID2D1Factory *factory, ID2D1Bitmap *bitmap,
694 const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc)
696 d2d_brush_init(brush, factory, D2D_BRUSH_TYPE_BITMAP,
697 brush_desc, (ID2D1BrushVtbl *)&d2d_bitmap_brush_vtbl);
698 if ((brush->u.bitmap.bitmap = unsafe_impl_from_ID2D1Bitmap(bitmap)))
699 ID2D1Bitmap_AddRef(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
700 if (bitmap_brush_desc)
702 brush->u.bitmap.extend_mode_x = bitmap_brush_desc->extendModeX;
703 brush->u.bitmap.extend_mode_y = bitmap_brush_desc->extendModeY;
704 brush->u.bitmap.interpolation_mode = bitmap_brush_desc->interpolationMode;
706 else
708 brush->u.bitmap.extend_mode_x = D2D1_EXTEND_MODE_CLAMP;
709 brush->u.bitmap.extend_mode_y = D2D1_EXTEND_MODE_CLAMP;
710 brush->u.bitmap.interpolation_mode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
714 struct d2d_brush *unsafe_impl_from_ID2D1Brush(ID2D1Brush *iface)
716 if (!iface)
717 return NULL;
718 assert(iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_solid_color_brush_vtbl
719 || iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_linear_gradient_brush_vtbl
720 || iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_bitmap_brush_vtbl);
721 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
724 static D3D10_TEXTURE_ADDRESS_MODE texture_address_mode_from_extend_mode(D2D1_EXTEND_MODE mode)
726 switch (mode)
728 case D2D1_EXTEND_MODE_CLAMP:
729 return D3D10_TEXTURE_ADDRESS_CLAMP;
730 case D2D1_EXTEND_MODE_WRAP:
731 return D3D10_TEXTURE_ADDRESS_WRAP;
732 case D2D1_EXTEND_MODE_MIRROR:
733 return D3D10_TEXTURE_ADDRESS_MIRROR;
734 default:
735 FIXME("Unhandled extend mode %#x.\n", mode);
736 return D3D10_TEXTURE_ADDRESS_CLAMP;
740 static BOOL d2d_brush_fill_cb(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target, void *cb)
742 struct d2d_bitmap_brush_cb *bitmap_brush_cb;
743 D2D1_COLOR_F *color;
745 if (brush->type == D2D_BRUSH_TYPE_SOLID)
747 color = cb;
749 *color = brush->u.solid.color;
750 color->a *= brush->opacity;
751 color->r *= color->a;
752 color->g *= color->a;
753 color->b *= color->a;
755 return TRUE;
758 if (brush->type == D2D_BRUSH_TYPE_BITMAP)
760 struct d2d_bitmap *bitmap = brush->u.bitmap.bitmap;
761 D2D_MATRIX_3X2_F w, b;
762 float dpi_scale, d;
764 bitmap_brush_cb = cb;
766 /* Scale for dpi. */
767 w = render_target->drawing_state.transform;
768 dpi_scale = render_target->dpi_x / 96.0f;
769 w._11 *= dpi_scale;
770 w._21 *= dpi_scale;
771 w._31 *= dpi_scale;
772 dpi_scale = render_target->dpi_y / 96.0f;
773 w._12 *= dpi_scale;
774 w._22 *= dpi_scale;
775 w._32 *= dpi_scale;
777 /* Scale for bitmap size and dpi. */
778 b = brush->transform;
779 dpi_scale = bitmap->pixel_size.width * (96.0f / bitmap->dpi_x);
780 b._11 *= dpi_scale;
781 b._21 *= dpi_scale;
782 dpi_scale = bitmap->pixel_size.height * (96.0f / bitmap->dpi_y);
783 b._12 *= dpi_scale;
784 b._22 *= dpi_scale;
786 d2d_matrix_multiply(&b, &w);
788 /* Invert the matrix. (Because the matrix is applied to the sampling
789 * coordinates. I.e., to scale the bitmap by 2 we need to divide the
790 * coordinates by 2.) */
791 d = b._11 * b._22 - b._21 * b._12;
792 if (d != 0.0f)
794 bitmap_brush_cb->_11 = b._22 / d;
795 bitmap_brush_cb->_21 = -b._21 / d;
796 bitmap_brush_cb->_31 = (b._21 * b._32 - b._31 * b._22) / d;
797 bitmap_brush_cb->_12 = -b._12 / d;
798 bitmap_brush_cb->_22 = b._11 / d;
799 bitmap_brush_cb->_32 = -(b._11 * b._32 - b._31 * b._12) / d;
801 bitmap_brush_cb->opacity = brush->opacity;
802 bitmap_brush_cb->ignore_alpha = bitmap->format.alphaMode == D2D1_ALPHA_MODE_IGNORE;
804 return TRUE;
807 FIXME("Unhandled brush type %#x.\n", brush->type);
808 return FALSE;
811 HRESULT d2d_brush_get_ps_cb(struct d2d_brush *brush, struct d2d_brush *opacity_brush,
812 struct d2d_d3d_render_target *render_target, ID3D10Buffer **ps_cb)
814 D3D10_SUBRESOURCE_DATA buffer_data;
815 D3D10_BUFFER_DESC buffer_desc;
816 BYTE *cb_data;
817 HRESULT hr;
819 static const size_t brush_sizes[] =
821 /* D2D_BRUSH_TYPE_SOLID */ sizeof(D2D1_COLOR_F),
822 /* D2D_BRUSH_TYPE_LINEAR */ 0,
823 /* D2D_BRUSH_TYPE_BITMAP */ sizeof(struct d2d_bitmap_brush_cb),
826 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
827 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
828 buffer_desc.CPUAccessFlags = 0;
829 buffer_desc.MiscFlags = 0;
831 buffer_data.SysMemPitch = 0;
832 buffer_data.SysMemSlicePitch = 0;
834 if (brush->type >= sizeof(brush_sizes) / sizeof(*brush_sizes))
836 ERR("Unhandled brush type %#x.\n", brush->type);
837 return E_NOTIMPL;
840 buffer_desc.ByteWidth = brush_sizes[brush->type];
841 if (opacity_brush)
843 if (opacity_brush->type >= sizeof(brush_sizes) / sizeof(*brush_sizes))
845 ERR("Unhandled opacity brush type %#x.\n", brush->type);
846 return E_NOTIMPL;
848 buffer_desc.ByteWidth += brush_sizes[opacity_brush->type];
851 if (!(cb_data = HeapAlloc(GetProcessHeap(), 0, buffer_desc.ByteWidth)))
853 ERR("Failed to allocate constant buffer data.\n");
854 return E_OUTOFMEMORY;
856 buffer_data.pSysMem = cb_data;
858 if (!d2d_brush_fill_cb(brush, render_target, cb_data))
860 HeapFree(GetProcessHeap(), 0, cb_data);
861 return E_NOTIMPL;
863 if (opacity_brush && !d2d_brush_fill_cb(opacity_brush, render_target, cb_data + brush_sizes[brush->type]))
865 HeapFree(GetProcessHeap(), 0, cb_data);
866 return E_NOTIMPL;
869 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, ps_cb)))
870 ERR("Failed to create constant buffer, hr %#x.\n", hr);
871 HeapFree(GetProcessHeap(), 0, cb_data);
873 return hr;
876 static void d2d_brush_bind_bitmap(struct d2d_brush *brush, ID3D10Device *device,
877 unsigned int resource_idx, unsigned int sampler_idx)
879 HRESULT hr;
881 ID3D10Device_PSSetShaderResources(device, resource_idx, 1, &brush->u.bitmap.bitmap->view);
882 if (!brush->u.bitmap.sampler_state)
884 D3D10_SAMPLER_DESC sampler_desc;
886 if (brush->u.bitmap.interpolation_mode == D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR)
887 sampler_desc.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT;
888 else
889 sampler_desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
890 sampler_desc.AddressU = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_x);
891 sampler_desc.AddressV = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_y);
892 sampler_desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
893 sampler_desc.MipLODBias = 0.0f;
894 sampler_desc.MaxAnisotropy = 0;
895 sampler_desc.ComparisonFunc = D3D10_COMPARISON_NEVER;
896 sampler_desc.BorderColor[0] = 0.0f;
897 sampler_desc.BorderColor[1] = 0.0f;
898 sampler_desc.BorderColor[2] = 0.0f;
899 sampler_desc.BorderColor[3] = 0.0f;
900 sampler_desc.MinLOD = 0.0f;
901 sampler_desc.MaxLOD = 0.0f;
903 if (FAILED(hr = ID3D10Device_CreateSamplerState(device,
904 &sampler_desc, &brush->u.bitmap.sampler_state)))
905 ERR("Failed to create sampler state, hr %#x.\n", hr);
907 ID3D10Device_PSSetSamplers(device, sampler_idx, 1, &brush->u.bitmap.sampler_state);
910 void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_brush *opacity_brush,
911 struct d2d_d3d_render_target *render_target, enum d2d_shape_type shape_type)
913 static const float blend_factor[] = {1.0f, 1.0f, 1.0f, 1.0f};
914 unsigned int resource_idx = 0, sampler_idx = 0;
915 ID3D10Device *device = render_target->device;
916 enum d2d_brush_type opacity_brush_type;
917 ID3D10PixelShader *ps;
919 ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK);
920 opacity_brush_type = opacity_brush ? opacity_brush->type : D2D_BRUSH_TYPE_COUNT;
921 if (!(ps = render_target->shape_resources[shape_type].ps[brush->type][opacity_brush_type]))
922 FIXME("No pixel shader for shape type %#x and brush types %#x/%#x.\n",
923 shape_type, brush->type, opacity_brush_type);
924 ID3D10Device_PSSetShader(device, ps);
926 if (brush->type == D2D_BRUSH_TYPE_BITMAP)
927 d2d_brush_bind_bitmap(brush, device, resource_idx++, sampler_idx++);
928 else if (brush->type != D2D_BRUSH_TYPE_SOLID)
929 FIXME("Unhandled brush type %#x.\n", brush->type);
931 if (opacity_brush)
933 if (opacity_brush->type == D2D_BRUSH_TYPE_BITMAP)
934 d2d_brush_bind_bitmap(opacity_brush, device, resource_idx++, sampler_idx++);
935 else if (opacity_brush->type != D2D_BRUSH_TYPE_SOLID)
936 FIXME("Unhandled opacity brush type %#x.\n", opacity_brush->type);