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