xref: /reactos/win32ss/gdi/eng/transblt.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          GDI TransparentBlt Function
5  * FILE:             win32ss/gdi/eng/transblt.c
6  * PROGRAMER:        Thomas Weidenmueller (w3seek@users.sourceforge.net)
7  */
8 
9 #include <win32k.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 BOOL
15 APIENTRY
EngTransparentBlt(SURFOBJ * psoDest,SURFOBJ * psoSource,CLIPOBJ * Clip,XLATEOBJ * ColorTranslation,PRECTL DestRect,PRECTL SourceRect,ULONG iTransColor,ULONG Reserved)16 EngTransparentBlt(
17     SURFOBJ *psoDest,
18     SURFOBJ *psoSource,
19     CLIPOBJ *Clip,
20     XLATEOBJ *ColorTranslation,
21     PRECTL DestRect,
22     PRECTL SourceRect,
23     ULONG iTransColor,
24     ULONG Reserved)
25 {
26     BOOL Ret = TRUE;
27     BYTE ClippingType;
28     INTENG_ENTER_LEAVE EnterLeaveSource, EnterLeaveDest;
29     SURFOBJ *InputObj, *OutputObj;
30     RECTL OutputRect, InputRect;
31     POINTL Translate;
32 
33     LONG DstHeight;
34     LONG DstWidth;
35     LONG SrcHeight;
36     LONG SrcWidth;
37 
38     InputRect = *SourceRect;
39 
40     if (!IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, &Translate, &InputObj))
41     {
42         return FALSE;
43     }
44     InputRect.left += Translate.x;
45     InputRect.right += Translate.x;
46     InputRect.top += Translate.y;
47     InputRect.bottom += Translate.y;
48 
49     OutputRect = *DestRect;
50     if (OutputRect.right < OutputRect.left)
51     {
52         OutputRect.left = DestRect->right;
53         OutputRect.right = DestRect->left;
54     }
55     if (OutputRect.bottom < OutputRect.top)
56     {
57         OutputRect.top = DestRect->bottom;
58         OutputRect.bottom = DestRect->top;
59     }
60 
61     if (Clip)
62     {
63         if (OutputRect.left < Clip->rclBounds.left)
64         {
65             InputRect.left += Clip->rclBounds.left - OutputRect.left;
66             OutputRect.left = Clip->rclBounds.left;
67         }
68         if (Clip->rclBounds.right < OutputRect.right)
69         {
70             InputRect.right -=  OutputRect.right - Clip->rclBounds.right;
71             OutputRect.right = Clip->rclBounds.right;
72         }
73         if (OutputRect.top < Clip->rclBounds.top)
74         {
75             InputRect.top += Clip->rclBounds.top - OutputRect.top;
76             OutputRect.top = Clip->rclBounds.top;
77         }
78         if (Clip->rclBounds.bottom < OutputRect.bottom)
79         {
80             InputRect.bottom -=  OutputRect.bottom - Clip->rclBounds.bottom;
81             OutputRect.bottom = Clip->rclBounds.bottom;
82         }
83     }
84 
85     /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
86        nothing to do */
87     if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
88     {
89         IntEngLeave(&EnterLeaveSource);
90         return TRUE;
91     }
92 
93     if (!IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &OutputObj))
94     {
95         IntEngLeave(&EnterLeaveSource);
96         return FALSE;
97     }
98 
99     OutputRect.left = DestRect->left + Translate.x;
100     OutputRect.right = DestRect->right + Translate.x;
101     OutputRect.top = DestRect->top + Translate.y;
102     OutputRect.bottom = DestRect->bottom + Translate.y;
103 
104     ClippingType = (Clip ? Clip->iDComplexity : DC_TRIVIAL);
105 
106     DstHeight = OutputRect.bottom - OutputRect.top;
107     DstWidth = OutputRect.right - OutputRect.left;
108     SrcHeight = InputRect.bottom - InputRect.top;
109     SrcWidth = InputRect.right - InputRect.left;
110     switch (ClippingType)
111     {
112         case DC_TRIVIAL:
113         {
114             Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt(
115                       OutputObj, InputObj, &OutputRect, &InputRect, ColorTranslation, iTransColor);
116             break;
117         }
118         case DC_RECT:
119         {
120             RECTL ClipRect, CombinedRect;
121             RECTL InputToCombinedRect;
122 
123             ClipRect.left = Clip->rclBounds.left + Translate.x;
124             ClipRect.right = Clip->rclBounds.right + Translate.x;
125             ClipRect.top = Clip->rclBounds.top + Translate.y;
126             ClipRect.bottom = Clip->rclBounds.bottom + Translate.y;
127             if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
128             {
129                 InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight;
130                 InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight;
131                 InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth;
132                 InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth;
133                 Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt(
134                           OutputObj, InputObj, &CombinedRect, &InputToCombinedRect, ColorTranslation, iTransColor);
135             }
136             break;
137         }
138         case DC_COMPLEX:
139         {
140             ULONG Direction, i;
141             RECT_ENUM RectEnum;
142             BOOL EnumMore;
143 
144             if (OutputObj == InputObj)
145             {
146                 if (OutputRect.top < InputRect.top)
147                 {
148                     Direction = OutputRect.left < (InputRect.left ? CD_RIGHTDOWN : CD_LEFTDOWN);
149                 }
150                 else
151                 {
152                     Direction = OutputRect.left < (InputRect.left ? CD_RIGHTUP : CD_LEFTUP);
153                 }
154             }
155             else
156             {
157                 Direction = CD_ANY;
158             }
159 
160             CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, Direction, 0);
161             do
162             {
163                 EnumMore = CLIPOBJ_bEnum(Clip, sizeof(RectEnum), (PVOID)&RectEnum);
164                 for (i = 0; i < RectEnum.c; i++)
165                 {
166                     RECTL ClipRect, CombinedRect;
167                     RECTL InputToCombinedRect;
168 
169                     ClipRect.left = RectEnum.arcl[i].left + Translate.x;
170                     ClipRect.right = RectEnum.arcl[i].right + Translate.x;
171                     ClipRect.top = RectEnum.arcl[i].top + Translate.y;
172                     ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
173                     if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
174                     {
175                         InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight;
176                         InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight;
177                         InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth;
178                         InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth;
179 
180                         Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt(
181                                   OutputObj, InputObj, &CombinedRect, &InputToCombinedRect, ColorTranslation, iTransColor);
182                         if (!Ret)
183                         {
184                             break;
185                         }
186                     }
187                 }
188             }
189             while (EnumMore && Ret);
190             break;
191         }
192         default:
193         {
194             Ret = FALSE;
195             break;
196         }
197     }
198 
199     IntEngLeave(&EnterLeaveDest);
200     IntEngLeave(&EnterLeaveSource);
201 
202     return Ret;
203 }
204 
205 BOOL
206 FASTCALL
IntEngTransparentBlt(SURFOBJ * psoDest,SURFOBJ * psoSource,CLIPOBJ * Clip,XLATEOBJ * ColorTranslation,PRECTL DestRect,PRECTL SourceRect,ULONG iTransColor,ULONG Reserved)207 IntEngTransparentBlt(
208     SURFOBJ *psoDest,
209     SURFOBJ *psoSource,
210     CLIPOBJ *Clip,
211     XLATEOBJ *ColorTranslation,
212     PRECTL DestRect,
213     PRECTL SourceRect,
214     ULONG iTransColor,
215     ULONG Reserved)
216 {
217     BOOL Ret;
218     RECTL OutputRect, InputClippedRect;
219     SURFACE *psurfDest;
220     SURFACE *psurfSource;
221     RECTL InputRect;
222     LONG InputClWidth, InputClHeight, InputWidth, InputHeight;
223 
224     ASSERT(psoDest);
225     ASSERT(psoSource);
226     ASSERT(DestRect);
227 
228     psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
229     psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
230 
231     ASSERT(psurfDest);
232     ASSERT(psurfSource);
233 
234     /* If no clip object is given, use trivial one */
235     if (!Clip) Clip = (CLIPOBJ *)&gxcoTrivial;
236 
237     InputClippedRect = *DestRect;
238     if (InputClippedRect.right < InputClippedRect.left)
239     {
240         InputClippedRect.left = DestRect->right;
241         InputClippedRect.right = DestRect->left;
242     }
243     if (InputClippedRect.bottom < InputClippedRect.top)
244     {
245         InputClippedRect.top = DestRect->bottom;
246         InputClippedRect.bottom = DestRect->top;
247     }
248 
249     InputRect = *SourceRect;
250     /* Clip against the bounds of the clipping region so we won't try to write
251      * outside the surface */
252     if (Clip->iDComplexity != DC_TRIVIAL)
253     {
254         if (!RECTL_bIntersectRect(&OutputRect, &InputClippedRect, &Clip->rclBounds))
255         {
256             return TRUE;
257         }
258         /* Update source rect */
259         InputClWidth = InputClippedRect.right - InputClippedRect.left;
260         InputClHeight = InputClippedRect.bottom - InputClippedRect.top;
261         InputWidth = InputRect.right - InputRect.left;
262         InputHeight = InputRect.bottom - InputRect.top;
263 
264         InputRect.left += (InputWidth * (OutputRect.left - InputClippedRect.left)) / InputClWidth;
265         InputRect.right -= (InputWidth * (InputClippedRect.right - OutputRect.right)) / InputClWidth;
266         InputRect.top += (InputHeight * (OutputRect.top - InputClippedRect.top)) / InputClHeight;
267         InputRect.bottom -= (InputHeight * (InputClippedRect.bottom - OutputRect.bottom)) / InputClHeight;
268     }
269     else
270     {
271         OutputRect = InputClippedRect;
272     }
273 
274     if (psurfDest->flags & HOOK_TRANSPARENTBLT)
275     {
276         Ret = GDIDEVFUNCS(psoDest).TransparentBlt(psoDest,
277                                                   psoSource,
278                                                   Clip,
279                                                   ColorTranslation,
280                                                   &OutputRect,
281                                                   &InputRect,
282                                                   iTransColor,
283                                                   Reserved);
284     }
285     else
286         Ret = FALSE;
287 
288     if (!Ret)
289     {
290         Ret = EngTransparentBlt(psoDest,
291                                 psoSource,
292                                 Clip,
293                                 ColorTranslation,
294                                 &OutputRect,
295                                 &InputRect,
296                                 iTransColor,
297                                 Reserved);
298     }
299 
300     return Ret;
301 }
302 
303 /* EOF */
304