Compensate BrushOrigin for translation
[reactos.git] / reactos / subsys / win32k / eng / bitblt.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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: bitblt.c,v 1.49 2004/04/09 22:13:26 gvg Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI BitBlt Functions
24 * FILE: subsys/win32k/eng/bitblt.c
25 * PROGRAMER: Jason Filby
26 * REVISION HISTORY:
27 * 2/10/1999: Created
28 */
29
30 #include <ddk/winddi.h>
31 #include <ddk/ntddk.h>
32 #include <ddk/ntddmou.h>
33 #include <ntos/minmax.h>
34 #include "brush.h"
35 #include "clip.h"
36 #include "objects.h"
37 #include "../dib/dib.h"
38 #include "misc.h"
39 #include <include/mouse.h>
40 #include <include/object.h>
41 #include <include/dib.h>
42 #include <include/surface.h>
43 #include <include/eng.h>
44 #include <include/inteng.h>
45
46 #define NDEBUG
47 #include <win32k/debug1.h>
48
49 typedef BOOLEAN STDCALL (*PBLTRECTFUNC)(SURFOBJ* OutputObj,
50 SURFGDI* OutputGDI,
51 SURFOBJ* InputObj,
52 SURFGDI* InputGDI,
53 SURFOBJ* Mask,
54 XLATEOBJ* ColorTranslation,
55 RECTL* OutputRect,
56 POINTL* InputPoint,
57 POINTL* MaskOrigin,
58 BRUSHOBJ* Brush,
59 POINTL* BrushOrigin,
60 ROP4 Rop4);
61 typedef BOOLEAN STDCALL (*PSTRETCHRECTFUNC)(SURFOBJ* OutputObj,
62 SURFGDI* OutputGDI,
63 SURFOBJ* InputObj,
64 SURFGDI* InputGDI,
65 SURFOBJ* Mask,
66 XLATEOBJ* ColorTranslation,
67 RECTL* OutputRect,
68 RECTL* InputRect,
69 POINTL* MaskOrigin,
70 POINTL* BrushOrigin,
71 ULONG Mode);
72
73 BOOL STDCALL EngIntersectRect(RECTL* prcDst, RECTL* prcSrc1, RECTL* prcSrc2)
74 {
75 static const RECTL rclEmpty = { 0, 0, 0, 0 };
76
77 prcDst->left = max(prcSrc1->left, prcSrc2->left);
78 prcDst->right = min(prcSrc1->right, prcSrc2->right);
79
80 if (prcDst->left < prcDst->right)
81 {
82 prcDst->top = max(prcSrc1->top, prcSrc2->top);
83 prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
84
85 if (prcDst->top < prcDst->bottom)
86 {
87 return TRUE;
88 }
89 }
90
91 *prcDst = rclEmpty;
92
93 return FALSE;
94 }
95
96 static BOOLEAN STDCALL
97 BltMask(SURFOBJ* Dest,
98 SURFGDI* DestGDI,
99 SURFOBJ* Source,
100 SURFGDI* SourceGDI,
101 SURFOBJ* Mask,
102 XLATEOBJ* ColorTranslation,
103 RECTL* DestRect,
104 POINTL* SourcePoint,
105 POINTL* MaskPoint,
106 BRUSHOBJ* Brush,
107 POINTL* BrushPoint,
108 ROP4 Rop4)
109 {
110 LONG i, j, dx, dy, c8;
111 BYTE *tMask, *lMask;
112 static BYTE maskbit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
113 /* Pattern brushes */
114 PGDIBRUSHOBJ GdiBrush;
115 HBITMAP PatternSurface = NULL;
116 SURFOBJ *PatternObj;
117 ULONG PatternWidth, PatternHeight, PatternY;
118
119 if (Mask == NULL)
120 {
121 return FALSE;
122 }
123
124 dx = DestRect->right - DestRect->left;
125 dy = DestRect->bottom - DestRect->top;
126
127 if (Brush->iSolidColor == 0xFFFFFFFF)
128 {
129 PBITMAPOBJ PatternBitmap;
130
131 GdiBrush = CONTAINING_RECORD(
132 Brush,
133 GDIBRUSHOBJ,
134 BrushObject);
135
136 PatternBitmap = BITMAPOBJ_LockBitmap(GdiBrush->hbmPattern);
137 PatternSurface = BitmapToSurf(PatternBitmap, Dest->hdev);
138 BITMAPOBJ_UnlockBitmap(GdiBrush->hbmPattern);
139
140 PatternObj = (SURFOBJ*)AccessUserObject((ULONG)PatternSurface);
141 PatternWidth = PatternObj->sizlBitmap.cx;
142 PatternHeight = PatternObj->sizlBitmap.cy;
143 }
144
145 tMask = Mask->pvScan0 + SourcePoint->y * Mask->lDelta + (SourcePoint->x >> 3);
146 for (j = 0; j < dy; j++)
147 {
148 lMask = tMask;
149 c8 = SourcePoint->x & 0x07;
150
151 if(PatternSurface)
152 PatternY = (DestRect->top + j) % PatternHeight;
153
154 for (i = 0; i < dx; i++)
155 {
156 if (0 != (*lMask & maskbit[c8]))
157 {
158 if (PatternSurface == NULL)
159 {
160 DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
161 }
162 else
163 {
164 DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j,
165 DIB_1BPP_GetPixel(PatternObj, (DestRect->left + i) % PatternWidth, PatternY) ? GdiBrush->crFore : GdiBrush->crBack);
166 }
167 }
168 c8++;
169 if (8 == c8)
170 {
171 lMask++;
172 c8 = 0;
173 }
174 }
175 tMask += Mask->lDelta;
176 }
177
178 if (PatternSurface != NULL)
179 EngDeleteSurface((HSURF)PatternSurface);
180
181 return TRUE;
182 }
183
184 static BOOLEAN STDCALL
185 BltPatCopy(SURFOBJ* Dest,
186 SURFGDI* DestGDI,
187 SURFOBJ* Source,
188 SURFGDI* SourceGDI,
189 SURFOBJ* Mask,
190 XLATEOBJ* ColorTranslation,
191 RECTL* DestRect,
192 POINTL* SourcePoint,
193 POINTL* MaskPoint,
194 BRUSHOBJ* Brush,
195 POINTL* BrushPoint,
196 ROP4 Rop4)
197 {
198 // These functions are assigned if we're working with a DIB
199 // The assigned functions depend on the bitsPerPixel of the DIB
200 LONG y;
201 ULONG LineWidth;
202
203 LineWidth = DestRect->right - DestRect->left;
204 for (y = DestRect->top; y < DestRect->bottom; y++)
205 {
206 DestGDI->DIB_HLine(Dest, DestRect->left, DestRect->right, y, Brush->iSolidColor);
207 }
208
209 return TRUE;
210 }
211
212 static BOOLEAN STDCALL
213 CallDibBitBlt(SURFOBJ* OutputObj,
214 SURFGDI* OutputGDI,
215 SURFOBJ* InputObj,
216 SURFGDI* InputGDI,
217 SURFOBJ* Mask,
218 XLATEOBJ* ColorTranslation,
219 RECTL* OutputRect,
220 POINTL* InputPoint,
221 POINTL* MaskOrigin,
222 BRUSHOBJ* Brush,
223 POINTL* BrushOrigin,
224 ROP4 Rop4)
225 {
226 POINTL RealBrushOrigin;
227 if (BrushOrigin == NULL)
228 {
229 RealBrushOrigin.x = RealBrushOrigin.y = 0;
230 }
231 else
232 {
233 RealBrushOrigin = *BrushOrigin;
234 }
235 return OutputGDI->DIB_BitBlt(OutputObj, InputObj, OutputGDI, InputGDI, OutputRect, InputPoint, Brush, RealBrushOrigin, ColorTranslation, Rop4);
236 }
237
238 INT abs(INT nm);
239
240 /*
241 * @implemented
242 */
243 BOOL STDCALL
244 EngBitBlt(SURFOBJ *DestObj,
245 SURFOBJ *SourceObj,
246 SURFOBJ *Mask,
247 CLIPOBJ *ClipRegion,
248 XLATEOBJ *ColorTranslation,
249 RECTL *DestRect,
250 POINTL *SourcePoint,
251 POINTL *MaskOrigin,
252 BRUSHOBJ *Brush,
253 POINTL *BrushOrigin,
254 ROP4 Rop4)
255 {
256 BYTE clippingType;
257 RECTL CombinedRect;
258 RECT_ENUM RectEnum;
259 BOOL EnumMore;
260 SURFGDI* OutputGDI;
261 SURFGDI* InputGDI;
262 POINTL InputPoint;
263 RECTL InputRect;
264 RECTL OutputRect;
265 POINTL Translate;
266 INTENG_ENTER_LEAVE EnterLeaveSource;
267 INTENG_ENTER_LEAVE EnterLeaveDest;
268 SURFOBJ* InputObj;
269 SURFOBJ* OutputObj;
270 PBLTRECTFUNC BltRectFunc;
271 BOOLEAN Ret;
272 RECTL ClipRect;
273 unsigned i;
274 POINTL Pt;
275 ULONG Direction;
276 BOOL UsesSource;
277 BOOL UsesPattern;
278 POINTL AdjustedBrushOrigin;
279
280 UsesSource = ((Rop4 & 0xCC0000) >> 2) != (Rop4 & 0x330000);
281 UsesPattern = ((Rop4 & 0xF00000) >> 4) != (Rop4 & 0x0F0000);
282 if (ROP_NOOP == Rop4)
283 {
284 /* Copy destination onto itself: nop */
285 return TRUE;
286 }
287
288 if (NULL != SourcePoint)
289 {
290 InputRect.left = SourcePoint->x;
291 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
292 InputRect.top = SourcePoint->y;
293 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
294 }
295 else
296 {
297 InputRect.left = 0;
298 InputRect.right = DestRect->right - DestRect->left;
299 InputRect.top = 0;
300 InputRect.bottom = DestRect->bottom - DestRect->top;
301 }
302
303 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
304 {
305 return FALSE;
306 }
307
308 if (NULL != SourcePoint)
309 {
310 InputPoint.x = SourcePoint->x + Translate.x;
311 InputPoint.y = SourcePoint->y + Translate.y;
312 }
313 else
314 {
315 InputPoint.x = 0;
316 InputPoint.y = 0;
317 }
318
319 if (NULL != InputObj)
320 {
321 InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
322 }
323 else
324 {
325 InputGDI = NULL;
326 }
327
328 OutputRect = *DestRect;
329 if (NULL != ClipRegion)
330 {
331 if (OutputRect.left < ClipRegion->rclBounds.left)
332 {
333 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
334 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
335 OutputRect.left = ClipRegion->rclBounds.left;
336 }
337 if (ClipRegion->rclBounds.right < OutputRect.right)
338 {
339 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
340 OutputRect.right = ClipRegion->rclBounds.right;
341 }
342 if (OutputRect.top < ClipRegion->rclBounds.top)
343 {
344 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
345 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
346 OutputRect.top = ClipRegion->rclBounds.top;
347 }
348 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
349 {
350 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
351 OutputRect.bottom = ClipRegion->rclBounds.bottom;
352 }
353 }
354
355 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
356 nothing to do */
357 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
358 {
359 IntEngLeave(&EnterLeaveSource);
360 return TRUE;
361 }
362
363 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
364 {
365 IntEngLeave(&EnterLeaveSource);
366 return FALSE;
367 }
368
369 OutputRect.left = DestRect->left + Translate.x;
370 OutputRect.right = DestRect->right + Translate.x;
371 OutputRect.top = DestRect->top + Translate.y;
372 OutputRect.bottom = DestRect->bottom + Translate.y;
373
374 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
375 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
376
377 if (NULL != OutputObj)
378 {
379 OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
380 }
381
382 // Determine clipping type
383 if (ClipRegion == (CLIPOBJ *) NULL)
384 {
385 clippingType = DC_TRIVIAL;
386 } else {
387 clippingType = ClipRegion->iDComplexity;
388 }
389
390 if (0xaacc == Rop4)
391 {
392 BltRectFunc = BltMask;
393 }
394 else if (PATCOPY == Rop4)
395 {
396 #if 0
397 BltRectFunc = BltPatCopy;
398 #else
399 if (Brush->iSolidColor == 0xFFFFFFFF)
400 BltRectFunc = CallDibBitBlt;
401 else
402 BltRectFunc = BltPatCopy;
403 #endif
404 }
405 else
406 {
407 BltRectFunc = CallDibBitBlt;
408 }
409
410
411 switch(clippingType)
412 {
413 case DC_TRIVIAL:
414 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
415 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4);
416 break;
417 case DC_RECT:
418 // Clip the blt to the clip rectangle
419 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
420 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
421 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
422 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
423 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
424 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
425 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
426 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
427 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4);
428 break;
429 case DC_COMPLEX:
430 Ret = TRUE;
431 if (OutputObj == InputObj)
432 {
433 if (OutputRect.top < InputPoint.y)
434 {
435 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
436 }
437 else
438 {
439 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
440 }
441 }
442 else
443 {
444 Direction = CD_ANY;
445 }
446 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
447 do
448 {
449 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
450
451 for (i = 0; i < RectEnum.c; i++)
452 {
453 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
454 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
455 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
456 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
457 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
458 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
459 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
460 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
461 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4) &&
462 Ret;
463 }
464 }
465 while(EnumMore);
466 break;
467 }
468
469
470 IntEngLeave(&EnterLeaveDest);
471 IntEngLeave(&EnterLeaveSource);
472
473 return Ret;
474 }
475
476 BOOL STDCALL
477 IntEngBitBlt(SURFOBJ *DestObj,
478 SURFOBJ *SourceObj,
479 SURFOBJ *Mask,
480 CLIPOBJ *ClipRegion,
481 XLATEOBJ *ColorTranslation,
482 RECTL *DestRect,
483 POINTL *SourcePoint,
484 POINTL *MaskOrigin,
485 BRUSHOBJ *Brush,
486 POINTL *BrushOrigin,
487 ROP4 Rop4)
488 {
489 BOOLEAN ret;
490 SURFGDI *DestGDI;
491 SURFGDI *SourceGDI;
492 RECTL InputClippedRect;
493 RECTL OutputRect;
494 POINTL InputPoint;
495 BOOLEAN UsesSource;
496
497 InputClippedRect = *DestRect;
498 if (InputClippedRect.right < InputClippedRect.left)
499 {
500 InputClippedRect.left = DestRect->right;
501 InputClippedRect.right = DestRect->left;
502 }
503 if (InputClippedRect.bottom < InputClippedRect.top)
504 {
505 InputClippedRect.top = DestRect->bottom;
506 InputClippedRect.bottom = DestRect->top;
507 }
508 UsesSource = ((Rop4 & 0xCC0000) >> 2) != (Rop4 & 0x330000);
509 if (UsesSource)
510 {
511 if (NULL == SourcePoint || NULL == SourceObj)
512 {
513 return FALSE;
514 }
515 InputPoint = *SourcePoint;
516 SourceGDI = (SURFGDI*) AccessInternalObjectFromUserObject(SourceObj);
517
518 /* Make sure we don't try to copy anything outside the valid source region */
519 if (InputPoint.x < 0)
520 {
521 InputClippedRect.left -= InputPoint.x;
522 InputPoint.x = 0;
523 }
524 if (InputPoint.y < 0)
525 {
526 InputClippedRect.top -= InputPoint.y;
527 InputPoint.y = 0;
528 }
529 if (SourceObj->sizlBitmap.cx < InputPoint.x + InputClippedRect.right - InputClippedRect.left)
530 {
531 InputClippedRect.right = InputClippedRect.left + SourceObj->sizlBitmap.cx - InputPoint.x;
532 }
533 if (SourceObj->sizlBitmap.cy < InputPoint.y + InputClippedRect.bottom - InputClippedRect.top)
534 {
535 InputClippedRect.bottom = InputClippedRect.top + SourceObj->sizlBitmap.cy - InputPoint.y;
536 }
537
538 if (InputClippedRect.right < InputClippedRect.left ||
539 InputClippedRect.bottom < InputClippedRect.top)
540 {
541 /* Everything clipped away, nothing to do */
542 return TRUE;
543 }
544 }
545
546 /* Clip against the bounds of the clipping region so we won't try to write
547 * outside the surface */
548 if (NULL != ClipRegion)
549 {
550 if (! EngIntersectRect(&OutputRect, &InputClippedRect, &ClipRegion->rclBounds))
551 {
552 return TRUE;
553 }
554 InputPoint.x += OutputRect.left - DestRect->left;
555 InputPoint.y += OutputRect.top - DestRect->top;
556 }
557 else
558 {
559 OutputRect = InputClippedRect;
560 }
561
562 if (UsesSource)
563 {
564 MouseSafetyOnDrawStart(SourceObj, SourceGDI, InputPoint.x, InputPoint.y,
565 (InputPoint.x + abs(DestRect->right - DestRect->left)),
566 (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
567 }
568
569 /* No success yet */
570 ret = FALSE;
571 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
572 MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
573 OutputRect.right, OutputRect.bottom);
574
575 /* Call the driver's DrvBitBlt if available */
576 if (NULL != DestGDI->BitBlt)
577 {
578 IntLockGDIDriver(DestGDI);
579 ret = DestGDI->BitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
580 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
581 Rop4);
582 IntUnLockGDIDriver(DestGDI);
583 }
584
585 if (! ret)
586 {
587 IntLockGDIDriver(DestGDI);
588 ret = EngBitBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
589 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
590 Rop4);
591 IntUnLockGDIDriver(DestGDI);
592 }
593
594 MouseSafetyOnDrawEnd(DestObj, DestGDI);
595 if (UsesSource)
596 {
597 MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
598 }
599
600 return ret;
601 }
602
603 static BOOLEAN STDCALL
604 CallDibStretchBlt(SURFOBJ* OutputObj,
605 SURFGDI* OutputGDI,
606 SURFOBJ* InputObj,
607 SURFGDI* InputGDI,
608 SURFOBJ* Mask,
609 XLATEOBJ* ColorTranslation,
610 RECTL* OutputRect,
611 RECTL* InputRect,
612 POINTL* MaskOrigin,
613 POINTL* BrushOrigin,
614 ULONG Mode)
615 {
616 POINTL RealBrushOrigin;
617 if (BrushOrigin == NULL)
618 {
619 RealBrushOrigin.x = RealBrushOrigin.y = 0;
620 }
621 else
622 {
623 RealBrushOrigin = *BrushOrigin;
624 }
625 return OutputGDI->DIB_StretchBlt(OutputObj, InputObj, OutputGDI, InputGDI, OutputRect, InputRect, MaskOrigin, RealBrushOrigin, ColorTranslation, Mode);
626 }
627
628
629 BOOL
630 STDCALL
631 EngStretchBlt(
632 IN SURFOBJ *DestObj,
633 IN SURFOBJ *SourceObj,
634 IN SURFOBJ *Mask,
635 IN CLIPOBJ *ClipRegion,
636 IN XLATEOBJ *ColorTranslation,
637 IN COLORADJUSTMENT *pca,
638 IN POINTL *BrushOrigin,
639 IN RECTL *prclDest,
640 IN RECTL *prclSrc,
641 IN POINTL *MaskOrigin,
642 IN ULONG Mode
643 )
644 {
645 // www.osr.com/ddk/graphics/gdifncs_0bs7.htm
646
647 BYTE clippingType;
648 RECTL CombinedRect;
649 // RECT_ENUM RectEnum;
650 // BOOL EnumMore;
651 SURFGDI* OutputGDI;
652 SURFGDI* InputGDI;
653 POINTL InputPoint;
654 RECTL InputRect;
655 RECTL OutputRect;
656 POINTL Translate;
657 INTENG_ENTER_LEAVE EnterLeaveSource;
658 INTENG_ENTER_LEAVE EnterLeaveDest;
659 SURFOBJ* InputObj;
660 SURFOBJ* OutputObj;
661 PSTRETCHRECTFUNC BltRectFunc;
662 BOOLEAN Ret;
663 RECTL ClipRect;
664 // unsigned i;
665 POINTL Pt;
666 // ULONG Direction;
667 POINTL AdjustedBrushOrigin;
668
669 InputRect.left = prclSrc->left;
670 InputRect.right = prclSrc->right;
671 InputRect.top = prclSrc->top;
672 InputRect.bottom = prclSrc->bottom;
673
674 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
675 {
676 return FALSE;
677 }
678
679 InputPoint.x = InputRect.left + Translate.x;
680 InputPoint.y = InputRect.top + Translate.y;
681
682 if (NULL != InputObj)
683 {
684 InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
685 }
686 else
687 {
688 InputGDI = NULL;
689 }
690
691 OutputRect = *prclDest;
692 if (NULL != ClipRegion)
693 {
694 if (OutputRect.left < ClipRegion->rclBounds.left)
695 {
696 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
697 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
698 OutputRect.left = ClipRegion->rclBounds.left;
699 }
700 if (ClipRegion->rclBounds.right < OutputRect.right)
701 {
702 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
703 OutputRect.right = ClipRegion->rclBounds.right;
704 }
705 if (OutputRect.top < ClipRegion->rclBounds.top)
706 {
707 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
708 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
709 OutputRect.top = ClipRegion->rclBounds.top;
710 }
711 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
712 {
713 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
714 OutputRect.bottom = ClipRegion->rclBounds.bottom;
715 }
716 }
717
718 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
719 nothing to do */
720 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
721 {
722 IntEngLeave(&EnterLeaveSource);
723 return TRUE;
724 }
725
726 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
727 {
728 IntEngLeave(&EnterLeaveSource);
729 return FALSE;
730 }
731
732 OutputRect.left = prclDest->left + Translate.x;
733 OutputRect.right = prclDest->right + Translate.x;
734 OutputRect.top = prclDest->top + Translate.y;
735 OutputRect.bottom = prclDest->bottom + Translate.y;
736
737 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
738 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
739
740 if (NULL != OutputObj)
741 {
742 OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
743 }
744
745 // Determine clipping type
746 if (ClipRegion == (CLIPOBJ *) NULL)
747 {
748 clippingType = DC_TRIVIAL;
749 } else {
750 clippingType = ClipRegion->iDComplexity;
751 }
752
753 if (Mask != NULL)//(0xaacc == Rop4)
754 {
755 //BltRectFunc = BltMask;
756 DPRINT("EngStretchBlt isn't capable of handling mask yet.\n");
757 IntEngLeave(&EnterLeaveDest);
758 IntEngLeave(&EnterLeaveSource);
759
760 return FALSE;
761 }
762 else
763 {
764 BltRectFunc = CallDibStretchBlt;
765 }
766
767
768 switch(clippingType)
769 {
770 case DC_TRIVIAL:
771 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
772 &OutputRect, &InputRect, MaskOrigin, &AdjustedBrushOrigin, Mode);
773 break;
774 case DC_RECT:
775 // Clip the blt to the clip rectangle
776 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
777 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
778 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
779 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
780 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
781 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
782 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
783 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
784 &OutputRect, &InputRect, MaskOrigin, &AdjustedBrushOrigin, Mode);
785 //Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
786 // &CombinedRect, &Pt, MaskOrigin, Brush, BrushOrigin, Rop4);
787 DPRINT("EngStretchBlt() doesn't support DC_RECT clipping yet, so blitting w/o clip.\n");
788 break;
789 // TODO: Complex clipping
790 /*
791 case DC_COMPLEX:
792 Ret = TRUE;
793 if (OutputObj == InputObj)
794 {
795 if (OutputRect.top < InputPoint.y)
796 {
797 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
798 }
799 else
800 {
801 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
802 }
803 }
804 else
805 {
806 Direction = CD_ANY;
807 }
808 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
809 do
810 {
811 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
812
813 for (i = 0; i < RectEnum.c; i++)
814 {
815 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
816 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
817 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
818 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
819 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
820 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
821 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
822 Ret = (*BltRectFunc)(OutputObj, OutputGDI, InputObj, InputGDI, Mask, ColorTranslation,
823 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4) &&
824 Ret;
825 }
826 }
827 while(EnumMore);
828 break;
829 */
830 }
831
832
833 IntEngLeave(&EnterLeaveDest);
834 IntEngLeave(&EnterLeaveSource);
835
836 return Ret;
837 }
838
839 BOOL STDCALL
840 IntEngStretchBlt(SURFOBJ *DestObj,
841 SURFOBJ *SourceObj,
842 SURFOBJ *Mask,
843 CLIPOBJ *ClipRegion,
844 XLATEOBJ *ColorTranslation,
845 RECTL *DestRect,
846 RECTL *SourceRect,
847 POINTL *pMaskOrigin,
848 BRUSHOBJ *Brush,
849 POINTL *BrushOrigin,
850 ULONG Mode)
851 {
852 BOOLEAN ret;
853 SURFGDI *DestGDI;
854 SURFGDI *SourceGDI;
855 RECTL OutputRect;
856 RECTL InputRect;
857 COLORADJUSTMENT ca;
858 POINT MaskOrigin;
859
860 if (pMaskOrigin != NULL)
861 {
862 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
863 }
864
865 if (NULL != SourceRect)
866 {
867 InputRect = *SourceRect;
868 }
869
870 // FIXME: Clipping is taken from IntEngBitBlt w/o modifications!
871
872 /* Clip against the bounds of the clipping region so we won't try to write
873 * outside the surface */
874 if (NULL != ClipRegion)
875 {
876 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
877 {
878 return TRUE;
879 }
880 DPRINT("Clipping isn't handled in IntEngStretchBlt() correctly yet\n");
881 //InputPoint.x += OutputRect.left - DestRect->left;
882 //InputPoint.y += OutputRect.top - DestRect->top;
883 }
884 else
885 {
886 OutputRect = *DestRect;
887 }
888
889 if (NULL != SourceObj)
890 {
891 SourceGDI = (SURFGDI*) AccessInternalObjectFromUserObject(SourceObj);
892 MouseSafetyOnDrawStart(SourceObj, SourceGDI, InputRect.left, InputRect.top,
893 (InputRect.left + abs(InputRect.right - InputRect.left)),
894 (InputRect.top + abs(InputRect.bottom - InputRect.top)));
895 }
896
897 /* No success yet */
898 ret = FALSE;
899 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
900 MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
901 OutputRect.right, OutputRect.bottom);
902
903 /* Prepare color adjustment */
904
905 /* Call the driver's DrvStretchBlt if available */
906 if (NULL != DestGDI->StretchBlt)
907 {
908 /* Drv->StretchBlt (look at http://www.osr.com/ddk/graphics/ddifncs_3ew7.htm )
909 SURFOBJ *psoMask // optional, if it exists, then rop4=0xCCAA, otherwise rop4=0xCCCC */
910 // FIXME: MaskOrigin is always NULL !
911 IntLockGDIDriver(DestGDI);
912 ret = DestGDI->StretchBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
913 &ca, BrushOrigin, &OutputRect, &InputRect, NULL, Mode);
914 IntUnLockGDIDriver(DestGDI);
915 }
916
917 if (! ret)
918 {
919 // FIXME: see previous fixme
920 ret = EngStretchBlt(DestObj, SourceObj, Mask, ClipRegion, ColorTranslation,
921 &ca, BrushOrigin, &OutputRect, &InputRect, NULL, Mode);
922 }
923
924 MouseSafetyOnDrawEnd(DestObj, DestGDI);
925 if (NULL != SourceObj)
926 {
927 MouseSafetyOnDrawEnd(SourceObj, SourceGDI);
928 }
929
930 return ret;
931 }
932
933 /**** REACTOS FONT RENDERING CODE *********************************************/
934
935 /* renders the alpha mask bitmap */
936 static BOOLEAN STDCALL
937 AlphaBltMask(SURFOBJ* Dest,
938 SURFGDI* DestGDI,
939 SURFOBJ* Source,
940 SURFGDI* SourceGDI,
941 SURFOBJ* Mask,
942 XLATEOBJ* ColorTranslation,
943 XLATEOBJ* SrcColorTranslation,
944 RECTL* DestRect,
945 POINTL* SourcePoint,
946 POINTL* MaskPoint,
947 BRUSHOBJ* Brush,
948 POINTL* BrushPoint)
949 {
950 LONG i, j, dx, dy;
951 int r, g, b;
952 ULONG Background, BrushColor, NewColor;
953 BYTE *tMask, *lMask;
954
955 dx = DestRect->right - DestRect->left;
956 dy = DestRect->bottom - DestRect->top;
957
958 if (Mask != NULL)
959 {
960 BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, Brush->iSolidColor);
961 r = (int)GetRValue(BrushColor);
962 g = (int)GetGValue(BrushColor);
963 b = (int)GetBValue(BrushColor);
964
965 tMask = Mask->pvBits + (SourcePoint->y * Mask->lDelta) + SourcePoint->x;
966 for (j = 0; j < dy; j++)
967 {
968 lMask = tMask;
969 for (i = 0; i < dx; i++)
970 {
971 if (*lMask > 0)
972 {
973 if(*lMask == 0xff)
974 {
975 DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
976 }
977 else
978 {
979 Background = DIB_GetSource(Dest, DestGDI, DestRect->left + i, DestRect->top + j, SrcColorTranslation);
980
981 NewColor =
982 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
983 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
984 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
985
986 Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
987 DestGDI->DIB_PutPixel(Dest, DestRect->left + i, DestRect->top + j, Background);
988 }
989 }
990 lMask++;
991 }
992 tMask += Mask->lDelta;
993 }
994 return TRUE;
995 }
996 else
997 {
998 return FALSE;
999 }
1000 }
1001
1002 BOOL STDCALL
1003 EngMaskBitBlt(SURFOBJ *DestObj,
1004 SURFOBJ *Mask,
1005 CLIPOBJ *ClipRegion,
1006 XLATEOBJ *DestColorTranslation,
1007 XLATEOBJ *SourceColorTranslation,
1008 RECTL *DestRect,
1009 POINTL *SourcePoint,
1010 POINTL *MaskOrigin,
1011 BRUSHOBJ *Brush,
1012 POINTL *BrushOrigin)
1013 {
1014 BYTE clippingType;
1015 RECTL CombinedRect;
1016 RECT_ENUM RectEnum;
1017 BOOL EnumMore;
1018 SURFGDI* OutputGDI;
1019 SURFGDI* InputGDI;
1020 POINTL InputPoint;
1021 RECTL InputRect;
1022 RECTL OutputRect;
1023 POINTL Translate;
1024 INTENG_ENTER_LEAVE EnterLeaveSource;
1025 INTENG_ENTER_LEAVE EnterLeaveDest;
1026 SURFOBJ* InputObj;
1027 SURFOBJ* OutputObj;
1028 BOOLEAN Ret;
1029 RECTL ClipRect;
1030 unsigned i;
1031 POINTL Pt;
1032 ULONG Direction;
1033 SURFGDI* DestGDI;
1034 POINTL AdjustedBrushOrigin;
1035
1036 if (NULL != SourcePoint)
1037 {
1038 InputRect.left = SourcePoint->x;
1039 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
1040 InputRect.top = SourcePoint->y;
1041 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
1042 }
1043 else
1044 {
1045 InputRect.left = 0;
1046 InputRect.right = DestRect->right - DestRect->left;
1047 InputRect.top = 0;
1048 InputRect.bottom = DestRect->bottom - DestRect->top;
1049 }
1050
1051 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
1052 IntLockGDIDriver(DestGDI);
1053 if (! IntEngEnter(&EnterLeaveSource, NULL, &InputRect, TRUE, &Translate, &InputObj))
1054 {
1055 IntUnLockGDIDriver(DestGDI);
1056 return FALSE;
1057 }
1058
1059 if (NULL != SourcePoint)
1060 {
1061 InputPoint.x = SourcePoint->x + Translate.x;
1062 InputPoint.y = SourcePoint->y + Translate.y;
1063 }
1064 else
1065 {
1066 InputPoint.x = 0;
1067 InputPoint.y = 0;
1068 }
1069
1070 if (NULL != InputObj)
1071 {
1072 InputGDI = (SURFGDI*) AccessInternalObjectFromUserObject(InputObj);
1073 }
1074 else
1075 {
1076 InputGDI = NULL;
1077 }
1078
1079 OutputRect = *DestRect;
1080 if (NULL != ClipRegion)
1081 {
1082 if (OutputRect.left < ClipRegion->rclBounds.left)
1083 {
1084 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
1085 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
1086 OutputRect.left = ClipRegion->rclBounds.left;
1087 }
1088 if (ClipRegion->rclBounds.right < OutputRect.right)
1089 {
1090 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
1091 OutputRect.right = ClipRegion->rclBounds.right;
1092 }
1093 if (OutputRect.top < ClipRegion->rclBounds.top)
1094 {
1095 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
1096 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
1097 OutputRect.top = ClipRegion->rclBounds.top;
1098 }
1099 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
1100 {
1101 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
1102 OutputRect.bottom = ClipRegion->rclBounds.bottom;
1103 }
1104 }
1105
1106 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
1107 nothing to do */
1108 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
1109 {
1110 IntEngLeave(&EnterLeaveSource);
1111 IntUnLockGDIDriver(DestGDI);
1112 return TRUE;
1113 }
1114
1115 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
1116 {
1117 IntEngLeave(&EnterLeaveSource);
1118 IntUnLockGDIDriver(DestGDI);
1119 return FALSE;
1120 }
1121
1122 OutputRect.left = DestRect->left + Translate.x;
1123 OutputRect.right = DestRect->right + Translate.x;
1124 OutputRect.top = DestRect->top + Translate.y;
1125 OutputRect.bottom = DestRect->bottom + Translate.y;
1126
1127 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
1128 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
1129
1130 if (NULL != OutputObj)
1131 {
1132 OutputGDI = (SURFGDI*)AccessInternalObjectFromUserObject(OutputObj);
1133 }
1134
1135 // Determine clipping type
1136 if (ClipRegion == (CLIPOBJ *) NULL)
1137 {
1138 clippingType = DC_TRIVIAL;
1139 } else {
1140 clippingType = ClipRegion->iDComplexity;
1141 }
1142
1143 switch(clippingType)
1144 {
1145 case DC_TRIVIAL:
1146 if(Mask->iBitmapFormat == BMF_8BPP)
1147 Ret = AlphaBltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
1148 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin);
1149 else
1150 Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
1151 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin, 0xAACC);
1152 break;
1153 case DC_RECT:
1154 // Clip the blt to the clip rectangle
1155 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1156 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1157 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1158 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1159 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1160 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1161 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1162 if(Mask->iBitmapFormat == BMF_8BPP)
1163 Ret = AlphaBltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
1164 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin);
1165 else
1166 Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
1167 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, 0xAACC);
1168 break;
1169 case DC_COMPLEX:
1170 Ret = TRUE;
1171 if (OutputObj == InputObj)
1172 {
1173 if (OutputRect.top < InputPoint.y)
1174 {
1175 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1176 }
1177 else
1178 {
1179 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1180 }
1181 }
1182 else
1183 {
1184 Direction = CD_ANY;
1185 }
1186 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1187 do
1188 {
1189 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1190
1191 for (i = 0; i < RectEnum.c; i++)
1192 {
1193 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1194 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1195 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1196 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1197 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1198 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1199 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1200 if(Mask->iBitmapFormat == BMF_8BPP)
1201 Ret = AlphaBltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation, SourceColorTranslation,
1202 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin) && Ret;
1203 else
1204 Ret = BltMask(OutputObj, OutputGDI, InputObj, InputGDI, Mask, DestColorTranslation,
1205 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, 0xAACC) && Ret;
1206 }
1207 }
1208 while(EnumMore);
1209 break;
1210 }
1211
1212
1213 IntEngLeave(&EnterLeaveDest);
1214 IntEngLeave(&EnterLeaveSource);
1215
1216 IntUnLockGDIDriver(DestGDI);
1217
1218 /* Dummy BitBlt to let driver know that something has changed.
1219 0x00AA0029 is the Rop for D (no-op) */
1220 IntEngBitBlt(DestObj, NULL, Mask, ClipRegion, DestColorTranslation,
1221 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, ROP_NOOP);
1222
1223 return Ret;
1224 }
1225
1226 BOOL STDCALL
1227 IntEngMaskBlt(SURFOBJ *DestObj,
1228 SURFOBJ *Mask,
1229 CLIPOBJ *ClipRegion,
1230 XLATEOBJ *DestColorTranslation,
1231 XLATEOBJ *SourceColorTranslation,
1232 RECTL *DestRect,
1233 POINTL *SourcePoint,
1234 POINTL *MaskOrigin,
1235 BRUSHOBJ *Brush,
1236 POINTL *BrushOrigin)
1237 {
1238 BOOLEAN ret;
1239 SURFGDI *DestGDI;
1240 RECTL OutputRect;
1241 POINTL InputPoint;
1242
1243 if (NULL != SourcePoint)
1244 {
1245 InputPoint = *SourcePoint;
1246 }
1247
1248 /* Clip against the bounds of the clipping region so we won't try to write
1249 * outside the surface */
1250 if (NULL != ClipRegion)
1251 {
1252 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
1253 {
1254 return TRUE;
1255 }
1256 InputPoint.x += OutputRect.left - DestRect->left;
1257 InputPoint.y += OutputRect.top - DestRect->top;
1258 }
1259 else
1260 {
1261 OutputRect = *DestRect;
1262 }
1263
1264 /* No success yet */
1265 ret = FALSE;
1266 DestGDI = (SURFGDI*)AccessInternalObjectFromUserObject(DestObj);
1267 MouseSafetyOnDrawStart(DestObj, DestGDI, OutputRect.left, OutputRect.top,
1268 OutputRect.right, OutputRect.bottom);
1269
1270 ret = EngMaskBitBlt(DestObj, Mask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1271 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
1272
1273 MouseSafetyOnDrawEnd(DestObj, DestGDI);
1274
1275 return ret;
1276 }
1277 /* EOF */