Sync with trunk (r49303)
[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 InputRect;
29 RECTL OutputRect;
30 RECTL ClipRect;
31 RECTL CombinedRect;
32 RECTL Rect;
33 POINTL Translate;
34 INTENG_ENTER_LEAVE EnterLeaveSource;
35 INTENG_ENTER_LEAVE EnterLeaveDest;
36 SURFOBJ* InputObj;
37 SURFOBJ* OutputObj;
38 LONG ClippingType;
39 RECT_ENUM RectEnum;
40 BOOL EnumMore;
41 INT i;
42 BOOLEAN Ret;
43
44 DPRINT("EngAlphaBlend(psoDest:0x%p, psoSource:0x%p, ClipRegion:0x%p, ColorTranslation:0x%p,\n", psoDest, psoSource, ClipRegion, ColorTranslation);
45 DPRINT(" DestRect:{0x%x, 0x%x, 0x%x, 0x%x}, SourceRect:{0x%x, 0x%x, 0x%x, 0x%x},\n",
46 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom,
47 SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom);
48 DPRINT(" BlendObj:{0x%x, 0x%x, 0x%x, 0x%x}\n", BlendObj->BlendFunction.BlendOp,
49 BlendObj->BlendFunction.BlendFlags, BlendObj->BlendFunction.SourceConstantAlpha,
50 BlendObj->BlendFunction.AlphaFormat);
51
52 /* Validate output */
53 OutputRect = *DestRect;
54 if (OutputRect.right < OutputRect.left)
55 {
56 OutputRect.left = DestRect->right;
57 OutputRect.right = DestRect->left;
58 }
59 if (OutputRect.bottom < OutputRect.top)
60 {
61 OutputRect.left = DestRect->right;
62 OutputRect.right = DestRect->left;
63 }
64
65 /* Validate input */
66 InputRect = *SourceRect;
67 if ( (InputRect.top < 0) || (InputRect.bottom < 0) ||
68 (InputRect.left < 0) || (InputRect.right < 0) ||
69 InputRect.right > psoSource->sizlBitmap.cx ||
70 InputRect.bottom > psoSource->sizlBitmap.cy )
71 {
72 SetLastWin32Error(ERROR_INVALID_PARAMETER);
73 return FALSE;
74 }
75
76 if (psoDest == psoSource &&
77 !(OutputRect.left >= SourceRect->right || InputRect.left >= OutputRect.right ||
78 OutputRect.top >= SourceRect->bottom || InputRect.top >= OutputRect.bottom))
79 {
80 DPRINT1("Source and destination rectangles overlap!\n");
81 return FALSE;
82 }
83
84 if (BlendObj->BlendFunction.BlendOp != AC_SRC_OVER)
85 {
86 DPRINT1("BlendOp != AC_SRC_OVER (0x%x)\n", BlendObj->BlendFunction.BlendOp);
87 return FALSE;
88 }
89 if (BlendObj->BlendFunction.BlendFlags != 0)
90 {
91 DPRINT1("BlendFlags != 0 (0x%x)\n", BlendObj->BlendFunction.BlendFlags);
92 return FALSE;
93 }
94 if ((BlendObj->BlendFunction.AlphaFormat & ~AC_SRC_ALPHA) != 0)
95 {
96 DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendObj->BlendFunction.AlphaFormat);
97 return FALSE;
98 }
99
100 /* Check if there is anything to draw */
101 if (ClipRegion != NULL &&
102 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
103 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
104 {
105 /* Nothing to do */
106 return TRUE;
107 }
108
109 /* Now call the DIB function */
110 if (!IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, &Translate, &InputObj))
111 {
112 return FALSE;
113 }
114 InputRect.left += Translate.x;
115 InputRect.right += Translate.x;
116 InputRect.top += Translate.y;
117 InputRect.bottom += Translate.y;
118
119 if (!IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &OutputObj))
120 {
121 return FALSE;
122 }
123 OutputRect.left += Translate.x;
124 OutputRect.right += Translate.x;
125 OutputRect.top += Translate.y;
126 OutputRect.bottom += Translate.y;
127
128 Ret = FALSE;
129 ClippingType = (ClipRegion == NULL) ? DC_TRIVIAL : ClipRegion->iDComplexity;
130 switch (ClippingType)
131 {
132 case DC_TRIVIAL:
133 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
134 OutputObj, InputObj, &OutputRect, &InputRect, ClipRegion, ColorTranslation, BlendObj);
135 break;
136
137 case DC_RECT:
138 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
139 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
140 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
141 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
142 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
143 {
144 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
145 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
146 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
147 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
148 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
149 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj);
150 }
151 break;
152
153 case DC_COMPLEX:
154 Ret = TRUE;
155 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
156 do
157 {
158 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
159 (PVOID) &RectEnum);
160
161 for (i = 0; i < RectEnum.c; i++)
162 {
163 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
164 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
165 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
166 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
167 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
168 {
169 Rect.left = InputRect.left + CombinedRect.left - OutputRect.left;
170 Rect.right = InputRect.right + CombinedRect.right - OutputRect.right;
171 Rect.top = InputRect.top + CombinedRect.top - OutputRect.top;
172 Rect.bottom = InputRect.bottom + CombinedRect.bottom - OutputRect.bottom;
173 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
174 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj) && Ret;
175 }
176 }
177 }
178 while (EnumMore);
179 break;
180
181 default:
182 UNIMPLEMENTED;
183 ASSERT(FALSE);
184 break;
185 }
186
187 IntEngLeave(&EnterLeaveDest);
188 IntEngLeave(&EnterLeaveSource);
189
190 return Ret;
191 }
192
193 BOOL APIENTRY
194 IntEngAlphaBlend(IN SURFOBJ *psoDest,
195 IN SURFOBJ *psoSource,
196 IN CLIPOBJ *ClipRegion,
197 IN XLATEOBJ *ColorTranslation,
198 IN PRECTL DestRect,
199 IN PRECTL SourceRect,
200 IN BLENDOBJ *BlendObj)
201 {
202 BOOL ret = FALSE;
203 SURFACE *psurfDest;
204 SURFACE *psurfSource;
205
206 ASSERT(psoDest);
207 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
208
209 ASSERT(psoSource);
210 psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
211
212 ASSERT(DestRect);
213 ASSERT(SourceRect);
214
215 /* Check if there is anything to draw */
216 if (ClipRegion != NULL &&
217 (ClipRegion->rclBounds.left >= ClipRegion->rclBounds.right ||
218 ClipRegion->rclBounds.top >= ClipRegion->rclBounds.bottom))
219 {
220 /* Nothing to do */
221 return TRUE;
222 }
223
224 /* Call the driver's DrvAlphaBlend if available */
225 if (psurfDest->flags & HOOK_ALPHABLEND)
226 {
227 ret = GDIDEVFUNCS(psoDest).AlphaBlend(
228 psoDest, psoSource, ClipRegion, ColorTranslation,
229 DestRect, SourceRect, BlendObj);
230 }
231
232 if (! ret)
233 {
234 ret = EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation,
235 DestRect, SourceRect, BlendObj);
236 }
237
238 return ret;
239 }
240
241 /*
242 * @implemented
243 */
244 BOOL
245 APIENTRY
246 NtGdiEngAlphaBlend(IN SURFOBJ *psoDest,
247 IN SURFOBJ *psoSource,
248 IN CLIPOBJ *ClipRegion,
249 IN XLATEOBJ *ColorTranslation,
250 IN PRECTL upDestRect,
251 IN PRECTL upSourceRect,
252 IN BLENDOBJ *BlendObj)
253 {
254 RECTL DestRect;
255 RECTL SourceRect;
256
257 _SEH2_TRY
258 {
259 ProbeForRead(upDestRect, sizeof(RECTL), 1);
260 RtlCopyMemory(&DestRect,upDestRect, sizeof(RECTL));
261
262 ProbeForRead(upSourceRect, sizeof(RECTL), 1);
263 RtlCopyMemory(&SourceRect, upSourceRect, sizeof(RECTL));
264
265 }
266 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
267 {
268 _SEH2_YIELD(return FALSE);
269 }
270 _SEH2_END;
271
272 return EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation, &DestRect, &SourceRect, BlendObj);
273 }
274