9ee46b9e6c6dad2cae08143e865486cfee193c88
[reactos.git] / subsystems / win32 / win32k / eng / alphablend.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI alpha blending functions
5 * FILE: subsystems/win32/win32k/eng/alphablend.c
6 * PROGRAMER: Jason Filby
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14
15 /*
16 * @implemented
17 */
18 BOOL
19 APIENTRY
20 EngAlphaBlend(IN SURFOBJ *psoDest,
21 IN SURFOBJ *psoSource,
22 IN CLIPOBJ *ClipRegion,
23 IN XLATEOBJ *ColorTranslation,
24 IN PRECTL DestRect,
25 IN PRECTL SourceRect,
26 IN BLENDOBJ *BlendObj)
27 {
28 RECTL SourceStretchedRect;
29 SIZEL SourceStretchedSize;
30 HBITMAP SourceStretchedBitmap = 0;
31 SURFOBJ* SourceStretchedObj = NULL;
32 RECTL InputRect;
33 RECTL OutputRect;
34 RECTL ClipRect;
35 RECTL CombinedRect;
36 RECTL Rect;
37 POINTL Translate;
38 INTENG_ENTER_LEAVE EnterLeaveSource;
39 INTENG_ENTER_LEAVE EnterLeaveDest;
40 SURFOBJ* InputObj;
41 SURFOBJ* OutputObj;
42 LONG Width;
43 LONG ClippingType;
44 RECT_ENUM RectEnum;
45 BOOL EnumMore;
46 INT i;
47 BOOLEAN Ret;
48
49 DPRINT("EngAlphaBlend(psoDest:0x%p, psoSource:0x%p, ClipRegion:0x%p, ColorTranslation:0x%p,\n", psoDest, psoSource, ClipRegion, ColorTranslation);
50 DPRINT(" DestRect:{0x%x, 0x%x, 0x%x, 0x%x}, SourceRect:{0x%x, 0x%x, 0x%x, 0x%x},\n",
51 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom,
52 SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom);
53 DPRINT(" BlendObj:{0x%x, 0x%x, 0x%x, 0x%x}\n", BlendObj->BlendFunction.BlendOp,
54 BlendObj->BlendFunction.BlendFlags, BlendObj->BlendFunction.SourceConstantAlpha,
55 BlendObj->BlendFunction.AlphaFormat);
56
57 /* Validate output */
58 OutputRect = *DestRect;
59 if (OutputRect.right < OutputRect.left)
60 {
61 OutputRect.left = DestRect->right;
62 OutputRect.right = DestRect->left;
63 }
64 if (OutputRect.bottom < OutputRect.top)
65 {
66 OutputRect.left = DestRect->right;
67 OutputRect.right = DestRect->left;
68 }
69
70 /* Validate input */
71 InputRect = *SourceRect;
72 if ( (InputRect.top < 0) || (InputRect.bottom < 0) ||
73 (InputRect.left < 0) || (InputRect.right < 0) ||
74 InputRect.right > psoSource->sizlBitmap.cx ||
75 InputRect.bottom > psoSource->sizlBitmap.cy )
76 {
77 SetLastWin32Error(ERROR_INVALID_PARAMETER);
78 return FALSE;
79 }
80
81 if (psoDest == psoSource &&
82 !(OutputRect.left >= SourceRect->right || InputRect.left >= OutputRect.right ||
83 OutputRect.top >= SourceRect->bottom || InputRect.top >= OutputRect.bottom))
84 {
85 DPRINT1("Source and destination rectangles overlap!\n");
86 return FALSE;
87 }
88
89 if (BlendObj->BlendFunction.BlendOp != AC_SRC_OVER)
90 {
91 DPRINT1("BlendOp != AC_SRC_OVER (0x%x)\n", BlendObj->BlendFunction.BlendOp);
92 return FALSE;
93 }
94 if (BlendObj->BlendFunction.BlendFlags != 0)
95 {
96 DPRINT1("BlendFlags != 0 (0x%x)\n", BlendObj->BlendFunction.BlendFlags);
97 return FALSE;
98 }
99 if ((BlendObj->BlendFunction.AlphaFormat & ~AC_SRC_ALPHA) != 0)
100 {
101 DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendObj->BlendFunction.AlphaFormat);
102 return FALSE;
103 }
104
105 /* Check if there is anything to draw */
106 if (ClipRegion != NULL &&
107 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
108 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
109 {
110 /* Nothing to do */
111 return TRUE;
112 }
113
114 /* Stretch source if needed */
115 if (OutputRect.right - OutputRect.left != InputRect.right - InputRect.left ||
116 OutputRect.bottom - OutputRect.top != InputRect.bottom - InputRect.top)
117 {
118 SourceStretchedSize.cx = OutputRect.right - OutputRect.left;
119 SourceStretchedSize.cy = OutputRect.bottom - OutputRect.top;
120 Width = DIB_GetDIBWidthBytes(SourceStretchedSize.cx, BitsPerFormat(psoSource->iBitmapFormat));
121 /* FIXME: Maybe it is a good idea to use EngCreateDeviceBitmap and IntEngStretchBlt
122 if possible to get a HW accelerated stretch. */
123 SourceStretchedBitmap = EngCreateBitmap(SourceStretchedSize, Width, psoSource->iBitmapFormat,
124 BMF_TOPDOWN | BMF_NOZEROINIT, NULL);
125 if (SourceStretchedBitmap == 0)
126 {
127 DPRINT1("EngCreateBitmap failed!\n");
128 return FALSE;
129 }
130 SourceStretchedObj = EngLockSurface((HSURF)SourceStretchedBitmap);
131 if (SourceStretchedObj == NULL)
132 {
133 DPRINT1("EngLockSurface failed!\n");
134 EngDeleteSurface((HSURF)SourceStretchedBitmap);
135 return FALSE;
136 }
137
138 SourceStretchedRect.left = 0;
139 SourceStretchedRect.right = SourceStretchedSize.cx;
140 SourceStretchedRect.top = 0;
141 SourceStretchedRect.bottom = SourceStretchedSize.cy;
142 if (!IntEngStretchBlt(SourceStretchedObj, psoSource, NULL, NULL, NULL,
143 &SourceStretchedRect, SourceRect,
144 NULL, NULL, NULL, ROP3_TO_ROP4(SRCCOPY)))
145 {
146 DPRINT1("EngStretchBlt failed!\n");
147 EngUnlockSurface(SourceStretchedObj);
148 EngDeleteSurface((HSURF)SourceStretchedBitmap);
149 return FALSE;
150 }
151 InputRect.top = SourceStretchedRect.top;
152 InputRect.bottom = SourceStretchedRect.bottom;
153 InputRect.left = SourceStretchedRect.left;
154 InputRect.right = SourceStretchedRect.right;
155 psoSource = SourceStretchedObj;
156 }
157
158 /* Now call the DIB function */
159 if (!IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, &Translate, &InputObj))
160 {
161 if (SourceStretchedObj != NULL)
162 {
163 EngUnlockSurface(SourceStretchedObj);
164 }
165 if (SourceStretchedBitmap != 0)
166 {
167 EngDeleteSurface((HSURF)SourceStretchedBitmap);
168 }
169 return FALSE;
170 }
171 InputRect.left += Translate.x;
172 InputRect.right += Translate.x;
173 InputRect.top += Translate.y;
174 InputRect.bottom += Translate.y;
175
176 if (!IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &OutputObj))
177 {
178 IntEngLeave(&EnterLeaveSource);
179 if (SourceStretchedObj != NULL)
180 {
181 EngUnlockSurface(SourceStretchedObj);
182 }
183 if (SourceStretchedBitmap != 0)
184 {
185 EngDeleteSurface((HSURF)SourceStretchedBitmap);
186 }
187 return FALSE;
188 }
189 OutputRect.left += Translate.x;
190 OutputRect.right += Translate.x;
191 OutputRect.top += Translate.y;
192 OutputRect.bottom += Translate.y;
193
194 Ret = FALSE;
195 ClippingType = (ClipRegion == NULL) ? DC_TRIVIAL : ClipRegion->iDComplexity;
196 switch (ClippingType)
197 {
198 case DC_TRIVIAL:
199 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
200 OutputObj, InputObj, &OutputRect, &InputRect, ClipRegion, ColorTranslation, BlendObj);
201 break;
202
203 case DC_RECT:
204 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
205 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
206 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
207 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
208 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
209 {
210 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
211 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
212 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
213 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
214 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
215 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj);
216 }
217 break;
218
219 case DC_COMPLEX:
220 Ret = TRUE;
221 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
222 do
223 {
224 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
225 (PVOID) &RectEnum);
226
227 for (i = 0; i < RectEnum.c; i++)
228 {
229 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
230 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
231 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
232 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
233 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
234 {
235 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
236 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
237 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
238 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
239 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
240 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj) && Ret;
241 }
242 }
243 }
244 while (EnumMore);
245 break;
246
247 default:
248 UNIMPLEMENTED;
249 ASSERT(FALSE);
250 break;
251 }
252
253 IntEngLeave(&EnterLeaveDest);
254 IntEngLeave(&EnterLeaveSource);
255
256 if (SourceStretchedObj != NULL)
257 {
258 EngUnlockSurface(SourceStretchedObj);
259 }
260 if (SourceStretchedBitmap != 0)
261 {
262 EngDeleteSurface((HSURF)SourceStretchedBitmap);
263 }
264
265 return Ret;
266 }
267
268 BOOL APIENTRY
269 IntEngAlphaBlend(IN SURFOBJ *psoDest,
270 IN SURFOBJ *psoSource,
271 IN CLIPOBJ *ClipRegion,
272 IN XLATEOBJ *ColorTranslation,
273 IN PRECTL DestRect,
274 IN PRECTL SourceRect,
275 IN BLENDOBJ *BlendObj)
276 {
277 BOOL ret = FALSE;
278 SURFACE *psurfDest;
279 SURFACE *psurfSource;
280
281 ASSERT(psoDest);
282 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
283
284 ASSERT(psoSource);
285 psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
286
287 ASSERT(DestRect);
288 ASSERT(SourceRect);
289
290 /* Check if there is anything to draw */
291 if (ClipRegion != NULL &&
292 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
293 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
294 {
295 /* Nothing to do */
296 return TRUE;
297 }
298
299 /* Call the driver's DrvAlphaBlend if available */
300 if (psurfDest->flags & HOOK_ALPHABLEND)
301 {
302 ret = GDIDEVFUNCS(psoDest).AlphaBlend(
303 psoDest, psoSource, ClipRegion, ColorTranslation,
304 DestRect, SourceRect, BlendObj);
305 }
306
307 if (! ret)
308 {
309 ret = EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation,
310 DestRect, SourceRect, BlendObj);
311 }
312
313 return ret;
314 }
315
316 /*
317 * @implemented
318 */
319 BOOL
320 APIENTRY
321 NtGdiEngAlphaBlend(IN SURFOBJ *psoDest,
322 IN SURFOBJ *psoSource,
323 IN CLIPOBJ *ClipRegion,
324 IN XLATEOBJ *ColorTranslation,
325 IN PRECTL upDestRect,
326 IN PRECTL upSourceRect,
327 IN BLENDOBJ *BlendObj)
328 {
329 RECTL DestRect;
330 RECTL SourceRect;
331
332 _SEH2_TRY
333 {
334 ProbeForRead(upDestRect, sizeof(RECTL), 1);
335 RtlCopyMemory(&DestRect,upDestRect, sizeof(RECTL));
336
337 ProbeForRead(upSourceRect, sizeof(RECTL), 1);
338 RtlCopyMemory(&SourceRect, upSourceRect, sizeof(RECTL));
339
340 }
341 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
342 {
343 _SEH2_YIELD(return FALSE);
344 }
345 _SEH2_END;
346
347 return EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation, &DestRect, &SourceRect, BlendObj);
348 }
349