d2d1: Fix GetGradientStops() when asked for more stops than collection has.
[wine.git] / dlls / d2d1 / brush.c
blob601f40f88023e686ad55aa909ac8e55464806c1a
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));
113 static D2D1_GAMMA STDMETHODCALLTYPE d2d_gradient_GetColorInterpolationGamma(ID2D1GradientStopCollection *iface)
115 FIXME("iface %p stub!\n", iface);
117 return D2D1_GAMMA_1_0;
120 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_gradient_GetExtendMode(ID2D1GradientStopCollection *iface)
122 FIXME("iface %p stub!\n", iface);
124 return D2D1_EXTEND_MODE_CLAMP;
127 static const struct ID2D1GradientStopCollectionVtbl d2d_gradient_vtbl =
129 d2d_gradient_QueryInterface,
130 d2d_gradient_AddRef,
131 d2d_gradient_Release,
132 d2d_gradient_GetFactory,
133 d2d_gradient_GetGradientStopCount,
134 d2d_gradient_GetGradientStops,
135 d2d_gradient_GetColorInterpolationGamma,
136 d2d_gradient_GetExtendMode,
139 HRESULT d2d_gradient_create(ID2D1Factory *factory, const D2D1_GRADIENT_STOP *stops,
140 UINT32 stop_count, D2D1_GAMMA gamma, D2D1_EXTEND_MODE extend_mode, struct d2d_gradient **gradient)
142 if (!(*gradient = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**gradient))))
143 return E_OUTOFMEMORY;
145 FIXME("Ignoring gradient properties.\n");
147 (*gradient)->ID2D1GradientStopCollection_iface.lpVtbl = &d2d_gradient_vtbl;
148 (*gradient)->refcount = 1;
149 ID2D1Factory_AddRef((*gradient)->factory = factory);
151 (*gradient)->stop_count = stop_count;
152 if (!((*gradient)->stops = HeapAlloc(GetProcessHeap(), 0, stop_count * sizeof(*stops))))
154 HeapFree(GetProcessHeap(), 0, *gradient);
155 return E_OUTOFMEMORY;
157 memcpy((*gradient)->stops, stops, stop_count * sizeof(*stops));
159 TRACE("Created gradient %p.\n", *gradient);
160 return S_OK;
163 static void d2d_brush_destroy(struct d2d_brush *brush)
165 ID2D1Factory_Release(brush->factory);
166 HeapFree(GetProcessHeap(), 0, brush);
169 static void d2d_brush_init(struct d2d_brush *brush, ID2D1Factory *factory,
170 enum d2d_brush_type type, const D2D1_BRUSH_PROPERTIES *desc, const struct ID2D1BrushVtbl *vtbl)
172 static const D2D1_MATRIX_3X2_F identity =
174 1.0f, 0.0f,
175 0.0f, 1.0f,
176 0.0f, 0.0f,
179 brush->ID2D1Brush_iface.lpVtbl = vtbl;
180 brush->refcount = 1;
181 ID2D1Factory_AddRef(brush->factory = factory);
182 brush->opacity = desc ? desc->opacity : 1.0f;
183 brush->transform = desc ? desc->transform : identity;
184 brush->type = type;
187 static inline struct d2d_brush *impl_from_ID2D1SolidColorBrush(ID2D1SolidColorBrush *iface)
189 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
192 static HRESULT STDMETHODCALLTYPE d2d_solid_color_brush_QueryInterface(ID2D1SolidColorBrush *iface,
193 REFIID iid, void **out)
195 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
197 if (IsEqualGUID(iid, &IID_ID2D1SolidColorBrush)
198 || IsEqualGUID(iid, &IID_ID2D1Brush)
199 || IsEqualGUID(iid, &IID_ID2D1Resource)
200 || IsEqualGUID(iid, &IID_IUnknown))
202 ID2D1SolidColorBrush_AddRef(iface);
203 *out = iface;
204 return S_OK;
207 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
209 *out = NULL;
210 return E_NOINTERFACE;
213 static ULONG STDMETHODCALLTYPE d2d_solid_color_brush_AddRef(ID2D1SolidColorBrush *iface)
215 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
216 ULONG refcount = InterlockedIncrement(&brush->refcount);
218 TRACE("%p increasing refcount to %u.\n", iface, refcount);
220 return refcount;
223 static ULONG STDMETHODCALLTYPE d2d_solid_color_brush_Release(ID2D1SolidColorBrush *iface)
225 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
226 ULONG refcount = InterlockedDecrement(&brush->refcount);
228 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
230 if (!refcount)
231 d2d_brush_destroy(brush);
233 return refcount;
236 static void STDMETHODCALLTYPE d2d_solid_color_brush_GetFactory(ID2D1SolidColorBrush *iface, ID2D1Factory **factory)
238 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
240 TRACE("iface %p, factory %p.\n", iface, factory);
242 ID2D1Factory_AddRef(*factory = brush->factory);
245 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetOpacity(ID2D1SolidColorBrush *iface, float opacity)
247 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
249 TRACE("iface %p, opacity %.8e.\n", iface, opacity);
251 brush->opacity = opacity;
254 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetTransform(ID2D1SolidColorBrush *iface,
255 const D2D1_MATRIX_3X2_F *transform)
257 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
259 TRACE("iface %p, transform %p.\n", iface, transform);
261 brush->transform = *transform;
264 static float STDMETHODCALLTYPE d2d_solid_color_brush_GetOpacity(ID2D1SolidColorBrush *iface)
266 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
268 TRACE("iface %p.\n", iface);
270 return brush->opacity;
273 static void STDMETHODCALLTYPE d2d_solid_color_brush_GetTransform(ID2D1SolidColorBrush *iface,
274 D2D1_MATRIX_3X2_F *transform)
276 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
278 TRACE("iface %p, transform %p.\n", iface, transform);
280 *transform = brush->transform;
283 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetColor(ID2D1SolidColorBrush *iface, const D2D1_COLOR_F *color)
285 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
287 TRACE("iface %p, color %p.\n", iface, color);
289 brush->u.solid.color = *color;
292 static D2D1_COLOR_F * STDMETHODCALLTYPE d2d_solid_color_brush_GetColor(ID2D1SolidColorBrush *iface, D2D1_COLOR_F *color)
294 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
296 TRACE("iface %p, color %p.\n", iface, color);
298 *color = brush->u.solid.color;
299 return color;
302 static const struct ID2D1SolidColorBrushVtbl d2d_solid_color_brush_vtbl =
304 d2d_solid_color_brush_QueryInterface,
305 d2d_solid_color_brush_AddRef,
306 d2d_solid_color_brush_Release,
307 d2d_solid_color_brush_GetFactory,
308 d2d_solid_color_brush_SetOpacity,
309 d2d_solid_color_brush_SetTransform,
310 d2d_solid_color_brush_GetOpacity,
311 d2d_solid_color_brush_GetTransform,
312 d2d_solid_color_brush_SetColor,
313 d2d_solid_color_brush_GetColor,
316 HRESULT d2d_solid_color_brush_create(ID2D1Factory *factory, const D2D1_COLOR_F *color,
317 const D2D1_BRUSH_PROPERTIES *desc, struct d2d_brush **brush)
319 if (!(*brush = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**brush))))
320 return E_OUTOFMEMORY;
322 d2d_brush_init(*brush, factory, D2D_BRUSH_TYPE_SOLID, desc,
323 (ID2D1BrushVtbl *)&d2d_solid_color_brush_vtbl);
324 (*brush)->u.solid.color = *color;
326 TRACE("Created brush %p.\n", *brush);
327 return S_OK;
330 static inline struct d2d_brush *impl_from_ID2D1LinearGradientBrush(ID2D1LinearGradientBrush *iface)
332 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
335 static HRESULT STDMETHODCALLTYPE d2d_linear_gradient_brush_QueryInterface(ID2D1LinearGradientBrush *iface,
336 REFIID iid, void **out)
338 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
340 if (IsEqualGUID(iid, &IID_ID2D1LinearGradientBrush)
341 || IsEqualGUID(iid, &IID_ID2D1Brush)
342 || IsEqualGUID(iid, &IID_ID2D1Resource)
343 || IsEqualGUID(iid, &IID_IUnknown))
345 ID2D1LinearGradientBrush_AddRef(iface);
346 *out = iface;
347 return S_OK;
350 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
352 *out = NULL;
353 return E_NOINTERFACE;
356 static ULONG STDMETHODCALLTYPE d2d_linear_gradient_brush_AddRef(ID2D1LinearGradientBrush *iface)
358 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
359 ULONG refcount = InterlockedIncrement(&brush->refcount);
361 TRACE("%p increasing refcount to %u.\n", iface, refcount);
363 return refcount;
366 static ULONG STDMETHODCALLTYPE d2d_linear_gradient_brush_Release(ID2D1LinearGradientBrush *iface)
368 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
369 ULONG refcount = InterlockedDecrement(&brush->refcount);
371 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
373 if (!refcount)
375 ID2D1GradientStopCollection_Release(brush->u.linear.gradient);
376 d2d_brush_destroy(brush);
379 return refcount;
382 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetFactory(ID2D1LinearGradientBrush *iface,
383 ID2D1Factory **factory)
385 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
387 TRACE("iface %p, factory %p.\n", iface, factory);
389 ID2D1Factory_AddRef(*factory = brush->factory);
392 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetOpacity(ID2D1LinearGradientBrush *iface, float opacity)
394 FIXME("iface %p, opacity %.8e stub!\n", iface, opacity);
397 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetTransform(ID2D1LinearGradientBrush *iface,
398 const D2D1_MATRIX_3X2_F *transform)
400 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
402 TRACE("iface %p, transform %p.\n", iface, transform);
404 brush->transform = *transform;
407 static float STDMETHODCALLTYPE d2d_linear_gradient_brush_GetOpacity(ID2D1LinearGradientBrush *iface)
409 FIXME("iface %p stub!\n", iface);
411 return 0.0f;
414 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetTransform(ID2D1LinearGradientBrush *iface,
415 D2D1_MATRIX_3X2_F *transform)
417 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
419 TRACE("iface %p, transform %p.\n", iface, transform);
421 *transform = brush->transform;
424 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetStartPoint(ID2D1LinearGradientBrush *iface,
425 D2D1_POINT_2F start_point)
427 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
429 TRACE("iface %p, start_point {%.8e, %.8e}.\n", iface, start_point.x, start_point.y);
431 brush->u.linear.desc.startPoint = start_point;
434 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetEndPoint(ID2D1LinearGradientBrush *iface,
435 D2D1_POINT_2F end_point)
437 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
439 TRACE("iface %p, end_point {%.8e, %.8e}.\n", iface, end_point.x, end_point.y);
441 brush->u.linear.desc.endPoint = end_point;
444 static D2D1_POINT_2F * STDMETHODCALLTYPE d2d_linear_gradient_brush_GetStartPoint(ID2D1LinearGradientBrush *iface,
445 D2D1_POINT_2F *point)
447 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
449 TRACE("iface %p, point %p.\n", iface, point);
451 *point = brush->u.linear.desc.startPoint;
452 return point;
455 static D2D1_POINT_2F * STDMETHODCALLTYPE d2d_linear_gradient_brush_GetEndPoint(ID2D1LinearGradientBrush *iface,
456 D2D1_POINT_2F *point)
458 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
460 TRACE("iface %p, point %p.\n", iface, point);
462 *point = brush->u.linear.desc.endPoint;
463 return point;
466 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetGradientStopCollection(ID2D1LinearGradientBrush *iface,
467 ID2D1GradientStopCollection **gradient)
469 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
471 TRACE("iface %p, gradient %p.\n", iface, gradient);
473 ID2D1GradientStopCollection_AddRef(*gradient = brush->u.linear.gradient);
476 static const struct ID2D1LinearGradientBrushVtbl d2d_linear_gradient_brush_vtbl =
478 d2d_linear_gradient_brush_QueryInterface,
479 d2d_linear_gradient_brush_AddRef,
480 d2d_linear_gradient_brush_Release,
481 d2d_linear_gradient_brush_GetFactory,
482 d2d_linear_gradient_brush_SetOpacity,
483 d2d_linear_gradient_brush_SetTransform,
484 d2d_linear_gradient_brush_GetOpacity,
485 d2d_linear_gradient_brush_GetTransform,
486 d2d_linear_gradient_brush_SetStartPoint,
487 d2d_linear_gradient_brush_SetEndPoint,
488 d2d_linear_gradient_brush_GetStartPoint,
489 d2d_linear_gradient_brush_GetEndPoint,
490 d2d_linear_gradient_brush_GetGradientStopCollection,
493 HRESULT d2d_linear_gradient_brush_create(ID2D1Factory *factory, const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc,
494 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1GradientStopCollection *gradient, struct d2d_brush **brush)
496 if (!(*brush = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**brush))))
497 return E_OUTOFMEMORY;
499 d2d_brush_init(*brush, factory, D2D_BRUSH_TYPE_LINEAR, brush_desc,
500 (ID2D1BrushVtbl *)&d2d_linear_gradient_brush_vtbl);
501 (*brush)->u.linear.desc = *gradient_brush_desc;
502 ID2D1GradientStopCollection_AddRef((*brush)->u.linear.gradient = gradient);
504 TRACE("Created brush %p.\n", *brush);
505 return S_OK;
508 static inline struct d2d_brush *impl_from_ID2D1BitmapBrush(ID2D1BitmapBrush *iface)
510 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
513 static HRESULT STDMETHODCALLTYPE d2d_bitmap_brush_QueryInterface(ID2D1BitmapBrush *iface,
514 REFIID iid, void **out)
516 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
518 if (IsEqualGUID(iid, &IID_ID2D1BitmapBrush)
519 || IsEqualGUID(iid, &IID_ID2D1Brush)
520 || IsEqualGUID(iid, &IID_ID2D1Resource)
521 || IsEqualGUID(iid, &IID_IUnknown))
523 ID2D1BitmapBrush_AddRef(iface);
524 *out = iface;
525 return S_OK;
528 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
530 *out = NULL;
531 return E_NOINTERFACE;
534 static ULONG STDMETHODCALLTYPE d2d_bitmap_brush_AddRef(ID2D1BitmapBrush *iface)
536 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
537 ULONG refcount = InterlockedIncrement(&brush->refcount);
539 TRACE("%p increasing refcount to %u.\n", iface, refcount);
541 return refcount;
544 static ULONG STDMETHODCALLTYPE d2d_bitmap_brush_Release(ID2D1BitmapBrush *iface)
546 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
547 ULONG refcount = InterlockedDecrement(&brush->refcount);
549 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
551 if (!refcount)
553 if (brush->u.bitmap.sampler_state)
554 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
555 if (brush->u.bitmap.bitmap)
556 ID2D1Bitmap_Release(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
557 d2d_brush_destroy(brush);
560 return refcount;
563 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetFactory(ID2D1BitmapBrush *iface,
564 ID2D1Factory **factory)
566 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
568 TRACE("iface %p, factory %p.\n", iface, factory);
570 ID2D1Factory_AddRef(*factory = brush->factory);
573 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetOpacity(ID2D1BitmapBrush *iface, float opacity)
575 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
577 TRACE("iface %p, opacity %.8e.\n", iface, opacity);
579 brush->opacity = opacity;
582 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetTransform(ID2D1BitmapBrush *iface,
583 const D2D1_MATRIX_3X2_F *transform)
585 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
587 TRACE("iface %p, transform %p.\n", iface, transform);
589 brush->transform = *transform;
592 static float STDMETHODCALLTYPE d2d_bitmap_brush_GetOpacity(ID2D1BitmapBrush *iface)
594 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
596 TRACE("iface %p.\n", iface);
598 return brush->opacity;
601 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetTransform(ID2D1BitmapBrush *iface,
602 D2D1_MATRIX_3X2_F *transform)
604 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
606 TRACE("iface %p, transform %p.\n", iface, transform);
608 *transform = brush->transform;
611 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetExtendModeX(ID2D1BitmapBrush *iface, D2D1_EXTEND_MODE mode)
613 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
615 TRACE("iface %p, mode %#x.\n", iface, mode);
617 brush->u.bitmap.extend_mode_x = mode;
618 if (brush->u.bitmap.sampler_state)
620 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
621 brush->u.bitmap.sampler_state = NULL;
625 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetExtendModeY(ID2D1BitmapBrush *iface, D2D1_EXTEND_MODE mode)
627 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
629 TRACE("iface %p, mode %#x.\n", iface, mode);
631 brush->u.bitmap.extend_mode_y = mode;
632 if (brush->u.bitmap.sampler_state)
634 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
635 brush->u.bitmap.sampler_state = NULL;
639 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetInterpolationMode(ID2D1BitmapBrush *iface,
640 D2D1_BITMAP_INTERPOLATION_MODE mode)
642 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
644 TRACE("iface %p, mode %#x.\n", iface, mode);
646 brush->u.bitmap.interpolation_mode = mode;
647 if (brush->u.bitmap.sampler_state)
649 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
650 brush->u.bitmap.sampler_state = NULL;
654 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetBitmap(ID2D1BitmapBrush *iface, ID2D1Bitmap *bitmap)
656 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
658 TRACE("iface %p, bitmap %p.\n", iface, bitmap);
660 if (bitmap)
661 ID2D1Bitmap_AddRef(bitmap);
662 if (brush->u.bitmap.bitmap)
663 ID2D1Bitmap_Release(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
664 brush->u.bitmap.bitmap = unsafe_impl_from_ID2D1Bitmap(bitmap);
667 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetExtendModeX(ID2D1BitmapBrush *iface)
669 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
671 TRACE("iface %p.\n", iface);
673 return brush->u.bitmap.extend_mode_x;
676 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetExtendModeY(ID2D1BitmapBrush *iface)
678 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
680 TRACE("iface %p.\n", iface);
682 return brush->u.bitmap.extend_mode_y;
685 static D2D1_BITMAP_INTERPOLATION_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetInterpolationMode(ID2D1BitmapBrush *iface)
687 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
689 TRACE("iface %p.\n", iface);
691 return brush->u.bitmap.interpolation_mode;
694 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetBitmap(ID2D1BitmapBrush *iface, ID2D1Bitmap **bitmap)
696 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
698 TRACE("iface %p, bitmap %p.\n", iface, bitmap);
700 if ((*bitmap = &brush->u.bitmap.bitmap->ID2D1Bitmap_iface))
701 ID2D1Bitmap_AddRef(*bitmap);
704 static const struct ID2D1BitmapBrushVtbl d2d_bitmap_brush_vtbl =
706 d2d_bitmap_brush_QueryInterface,
707 d2d_bitmap_brush_AddRef,
708 d2d_bitmap_brush_Release,
709 d2d_bitmap_brush_GetFactory,
710 d2d_bitmap_brush_SetOpacity,
711 d2d_bitmap_brush_SetTransform,
712 d2d_bitmap_brush_GetOpacity,
713 d2d_bitmap_brush_GetTransform,
714 d2d_bitmap_brush_SetExtendModeX,
715 d2d_bitmap_brush_SetExtendModeY,
716 d2d_bitmap_brush_SetInterpolationMode,
717 d2d_bitmap_brush_SetBitmap,
718 d2d_bitmap_brush_GetExtendModeX,
719 d2d_bitmap_brush_GetExtendModeY,
720 d2d_bitmap_brush_GetInterpolationMode,
721 d2d_bitmap_brush_GetBitmap,
724 HRESULT d2d_bitmap_brush_create(ID2D1Factory *factory, ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc,
725 const D2D1_BRUSH_PROPERTIES *brush_desc, struct d2d_brush **brush)
727 if (!(*brush = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**brush))))
728 return E_OUTOFMEMORY;
730 d2d_brush_init(*brush, factory, D2D_BRUSH_TYPE_BITMAP,
731 brush_desc, (ID2D1BrushVtbl *)&d2d_bitmap_brush_vtbl);
732 if (((*brush)->u.bitmap.bitmap = unsafe_impl_from_ID2D1Bitmap(bitmap)))
733 ID2D1Bitmap_AddRef(&(*brush)->u.bitmap.bitmap->ID2D1Bitmap_iface);
734 if (bitmap_brush_desc)
736 (*brush)->u.bitmap.extend_mode_x = bitmap_brush_desc->extendModeX;
737 (*brush)->u.bitmap.extend_mode_y = bitmap_brush_desc->extendModeY;
738 (*brush)->u.bitmap.interpolation_mode = bitmap_brush_desc->interpolationMode;
740 else
742 (*brush)->u.bitmap.extend_mode_x = D2D1_EXTEND_MODE_CLAMP;
743 (*brush)->u.bitmap.extend_mode_y = D2D1_EXTEND_MODE_CLAMP;
744 (*brush)->u.bitmap.interpolation_mode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
747 TRACE("Created brush %p.\n", *brush);
748 return S_OK;
751 struct d2d_brush *unsafe_impl_from_ID2D1Brush(ID2D1Brush *iface)
753 if (!iface)
754 return NULL;
755 assert(iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_solid_color_brush_vtbl
756 || iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_linear_gradient_brush_vtbl
757 || iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_bitmap_brush_vtbl);
758 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
761 static D3D10_TEXTURE_ADDRESS_MODE texture_address_mode_from_extend_mode(D2D1_EXTEND_MODE mode)
763 switch (mode)
765 case D2D1_EXTEND_MODE_CLAMP:
766 return D3D10_TEXTURE_ADDRESS_CLAMP;
767 case D2D1_EXTEND_MODE_WRAP:
768 return D3D10_TEXTURE_ADDRESS_WRAP;
769 case D2D1_EXTEND_MODE_MIRROR:
770 return D3D10_TEXTURE_ADDRESS_MIRROR;
771 default:
772 FIXME("Unhandled extend mode %#x.\n", mode);
773 return D3D10_TEXTURE_ADDRESS_CLAMP;
777 static BOOL d2d_brush_fill_cb(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target, void *cb)
779 struct d2d_bitmap_brush_cb *bitmap_brush_cb;
780 D2D1_COLOR_F *color;
782 if (brush->type == D2D_BRUSH_TYPE_SOLID)
784 color = cb;
786 *color = brush->u.solid.color;
787 color->a *= brush->opacity;
788 color->r *= color->a;
789 color->g *= color->a;
790 color->b *= color->a;
792 return TRUE;
795 if (brush->type == D2D_BRUSH_TYPE_BITMAP)
797 struct d2d_bitmap *bitmap = brush->u.bitmap.bitmap;
798 D2D_MATRIX_3X2_F w, b;
799 float dpi_scale, d;
801 bitmap_brush_cb = cb;
803 /* Scale for dpi. */
804 w = render_target->drawing_state.transform;
805 dpi_scale = render_target->desc.dpiX / 96.0f;
806 w._11 *= dpi_scale;
807 w._21 *= dpi_scale;
808 w._31 *= dpi_scale;
809 dpi_scale = render_target->desc.dpiY / 96.0f;
810 w._12 *= dpi_scale;
811 w._22 *= dpi_scale;
812 w._32 *= dpi_scale;
814 /* Scale for bitmap size and dpi. */
815 b = brush->transform;
816 dpi_scale = bitmap->pixel_size.width * (96.0f / bitmap->dpi_x);
817 b._11 *= dpi_scale;
818 b._21 *= dpi_scale;
819 dpi_scale = bitmap->pixel_size.height * (96.0f / bitmap->dpi_y);
820 b._12 *= dpi_scale;
821 b._22 *= dpi_scale;
823 d2d_matrix_multiply(&b, &w);
825 /* Invert the matrix. (Because the matrix is applied to the sampling
826 * coordinates. I.e., to scale the bitmap by 2 we need to divide the
827 * coordinates by 2.) */
828 d = b._11 * b._22 - b._21 * b._12;
829 if (d != 0.0f)
831 bitmap_brush_cb->_11 = b._22 / d;
832 bitmap_brush_cb->_21 = -b._21 / d;
833 bitmap_brush_cb->_31 = (b._21 * b._32 - b._31 * b._22) / d;
834 bitmap_brush_cb->_12 = -b._12 / d;
835 bitmap_brush_cb->_22 = b._11 / d;
836 bitmap_brush_cb->_32 = -(b._11 * b._32 - b._31 * b._12) / d;
838 bitmap_brush_cb->opacity = brush->opacity;
839 bitmap_brush_cb->ignore_alpha = bitmap->format.alphaMode == D2D1_ALPHA_MODE_IGNORE;
841 return TRUE;
844 FIXME("Unhandled brush type %#x.\n", brush->type);
845 return FALSE;
848 HRESULT d2d_brush_get_ps_cb(struct d2d_brush *brush, struct d2d_brush *opacity_brush,
849 struct d2d_d3d_render_target *render_target, ID3D10Buffer **ps_cb)
851 D3D10_SUBRESOURCE_DATA buffer_data;
852 D3D10_BUFFER_DESC buffer_desc;
853 BYTE *cb_data;
854 HRESULT hr;
856 static const size_t brush_sizes[] =
858 /* D2D_BRUSH_TYPE_SOLID */ sizeof(D2D1_COLOR_F),
859 /* D2D_BRUSH_TYPE_LINEAR */ 0,
860 /* D2D_BRUSH_TYPE_BITMAP */ sizeof(struct d2d_bitmap_brush_cb),
863 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
864 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
865 buffer_desc.CPUAccessFlags = 0;
866 buffer_desc.MiscFlags = 0;
868 buffer_data.SysMemPitch = 0;
869 buffer_data.SysMemSlicePitch = 0;
871 if (brush->type >= sizeof(brush_sizes) / sizeof(*brush_sizes))
873 ERR("Unhandled brush type %#x.\n", brush->type);
874 return E_NOTIMPL;
877 buffer_desc.ByteWidth = brush_sizes[brush->type];
878 if (opacity_brush)
880 if (opacity_brush->type >= sizeof(brush_sizes) / sizeof(*brush_sizes))
882 ERR("Unhandled opacity brush type %#x.\n", opacity_brush->type);
883 return E_NOTIMPL;
885 buffer_desc.ByteWidth += brush_sizes[opacity_brush->type];
888 if (!(cb_data = HeapAlloc(GetProcessHeap(), 0, buffer_desc.ByteWidth)))
890 ERR("Failed to allocate constant buffer data.\n");
891 return E_OUTOFMEMORY;
893 buffer_data.pSysMem = cb_data;
895 if (!d2d_brush_fill_cb(brush, render_target, cb_data))
897 HeapFree(GetProcessHeap(), 0, cb_data);
898 return E_NOTIMPL;
900 if (opacity_brush && !d2d_brush_fill_cb(opacity_brush, render_target, cb_data + brush_sizes[brush->type]))
902 HeapFree(GetProcessHeap(), 0, cb_data);
903 return E_NOTIMPL;
906 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, ps_cb)))
907 ERR("Failed to create constant buffer, hr %#x.\n", hr);
908 HeapFree(GetProcessHeap(), 0, cb_data);
910 return hr;
913 static void d2d_brush_bind_bitmap(struct d2d_brush *brush, ID3D10Device *device,
914 unsigned int resource_idx, unsigned int sampler_idx)
916 HRESULT hr;
918 ID3D10Device_PSSetShaderResources(device, resource_idx, 1, &brush->u.bitmap.bitmap->view);
919 if (!brush->u.bitmap.sampler_state)
921 D3D10_SAMPLER_DESC sampler_desc;
923 if (brush->u.bitmap.interpolation_mode == D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR)
924 sampler_desc.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT;
925 else
926 sampler_desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
927 sampler_desc.AddressU = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_x);
928 sampler_desc.AddressV = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_y);
929 sampler_desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
930 sampler_desc.MipLODBias = 0.0f;
931 sampler_desc.MaxAnisotropy = 0;
932 sampler_desc.ComparisonFunc = D3D10_COMPARISON_NEVER;
933 sampler_desc.BorderColor[0] = 0.0f;
934 sampler_desc.BorderColor[1] = 0.0f;
935 sampler_desc.BorderColor[2] = 0.0f;
936 sampler_desc.BorderColor[3] = 0.0f;
937 sampler_desc.MinLOD = 0.0f;
938 sampler_desc.MaxLOD = 0.0f;
940 if (FAILED(hr = ID3D10Device_CreateSamplerState(device,
941 &sampler_desc, &brush->u.bitmap.sampler_state)))
942 ERR("Failed to create sampler state, hr %#x.\n", hr);
944 ID3D10Device_PSSetSamplers(device, sampler_idx, 1, &brush->u.bitmap.sampler_state);
947 void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_brush *opacity_brush,
948 struct d2d_d3d_render_target *render_target, enum d2d_shape_type shape_type)
950 static const float blend_factor[] = {1.0f, 1.0f, 1.0f, 1.0f};
951 unsigned int resource_idx = 0, sampler_idx = 0;
952 ID3D10Device *device = render_target->device;
953 enum d2d_brush_type opacity_brush_type;
954 ID3D10PixelShader *ps;
956 ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK);
957 opacity_brush_type = opacity_brush ? opacity_brush->type : D2D_BRUSH_TYPE_COUNT;
958 if (!(ps = render_target->shape_resources[shape_type].ps[brush->type][opacity_brush_type]))
959 FIXME("No pixel shader for shape type %#x and brush types %#x/%#x.\n",
960 shape_type, brush->type, opacity_brush_type);
961 ID3D10Device_PSSetShader(device, ps);
963 if (brush->type == D2D_BRUSH_TYPE_BITMAP)
964 d2d_brush_bind_bitmap(brush, device, resource_idx++, sampler_idx++);
965 else if (brush->type != D2D_BRUSH_TYPE_SOLID)
966 FIXME("Unhandled brush type %#x.\n", brush->type);
968 if (opacity_brush)
970 if (opacity_brush->type == D2D_BRUSH_TYPE_BITMAP)
971 d2d_brush_bind_bitmap(opacity_brush, device, resource_idx++, sampler_idx++);
972 else if (opacity_brush->type != D2D_BRUSH_TYPE_SOLID)
973 FIXME("Unhandled opacity brush type %#x.\n", opacity_brush->type);