xref: /reactos/win32ss/gdi/eng/alphablend.c (revision 9c544a55)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          GDI alpha blending functions
5  * FILE:             win32ss/gdi/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         IntEngLeave(&EnterLeaveSource);
115         return FALSE;
116     }
117     OutputRect.left += Translate.x;
118     OutputRect.right += Translate.x;
119     OutputRect.top += Translate.y;
120     OutputRect.bottom += Translate.y;
121 
122     ASSERT(InputRect.left <= InputRect.right && InputRect.top <= InputRect.bottom);
123 
124     Ret = FALSE;
125     ClippingType = (ClipRegion == NULL) ? DC_TRIVIAL : ClipRegion->iDComplexity;
126     switch (ClippingType)
127     {
128         case DC_TRIVIAL:
129             Ret = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_AlphaBlend(
130                       OutputObj, InputObj, &OutputRect, &InputRect, ClipRegion, ColorTranslation, BlendObj);
131             break;
132 
133         case DC_RECT:
134             Ret = TRUE;
135             ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
136             ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
137             ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
138             ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
139             if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
140             {
141                 /* take into acount clipping results when calculating new input rect (scaled to input rect size) */
142                 Rect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left);
143                 Rect.right = InputRect.right + (CombinedRect.right - OutputRect.right) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left);
144                 Rect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top);
145                 Rect.bottom = InputRect.bottom + (CombinedRect.bottom - OutputRect.bottom) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top);
146 
147                 /* Aplha blend one rect */
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                         /* take into acount clipping results when calculating new input rect (scaled to input rect size) */
170                         Rect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left);
171                         Rect.right = InputRect.right + (CombinedRect.right - OutputRect.right) * (InputRect.right - InputRect.left) / (OutputRect.right - OutputRect.left);
172                         Rect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top);
173                         Rect.bottom = InputRect.bottom + (CombinedRect.bottom - OutputRect.bottom) * (InputRect.bottom - InputRect.top) / (OutputRect.bottom - OutputRect.top);
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 = (CLIPOBJ *)&gxcoTrivial;
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 
280