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