43708da5dbc9e02228a9b76d41ce39c68db7e483
[reactos.git] / reactos / win32ss / gdi / eng / transblt.c
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
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
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 = &gxcoTrivial.ClipObj;
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 */