dbd8ea9ba5cd01ebc2cfc9834a136de73dec558c
[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 (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 = DestRect->left + Translate.x;
366 OutputRect.right = DestRect->right + Translate.x;
367 OutputRect.top = DestRect->top + Translate.y;
368 OutputRect.bottom = DestRect->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 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
416 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
417 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
418 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
419 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4);
420 break;
421 case DC_COMPLEX:
422 Ret = TRUE;
423 if (OutputObj == InputObj)
424 {
425 if (OutputRect.top < InputPoint.y)
426 {
427 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
428 }
429 else
430 {
431 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
432 }
433 }
434 else
435 {
436 Direction = CD_ANY;
437 }
438 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
439 do
440 {
441 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
442
443 for (i = 0; i < RectEnum.c; i++)
444 {
445 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
446 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
447 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
448 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
449 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
450 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
451 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
452 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
453 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, Rop4) &&
454 Ret;
455 }
456 }
457 while(EnumMore);
458 break;
459 }
460
461
462 IntEngLeave(&EnterLeaveDest);
463 IntEngLeave(&EnterLeaveSource);
464
465 return Ret;
466 }
467
468 BOOL STDCALL
469 IntEngBitBlt(BITMAPOBJ *DestObj,
470 BITMAPOBJ *SourceObj,
471 BITMAPOBJ *MaskObj,
472 CLIPOBJ *ClipRegion,
473 XLATEOBJ *ColorTranslation,
474 RECTL *DestRect,
475 POINTL *SourcePoint,
476 POINTL *MaskOrigin,
477 BRUSHOBJ *Brush,
478 POINTL *BrushOrigin,
479 ROP4 Rop4)
480 {
481 BOOLEAN ret;
482 RECTL InputClippedRect;
483 RECTL OutputRect;
484 POINTL InputPoint;
485 BOOLEAN UsesSource;
486 SURFOBJ *DestSurf;
487 SURFOBJ *SourceSurf = SourceObj ? &SourceObj->SurfObj : NULL;
488 SURFOBJ *MaskSurf = MaskObj ? &MaskObj->SurfObj : NULL;
489
490 ASSERT(DestObj);
491 DestSurf = &DestObj->SurfObj;
492 ASSERT(DestSurf);
493
494 InputClippedRect = *DestRect;
495 if (InputClippedRect.right < InputClippedRect.left)
496 {
497 InputClippedRect.left = DestRect->right;
498 InputClippedRect.right = DestRect->left;
499 }
500 if (InputClippedRect.bottom < InputClippedRect.top)
501 {
502 InputClippedRect.top = DestRect->bottom;
503 InputClippedRect.bottom = DestRect->top;
504 }
505 UsesSource = ROP4_USES_SOURCE(Rop4);
506 if (UsesSource)
507 {
508 if (NULL == SourcePoint || NULL == SourceSurf)
509 {
510 return FALSE;
511 }
512 InputPoint = *SourcePoint;
513
514 /* Make sure we don't try to copy anything outside the valid source region */
515 if (InputPoint.x < 0)
516 {
517 InputClippedRect.left -= InputPoint.x;
518 InputPoint.x = 0;
519 }
520 if (InputPoint.y < 0)
521 {
522 InputClippedRect.top -= InputPoint.y;
523 InputPoint.y = 0;
524 }
525 if (SourceSurf->sizlBitmap.cx < InputPoint.x + InputClippedRect.right - InputClippedRect.left)
526 {
527 InputClippedRect.right = InputClippedRect.left + SourceSurf->sizlBitmap.cx - InputPoint.x;
528 }
529 if (SourceSurf->sizlBitmap.cy < InputPoint.y + InputClippedRect.bottom - InputClippedRect.top)
530 {
531 InputClippedRect.bottom = InputClippedRect.top + SourceSurf->sizlBitmap.cy - InputPoint.y;
532 }
533
534 if (InputClippedRect.right < InputClippedRect.left ||
535 InputClippedRect.bottom < InputClippedRect.top)
536 {
537 /* Everything clipped away, nothing to do */
538 return TRUE;
539 }
540 }
541
542 /* Clip against the bounds of the clipping region so we won't try to write
543 * outside the surface */
544 if (NULL != ClipRegion)
545 {
546 if (! EngIntersectRect(&OutputRect, &InputClippedRect, &ClipRegion->rclBounds))
547 {
548 return TRUE;
549 }
550 InputPoint.x += OutputRect.left - DestRect->left;
551 InputPoint.y += OutputRect.top - DestRect->top;
552 }
553 else
554 {
555 OutputRect = InputClippedRect;
556 }
557
558 if (UsesSource)
559 {
560 MouseSafetyOnDrawStart(SourceSurf, InputPoint.x, InputPoint.y,
561 (InputPoint.x + abs(DestRect->right - DestRect->left)),
562 (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
563 }
564
565 /* No success yet */
566 ret = FALSE;
567 MouseSafetyOnDrawStart(DestSurf, OutputRect.left, OutputRect.top,
568 OutputRect.right, OutputRect.bottom);
569
570 /* Call the driver's DrvBitBlt if available */
571 if (DestObj->flHooks & HOOK_BITBLT)
572 {
573 ret = GDIDEVFUNCS(DestSurf).BitBlt(
574 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
575 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
576 Rop4);
577 }
578
579 if (! ret)
580 {
581 ret = EngBitBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
582 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
583 Rop4);
584 }
585
586 MouseSafetyOnDrawEnd(DestSurf);
587 if (UsesSource)
588 {
589 MouseSafetyOnDrawEnd(SourceSurf);
590 }
591
592 return ret;
593 }
594
595 static BOOLEAN STDCALL
596 CallDibStretchBlt(SURFOBJ* OutputObj,
597 SURFOBJ* InputObj,
598 SURFOBJ* Mask,
599 CLIPOBJ* ClipRegion,
600 XLATEOBJ* ColorTranslation,
601 RECTL* OutputRect,
602 RECTL* InputRect,
603 POINTL* MaskOrigin,
604 POINTL* BrushOrigin,
605 ULONG Mode)
606 {
607 POINTL RealBrushOrigin;
608 if (BrushOrigin == NULL)
609 {
610 RealBrushOrigin.x = RealBrushOrigin.y = 0;
611 }
612 else
613 {
614 RealBrushOrigin = *BrushOrigin;
615 }
616 return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_StretchBlt(
617 OutputObj, InputObj, OutputRect, InputRect, MaskOrigin, RealBrushOrigin, ClipRegion, ColorTranslation, Mode);
618 }
619
620
621 BOOL
622 STDCALL
623 EngStretchBlt(
624 IN SURFOBJ *DestObj,
625 IN SURFOBJ *SourceObj,
626 IN SURFOBJ *Mask,
627 IN CLIPOBJ *ClipRegion,
628 IN XLATEOBJ *ColorTranslation,
629 IN COLORADJUSTMENT *pca,
630 IN POINTL *BrushOrigin,
631 IN RECTL *prclDest,
632 IN RECTL *prclSrc,
633 IN POINTL *MaskOrigin,
634 IN ULONG Mode
635 )
636 {
637 // www.osr.com/ddk/graphics/gdifncs_0bs7.htm
638
639 POINTL InputPoint;
640 RECTL InputRect;
641 RECTL OutputRect;
642 POINTL Translate;
643 INTENG_ENTER_LEAVE EnterLeaveSource;
644 INTENG_ENTER_LEAVE EnterLeaveDest;
645 SURFOBJ* InputObj;
646 SURFOBJ* OutputObj;
647 PSTRETCHRECTFUNC BltRectFunc;
648 BOOLEAN Ret;
649 POINTL AdjustedBrushOrigin;
650
651 InputRect.left = prclSrc->left;
652 InputRect.right = prclSrc->right;
653 InputRect.top = prclSrc->top;
654 InputRect.bottom = prclSrc->bottom;
655
656 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
657 {
658 return FALSE;
659 }
660
661 InputPoint.x = InputRect.left + Translate.x;
662 InputPoint.y = InputRect.top + Translate.y;
663
664 OutputRect = *prclDest;
665
666 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
667 nothing to do */
668 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
669 {
670 IntEngLeave(&EnterLeaveSource);
671 return TRUE;
672 }
673
674 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
675 {
676 IntEngLeave(&EnterLeaveSource);
677 return FALSE;
678 }
679
680 OutputRect.left = prclDest->left + Translate.x;
681 OutputRect.right = prclDest->right + Translate.x;
682 OutputRect.top = prclDest->top + Translate.y;
683 OutputRect.bottom = prclDest->bottom + Translate.y;
684
685 if (NULL != BrushOrigin)
686 {
687 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
688 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
689 }
690 else
691 {
692 AdjustedBrushOrigin = Translate;
693 }
694
695 if (Mask != NULL)
696 {
697 //BltRectFunc = BltMask;
698 DPRINT("EngStretchBlt isn't capable of handling mask yet.\n");
699 IntEngLeave(&EnterLeaveDest);
700 IntEngLeave(&EnterLeaveSource);
701
702 return FALSE;
703 }
704 else
705 {
706 BltRectFunc = CallDibStretchBlt;
707 }
708
709
710 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ClipRegion,
711 ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
712 &AdjustedBrushOrigin, Mode);
713
714 IntEngLeave(&EnterLeaveDest);
715 IntEngLeave(&EnterLeaveSource);
716
717 return Ret;
718 }
719
720 BOOL STDCALL
721 IntEngStretchBlt(BITMAPOBJ *DestObj,
722 BITMAPOBJ *SourceObj,
723 BITMAPOBJ *MaskObj,
724 CLIPOBJ *ClipRegion,
725 XLATEOBJ *ColorTranslation,
726 RECTL *DestRect,
727 RECTL *SourceRect,
728 POINTL *pMaskOrigin,
729 BRUSHOBJ *Brush,
730 POINTL *BrushOrigin,
731 ULONG Mode)
732 {
733 BOOLEAN ret;
734 COLORADJUSTMENT ca;
735 POINT MaskOrigin;
736 SURFOBJ *DestSurf;
737 SURFOBJ *SourceSurf = SourceObj ? &SourceObj->SurfObj : NULL;
738 SURFOBJ *MaskSurf = MaskObj ? &MaskObj->SurfObj : NULL;
739
740 ASSERT(DestObj);
741 DestSurf = &DestObj->SurfObj;
742 ASSERT(DestSurf);
743
744 if (pMaskOrigin != NULL)
745 {
746 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
747 }
748
749 if (NULL != SourceSurf)
750 {
751 ASSERT(SourceRect);
752 MouseSafetyOnDrawStart(SourceSurf, SourceRect->left, SourceRect->top,
753 SourceRect->right, SourceRect->bottom);
754 }
755
756 /* No success yet */
757 ret = FALSE;
758 ASSERT(DestRect);
759 MouseSafetyOnDrawStart(DestSurf, DestRect->left, DestRect->top,
760 DestRect->right, DestRect->bottom);
761
762 /* Prepare color adjustment */
763
764 /* Call the driver's DrvStretchBlt if available */
765 if (DestObj->flHooks & HOOK_STRETCHBLT)
766 {
767 /* Drv->StretchBlt (look at http://www.osr.com/ddk/graphics/ddifncs_3ew7.htm )
768 SURFOBJ *psoMask // optional, if it exists, then rop4=0xCCAA, otherwise rop4=0xCCCC */
769 // FIXME: MaskOrigin is always NULL !
770 ret = GDIDEVFUNCS(DestSurf).StretchBlt(
771 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
772 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
773 }
774
775 if (! ret)
776 {
777 // FIXME: see previous fixme
778 ret = EngStretchBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
779 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
780 }
781
782 MouseSafetyOnDrawEnd(DestSurf);
783 if (NULL != SourceSurf)
784 {
785 MouseSafetyOnDrawEnd(SourceSurf);
786 }
787
788 return ret;
789 }
790
791 /**** REACTOS FONT RENDERING CODE *********************************************/
792
793 /* renders the alpha mask bitmap */
794 static BOOLEAN STDCALL
795 AlphaBltMask(SURFOBJ* Dest,
796 SURFOBJ* Source,
797 SURFOBJ* Mask,
798 XLATEOBJ* ColorTranslation,
799 XLATEOBJ* SrcColorTranslation,
800 RECTL* DestRect,
801 POINTL* SourcePoint,
802 POINTL* MaskPoint,
803 BRUSHOBJ* Brush,
804 POINTL* BrushPoint)
805 {
806 LONG i, j, dx, dy;
807 int r, g, b;
808 ULONG Background, BrushColor, NewColor;
809 BYTE *tMask, *lMask;
810
811 dx = DestRect->right - DestRect->left;
812 dy = DestRect->bottom - DestRect->top;
813
814 if (Mask != NULL)
815 {
816 BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, Brush->iSolidColor);
817 r = (int)GetRValue(BrushColor);
818 g = (int)GetGValue(BrushColor);
819 b = (int)GetBValue(BrushColor);
820
821 tMask = Mask->pvScan0 + (SourcePoint->y * Mask->lDelta) + SourcePoint->x;
822 for (j = 0; j < dy; j++)
823 {
824 lMask = tMask;
825 for (i = 0; i < dx; i++)
826 {
827 if (*lMask > 0)
828 {
829 if (*lMask == 0xff)
830 {
831 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
832 Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
833 }
834 else
835 {
836 Background = DIB_GetSource(Dest, DestRect->left + i, DestRect->top + j,
837 SrcColorTranslation);
838
839 NewColor =
840 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
841 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
842 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
843
844 Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
845 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
846 Dest, DestRect->left + i, DestRect->top + j, Background);
847 }
848 }
849 lMask++;
850 }
851 tMask += Mask->lDelta;
852 }
853 return TRUE;
854 }
855 else
856 {
857 return FALSE;
858 }
859 }
860
861 BOOL STDCALL
862 EngMaskBitBlt(SURFOBJ *DestObj,
863 SURFOBJ *Mask,
864 CLIPOBJ *ClipRegion,
865 XLATEOBJ *DestColorTranslation,
866 XLATEOBJ *SourceColorTranslation,
867 RECTL *DestRect,
868 POINTL *SourcePoint,
869 POINTL *MaskOrigin,
870 BRUSHOBJ *Brush,
871 POINTL *BrushOrigin)
872 {
873 BYTE clippingType;
874 RECTL CombinedRect;
875 RECT_ENUM RectEnum;
876 BOOL EnumMore;
877 POINTL InputPoint;
878 RECTL InputRect;
879 RECTL OutputRect;
880 POINTL Translate;
881 INTENG_ENTER_LEAVE EnterLeaveSource;
882 INTENG_ENTER_LEAVE EnterLeaveDest;
883 SURFOBJ* InputObj;
884 SURFOBJ* OutputObj;
885 BOOLEAN Ret = TRUE;
886 RECTL ClipRect;
887 unsigned i;
888 POINTL Pt;
889 ULONG Direction;
890 POINTL AdjustedBrushOrigin;
891
892 ASSERT ( Mask );
893
894 if (NULL != SourcePoint)
895 {
896 InputRect.left = SourcePoint->x;
897 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
898 InputRect.top = SourcePoint->y;
899 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
900 }
901 else
902 {
903 InputRect.left = 0;
904 InputRect.right = DestRect->right - DestRect->left;
905 InputRect.top = 0;
906 InputRect.bottom = DestRect->bottom - DestRect->top;
907 }
908
909 if (! IntEngEnter(&EnterLeaveSource, DestObj, &InputRect, TRUE, &Translate, &InputObj))
910 {
911 return FALSE;
912 }
913
914 if (NULL != SourcePoint)
915 {
916 InputPoint.x = SourcePoint->x + Translate.x;
917 InputPoint.y = SourcePoint->y + Translate.y;
918 }
919 else
920 {
921 InputPoint.x = 0;
922 InputPoint.y = 0;
923 }
924
925 OutputRect = *DestRect;
926 if (NULL != ClipRegion)
927 {
928 if (OutputRect.left < ClipRegion->rclBounds.left)
929 {
930 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
931 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
932 OutputRect.left = ClipRegion->rclBounds.left;
933 }
934 if (ClipRegion->rclBounds.right < OutputRect.right)
935 {
936 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
937 OutputRect.right = ClipRegion->rclBounds.right;
938 }
939 if (OutputRect.top < ClipRegion->rclBounds.top)
940 {
941 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
942 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
943 OutputRect.top = ClipRegion->rclBounds.top;
944 }
945 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
946 {
947 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
948 OutputRect.bottom = ClipRegion->rclBounds.bottom;
949 }
950 }
951
952 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
953 nothing to do */
954 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
955 {
956 IntEngLeave(&EnterLeaveSource);
957 return TRUE;
958 }
959
960 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
961 {
962 IntEngLeave(&EnterLeaveSource);
963 return FALSE;
964 }
965
966 OutputRect.left = DestRect->left + Translate.x;
967 OutputRect.right = DestRect->right + Translate.x;
968 OutputRect.top = DestRect->top + Translate.y;
969 OutputRect.bottom = DestRect->bottom + Translate.y;
970
971 if(BrushOrigin)
972 {
973 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
974 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
975 }
976 else
977 AdjustedBrushOrigin = Translate;
978
979 // Determine clipping type
980 if (ClipRegion == (CLIPOBJ *) NULL)
981 {
982 clippingType = DC_TRIVIAL;
983 } else {
984 clippingType = ClipRegion->iDComplexity;
985 }
986
987 switch(clippingType)
988 {
989 case DC_TRIVIAL:
990 if(Mask->iBitmapFormat == BMF_8BPP)
991 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
992 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin);
993 else
994 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
995 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin,
996 R4_MASK);
997 break;
998 case DC_RECT:
999 // Clip the blt to the clip rectangle
1000 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1001 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1002 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1003 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1004 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1005 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1006 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1007 if(Mask->iBitmapFormat == BMF_8BPP)
1008 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1009 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin);
1010 else
1011 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1012 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, R4_MASK);
1013 break;
1014 case DC_COMPLEX:
1015 Ret = TRUE;
1016 if (OutputObj == InputObj)
1017 {
1018 if (OutputRect.top < InputPoint.y)
1019 {
1020 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1021 }
1022 else
1023 {
1024 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1025 }
1026 }
1027 else
1028 {
1029 Direction = CD_ANY;
1030 }
1031 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1032 do
1033 {
1034 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1035
1036 for (i = 0; i < RectEnum.c; i++)
1037 {
1038 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1039 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1040 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1041 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1042 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1043 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1044 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1045 if(Mask->iBitmapFormat == BMF_8BPP)
1046 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1047 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin) && Ret;
1048 else
1049 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1050 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, R4_MASK) && Ret;
1051 }
1052 }
1053 while(EnumMore);
1054 break;
1055 }
1056
1057
1058 IntEngLeave(&EnterLeaveDest);
1059 IntEngLeave(&EnterLeaveSource);
1060
1061 return Ret;
1062 }
1063
1064 BOOL STDCALL
1065 IntEngMaskBlt(SURFOBJ *DestObj,
1066 SURFOBJ *Mask,
1067 CLIPOBJ *ClipRegion,
1068 XLATEOBJ *DestColorTranslation,
1069 XLATEOBJ *SourceColorTranslation,
1070 RECTL *DestRect,
1071 POINTL *SourcePoint,
1072 POINTL *MaskOrigin,
1073 BRUSHOBJ *Brush,
1074 POINTL *BrushOrigin)
1075 {
1076 BOOLEAN ret;
1077 RECTL OutputRect;
1078 POINTL InputPoint;
1079
1080 ASSERT(Mask);
1081
1082 if (NULL != SourcePoint)
1083 {
1084 InputPoint = *SourcePoint;
1085 }
1086
1087 /* Clip against the bounds of the clipping region so we won't try to write
1088 * outside the surface */
1089 if (NULL != ClipRegion)
1090 {
1091 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
1092 {
1093 return TRUE;
1094 }
1095 InputPoint.x += OutputRect.left - DestRect->left;
1096 InputPoint.y += OutputRect.top - DestRect->top;
1097 }
1098 else
1099 {
1100 OutputRect = *DestRect;
1101 }
1102
1103 /* No success yet */
1104 ret = FALSE;
1105 ASSERT(DestObj);
1106 MouseSafetyOnDrawStart(DestObj, OutputRect.left, OutputRect.top,
1107 OutputRect.right, OutputRect.bottom);
1108
1109 /* Dummy BitBlt to let driver know that it should flush its changes.
1110 This should really be done using a call to DrvSynchronizeSurface,
1111 but the VMware driver doesn't hook that call. */
1112 /* FIXME: Remove the typecast! */
1113 IntEngBitBlt((BITMAPOBJ*)DestObj, NULL, (BITMAPOBJ*)Mask, ClipRegion, DestColorTranslation,
1114 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, R4_NOOP);
1115
1116 ret = EngMaskBitBlt(DestObj, Mask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1117 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
1118
1119 /* Dummy BitBlt to let driver know that something has changed. */
1120 /* FIXME: Remove the typecast! */
1121 IntEngBitBlt((BITMAPOBJ*)DestObj, NULL, (BITMAPOBJ*)Mask, ClipRegion, DestColorTranslation,
1122 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, R4_NOOP);
1123
1124 MouseSafetyOnDrawEnd(DestObj);
1125
1126 return ret;
1127 }
1128 /* EOF */