22312f3d4eb076d2a70d0fb7f6ab4a1e16c21c9b
[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.63 2004/12/14 03:28:34 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 = &DestObj->SurfObj;
750 SURFOBJ *SourceSurf = SourceObj ? &SourceObj->SurfObj : NULL;
751 SURFOBJ *MaskSurf = MaskObj ? &MaskObj->SurfObj : NULL;
752
753 if (pMaskOrigin != NULL)
754 {
755 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
756 }
757
758 if (NULL != SourceObj)
759 {
760 MouseSafetyOnDrawStart(SourceSurf, SourceRect->left, SourceRect->top,
761 SourceRect->right, SourceRect->bottom);
762 }
763
764 /* No success yet */
765 ret = FALSE;
766 MouseSafetyOnDrawStart(DestSurf, DestRect->left, DestRect->top,
767 DestRect->right, DestRect->bottom);
768
769 /* Prepare color adjustment */
770
771 /* Call the driver's DrvStretchBlt if available */
772 if (DestObj->flHooks & HOOK_STRETCHBLT)
773 {
774 /* Drv->StretchBlt (look at http://www.osr.com/ddk/graphics/ddifncs_3ew7.htm )
775 SURFOBJ *psoMask // optional, if it exists, then rop4=0xCCAA, otherwise rop4=0xCCCC */
776 // FIXME: MaskOrigin is always NULL !
777 ret = GDIDEVFUNCS(DestSurf).StretchBlt(
778 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
779 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
780 }
781
782 if (! ret)
783 {
784 // FIXME: see previous fixme
785 ret = EngStretchBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
786 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
787 }
788
789 MouseSafetyOnDrawEnd(DestSurf);
790 if (NULL != SourceSurf)
791 {
792 MouseSafetyOnDrawEnd(SourceSurf);
793 }
794
795 return ret;
796 }
797
798 /**** REACTOS FONT RENDERING CODE *********************************************/
799
800 /* renders the alpha mask bitmap */
801 static BOOLEAN STDCALL
802 AlphaBltMask(SURFOBJ* Dest,
803 SURFOBJ* Source,
804 SURFOBJ* Mask,
805 XLATEOBJ* ColorTranslation,
806 XLATEOBJ* SrcColorTranslation,
807 RECTL* DestRect,
808 POINTL* SourcePoint,
809 POINTL* MaskPoint,
810 BRUSHOBJ* Brush,
811 POINTL* BrushPoint)
812 {
813 LONG i, j, dx, dy;
814 int r, g, b;
815 ULONG Background, BrushColor, NewColor;
816 BYTE *tMask, *lMask;
817
818 dx = DestRect->right - DestRect->left;
819 dy = DestRect->bottom - DestRect->top;
820
821 if (Mask != NULL)
822 {
823 BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, Brush->iSolidColor);
824 r = (int)GetRValue(BrushColor);
825 g = (int)GetGValue(BrushColor);
826 b = (int)GetBValue(BrushColor);
827
828 tMask = Mask->pvBits + (SourcePoint->y * Mask->lDelta) + SourcePoint->x;
829 for (j = 0; j < dy; j++)
830 {
831 lMask = tMask;
832 for (i = 0; i < dx; i++)
833 {
834 if (*lMask > 0)
835 {
836 if(*lMask == 0xff)
837 {
838 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
839 Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
840 }
841 else
842 {
843 Background = DIB_GetSource(Dest, DestRect->left + i, DestRect->top + j, SrcColorTranslation);
844
845 NewColor =
846 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
847 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
848 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
849
850 Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
851 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
852 Dest, DestRect->left + i, DestRect->top + j, Background);
853 }
854 }
855 lMask++;
856 }
857 tMask += Mask->lDelta;
858 }
859 return TRUE;
860 }
861 else
862 {
863 return FALSE;
864 }
865 }
866
867 BOOL STDCALL
868 EngMaskBitBlt(SURFOBJ *DestObj,
869 SURFOBJ *Mask,
870 CLIPOBJ *ClipRegion,
871 XLATEOBJ *DestColorTranslation,
872 XLATEOBJ *SourceColorTranslation,
873 RECTL *DestRect,
874 POINTL *SourcePoint,
875 POINTL *MaskOrigin,
876 BRUSHOBJ *Brush,
877 POINTL *BrushOrigin)
878 {
879 BYTE clippingType;
880 RECTL CombinedRect;
881 RECT_ENUM RectEnum;
882 BOOL EnumMore;
883 POINTL InputPoint;
884 RECTL InputRect;
885 RECTL OutputRect;
886 POINTL Translate;
887 INTENG_ENTER_LEAVE EnterLeaveSource;
888 INTENG_ENTER_LEAVE EnterLeaveDest;
889 SURFOBJ* InputObj;
890 SURFOBJ* OutputObj;
891 BOOLEAN Ret = TRUE;
892 RECTL ClipRect;
893 unsigned i;
894 POINTL Pt;
895 ULONG Direction;
896 POINTL AdjustedBrushOrigin;
897
898 if (NULL != SourcePoint)
899 {
900 InputRect.left = SourcePoint->x;
901 InputRect.right = SourcePoint->x + (DestRect->right - DestRect->left);
902 InputRect.top = SourcePoint->y;
903 InputRect.bottom = SourcePoint->y + (DestRect->bottom - DestRect->top);
904 }
905 else
906 {
907 InputRect.left = 0;
908 InputRect.right = DestRect->right - DestRect->left;
909 InputRect.top = 0;
910 InputRect.bottom = DestRect->bottom - DestRect->top;
911 }
912
913 if (! IntEngEnter(&EnterLeaveSource, NULL, &InputRect, TRUE, &Translate, &InputObj))
914 {
915 return FALSE;
916 }
917
918 if (NULL != SourcePoint)
919 {
920 InputPoint.x = SourcePoint->x + Translate.x;
921 InputPoint.y = SourcePoint->y + Translate.y;
922 }
923 else
924 {
925 InputPoint.x = 0;
926 InputPoint.y = 0;
927 }
928
929 OutputRect = *DestRect;
930 if (NULL != ClipRegion)
931 {
932 if (OutputRect.left < ClipRegion->rclBounds.left)
933 {
934 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
935 InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
936 OutputRect.left = ClipRegion->rclBounds.left;
937 }
938 if (ClipRegion->rclBounds.right < OutputRect.right)
939 {
940 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
941 OutputRect.right = ClipRegion->rclBounds.right;
942 }
943 if (OutputRect.top < ClipRegion->rclBounds.top)
944 {
945 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
946 InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
947 OutputRect.top = ClipRegion->rclBounds.top;
948 }
949 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
950 {
951 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
952 OutputRect.bottom = ClipRegion->rclBounds.bottom;
953 }
954 }
955
956 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
957 nothing to do */
958 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
959 {
960 IntEngLeave(&EnterLeaveSource);
961 return TRUE;
962 }
963
964 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
965 {
966 IntEngLeave(&EnterLeaveSource);
967 return FALSE;
968 }
969
970 OutputRect.left = DestRect->left + Translate.x;
971 OutputRect.right = DestRect->right + Translate.x;
972 OutputRect.top = DestRect->top + Translate.y;
973 OutputRect.bottom = DestRect->bottom + Translate.y;
974
975 if(BrushOrigin)
976 {
977 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
978 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
979 }
980 else
981 AdjustedBrushOrigin = Translate;
982
983 // Determine clipping type
984 if (ClipRegion == (CLIPOBJ *) NULL)
985 {
986 clippingType = DC_TRIVIAL;
987 } else {
988 clippingType = ClipRegion->iDComplexity;
989 }
990
991 switch(clippingType)
992 {
993 case DC_TRIVIAL:
994 if(Mask->iBitmapFormat == BMF_8BPP)
995 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
996 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin);
997 else
998 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
999 &OutputRect, &InputPoint, MaskOrigin, Brush, &AdjustedBrushOrigin, 0xAACC);
1000 break;
1001 case DC_RECT:
1002 // Clip the blt to the clip rectangle
1003 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1004 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1005 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1006 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1007 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1008 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1009 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1010 if(Mask->iBitmapFormat == BMF_8BPP)
1011 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1012 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin);
1013 else
1014 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1015 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, 0xAACC);
1016 break;
1017 case DC_COMPLEX:
1018 Ret = TRUE;
1019 if (OutputObj == InputObj)
1020 {
1021 if (OutputRect.top < InputPoint.y)
1022 {
1023 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1024 }
1025 else
1026 {
1027 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1028 }
1029 }
1030 else
1031 {
1032 Direction = CD_ANY;
1033 }
1034 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1035 do
1036 {
1037 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1038
1039 for (i = 0; i < RectEnum.c; i++)
1040 {
1041 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1042 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1043 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1044 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1045 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1046 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1047 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1048 if(Mask->iBitmapFormat == BMF_8BPP)
1049 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1050 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin) && Ret;
1051 else
1052 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1053 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, 0xAACC) && Ret;
1054 }
1055 }
1056 while(EnumMore);
1057 break;
1058 }
1059
1060
1061 IntEngLeave(&EnterLeaveDest);
1062 IntEngLeave(&EnterLeaveSource);
1063
1064 /* Dummy BitBlt to let driver know that something has changed.
1065 0x00AA0029 is the Rop for D (no-op) */
1066 /* FIXME: Remove the typecast! */
1067 IntEngBitBlt((BITMAPOBJ*)DestObj, NULL, (BITMAPOBJ*)Mask, ClipRegion, DestColorTranslation,
1068 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, ROP_NOOP);
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 if (NULL != SourcePoint)
1090 {
1091 InputPoint = *SourcePoint;
1092 }
1093
1094 /* Clip against the bounds of the clipping region so we won't try to write
1095 * outside the surface */
1096 if (NULL != ClipRegion)
1097 {
1098 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
1099 {
1100 return TRUE;
1101 }
1102 InputPoint.x += OutputRect.left - DestRect->left;
1103 InputPoint.y += OutputRect.top - DestRect->top;
1104 }
1105 else
1106 {
1107 OutputRect = *DestRect;
1108 }
1109
1110 /* No success yet */
1111 ret = FALSE;
1112 MouseSafetyOnDrawStart(DestObj, OutputRect.left, OutputRect.top,
1113 OutputRect.right, OutputRect.bottom);
1114
1115 ret = EngMaskBitBlt(DestObj, Mask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1116 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
1117
1118 MouseSafetyOnDrawEnd(DestObj);
1119
1120 return ret;
1121 }
1122 /* EOF */