Revert the sync.
[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 <w32k.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 /* FIXME: IntEngStretchBlt isn't used here atm because it results in a
143 try to acquire an already acquired mutex (lock the already locked source surface) */
144 /*if (!IntEngStretchBlt(SourceStretchedObj, psoSource, NULL, NULL,
145 NULL, &SourceStretchedRect, SourceRect, NULL,
146 NULL, NULL, COLORONCOLOR))*/
147 if (!EngStretchBlt(SourceStretchedObj, psoSource, NULL, NULL, NULL,
148 NULL, NULL, &SourceStretchedRect, &InputRect,
149 NULL, COLORONCOLOR))
150 {
151 DPRINT1("EngStretchBlt failed!\n");
152 EngFreeMem(SourceStretchedObj->pvBits);
153 EngUnlockSurface(SourceStretchedObj);
154 EngDeleteSurface((HSURF)SourceStretchedBitmap);
155 return FALSE;
156 }
157 InputRect.top = SourceStretchedRect.top;
158 InputRect.bottom = SourceStretchedRect.bottom;
159 InputRect.left = SourceStretchedRect.left;
160 InputRect.right = SourceStretchedRect.right;
161 psoSource = SourceStretchedObj;
162 }
163
164 /* Now call the DIB function */
165 if (!IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, &Translate, &InputObj))
166 {
167 if (SourceStretchedObj != NULL)
168 {
169 EngFreeMem(SourceStretchedObj->pvBits);
170 EngUnlockSurface(SourceStretchedObj);
171 }
172 if (SourceStretchedBitmap != 0)
173 {
174 EngDeleteSurface((HSURF)SourceStretchedBitmap);
175 }
176 return FALSE;
177 }
178 InputRect.left += Translate.x;
179 InputRect.right += Translate.x;
180 InputRect.top += Translate.y;
181 InputRect.bottom += Translate.y;
182
183 if (!IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &OutputObj))
184 {
185 IntEngLeave(&EnterLeaveSource);
186 if (SourceStretchedObj != NULL)
187 {
188 EngFreeMem(SourceStretchedObj->pvBits);
189 EngUnlockSurface(SourceStretchedObj);
190 }
191 if (SourceStretchedBitmap != 0)
192 {
193 EngDeleteSurface((HSURF)SourceStretchedBitmap);
194 }
195 return FALSE;
196 }
197 OutputRect.left += Translate.x;
198 OutputRect.right += Translate.x;
199 OutputRect.top += Translate.y;
200 OutputRect.bottom += Translate.y;
201
202 Ret = FALSE;
203 ClippingType = (ClipRegion == NULL) ? DC_TRIVIAL : ClipRegion->iDComplexity;
204 switch (ClippingType)
205 {
206 case DC_TRIVIAL:
207 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
208 OutputObj, InputObj, &OutputRect, &InputRect, ClipRegion, ColorTranslation, BlendObj);
209 break;
210
211 case DC_RECT:
212 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
213 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
214 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
215 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
216 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
217 {
218 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
219 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
220 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
221 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
222 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
223 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj);
224 }
225 break;
226
227 case DC_COMPLEX:
228 Ret = TRUE;
229 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
230 do
231 {
232 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
233 (PVOID) &RectEnum);
234
235 for (i = 0; i < RectEnum.c; i++)
236 {
237 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
238 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
239 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
240 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
241 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
242 {
243 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
244 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
245 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
246 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
247 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
248 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj) && Ret;
249 }
250 }
251 }
252 while (EnumMore);
253 break;
254
255 default:
256 UNIMPLEMENTED;
257 ASSERT(FALSE);
258 break;
259 }
260
261 IntEngLeave(&EnterLeaveDest);
262 IntEngLeave(&EnterLeaveSource);
263
264 if (SourceStretchedObj != NULL)
265 {
266 EngFreeMem(SourceStretchedObj->pvBits);
267 EngUnlockSurface(SourceStretchedObj);
268 }
269 if (SourceStretchedBitmap != 0)
270 {
271 EngDeleteSurface((HSURF)SourceStretchedBitmap);
272 }
273
274 return Ret;
275 }
276
277 BOOL APIENTRY
278 IntEngAlphaBlend(IN SURFOBJ *psoDest,
279 IN SURFOBJ *psoSource,
280 IN CLIPOBJ *ClipRegion,
281 IN XLATEOBJ *ColorTranslation,
282 IN PRECTL DestRect,
283 IN PRECTL SourceRect,
284 IN BLENDOBJ *BlendObj)
285 {
286 BOOL ret = FALSE;
287 SURFACE *psurfDest;
288 SURFACE *psurfSource;
289
290 ASSERT(psoDest);
291 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
292
293 ASSERT(psoSource);
294 psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
295
296 ASSERT(DestRect);
297 ASSERT(SourceRect);
298
299 /* Check if there is anything to draw */
300 if (ClipRegion != NULL &&
301 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
302 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
303 {
304 /* Nothing to do */
305 return TRUE;
306 }
307
308 SURFACE_LockBitmapBits(psurfDest);
309 MouseSafetyOnDrawStart(psoDest, DestRect->left, DestRect->top,
310 DestRect->right, DestRect->bottom);
311
312 if (psoSource != psoDest)
313 SURFACE_LockBitmapBits(psurfSource);
314 MouseSafetyOnDrawStart(psoSource, SourceRect->left, SourceRect->top,
315 SourceRect->right, SourceRect->bottom);
316
317 /* Call the driver's DrvAlphaBlend if available */
318 if (psurfDest->flHooks & HOOK_ALPHABLEND)
319 {
320 ret = GDIDEVFUNCS(psoDest).AlphaBlend(
321 psoDest, psoSource, ClipRegion, ColorTranslation,
322 DestRect, SourceRect, BlendObj);
323 }
324
325 if (! ret)
326 {
327 ret = EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation,
328 DestRect, SourceRect, BlendObj);
329 }
330
331 MouseSafetyOnDrawEnd(psoSource);
332 if (psoSource != psoDest)
333 SURFACE_UnlockBitmapBits(psurfSource);
334 MouseSafetyOnDrawEnd(psoDest);
335 SURFACE_UnlockBitmapBits(psurfDest);
336
337 return ret;
338 }
339
340 /*
341 * @implemented
342 */
343 BOOL
344 APIENTRY
345 NtGdiEngAlphaBlend(IN SURFOBJ *psoDest,
346 IN SURFOBJ *psoSource,
347 IN CLIPOBJ *ClipRegion,
348 IN XLATEOBJ *ColorTranslation,
349 IN PRECTL upDestRect,
350 IN PRECTL upSourceRect,
351 IN BLENDOBJ *BlendObj)
352 {
353 RECTL DestRect;
354 RECTL SourceRect;
355
356 _SEH2_TRY
357 {
358 ProbeForRead(upDestRect, sizeof(RECTL), 1);
359 RtlCopyMemory(&DestRect,upDestRect, sizeof(RECTL));
360
361 ProbeForRead(upSourceRect, sizeof(RECTL), 1);
362 RtlCopyMemory(&SourceRect, upSourceRect, sizeof(RECTL));
363
364 }
365 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
366 {
367 _SEH2_YIELD(return FALSE);
368 }
369 _SEH2_END;
370
371 return EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation, &DestRect, &SourceRect, BlendObj);
372 }
373