Merge from amd64-branch:
[reactos.git] / reactos / subsystems / win32 / win32k / eng / transblt.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI TransparentBlt Function
24 * FILE: subsys/win32k/eng/transblt.c
25 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 4/6/2004: Created
28 */
29
30 #include <w32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35 BOOL APIENTRY
36 EngTransparentBlt(SURFOBJ *psoDest,
37 SURFOBJ *psoSource,
38 CLIPOBJ *Clip,
39 XLATEOBJ *ColorTranslation,
40 PRECTL DestRect,
41 PRECTL SourceRect,
42 ULONG iTransColor,
43 ULONG Reserved)
44 {
45 BOOL Ret = TRUE;
46 BYTE ClippingType;
47 INTENG_ENTER_LEAVE EnterLeaveSource, EnterLeaveDest;
48 SURFOBJ *InputObj, *OutputObj;
49 RECTL OutputRect, InputRect;
50 POINTL Translate;
51
52 LONG DstHeight;
53 LONG DstWidth;
54 LONG SrcHeight;
55 LONG SrcWidth;
56
57 InputRect = *SourceRect;
58
59 if(!IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, &Translate, &InputObj))
60 {
61 return FALSE;
62 }
63 InputRect.left += Translate.x;
64 InputRect.right += Translate.x;
65 InputRect.top += Translate.y;
66 InputRect.bottom += Translate.y;
67
68 OutputRect = *DestRect;
69 if (OutputRect.right < OutputRect.left)
70 {
71 OutputRect.left = DestRect->right;
72 OutputRect.right = DestRect->left;
73 }
74 if (OutputRect.bottom < OutputRect.top)
75 {
76 OutputRect.top = DestRect->bottom;
77 OutputRect.bottom = DestRect->top;
78 }
79
80 if(Clip)
81 {
82 if(OutputRect.left < Clip->rclBounds.left)
83 {
84 InputRect.left += Clip->rclBounds.left - OutputRect.left;
85 OutputRect.left = Clip->rclBounds.left;
86 }
87 if(Clip->rclBounds.right < OutputRect.right)
88 {
89 InputRect.right -= OutputRect.right - Clip->rclBounds.right;
90 OutputRect.right = Clip->rclBounds.right;
91 }
92 if(OutputRect.top < Clip->rclBounds.top)
93 {
94 InputRect.top += Clip->rclBounds.top - OutputRect.top;
95 OutputRect.top = Clip->rclBounds.top;
96 }
97 if(Clip->rclBounds.bottom < OutputRect.bottom)
98 {
99 InputRect.bottom -= OutputRect.bottom - Clip->rclBounds.bottom;
100 OutputRect.bottom = Clip->rclBounds.bottom;
101 }
102 }
103
104 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
105 nothing to do */
106 if(OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
107 {
108 IntEngLeave(&EnterLeaveSource);
109 return TRUE;
110 }
111
112 if(!IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &OutputObj))
113 {
114 IntEngLeave(&EnterLeaveSource);
115 return FALSE;
116 }
117
118 OutputRect.left = DestRect->left + Translate.x;
119 OutputRect.right = DestRect->right + Translate.x;
120 OutputRect.top = DestRect->top + Translate.y;
121 OutputRect.bottom = DestRect->bottom + Translate.y;
122
123 ClippingType = (Clip ? Clip->iDComplexity : DC_TRIVIAL);
124
125 DstHeight = OutputRect.bottom - OutputRect.top;
126 DstWidth = OutputRect.right - OutputRect.left;
127 SrcHeight = InputRect.bottom - InputRect.top;
128 SrcWidth = InputRect.right - InputRect.left;
129 switch(ClippingType)
130 {
131 case DC_TRIVIAL:
132 {
133 Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt(
134 OutputObj, InputObj, &OutputRect, &InputRect, ColorTranslation, iTransColor);
135 break;
136 }
137 case DC_RECT:
138 {
139 RECTL ClipRect, CombinedRect;
140 RECTL InputToCombinedRect;
141
142 ClipRect.left = Clip->rclBounds.left + Translate.x;
143 ClipRect.right = Clip->rclBounds.right + Translate.x;
144 ClipRect.top = Clip->rclBounds.top + Translate.y;
145 ClipRect.bottom = Clip->rclBounds.bottom + Translate.y;
146 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
147 {
148 InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight;
149 InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight;
150 InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth;
151 InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth;
152 Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt(
153 OutputObj, InputObj, &CombinedRect, &InputToCombinedRect, ColorTranslation, iTransColor);
154 }
155 break;
156 }
157 case DC_COMPLEX:
158 {
159 ULONG Direction, i;
160 RECT_ENUM RectEnum;
161 BOOL EnumMore;
162
163 if(OutputObj == InputObj)
164 {
165 if(OutputRect.top < InputRect.top)
166 {
167 Direction = OutputRect.left < (InputRect.left ? CD_RIGHTDOWN : CD_LEFTDOWN);
168 }
169 else
170 {
171 Direction = OutputRect.left < (InputRect.left ? CD_RIGHTUP : CD_LEFTUP);
172 }
173 }
174 else
175 {
176 Direction = CD_ANY;
177 }
178
179 CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, Direction, 0);
180 do
181 {
182 EnumMore = CLIPOBJ_bEnum(Clip, sizeof(RectEnum), (PVOID)&RectEnum);
183 for (i = 0; i < RectEnum.c; i++)
184 {
185 RECTL ClipRect, CombinedRect;
186 RECTL InputToCombinedRect;
187
188 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
189 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
190 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
191 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
192 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
193 {
194 InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight;
195 InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight;
196 InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth;
197 InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth;
198
199 Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt(
200 OutputObj, InputObj, &CombinedRect, &InputToCombinedRect, ColorTranslation, iTransColor);
201 if(!Ret)
202 {
203 break;
204 }
205 }
206 }
207 } while(EnumMore && Ret);
208 break;
209 }
210 default:
211 {
212 Ret = FALSE;
213 break;
214 }
215 }
216
217 IntEngLeave(&EnterLeaveDest);
218 IntEngLeave(&EnterLeaveSource);
219
220 return Ret;
221 }
222
223 BOOL FASTCALL
224 IntEngTransparentBlt(SURFOBJ *psoDest,
225 SURFOBJ *psoSource,
226 CLIPOBJ *Clip,
227 XLATEOBJ *ColorTranslation,
228 PRECTL DestRect,
229 PRECTL SourceRect,
230 ULONG iTransColor,
231 ULONG Reserved)
232 {
233 BOOL Ret;
234 RECTL OutputRect, InputClippedRect;
235 SURFACE *psurfDest;
236 SURFACE *psurfSource;
237 RECTL InputRect;
238 LONG InputClWidth, InputClHeight, InputWidth, InputHeight;
239
240 ASSERT(psoDest);
241 ASSERT(psoSource);
242 ASSERT(DestRect);
243
244 psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
245 psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj);
246
247 ASSERT(psurfDest);
248 ASSERT(psurfSource);
249
250 InputClippedRect = *DestRect;
251 if(InputClippedRect.right < InputClippedRect.left)
252 {
253 InputClippedRect.left = DestRect->right;
254 InputClippedRect.right = DestRect->left;
255 }
256 if(InputClippedRect.bottom < InputClippedRect.top)
257 {
258 InputClippedRect.top = DestRect->bottom;
259 InputClippedRect.bottom = DestRect->top;
260 }
261
262 InputRect = *SourceRect;
263 /* Clip against the bounds of the clipping region so we won't try to write
264 * outside the surface */
265 if(Clip)
266 {
267 if(!RECTL_bIntersectRect(&OutputRect, &InputClippedRect, &Clip->rclBounds))
268 {
269 return TRUE;
270 }
271 /* Update source rect */
272 InputClWidth = InputClippedRect.right - InputClippedRect.left;
273 InputClHeight = InputClippedRect.bottom - InputClippedRect.top;
274 InputWidth = InputRect.right - InputRect.left;
275 InputHeight = InputRect.bottom - InputRect.top;
276
277 InputRect.left += (InputWidth * (OutputRect.left - InputClippedRect.left)) / InputClWidth;
278 InputRect.right -= (InputWidth * (InputClippedRect.right - OutputRect.right)) / InputClWidth;
279 InputRect.top += (InputHeight * (OutputRect.top - InputClippedRect.top)) / InputClHeight;
280 InputRect.bottom -= (InputHeight * (InputClippedRect.bottom - OutputRect.bottom)) / InputClHeight;
281 }
282 else
283 {
284 OutputRect = InputClippedRect;
285 }
286
287 if(psoSource != psoDest)
288 {
289 SURFACE_LockBitmapBits(psurfSource);
290 MouseSafetyOnDrawStart(psoSource, InputRect.left, InputRect.top,
291 InputRect.right, InputRect.bottom);
292 }
293 SURFACE_LockBitmapBits(psurfDest);
294 MouseSafetyOnDrawStart(psoDest, OutputRect.left, OutputRect.top,
295 OutputRect.right, OutputRect.bottom);
296
297 if(psurfDest->flHooks & HOOK_TRANSPARENTBLT)
298 {
299 Ret = GDIDEVFUNCS(psoDest).TransparentBlt(
300 psoDest, psoSource, Clip, ColorTranslation, &OutputRect,
301 &InputRect, iTransColor, Reserved);
302 }
303 else
304 Ret = FALSE;
305
306 if(!Ret)
307 {
308 Ret = EngTransparentBlt(psoDest, psoSource, Clip, ColorTranslation,
309 &OutputRect, &InputRect, iTransColor, Reserved);
310 }
311
312 MouseSafetyOnDrawEnd(psoDest);
313 SURFACE_UnlockBitmapBits(psurfDest);
314 if(psoSource != psoDest)
315 {
316 MouseSafetyOnDrawEnd(psoSource);
317 SURFACE_UnlockBitmapBits(psurfSource);
318 }
319
320 return Ret;
321 }
322
323 /* EOF */