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