[Win32SS]
[reactos.git] / reactos / win32ss / gdi / eng / bitblt.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: GDI BitBlt Functions
5 * FILE: win32ss/gdi/eng/bitblt.c
6 * PROGRAMER: Jason Filby
7 * Timo Kreuzer
8 */
9
10 #include <win32k.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 XCLIPOBJ gxcoTrivial =
16 {
17 /* CLIPOBJ */
18 {
19 0, /* iUniq */
20 {LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX}, /* rclBounds */
21 DC_TRIVIAL, /* idCOmplexity */
22 FC_RECT, /* iFComplexity */
23 TC_RECTANGLES, /* iMode */
24 0 /* fjOptions */
25 },
26 { 0, {0,0,0,0}, 0},
27 0, {0,0,0,0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
28 };
29
30 typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
31 SURFOBJ* InputObj,
32 SURFOBJ* Mask,
33 XLATEOBJ* ColorTranslation,
34 RECTL* OutputRect,
35 POINTL* InputPoint,
36 POINTL* MaskOrigin,
37 BRUSHOBJ* pbo,
38 POINTL* BrushOrigin,
39 ROP4 Rop4);
40
41 static BOOLEAN APIENTRY
42 BltMask(SURFOBJ* psoDest,
43 SURFOBJ* psoSource,
44 SURFOBJ* psoMask,
45 XLATEOBJ* ColorTranslation,
46 RECTL* prclDest,
47 POINTL* pptlSource,
48 POINTL* pptlMask,
49 BRUSHOBJ* pbo,
50 POINTL* pptlBrush,
51 ROP4 Rop4)
52 {
53 LONG x, y, cx, cy;
54 BYTE *pjMskLine, *pjMskCurrent;
55 BYTE fjMaskBit0, fjMaskBit;
56 /* Pattern brushes */
57 SURFOBJ *psoPattern;
58 ULONG PatternWidth = 0, PatternHeight = 0;
59 LONG PatternX0 = 0, PatternX = 0, PatternY = 0;
60 LONG SrcX = 0, SrcY = 0;
61 PFN_DIB_PutPixel fnDest_PutPixel = NULL;
62 PFN_DIB_GetPixel fnPattern_GetPixel = NULL, fnSrc_GetPixel = NULL, fnDest_GetPixel;
63 ULONG Pattern = 0, Source = 0, Dest = 0;
64 DWORD fgndRop, bkgndRop;
65
66 ASSERT(IS_VALID_ROP4(Rop4));
67 ASSERT(psoMask->iBitmapFormat == BMF_1BPP);
68
69 fgndRop = ROP4_FGND(Rop4);
70 bkgndRop = ROP4_BKGND(Rop4);
71
72 //DPRINT1("Rop4 : 0x%08x\n", Rop4);
73
74 /* Determine pattern */
75 if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
76 {
77 psoPattern = BRUSHOBJ_psoPattern(pbo);
78 if (psoPattern)
79 {
80 PatternWidth = psoPattern->sizlBitmap.cx;
81 PatternHeight = psoPattern->sizlBitmap.cy;
82 fnPattern_GetPixel = DibFunctionsForBitmapFormat[psoPattern->iBitmapFormat].DIB_GetPixel;
83 }
84 }
85 else
86 psoPattern = NULL;
87
88 cx = prclDest->right - prclDest->left;
89 cy = prclDest->bottom - prclDest->top;
90 if ((pptlMask->x + cx > psoMask->sizlBitmap.cx) ||
91 (pptlMask->y + cy > psoMask->sizlBitmap.cy))
92 {
93 return FALSE;
94 }
95
96 pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta + (pptlMask->x >> 3);
97 fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07);
98
99 fnDest_PutPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel;
100 fnDest_GetPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_GetPixel;
101
102 /* Do we have a source */
103 if(psoSource)
104 {
105 /* Sanity check */
106 ASSERT(ROP4_USES_SOURCE(Rop4));
107 fnSrc_GetPixel = DibFunctionsForBitmapFormat[psoSource->iBitmapFormat].DIB_GetPixel;
108 SrcY = pptlSource->y;
109 SrcX = pptlSource->x;
110 }
111
112 if (psoPattern)
113 {
114 PatternY = (prclDest->top - pptlBrush->y) % PatternHeight;
115 if (PatternY < 0)
116 {
117 PatternY += PatternHeight;
118 }
119 PatternX0 = (prclDest->left - pptlBrush->x) % PatternWidth;
120 if (PatternX0 < 0)
121 {
122 PatternX0 += PatternWidth;
123 }
124 PatternX = PatternX0;
125 }
126 else
127 {
128 Pattern = pbo ? pbo->iSolidColor : 0;
129 }
130
131 for (y = prclDest->top; y < prclDest->bottom; y++)
132 {
133 pjMskCurrent = pjMskLine;
134 fjMaskBit = fjMaskBit0;
135
136 for (x = prclDest->left; x < prclDest->right; x++)
137 {
138 Rop4 = (*pjMskCurrent & fjMaskBit) ? fgndRop : bkgndRop;
139
140 if(psoPattern)
141 {
142 if(ROP4_USES_PATTERN(Rop4))
143 Pattern = fnPattern_GetPixel(psoPattern, PatternX, PatternY);
144 PatternX++;
145 PatternX %= PatternWidth;
146 }
147
148 if(psoSource)
149 {
150 if(ROP4_USES_SOURCE(Rop4))
151 {
152 Source = XLATEOBJ_iXlate(ColorTranslation,
153 fnSrc_GetPixel(psoSource, SrcX, SrcY));
154 }
155 SrcX++;
156 }
157
158 if(ROP4_USES_DEST(Rop4))
159 Dest = fnDest_GetPixel(psoDest, x, y);
160
161 fnDest_PutPixel(psoDest,
162 x,
163 y,
164 DIB_DoRop(Rop4,
165 Dest,
166 Source,
167 Pattern));
168 fjMaskBit = _rotr8(fjMaskBit, 1);
169 pjMskCurrent += (fjMaskBit >> 7);
170 }
171 pjMskLine += psoMask->lDelta;
172 if(psoPattern)
173 {
174 PatternY++;
175 PatternY %= PatternHeight;
176 PatternX = PatternX0;
177 }
178 if(psoSource)
179 {
180 SrcY++;
181 SrcX = pptlSource->x;
182 }
183 }
184
185 return TRUE;
186 }
187
188 #ifndef _USE_DIBLIB_
189
190 static BOOLEAN APIENTRY
191 BltPatCopy(SURFOBJ* Dest,
192 SURFOBJ* Source,
193 SURFOBJ* Mask,
194 XLATEOBJ* ColorTranslation,
195 RECTL* DestRect,
196 POINTL* SourcePoint,
197 POINTL* MaskPoint,
198 BRUSHOBJ* pbo,
199 POINTL* BrushPoint,
200 DWORD Rop4)
201 {
202 // These functions are assigned if we're working with a DIB
203 // The assigned functions depend on the bitsPerPixel of the DIB
204
205 DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, pbo ? pbo->iSolidColor : 0);
206
207 return TRUE;
208 }
209
210 static BOOLEAN APIENTRY
211 CallDibBitBlt(SURFOBJ* OutputObj,
212 SURFOBJ* InputObj,
213 SURFOBJ* Mask,
214 XLATEOBJ* ColorTranslation,
215 RECTL* OutputRect,
216 POINTL* InputPoint,
217 POINTL* MaskOrigin,
218 BRUSHOBJ* pbo,
219 POINTL* BrushOrigin,
220 ROP4 Rop4)
221 {
222 BLTINFO BltInfo;
223 SURFOBJ *psoPattern;
224 BOOLEAN Result;
225
226 BltInfo.DestSurface = OutputObj;
227 BltInfo.SourceSurface = InputObj;
228 BltInfo.PatternSurface = NULL;
229 BltInfo.XlateSourceToDest = ColorTranslation;
230 BltInfo.DestRect = *OutputRect;
231 BltInfo.SourcePoint = *InputPoint;
232
233 if ((Rop4 & 0xFF) == R3_OPINDEX_SRCCOPY)
234 return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo);
235
236 BltInfo.Brush = pbo;
237 BltInfo.BrushOrigin = *BrushOrigin;
238 BltInfo.Rop4 = Rop4;
239
240 /* Pattern brush */
241 if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
242 {
243 psoPattern = BRUSHOBJ_psoPattern(pbo);
244 if (psoPattern)
245 {
246 BltInfo.PatternSurface = psoPattern;
247 }
248 else
249 {
250 /* FIXME: What to do here? */
251 }
252 }
253 else
254 {
255 psoPattern = NULL;
256 }
257
258 Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
259
260 return Result;
261 }
262
263 INT __cdecl abs(INT nm);
264
265
266 /*
267 * @implemented
268 */
269 BOOL APIENTRY
270 NtGdiEngBitBlt(
271 IN SURFOBJ *psoTrg,
272 IN SURFOBJ *psoSrc,
273 IN SURFOBJ *psoMask,
274 IN CLIPOBJ *pco,
275 IN XLATEOBJ *pxlo,
276 IN RECTL *prclTrg,
277 IN POINTL *pptlSrc,
278 IN POINTL *pptlMask,
279 IN BRUSHOBJ *pbo,
280 IN POINTL *pptlBrush,
281 IN ROP4 Rop4)
282 {
283 RECTL rclTrg;
284 POINTL ptlSrc;
285 POINTL ptlMask;
286 POINTL ptlBrush;
287
288 _SEH2_TRY
289 {
290 ProbeForRead(prclTrg, sizeof(RECTL), 1);
291 RtlCopyMemory(&rclTrg,prclTrg, sizeof(RECTL));
292
293 ProbeForRead(pptlSrc, sizeof(POINTL), 1);
294 RtlCopyMemory(&ptlSrc, pptlSrc, sizeof(POINTL));
295
296 ProbeForRead(pptlMask, sizeof(POINTL), 1);
297 RtlCopyMemory(&ptlMask, pptlMask, sizeof(POINTL));
298
299 ProbeForRead(pptlBrush, sizeof(POINTL), 1);
300 RtlCopyMemory(&ptlBrush, pptlBrush, sizeof(POINTL));
301
302 }
303 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
304 {
305 _SEH2_YIELD(return FALSE);
306 }
307 _SEH2_END;
308
309 return EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg, &ptlSrc, &ptlMask, pbo, &ptlBrush, Rop4);
310 }
311
312 /*
313 * @implemented
314 */
315 BOOL
316 APIENTRY
317 EngBitBlt(
318 _Inout_ SURFOBJ *psoTrg,
319 _In_opt_ SURFOBJ *psoSrc,
320 _In_opt_ SURFOBJ *psoMask,
321 _In_opt_ CLIPOBJ *pco,
322 _In_opt_ XLATEOBJ *pxlo,
323 _In_ RECTL *prclTrg,
324 _In_opt_ POINTL *pptlSrc,
325 _In_opt_ POINTL *pptlMask,
326 _In_opt_ BRUSHOBJ *pbo,
327 _In_opt_ POINTL *pptlBrush,
328 _In_ ROP4 rop4)
329 {
330 BYTE clippingType;
331 RECTL CombinedRect;
332 RECT_ENUM RectEnum;
333 BOOL EnumMore;
334 POINTL InputPoint;
335 RECTL InputRect;
336 RECTL OutputRect;
337 SURFOBJ* InputObj = 0;
338 SURFOBJ* OutputObj;
339 PBLTRECTFUNC BltRectFunc;
340 BOOLEAN Ret = TRUE;
341 RECTL ClipRect;
342 ULONG i;
343 POINTL Pt;
344 ULONG Direction;
345 BOOL UsesSource, UsesMask;
346 POINTL AdjustedBrushOrigin;
347
348 UsesSource = ROP4_USES_SOURCE(rop4);
349 UsesMask = ROP4_USES_MASK(rop4);
350
351 if (rop4 == ROP4_NOOP)
352 {
353 /* Copy destination onto itself: nop */
354 return TRUE;
355 }
356
357 //DPRINT1("rop4 : 0x%08x\n", rop4);
358
359 OutputRect = *prclTrg;
360 RECTL_vMakeWellOrdered(&OutputRect);
361
362 if (UsesSource)
363 {
364 if (!psoSrc || !pptlSrc)
365 {
366 return FALSE;
367 }
368
369 /* Make sure we don't try to copy anything outside the valid source
370 region */
371 InputPoint = *pptlSrc;
372 if (InputPoint.x < 0)
373 {
374 OutputRect.left -= InputPoint.x;
375 InputPoint.x = 0;
376 }
377 if (InputPoint.y < 0)
378 {
379 OutputRect.top -= InputPoint.y;
380 InputPoint.y = 0;
381 }
382 if (psoSrc->sizlBitmap.cx < InputPoint.x +
383 OutputRect.right - OutputRect.left)
384 {
385 OutputRect.right = OutputRect.left +
386 psoSrc->sizlBitmap.cx - InputPoint.x;
387 }
388 if (psoSrc->sizlBitmap.cy < InputPoint.y +
389 OutputRect.bottom - OutputRect.top)
390 {
391 OutputRect.bottom = OutputRect.top +
392 psoSrc->sizlBitmap.cy - InputPoint.y;
393 }
394
395 InputRect.left = InputPoint.x;
396 InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left);
397 InputRect.top = InputPoint.y;
398 InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top);
399
400 InputObj = psoSrc;
401 }
402 else
403 {
404 InputPoint.x = InputPoint.y = 0;
405 InputRect.left = 0;
406 InputRect.right = prclTrg->right - prclTrg->left;
407 InputRect.top = 0;
408 InputRect.bottom = prclTrg->bottom - prclTrg->top;
409 }
410
411 if (NULL != pco)
412 {
413 if (OutputRect.left < pco->rclBounds.left)
414 {
415 InputRect.left += pco->rclBounds.left - OutputRect.left;
416 InputPoint.x += pco->rclBounds.left - OutputRect.left;
417 OutputRect.left = pco->rclBounds.left;
418 }
419 if (pco->rclBounds.right < OutputRect.right)
420 {
421 InputRect.right -= OutputRect.right - pco->rclBounds.right;
422 OutputRect.right = pco->rclBounds.right;
423 }
424 if (OutputRect.top < pco->rclBounds.top)
425 {
426 InputRect.top += pco->rclBounds.top - OutputRect.top;
427 InputPoint.y += pco->rclBounds.top - OutputRect.top;
428 OutputRect.top = pco->rclBounds.top;
429 }
430 if (pco->rclBounds.bottom < OutputRect.bottom)
431 {
432 InputRect.bottom -= OutputRect.bottom - pco->rclBounds.bottom;
433 OutputRect.bottom = pco->rclBounds.bottom;
434 }
435 }
436
437 /* Check for degenerate case: if height or width of OutputRect is 0 pixels
438 there's nothing to do */
439 if (OutputRect.right <= OutputRect.left ||
440 OutputRect.bottom <= OutputRect.top)
441 {
442 return TRUE;
443 }
444
445 OutputObj = psoTrg;
446
447 if (pptlBrush)
448 {
449 AdjustedBrushOrigin.x = pptlBrush->x;
450 AdjustedBrushOrigin.y = pptlBrush->y;
451 }
452 else
453 {
454 AdjustedBrushOrigin.x = 0;
455 AdjustedBrushOrigin.y = 0;
456 }
457
458 /* Determine clipping type */
459 if (pco == (CLIPOBJ *) NULL)
460 {
461 clippingType = DC_TRIVIAL;
462 }
463 else
464 {
465 clippingType = pco->iDComplexity;
466 }
467
468 /* Check if we need a mask but have no mask surface */
469 if (UsesMask && (psoMask == NULL))
470 {
471 /* Check if the BRUSHOBJ can provide the mask */
472 psoMask = BRUSHOBJ_psoMask(pbo);
473 if (psoMask == NULL)
474 {
475 /* We have no mask, assume the mask is all foreground */
476 rop4 = (rop4 & 0xFF) | ((rop4 & 0xFF) << 8);
477 UsesMask = FALSE;
478 }
479 }
480
481 if (UsesMask)
482 {
483 BltRectFunc = BltMask;
484 }
485 else if ((rop4 & 0xFF) == R3_OPINDEX_PATCOPY)
486 {
487 if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
488 BltRectFunc = CallDibBitBlt;
489 else
490 BltRectFunc = BltPatCopy;
491 }
492 else
493 {
494 BltRectFunc = CallDibBitBlt;
495 }
496
497
498 switch (clippingType)
499 {
500 case DC_TRIVIAL:
501 Ret = (*BltRectFunc)(OutputObj,
502 InputObj,
503 psoMask,
504 pxlo,
505 &OutputRect,
506 &InputPoint,
507 pptlMask,
508 pbo,
509 &AdjustedBrushOrigin,
510 rop4);
511 break;
512 case DC_RECT:
513 /* Clip the blt to the clip rectangle */
514 ClipRect.left = pco->rclBounds.left;
515 ClipRect.right = pco->rclBounds.right;
516 ClipRect.top = pco->rclBounds.top;
517 ClipRect.bottom = pco->rclBounds.bottom;
518 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
519 {
520 #ifdef _USE_DIBLIB_
521 if (BrushOrigin)
522 {
523 AdjustedBrushOrigin.x = BrushOrigin->x + CombinedRect.left - OutputRect.left;
524 AdjustedBrushOrigin.y = BrushOrigin->y + CombinedRect.top - OutputRect.top;
525 }
526 #endif
527 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
528 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
529 Ret = (*BltRectFunc)(OutputObj,
530 InputObj,
531 psoMask,
532 pxlo,
533 &CombinedRect,
534 &Pt,
535 pptlMask,
536 pbo,
537 &AdjustedBrushOrigin,
538 rop4);
539 }
540 break;
541 case DC_COMPLEX:
542 Ret = TRUE;
543 if (OutputObj == InputObj)
544 {
545 if (OutputRect.top < InputPoint.y)
546 {
547 Direction = OutputRect.left < InputPoint.x ?
548 CD_RIGHTDOWN : CD_LEFTDOWN;
549 }
550 else
551 {
552 Direction = OutputRect.left < InputPoint.x ?
553 CD_RIGHTUP : CD_LEFTUP;
554 }
555 }
556 else
557 {
558 Direction = CD_ANY;
559 }
560 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, Direction, 0);
561 do
562 {
563 EnumMore = CLIPOBJ_bEnum(pco, sizeof(RectEnum),
564 (PVOID) &RectEnum);
565
566 for (i = 0; i < RectEnum.c; i++)
567 {
568 ClipRect.left = RectEnum.arcl[i].left;
569 ClipRect.right = RectEnum.arcl[i].right;
570 ClipRect.top = RectEnum.arcl[i].top;
571 ClipRect.bottom = RectEnum.arcl[i].bottom;
572 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
573 {
574 #ifdef _USE_DIBLIB_
575 if (BrushOrigin)
576 {
577 AdjustedBrushOrigin.x = BrushOrigin->x + CombinedRect.left - OutputRect.left;
578 AdjustedBrushOrigin.y = BrushOrigin->y + CombinedRect.top - OutputRect.top;
579 }
580 #endif
581 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
582 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
583 Ret = (*BltRectFunc)(OutputObj,
584 InputObj,
585 psoMask,
586 pxlo,
587 &CombinedRect,
588 &Pt,
589 pptlMask,
590 pbo,
591 &AdjustedBrushOrigin,
592 rop4) && Ret;
593 }
594 }
595 }
596 while (EnumMore);
597 break;
598 }
599
600 return Ret;
601 }
602
603 BOOL APIENTRY
604 IntEngBitBlt(
605 SURFOBJ *psoTrg,
606 SURFOBJ *psoSrc,
607 SURFOBJ *psoMask,
608 CLIPOBJ *pco,
609 XLATEOBJ *pxlo,
610 RECTL *prclTrg,
611 POINTL *pptlSrc,
612 POINTL *pptlMask,
613 BRUSHOBJ *pbo,
614 POINTL *pptlBrush,
615 ROP4 Rop4)
616 {
617 SURFACE *psurfTrg;
618 SURFACE *psurfSrc = NULL;
619 BOOL bResult;
620 RECTL rclClipped;
621 RECTL rclSrc;
622 POINTL ptlBrush;
623 PFN_DrvBitBlt pfnBitBlt;
624
625 ASSERT(psoTrg);
626 psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj);
627
628 /* FIXME: Should we really allow to pass non-well-ordered rects? */
629 rclClipped = *prclTrg;
630 RECTL_vMakeWellOrdered(&rclClipped);
631
632 //DPRINT1("Rop4 : 0x%08x\n", Rop4);
633
634 /* Sanity check */
635 ASSERT(IS_VALID_ROP4(Rop4));
636
637 if (pco)
638 {
639 /* Clip target rect against the bounds of the clipping region */
640 if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds))
641 {
642 /* Nothing left */
643 return TRUE;
644 }
645
646 /* Don't pass a clipobj with only a single rect */
647 if (pco->iDComplexity == DC_RECT)
648 pco = NULL;
649 }
650 else
651 pco = (CLIPOBJ *)&gxcoTrivial;
652
653 if (ROP4_USES_SOURCE(Rop4))
654 {
655 ASSERT(psoSrc);
656 psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj);
657
658 /* Calculate source rect */
659 rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left;
660 rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top;
661 rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left;
662 rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top;
663 pptlSrc = (PPOINTL)&rclSrc;
664 }
665 else
666 {
667 psoSrc = NULL;
668 psurfSrc = NULL;
669 }
670
671 if (pptlBrush)
672 {
673 #ifdef _USE_DIBLIB_
674 ptlBrush.x = pptlBrush->x + rclClipped.left - prclTrg->left;
675 ptlBrush.y = pptlBrush->y + rclClipped.top - prclTrg->top;
676 #else
677 ptlBrush = *pptlBrush;
678 #endif
679 }
680
681 /* Is the target surface device managed? */
682 if (psurfTrg->flags & HOOK_BITBLT)
683 {
684 /* Is the source a different device managed surface? */
685 if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flags & HOOK_BITBLT)
686 {
687 DPRINT1("Need to copy to standard bitmap format!\n");
688 ASSERT(FALSE);
689 }
690
691 pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;
692 }
693
694 /* Is the source surface device managed? */
695 else if (psoSrc && psurfSrc->flags & HOOK_BITBLT)
696 {
697 pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
698 }
699 else
700 {
701 pfnBitBlt = EngBitBlt;
702 }
703
704 bResult = pfnBitBlt(psoTrg,
705 psoSrc,
706 psoMask,
707 pco,
708 pxlo,
709 &rclClipped,
710 pptlSrc,
711 pptlMask,
712 pbo,
713 pptlBrush ? &ptlBrush : NULL,
714 Rop4);
715
716 // FIXME: cleanup temp surface!
717
718 return bResult;
719 }
720
721 #endif // !_USE_DIBLIB_
722
723 /**** REACTOS FONT RENDERING CODE *********************************************/
724
725 /* renders the alpha mask bitmap */
726 static BOOLEAN APIENTRY
727 AlphaBltMask(SURFOBJ* psoDest,
728 SURFOBJ* psoSource, // unused
729 SURFOBJ* psoMask,
730 XLATEOBJ* pxloRGB2Dest,
731 XLATEOBJ* pxloBrush,
732 RECTL* prclDest,
733 POINTL* pptlSource, // unused
734 POINTL* pptlMask,
735 BRUSHOBJ* pbo,
736 POINTL* pptlBrush)
737 {
738 LONG i, j, dx, dy;
739 int r, g, b;
740 ULONG Background, BrushColor, NewColor;
741 BYTE *tMask, *lMask;
742
743 ASSERT(psoSource == NULL);
744 ASSERT(pptlSource == NULL);
745
746 dx = prclDest->right - prclDest->left;
747 dy = prclDest->bottom - prclDest->top;
748
749 if (psoMask != NULL)
750 {
751 BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0);
752 r = (int)GetRValue(BrushColor);
753 g = (int)GetGValue(BrushColor);
754 b = (int)GetBValue(BrushColor);
755
756 tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x;
757 for (j = 0; j < dy; j++)
758 {
759 lMask = tMask;
760 for (i = 0; i < dx; i++)
761 {
762 if (*lMask > 0)
763 {
764 if (*lMask == 0xff)
765 {
766 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
767 psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0);
768 }
769 else
770 {
771 Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j,
772 pxloBrush);
773
774 NewColor =
775 RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
776 (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
777 (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
778
779 Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor);
780 DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
781 psoDest, prclDest->left + i, prclDest->top + j, Background);
782 }
783 }
784 lMask++;
785 }
786 tMask += psoMask->lDelta;
787 }
788 return TRUE;
789 }
790 else
791 {
792 return FALSE;
793 }
794 }
795
796 static
797 BOOL APIENTRY
798 EngMaskBitBlt(SURFOBJ *psoDest,
799 SURFOBJ *psoMask,
800 CLIPOBJ *ClipRegion,
801 XLATEOBJ *DestColorTranslation,
802 XLATEOBJ *SourceColorTranslation,
803 RECTL *DestRect,
804 POINTL *pptlMask,
805 BRUSHOBJ *pbo,
806 POINTL *BrushOrigin)
807 {
808 BYTE clippingType;
809 RECTL CombinedRect;
810 RECT_ENUM RectEnum;
811 BOOL EnumMore;
812 POINTL InputPoint;
813 RECTL InputRect;
814 RECTL OutputRect;
815 POINTL Translate;
816 INTENG_ENTER_LEAVE EnterLeaveSource;
817 INTENG_ENTER_LEAVE EnterLeaveDest;
818 SURFOBJ* psoInput;
819 SURFOBJ* psoOutput;
820 BOOLEAN Ret = TRUE;
821 RECTL ClipRect;
822 unsigned i;
823 POINTL Pt;
824 ULONG Direction;
825 POINTL AdjustedBrushOrigin;
826
827 ASSERT(psoMask);
828
829 if (pptlMask)
830 {
831 InputRect.left = pptlMask->x;
832 InputRect.right = pptlMask->x + (DestRect->right - DestRect->left);
833 InputRect.top = pptlMask->y;
834 InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top);
835 }
836 else
837 {
838 InputRect.left = 0;
839 InputRect.right = DestRect->right - DestRect->left;
840 InputRect.top = 0;
841 InputRect.bottom = DestRect->bottom - DestRect->top;
842 }
843
844 OutputRect = *DestRect;
845 if (NULL != ClipRegion)
846 {
847 if (OutputRect.left < ClipRegion->rclBounds.left)
848 {
849 InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
850 OutputRect.left = ClipRegion->rclBounds.left;
851 }
852 if (ClipRegion->rclBounds.right < OutputRect.right)
853 {
854 InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
855 OutputRect.right = ClipRegion->rclBounds.right;
856 }
857 if (OutputRect.top < ClipRegion->rclBounds.top)
858 {
859 InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
860 OutputRect.top = ClipRegion->rclBounds.top;
861 }
862 if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
863 {
864 InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
865 OutputRect.bottom = ClipRegion->rclBounds.bottom;
866 }
867 }
868
869 if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput))
870 {
871 return FALSE;
872 }
873
874 InputPoint.x = InputRect.left + Translate.x;
875 InputPoint.y = InputRect.top + Translate.y;
876
877 /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
878 nothing to do */
879 if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
880 {
881 IntEngLeave(&EnterLeaveSource);
882 return TRUE;
883 }
884
885 if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
886 {
887 IntEngLeave(&EnterLeaveSource);
888 return FALSE;
889 }
890
891 OutputRect.left = DestRect->left + Translate.x;
892 OutputRect.right = DestRect->right + Translate.x;
893 OutputRect.top = DestRect->top + Translate.y;
894 OutputRect.bottom = DestRect->bottom + Translate.y;
895
896 if (BrushOrigin)
897 {
898 AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
899 AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
900 }
901 else
902 AdjustedBrushOrigin = Translate;
903
904 // Determine clipping type
905 if (ClipRegion == (CLIPOBJ *) NULL)
906 {
907 clippingType = DC_TRIVIAL;
908 } else {
909 clippingType = ClipRegion->iDComplexity;
910 }
911
912 switch (clippingType)
913 {
914 case DC_TRIVIAL:
915 if (psoMask->iBitmapFormat == BMF_8BPP)
916 Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation,
917 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin);
918 else
919 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
920 &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin,
921 ROP4_MASK);
922 break;
923 case DC_RECT:
924 // Clip the blt to the clip rectangle
925 ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
926 ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
927 ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
928 ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
929 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
930 {
931 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
932 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
933 if (psoMask->iBitmapFormat == BMF_8BPP)
934 {
935 Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation,
936 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin);
937 }
938 else
939 {
940 Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
941 &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, ROP4_MASK);
942 }
943 }
944 break;
945 case DC_COMPLEX:
946 Ret = TRUE;
947 if (psoOutput == psoInput)
948 {
949 if (OutputRect.top < InputPoint.y)
950 {
951 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
952 }
953 else
954 {
955 Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
956 }
957 }
958 else
959 {
960 Direction = CD_ANY;
961 }
962 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
963 do
964 {
965 EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
966
967 for (i = 0; i < RectEnum.c; i++)
968 {
969 ClipRect.left = RectEnum.arcl[i].left + Translate.x;
970 ClipRect.right = RectEnum.arcl[i].right + Translate.x;
971 ClipRect.top = RectEnum.arcl[i].top + Translate.y;
972 ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
973 if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
974 {
975 Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
976 Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
977 if (psoMask->iBitmapFormat == BMF_8BPP)
978 {
979 Ret = AlphaBltMask(psoOutput, NULL, psoInput,
980 DestColorTranslation,
981 SourceColorTranslation,
982 &CombinedRect, NULL, &Pt, pbo,
983 &AdjustedBrushOrigin) && Ret;
984 }
985 else
986 {
987 Ret = BltMask(psoOutput, NULL, psoInput,
988 DestColorTranslation, &CombinedRect, NULL,
989 &Pt, pbo, &AdjustedBrushOrigin,
990 ROP4_MASK) && Ret;
991 }
992 }
993 }
994 }
995 while (EnumMore);
996 break;
997 }
998
999
1000 IntEngLeave(&EnterLeaveDest);
1001 IntEngLeave(&EnterLeaveSource);
1002
1003 return Ret;
1004 }
1005
1006 BOOL
1007 APIENTRY
1008 IntEngMaskBlt(
1009 _Inout_ SURFOBJ *psoDest,
1010 _In_ SURFOBJ *psoMask,
1011 _In_ CLIPOBJ *pco,
1012 _In_ XLATEOBJ *pxloDest,
1013 _In_ XLATEOBJ *pxloSource,
1014 _In_ RECTL *prclDest,
1015 _In_ POINTL *pptlMask,
1016 _In_ BRUSHOBJ *pbo,
1017 _In_ POINTL *pptlBrushOrg)
1018 {
1019 BOOLEAN ret;
1020 RECTL rcDest;
1021 POINTL ptMask = {0,0};
1022 PSURFACE psurfTemp;
1023 RECTL rcTemp;
1024
1025 ASSERT(psoDest);
1026 ASSERT(psoMask);
1027
1028 /* Is this a 1 BPP mask? */
1029 if (psoMask->iBitmapFormat == BMF_1BPP)
1030 {
1031 /* Use IntEngBitBlt with an appropriate ROP4 */
1032 return IntEngBitBlt(psoDest,
1033 NULL,
1034 psoMask,
1035 pco,
1036 pxloDest,
1037 prclDest,
1038 NULL,
1039 pptlMask,
1040 pbo,
1041 pptlBrushOrg,
1042 ROP4_MASKPAINT);
1043 }
1044
1045 ASSERT(psoMask->iBitmapFormat == BMF_8BPP);
1046
1047 if (pptlMask)
1048 {
1049 ptMask = *pptlMask;
1050 }
1051
1052 /* Clip against the bounds of the clipping region so we won't try to write
1053 * outside the surface */
1054 if (pco != NULL)
1055 {
1056 /* Intersect with the clip bounds and check if everything was clipped */
1057 if (!RECTL_bIntersectRect(&rcDest, prclDest, &pco->rclBounds))
1058 {
1059 return TRUE;
1060 }
1061
1062 /* Adjust the mask point */
1063 ptMask.x += rcDest.left - prclDest->left;
1064 ptMask.y += rcDest.top - prclDest->top;
1065 }
1066 else
1067 {
1068 rcDest = *prclDest;
1069 }
1070
1071 /* Check if the target surface is device managed */
1072 if (psoDest->iType != STYPE_BITMAP)
1073 {
1074 rcTemp.left = 0;
1075 rcTemp.top = 0;
1076 rcTemp.right = rcDest.right - rcDest.left;
1077 rcTemp.bottom = rcDest.bottom - rcDest.top;
1078
1079 /* Allocate a temporary surface */
1080 psurfTemp = SURFACE_AllocSurface(STYPE_BITMAP,
1081 rcTemp.right,
1082 rcTemp.bottom,
1083 psoDest->iBitmapFormat,
1084 0,
1085 0,
1086 0,
1087 NULL);
1088 if (psurfTemp == NULL)
1089 {
1090 return FALSE;
1091 }
1092
1093 /* Copy the current target surface bits to the temp surface */
1094 ret = EngCopyBits(&psurfTemp->SurfObj,
1095 psoDest,
1096 NULL, // pco
1097 NULL, // pxlo
1098 &rcTemp,
1099 (PPOINTL)&rcDest);
1100
1101 if (ret)
1102 {
1103 /* Do the operation on the temp surface */
1104 ret = EngMaskBitBlt(&psurfTemp->SurfObj,
1105 psoMask,
1106 NULL,
1107 pxloDest,
1108 pxloSource,
1109 &rcTemp,
1110 &ptMask,
1111 pbo,
1112 pptlBrushOrg);
1113 }
1114
1115 if (ret)
1116 {
1117 /* Copy the result back to the dest surface */
1118 ret = EngCopyBits(psoDest,
1119 &psurfTemp->SurfObj,
1120 pco,
1121 NULL,
1122 &rcDest,
1123 (PPOINTL)&rcTemp);
1124 }
1125
1126 /* Delete the temp surface */
1127 GDIOBJ_vDeleteObject(&psurfTemp->BaseObject);
1128 }
1129 else
1130 {
1131 /* Do the operation on the target surface */
1132 ret = EngMaskBitBlt(psoDest,
1133 psoMask,
1134 pco,
1135 pxloDest,
1136 pxloSource,
1137 &rcDest,
1138 &ptMask,
1139 pbo,
1140 pptlBrushOrg);
1141 }
1142
1143 return ret;
1144 }
1145
1146 /* EOF */