6293a3e0413b2be45bcc180a380d0cb488db1568
[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.60 2004/12/12 21:38:25 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;
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 = &DestObj->SurfObj;
500 SURFOBJ *SourceSurf = SourceObj ? &SourceObj->SurfObj : NULL;
501 SURFOBJ *MaskSurf = MaskObj ? &MaskObj->SurfObj : NULL;
502
503 InputClippedRect = *DestRect;
504 if (InputClippedRect.right < InputClippedRect.left)
505 {
506 InputClippedRect.left = DestRect->right;
507 InputClippedRect.right = DestRect->left;
508 }
509 if (InputClippedRect.bottom < InputClippedRect.top)
510 {
511 InputClippedRect.top = DestRect->bottom;
512 InputClippedRect.bottom = DestRect->top;
513 }
514 UsesSource = ((Rop4 & 0xCC0000) >> 2) != (Rop4 & 0x330000);
515 if (UsesSource)
516 {
517 if (NULL == SourcePoint || NULL == SourceObj)
518 {
519 return FALSE;
520 }
521 InputPoint = *SourcePoint;
522
523 /* Make sure we don't try to copy anything outside the valid source region */
524 if (InputPoint.x < 0)
525 {
526 InputClippedRect.left -= InputPoint.x;
527 InputPoint.x = 0;
528 }
529 if (InputPoint.y < 0)
530 {
531 InputClippedRect.top -= InputPoint.y;
532 InputPoint.y = 0;
533 }
534 if (SourceSurf->sizlBitmap.cx < InputPoint.x + InputClippedRect.right - InputClippedRect.left)
535 {
536 InputClippedRect.right = InputClippedRect.left + SourceSurf->sizlBitmap.cx - InputPoint.x;
537 }
538 if (SourceSurf->sizlBitmap.cy < InputPoint.y + InputClippedRect.bottom - InputClippedRect.top)
539 {
540 InputClippedRect.bottom = InputClippedRect.top + SourceSurf->sizlBitmap.cy - InputPoint.y;
541 }
542
543 if (InputClippedRect.right < InputClippedRect.left ||
544 InputClippedRect.bottom < InputClippedRect.top)
545 {
546 /* Everything clipped away, nothing to do */
547 return TRUE;
548 }
549 }
550
551 /* Clip against the bounds of the clipping region so we won't try to write
552 * outside the surface */
553 if (NULL != ClipRegion)
554 {
555 if (! EngIntersectRect(&OutputRect, &InputClippedRect, &ClipRegion->rclBounds))
556 {
557 return TRUE;
558 }
559 InputPoint.x += OutputRect.left - DestRect->left;
560 InputPoint.y += OutputRect.top - DestRect->top;
561 }
562 else
563 {
564 OutputRect = InputClippedRect;
565 }
566
567 if (UsesSource)
568 {
569 MouseSafetyOnDrawStart(SourceSurf, InputPoint.x, InputPoint.y,
570 (InputPoint.x + abs(DestRect->right - DestRect->left)),
571 (InputPoint.y + abs(DestRect->bottom - DestRect->top)));
572 }
573
574 /* No success yet */
575 ret = FALSE;
576 MouseSafetyOnDrawStart(DestSurf, OutputRect.left, OutputRect.top,
577 OutputRect.right, OutputRect.bottom);
578
579 /* Call the driver's DrvBitBlt if available */
580 if (DestObj->flHooks & HOOK_BITBLT)
581 {
582 ret = GDIDEVFUNCS(DestSurf).BitBlt(
583 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
584 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
585 Rop4);
586 }
587
588 if (! ret)
589 {
590 ret = EngBitBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
591 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin,
592 Rop4);
593 }
594
595 MouseSafetyOnDrawEnd(DestSurf);
596 if (UsesSource)
597 {
598 MouseSafetyOnDrawEnd(SourceSurf);
599 }
600
601 return ret;
602 }
603
604 static BOOLEAN STDCALL
605 CallDibStretchBlt(SURFOBJ* OutputObj,
606 SURFOBJ* InputObj,
607 SURFOBJ* Mask,
608 CLIPOBJ* ClipRegion,
609 XLATEOBJ* ColorTranslation,
610 RECTL* OutputRect,
611 RECTL* InputRect,
612 POINTL* MaskOrigin,
613 POINTL* BrushOrigin,
614 ULONG Mode)
615 {
616 POINTL RealBrushOrigin;
617 if (BrushOrigin == NULL)
618 {
619 RealBrushOrigin.x = RealBrushOrigin.y = 0;
620 }
621 else
622 {
623 RealBrushOrigin = *BrushOrigin;
624 }
625 return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_StretchBlt(
626 OutputObj, InputObj, OutputRect, InputRect, MaskOrigin, RealBrushOrigin, ClipRegion, ColorTranslation, Mode);
627 }
628
629
630 BOOL
631 STDCALL
632 EngStretchBlt(
633 IN SURFOBJ *DestObj,
634 IN SURFOBJ *SourceObj,
635 IN SURFOBJ *Mask,
636 IN CLIPOBJ *ClipRegion,
637 IN XLATEOBJ *ColorTranslation,
638 IN COLORADJUSTMENT *pca,
639 IN POINTL *BrushOrigin,
640 IN RECTL *prclDest,
641 IN RECTL *prclSrc,
642 IN POINTL *MaskOrigin,
643 IN ULONG Mode
644 )
645 {
646 // www.osr.com/ddk/graphics/gdifncs_0bs7.htm
647
648 POINTL InputPoint;
649 RECTL InputRect;
650 RECTL OutputRect;
651 POINTL Translate;
652 INTENG_ENTER_LEAVE EnterLeaveSource;
653 INTENG_ENTER_LEAVE EnterLeaveDest;
654 SURFOBJ* InputObj;
655 SURFOBJ* OutputObj;
656 PSTRETCHRECTFUNC BltRectFunc;
657 BOOLEAN Ret;
658 POINTL AdjustedBrushOrigin;
659
660 InputRect.left = prclSrc->left;
661 InputRect.right = prclSrc->right;
662 InputRect.top = prclSrc->top;
663 InputRect.bottom = prclSrc->bottom;
664
665 if (! IntEngEnter(&EnterLeaveSource, SourceObj, &InputRect, TRUE, &Translate, &InputObj))
666 {
667 return FALSE;
668 }
669
670 InputPoint.x = InputRect.left + Translate.x;
671 InputPoint.y = InputRect.top + Translate.y;
672
673 OutputRect = *prclDest;
674
675 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
676 nothing to do */
677 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
678 {
679 IntEngLeave(&EnterLeaveSource);
680 return TRUE;
681 }
682
683 if (! IntEngEnter(&EnterLeaveDest, DestObj, &OutputRect, FALSE, &Translate, &OutputObj))
684 {
685 IntEngLeave(&EnterLeaveSource);
686 return FALSE;
687 }
688
689 OutputRect.left = prclDest->left + Translate.x;
690 OutputRect.right = prclDest->right + Translate.x;
691 OutputRect.top = prclDest->top + Translate.y;
692 OutputRect.bottom = prclDest->bottom + Translate.y;
693
694 if (NULL != BrushOrigin)
695 {
696 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
697 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
698 }
699 else
700 {
701 AdjustedBrushOrigin = Translate;
702 }
703
704 if (Mask != NULL)
705 {
706 //BltRectFunc = BltMask;
707 DPRINT("EngStretchBlt isn't capable of handling mask yet.\n");
708 IntEngLeave(&EnterLeaveDest);
709 IntEngLeave(&EnterLeaveSource);
710
711 return FALSE;
712 }
713 else
714 {
715 BltRectFunc = CallDibStretchBlt;
716 }
717
718
719 Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ClipRegion,
720 ColorTranslation, &OutputRect, &InputRect, MaskOrigin,
721 &AdjustedBrushOrigin, Mode);
722
723 IntEngLeave(&EnterLeaveDest);
724 IntEngLeave(&EnterLeaveSource);
725
726 return Ret;
727 }
728
729 BOOL STDCALL
730 IntEngStretchBlt(BITMAPOBJ *DestObj,
731 BITMAPOBJ *SourceObj,
732 BITMAPOBJ *MaskObj,
733 CLIPOBJ *ClipRegion,
734 XLATEOBJ *ColorTranslation,
735 RECTL *DestRect,
736 RECTL *SourceRect,
737 POINTL *pMaskOrigin,
738 BRUSHOBJ *Brush,
739 POINTL *BrushOrigin,
740 ULONG Mode)
741 {
742 BOOLEAN ret;
743 COLORADJUSTMENT ca;
744 POINT MaskOrigin;
745 SURFOBJ *DestSurf = &DestObj->SurfObj;
746 SURFOBJ *SourceSurf = SourceObj ? &SourceObj->SurfObj : NULL;
747 SURFOBJ *MaskSurf = MaskObj ? &MaskObj->SurfObj : NULL;
748
749 if (pMaskOrigin != NULL)
750 {
751 MaskOrigin.x = pMaskOrigin->x; MaskOrigin.y = pMaskOrigin->y;
752 }
753
754 if (NULL != SourceObj)
755 {
756 MouseSafetyOnDrawStart(SourceSurf, SourceRect->left, SourceRect->top,
757 SourceRect->right, SourceRect->bottom);
758 }
759
760 /* No success yet */
761 ret = FALSE;
762 MouseSafetyOnDrawStart(DestSurf, DestRect->left, DestRect->top,
763 DestRect->right, DestRect->bottom);
764
765 /* Prepare color adjustment */
766
767 /* Call the driver's DrvStretchBlt if available */
768 if (DestObj->flHooks & HOOK_STRETCHBLT)
769 {
770 /* Drv->StretchBlt (look at http://www.osr.com/ddk/graphics/ddifncs_3ew7.htm )
771 SURFOBJ *psoMask // optional, if it exists, then rop4=0xCCAA, otherwise rop4=0xCCCC */
772 // FIXME: MaskOrigin is always NULL !
773 ret = GDIDEVFUNCS(DestSurf).StretchBlt(
774 DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
775 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
776 }
777
778 if (! ret)
779 {
780 // FIXME: see previous fixme
781 ret = EngStretchBlt(DestSurf, SourceSurf, MaskSurf, ClipRegion, ColorTranslation,
782 &ca, BrushOrigin, DestRect, SourceRect, NULL, Mode);
783 }
784
785 MouseSafetyOnDrawEnd(DestSurf);
786 if (NULL != SourceSurf)
787 {
788 MouseSafetyOnDrawEnd(SourceSurf);
789 }
790
791 return ret;
792 }
793
794 /**** REACTOS FONT RENDERING CODE *********************************************/
795
796 /* renders the alpha mask bitmap */
797 static BOOLEAN STDCALL
798 AlphaBltMask(SURFOBJ* Dest,
799 SURFOBJ* Source,
800 SURFOBJ* Mask,
801 XLATEOBJ* ColorTranslation,
802 XLATEOBJ* SrcColorTranslation,
803 RECTL* DestRect,
804 POINTL* SourcePoint,
805 POINTL* MaskPoint,
806 BRUSHOBJ* Brush,
807 POINTL* BrushPoint)
808 {
809 LONG i, j, dx, dy;
810 int r, g, b;
811 ULONG Background, BrushColor, NewColor;
812 BYTE *tMask, *lMask;
813
814 dx = DestRect->right - DestRect->left;
815 dy = DestRect->bottom - DestRect->top;
816
817 if (Mask != NULL)
818 {
819 BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, Brush->iSolidColor);
820 r = (int)GetRValue(BrushColor);
821 g = (int)GetGValue(BrushColor);
822 b = (int)GetBValue(BrushColor);
823
824 tMask = Mask->pvBits + (SourcePoint->y * Mask->lDelta) + SourcePoint->x;
825 for (j = 0; j < dy; j++)
826 {
827 lMask = tMask;
828 for (i = 0; i < dx; i++)
829 {
830 if (*lMask > 0)
831 {
832 if(*lMask == 0xff)
833 {
834 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
835 Dest, DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
836 }
837 else
838 {
839 Background = DIB_GetSource(Dest, DestRect->left + i, DestRect->top + j, SrcColorTranslation);
840
841 NewColor =
842 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
843 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
844 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
845
846 Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
847 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_PutPixel(
848 Dest, DestRect->left + i, DestRect->top + j, Background);
849 }
850 }
851 lMask++;
852 }
853 tMask += Mask->lDelta;
854 }
855 return TRUE;
856 }
857 else
858 {
859 return FALSE;
860 }
861 }
862
863 BOOL STDCALL
864 EngMaskBitBlt(SURFOBJ *DestObj,
865 SURFOBJ *Mask,
866 CLIPOBJ *ClipRegion,
867 XLATEOBJ *DestColorTranslation,
868 XLATEOBJ *SourceColorTranslation,
869 RECTL *DestRect,
870 POINTL *SourcePoint,
871 POINTL *MaskOrigin,
872 BRUSHOBJ *Brush,
873 POINTL *BrushOrigin)
874 {
875 BYTE clippingType;
876 RECTL CombinedRect;
877 RECT_ENUM RectEnum;
878 BOOL EnumMore;
879 POINTL InputPoint;
880 RECTL InputRect;
881 RECTL OutputRect;
882 POINTL Translate;
883 INTENG_ENTER_LEAVE EnterLeaveSource;
884 INTENG_ENTER_LEAVE EnterLeaveDest;
885 SURFOBJ* InputObj;
886 SURFOBJ* OutputObj;
887 BOOLEAN Ret = TRUE;
888 RECTL ClipRect;
889 unsigned i;
890 POINTL Pt;
891 ULONG Direction;
892 POINTL AdjustedBrushOrigin;
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, NULL, &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, 0xAACC);
996 break;
997 case DC_RECT:
998 // Clip the blt to the clip rectangle
999 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
1000 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
1001 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
1002 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
1003 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1004 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1005 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1006 if(Mask->iBitmapFormat == BMF_8BPP)
1007 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1008 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin);
1009 else
1010 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1011 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, 0xAACC);
1012 break;
1013 case DC_COMPLEX:
1014 Ret = TRUE;
1015 if (OutputObj == InputObj)
1016 {
1017 if (OutputRect.top < InputPoint.y)
1018 {
1019 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
1020 }
1021 else
1022 {
1023 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
1024 }
1025 }
1026 else
1027 {
1028 Direction = CD_ANY;
1029 }
1030 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
1031 do
1032 {
1033 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
1034
1035 for (i = 0; i < RectEnum.c; i++)
1036 {
1037 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
1038 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
1039 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
1040 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
1041 EngIntersectRect(&CombinedRect, &OutputRect, &ClipRect);
1042 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
1043 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
1044 if(Mask->iBitmapFormat == BMF_8BPP)
1045 Ret = AlphaBltMask(OutputObj, InputObj, Mask, DestColorTranslation, SourceColorTranslation,
1046 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin) && Ret;
1047 else
1048 Ret = BltMask(OutputObj, InputObj, Mask, DestColorTranslation,
1049 &CombinedRect, &Pt, MaskOrigin, Brush, &AdjustedBrushOrigin, 0xAACC) && Ret;
1050 }
1051 }
1052 while(EnumMore);
1053 break;
1054 }
1055
1056
1057 IntEngLeave(&EnterLeaveDest);
1058 IntEngLeave(&EnterLeaveSource);
1059
1060 /* Dummy BitBlt to let driver know that something has changed.
1061 0x00AA0029 is the Rop for D (no-op) */
1062 /* FIXME: Remove the typecast! */
1063 IntEngBitBlt((BITMAPOBJ*)DestObj, NULL, (BITMAPOBJ*)Mask, ClipRegion, DestColorTranslation,
1064 DestRect, SourcePoint, MaskOrigin, Brush, BrushOrigin, ROP_NOOP);
1065
1066 return Ret;
1067 }
1068
1069 BOOL STDCALL
1070 IntEngMaskBlt(SURFOBJ *DestObj,
1071 SURFOBJ *Mask,
1072 CLIPOBJ *ClipRegion,
1073 XLATEOBJ *DestColorTranslation,
1074 XLATEOBJ *SourceColorTranslation,
1075 RECTL *DestRect,
1076 POINTL *SourcePoint,
1077 POINTL *MaskOrigin,
1078 BRUSHOBJ *Brush,
1079 POINTL *BrushOrigin)
1080 {
1081 BOOLEAN ret;
1082 RECTL OutputRect;
1083 POINTL InputPoint;
1084
1085 if (NULL != SourcePoint)
1086 {
1087 InputPoint = *SourcePoint;
1088 }
1089
1090 /* Clip against the bounds of the clipping region so we won't try to write
1091 * outside the surface */
1092 if (NULL != ClipRegion)
1093 {
1094 if (! EngIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
1095 {
1096 return TRUE;
1097 }
1098 InputPoint.x += OutputRect.left - DestRect->left;
1099 InputPoint.y += OutputRect.top - DestRect->top;
1100 }
1101 else
1102 {
1103 OutputRect = *DestRect;
1104 }
1105
1106 /* No success yet */
1107 ret = FALSE;
1108 MouseSafetyOnDrawStart(DestObj, OutputRect.left, OutputRect.top,
1109 OutputRect.right, OutputRect.bottom);
1110
1111 ret = EngMaskBitBlt(DestObj, Mask, ClipRegion, DestColorTranslation, SourceColorTranslation,
1112 &OutputRect, &InputPoint, MaskOrigin, Brush, BrushOrigin);
1113
1114 MouseSafetyOnDrawEnd(DestObj);
1115
1116 return ret;
1117 }
1118 /* EOF */