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