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