[KERNEL32][CONSRV]
[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
145 /* Aplha blend one rect */
146 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
147 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj);
148 }
149 break;
150
151 case DC_COMPLEX:
152 Ret = TRUE;
153 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
154 do
155 {
156 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
157 (PVOID) &RectEnum);
158
159 for (i = 0; i < RectEnum.c; i++)
160 {
161 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
162 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
163 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
164 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
165 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
166 {
167 /* take into acount clipping results when calculating new input rect (scaled to input rect size) */
168 Rect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left);
169 Rect.right = InputRect.right + (CombinedRect.right - OutputRect.right) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left);
170 Rect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top);
171 Rect.bottom = InputRect.bottom + (CombinedRect.bottom - OutputRect.bottom) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top);
172
173 /* Alpha blend one rect */
174 Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
175 OutputObj, InputObj, &CombinedRect, &Rect, ClipRegion, ColorTranslation, BlendObj) && Ret;
176 }
177 }
178 }
179 while (EnumMore);
180 break;
181
182 default:
183 UNIMPLEMENTED;
184 ASSERT(FALSE);
185 break;
186 }
187
188 IntEngLeave(&EnterLeaveDest);
189 IntEngLeave(&EnterLeaveSource);
190
191 return Ret;
192 }
193
194 BOOL
195 APIENTRY
196 IntEngAlphaBlend(
197 _Inout_ SURFOBJ *psoDest,
198 _In_ SURFOBJ *psoSource,
199 _In_opt_ CLIPOBJ *pco,
200 _In_opt_ XLATEOBJ *pxlo,
201 _In_ RECTL *prclDest,
202 _In_ RECTL *prclSrc,
203 _In_ BLENDOBJ *pBlendObj)
204 {
205 BOOL ret = FALSE;
206 SURFACE *psurfDest;
207
208 ASSERT(psoDest);
209 ASSERT(psoSource);
210 ASSERT(prclDest);
211 ASSERT(prclSrc);
212 //ASSERT(pBlendObj);
213
214 /* If no clip object is given, use trivial one */
215 if (!pco) pco = &gxcoTrivial.ClipObj;
216
217 /* Check if there is anything to draw */
218 if ((pco->rclBounds.left >= pco->rclBounds.right) ||
219 (pco->rclBounds.top >= pco->rclBounds.bottom))
220 {
221 /* Nothing to do */
222 return TRUE;
223 }
224
225 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
226
227 /* Call the driver's DrvAlphaBlend if available */
228 if (psurfDest->flags & HOOK_ALPHABLEND)
229 {
230 ret = GDIDEVFUNCS(psoDest).AlphaBlend(
231 psoDest, psoSource, pco, pxlo,
232 prclDest, prclSrc, pBlendObj);
233 }
234
235 if (!ret)
236 {
237 ret = EngAlphaBlend(psoDest, psoSource, pco, pxlo,
238 prclDest, prclSrc, pBlendObj);
239 }
240
241 return ret;
242 }
243
244 /*
245 * @implemented
246 */
247 BOOL
248 APIENTRY
249 NtGdiEngAlphaBlend(IN SURFOBJ *psoDest,
250 IN SURFOBJ *psoSource,
251 IN CLIPOBJ *ClipRegion,
252 IN XLATEOBJ *ColorTranslation,
253 IN PRECTL upDestRect,
254 IN PRECTL upSourceRect,
255 IN BLENDOBJ *BlendObj)
256 {
257 RECTL DestRect;
258 RECTL SourceRect;
259
260 _SEH2_TRY
261 {
262 ProbeForRead(upDestRect, sizeof(RECTL), 1);
263 RtlCopyMemory(&DestRect,upDestRect, sizeof(RECTL));
264
265 ProbeForRead(upSourceRect, sizeof(RECTL), 1);
266 RtlCopyMemory(&SourceRect, upSourceRect, sizeof(RECTL));
267
268 }
269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
270 {
271 _SEH2_YIELD(return FALSE);
272 }
273 _SEH2_END;
274
275 return EngAlphaBlend(psoDest, psoSource, ClipRegion, ColorTranslation, &DestRect, &SourceRect, BlendObj);
276 }
277