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