xref: /reactos/win32ss/gdi/dib/dib32bpp.c (revision 6b700c6a)
1 /*
2  * PROJECT:         Win32 subsystem
3  * LICENSE:         See COPYING in the top level directory
4  * FILE:            win32ss/gdi/dib/dib32bpp.c
5  * PURPOSE:         Device Independant Bitmap functions, 32bpp
6  * PROGRAMMERS:     Jason Filby
7  *                  Thomas Bluemel
8  *                  Gregor Anich
9  *                  Doug Lyons
10  */
11 
12 #include <win32k.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 #define DEC_OR_INC(var, decTrue, amount) \
18     ((var) = (decTrue) ? ((var) - (amount)) : ((var) + (amount)))
19 
20 VOID
21 DIB_32BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
22 {
23   PBYTE byteaddr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta;
24   PDWORD addr = (PDWORD)byteaddr + x;
25 
26   *addr = c;
27 }
28 
29 ULONG
30 DIB_32BPP_GetPixel(SURFOBJ *SurfObj, LONG x, LONG y)
31 {
32   PBYTE byteaddr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta;
33   PDWORD addr = (PDWORD)byteaddr + x;
34 
35   return (ULONG)(*addr);
36 }
37 
38 VOID
39 DIB_32BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
40 {
41   PBYTE byteaddr = (PBYTE)SurfObj->pvScan0 + y1 * SurfObj->lDelta;
42   PDWORD addr = (PDWORD)byteaddr + x;
43   LONG lDelta = SurfObj->lDelta >> 2; // >> 2 == / sizeof(DWORD)
44 
45   byteaddr = (PBYTE)addr;
46   while (y1++ < y2)
47   {
48     *addr = (DWORD)c;
49     addr += lDelta;
50   }
51 }
52 
53 BOOLEAN
54 DIB_32BPP_BitBltSrcCopy(PBLTINFO BltInfo)
55 {
56   LONG     i, j, sx, sy, xColor, f1;
57   PBYTE    SourceBits, DestBits, SourceLine, DestLine;
58   PBYTE    SourceBitsT, SourceBitsB, DestBitsT, DestBitsB;
59   PBYTE    SourceBits_4BPP, SourceLine_4BPP;
60   PDWORD   Source32, Dest32;
61   DWORD    Index, DestWidth, DestHeight;
62   BOOLEAN  bTopToBottom, bLeftToRight;
63   BOOLEAN  blDeltaSrcNeg, blDeltaDestNeg;
64   BOOLEAN  blDeltaAdjustDone = FALSE;
65 
66   DPRINT("DIB_32BPP_BitBltSrcCopy: SourcePoint (%d, %d), SourceSurface cx/cy (%d/%d), "
67          "DestSurface cx/cy (%d/%d) DestRect: (%d,%d)-(%d,%d)\n",
68          BltInfo->SourcePoint.x, BltInfo->SourcePoint.y,
69          BltInfo->SourceSurface->sizlBitmap.cx, BltInfo->SourceSurface->sizlBitmap.cy,
70          BltInfo->DestSurface->sizlBitmap.cx, BltInfo->DestSurface->sizlBitmap.cy,
71          BltInfo->DestRect.left, BltInfo->DestRect.top, BltInfo->DestRect.right, BltInfo->DestRect.bottom);
72 
73   DPRINT("BltInfo->DestSurface->lDelta is '%d' and BltInfo->SourceSurface->lDelta is '%d'.\n",
74            BltInfo->DestSurface->lDelta,  BltInfo->SourceSurface->lDelta);
75 
76   DPRINT("iBitmapFormat is %d and width,height is (%d,%d).\n", BltInfo->SourceSurface->iBitmapFormat,
77          BltInfo->DestRect.right - BltInfo->DestRect.left, BltInfo->DestRect.bottom - BltInfo->DestRect.top);
78 
79   DPRINT("BltInfo->SourcePoint.x is '%d' and BltInfo->SourcePoint.y is '%d'.\n",
80          BltInfo->SourcePoint.x, BltInfo->SourcePoint.y);
81 
82   /* Do not deal with negative numbers for these values */
83   if ((BltInfo->DestRect.left < 0) || (BltInfo->DestRect.top < 0) ||
84       (BltInfo->DestRect.right < 0) || (BltInfo->DestRect.bottom < 0))
85     return FALSE;
86 
87   /* Detect negative lDelta's meaning Bottom-Up bitmaps */
88   blDeltaSrcNeg = BltInfo->SourceSurface->lDelta < 0;
89   blDeltaDestNeg = BltInfo->DestSurface->lDelta < 0;
90 
91   /* Get back left to right flip here */
92   bLeftToRight = BltInfo->DestRect.left > BltInfo->DestRect.right;
93 
94   /* Check for top to bottom flip needed. */
95   bTopToBottom = BltInfo->DestRect.top > BltInfo->DestRect.bottom;
96 
97   DPRINT("bTopToBottom is '%d' and DestSurface->lDelta < 0 is '%d' and SourceSurface->lDelta < 0 is '%d'.\n",
98            bTopToBottom, BltInfo->DestSurface->lDelta < 0 ? 1 : 0,  BltInfo->SourceSurface->lDelta < 0 ? 1 : 0);
99 
100   /* Make WellOrdered with top < bottom and left < right */
101   RECTL_vMakeWellOrdered(&BltInfo->DestRect);
102 
103   DestWidth = BltInfo->DestRect.right - BltInfo->DestRect.left;
104   DestHeight = BltInfo->DestRect.bottom - BltInfo->DestRect.top;
105 
106   DestBits = (PBYTE)BltInfo->DestSurface->pvScan0
107     + (BltInfo->DestRect.top * BltInfo->DestSurface->lDelta)
108     + 4 * BltInfo->DestRect.left;
109 
110   DPRINT("iBitmapFormat is %d and width,height is (%d,%d).\n", BltInfo->SourceSurface->iBitmapFormat,
111          DestWidth, DestHeight);
112 
113   switch (BltInfo->SourceSurface->iBitmapFormat)
114   {
115   case BMF_1BPP:
116     DPRINT("1BPP Case Selected with DestRect Width of '%d'.\n",
117            DestWidth);
118 
119     if (bLeftToRight || bTopToBottom)
120     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
121 
122     sx = BltInfo->SourcePoint.x;
123 
124     /* This sets sy to the top line */
125     sy = BltInfo->SourcePoint.y;
126 
127     if (bTopToBottom)
128     {
129       /* This sets sy to the bottom line */
130       sy += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
131     }
132 
133     for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
134     {
135       sx = BltInfo->SourcePoint.x;
136 
137       if (bLeftToRight)
138       {
139         /* This sets the sx to the rightmost pixel */
140         sx += (DestWidth - 1);
141       }
142 
143       for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
144       {
145         if (DIB_1BPP_GetPixel(BltInfo->SourceSurface, sx, sy) == 0)
146         {
147           DIB_32BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 0));
148         }
149         else
150         {
151           DIB_32BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 1));
152         }
153 
154         DEC_OR_INC(sx, bLeftToRight, 1);
155       }
156       DEC_OR_INC(sy, bTopToBottom, 1);
157     }
158     break;
159 
160   case BMF_4BPP:
161     DPRINT("4BPP Case Selected with DestRect Width of '%d'.\n",
162            DestWidth);
163 
164     if (bLeftToRight || bTopToBottom)
165     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
166 
167     /* This sets SourceBits_4BPP to the top line */
168     SourceBits_4BPP = (PBYTE)BltInfo->SourceSurface->pvScan0
169       + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
170       + (BltInfo->SourcePoint.x >> 1);
171 
172     if (bTopToBottom)
173     {
174       /* This sets SourceBits_4BPP to the bottom line */
175       SourceBits_4BPP += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
176     }
177 
178     for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
179     {
180       SourceLine_4BPP = SourceBits_4BPP;
181       sx = BltInfo->SourcePoint.x;
182 
183       if (bLeftToRight)
184       {
185         /* This sets sx to the rightmost pixel */
186         sx += (DestWidth - 1);
187       }
188 
189       f1 = sx & 1;
190 
191       for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
192       {
193         xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest,
194           (*SourceLine_4BPP & altnotmask[f1]) >> (4 * (1 - f1)));
195         DIB_32BPP_PutPixel(BltInfo->DestSurface, i, j, xColor);
196         if (f1 == 1) {
197           DEC_OR_INC(SourceLine_4BPP, bLeftToRight, 1);
198           f1 = 0;
199         } else {
200           f1 = 1;
201         }
202         DEC_OR_INC(sx, bLeftToRight, 1);
203       }
204       DEC_OR_INC(SourceBits_4BPP, bTopToBottom, BltInfo->SourceSurface->lDelta);
205     }
206     break;
207 
208   case BMF_8BPP:
209     DPRINT("8BPP Case Selected with DestRect Width of '%d'.\n",
210            DestWidth);
211 
212     if (bLeftToRight || bTopToBottom)
213     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
214 
215     /* This sets SourceLine to the top line */
216     SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0
217       + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
218       + BltInfo->SourcePoint.x;
219     DestLine = DestBits;
220 
221     if (bTopToBottom)
222     {
223       /* This sets SourceLine to the bottom line */
224       SourceLine += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
225     }
226 
227     for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
228     {
229       SourceBits = SourceLine;
230       DestBits = DestLine;
231 
232       if (bLeftToRight)
233       {
234         /* This sets the SourceBits to the rightmost pixel */
235         SourceBits += (DestWidth - 1);
236       }
237 
238       for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
239       {
240         xColor = *SourceBits;
241         *((PDWORD) DestBits) = (DWORD)XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
242         DEC_OR_INC(SourceBits, bLeftToRight, 1);
243         DestBits += 4;
244       }
245       DEC_OR_INC(SourceLine, bTopToBottom, BltInfo->SourceSurface->lDelta);
246       DestLine += BltInfo->DestSurface->lDelta;
247     }
248     break;
249 
250   case BMF_16BPP:
251     DPRINT("16BPP Case Selected with DestRect Width of '%d'.\n",
252             DestWidth);
253 
254     if (bLeftToRight || bTopToBottom)
255     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
256 
257     /* This sets SourceLine to the top line */
258     SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0
259       + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
260       + 2 * BltInfo->SourcePoint.x;
261     DestLine = DestBits;
262 
263     if (bTopToBottom)
264     {
265       /* This sets SourceLine to the bottom line */
266       SourceLine += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
267     }
268 
269     for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
270     {
271       SourceBits = SourceLine;
272       DestBits = DestLine;
273 
274       if (bLeftToRight)
275       {
276         /* This sets the SourceBits to the rightmost pixel */
277         SourceBits += (DestWidth - 1) * 2;
278       }
279 
280       for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
281       {
282         xColor = *((PWORD) SourceBits);
283         *((PDWORD) DestBits) = (DWORD)XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
284         DEC_OR_INC(SourceBits, bLeftToRight, 2);
285         DestBits += 4;
286       }
287 
288       DEC_OR_INC(SourceLine, bTopToBottom, BltInfo->SourceSurface->lDelta);
289       DestLine += BltInfo->DestSurface->lDelta;
290     }
291     break;
292 
293   case BMF_24BPP:
294     DPRINT("24BPP Case Selected with DestRect Width of '%d'.\n",
295       DestWidth);
296 
297     if (bLeftToRight || bTopToBottom)
298     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
299 
300     /* This sets SourceLine to the top line */
301     SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0
302       + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
303       + 3 * BltInfo->SourcePoint.x;
304 
305     if (bTopToBottom)
306     {
307       /* This sets SourceLine to the bottom line */
308       SourceLine += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
309     }
310 
311     DestLine = DestBits;
312 
313     for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
314     {
315       SourceBits = SourceLine;
316       DestBits = DestLine;
317 
318       if (bLeftToRight)
319       {
320         /* This sets the SourceBits to the rightmost pixel */
321         SourceBits += (DestWidth - 1) * 3;
322       }
323 
324       for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
325       {
326         xColor = (*(SourceBits + 2) << 0x10) +
327           (*(SourceBits + 1) << 0x08) +
328           (*(SourceBits));
329         *((PDWORD)DestBits) = (DWORD)XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
330         DEC_OR_INC(SourceBits, bLeftToRight, 3);
331         DestBits += 4;
332       }
333 
334       DEC_OR_INC(SourceLine, bTopToBottom, BltInfo->SourceSurface->lDelta);
335       DestLine += BltInfo->DestSurface->lDelta;
336     }
337     break;
338 
339   case BMF_32BPP:
340     DPRINT("32BPP Case Selected with SourcePoint (%d,%d) and DestRect Width/height of '%d/%d' DestRect: (%d,%d)-(%d,%d).\n",
341            BltInfo->SourcePoint.x, BltInfo->SourcePoint.y, DestWidth, DestHeight,
342            BltInfo->DestRect.left, BltInfo->DestRect.top, BltInfo->DestRect.right, BltInfo->DestRect.bottom);
343 
344     if (bLeftToRight || bTopToBottom)
345     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
346 
347     /* This handles the negative lDelta's which represent Top-to-Bottom bitmaps */
348     if (((blDeltaSrcNeg || blDeltaDestNeg) && !(blDeltaSrcNeg && blDeltaDestNeg)) && bTopToBottom)
349     {
350       DPRINT("Adjusting for lDelta's here.\n");
351       if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
352       {
353         /* SourceBits points to top-left pixel for lDelta < 0 and bottom-left for lDelta > 0 */
354         SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
355           + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
356           + 4 * BltInfo->SourcePoint.x;
357         for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
358         {
359           RtlMoveMemory(DestBits, SourceBits, 4 * DestWidth);
360           SourceBits += BltInfo->SourceSurface->lDelta;
361           DestBits += BltInfo->DestSurface->lDelta;
362         }
363       }
364       else
365       {
366         /* SourceBits points to bottom-left pixel for lDelta < 0 and top-left for lDelta > 0 */
367         SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
368           + ((BltInfo->SourcePoint.y
369           + DestHeight - 1) * BltInfo->SourceSurface->lDelta)
370           + 4 * BltInfo->SourcePoint.x;
371         /* SourceBits points to bottom-left pixel for lDelta < 0 and top-left for lDelta > 0 */
372         DestBits = (PBYTE)BltInfo->DestSurface->pvScan0
373           + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta)
374           + 4 * BltInfo->DestRect.left;
375         for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
376         {
377           RtlMoveMemory(DestBits, SourceBits, 4 * DestWidth);
378           SourceBits -= BltInfo->SourceSurface->lDelta;
379           DestBits -= BltInfo->DestSurface->lDelta;
380         }
381       }
382       blDeltaAdjustDone = TRUE;
383     }
384 
385     /* This tests for whether we can use simplified/quicker code below.
386      * It works for increasing source and destination areas only and there is no overlap and no flip.
387      */
388     if ((BltInfo->XlateSourceToDest == NULL ||
389       (BltInfo->XlateSourceToDest->flXlate & XO_TRIVIAL) != 0) &&
390       (!bTopToBottom && !bLeftToRight))
391     {
392       DPRINT("XO_TRIVIAL is TRUE.\n");
393 
394       if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
395       {
396         /* SourceBits points to top-left pixel for lDelta < 0 and bottom-left for lDelta > 0 */
397         SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
398           + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
399           + 4 * BltInfo->SourcePoint.x;
400         for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
401         {
402           RtlMoveMemory(DestBits, SourceBits, 4 * DestWidth);
403           SourceBits += BltInfo->SourceSurface->lDelta;
404           DestBits += BltInfo->DestSurface->lDelta;
405         }
406       }
407       else
408       {
409         /* SourceBits points to bottom-left pixel for lDelta < 0 and top-left for lDelta > 0 */
410         SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
411           + ((BltInfo->SourcePoint.y
412           + DestHeight - 1) * BltInfo->SourceSurface->lDelta)
413           + 4 * BltInfo->SourcePoint.x;
414         /* SourceBits points to bottom-left pixel for lDelta < 0 and top-left for lDelta > 0 */
415         DestBits = (PBYTE)BltInfo->DestSurface->pvScan0
416           + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta)
417           + 4 * BltInfo->DestRect.left;
418         for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
419         {
420           RtlMoveMemory(DestBits, SourceBits, 4 * DestWidth);
421           SourceBits -= BltInfo->SourceSurface->lDelta;
422           DestBits -= BltInfo->DestSurface->lDelta;
423         }
424       }
425     }
426     else
427     {
428       DPRINT("XO_TRIVIAL is NOT TRUE.\n");
429 
430       if (!bTopToBottom && !bLeftToRight)
431       {
432         if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
433         {
434           SourceBits = ((PBYTE)BltInfo->SourceSurface->pvScan0
435             + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
436             + 4 * BltInfo->SourcePoint.x);
437           for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
438           {
439             if (BltInfo->DestRect.left < BltInfo->SourcePoint.x)
440             {
441               Dest32 = (DWORD *) DestBits;
442               Source32 = (DWORD *) SourceBits;
443               for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
444               {
445                 *Dest32++ = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *Source32++);
446               }
447             }
448             else
449             {
450               Dest32 = (DWORD *) DestBits + (DestWidth - 1);
451               Source32 = (DWORD *) SourceBits + (DestWidth - 1);
452               for (i = BltInfo->DestRect.right - 1; BltInfo->DestRect.left <= i; i--)
453               {
454                 *Dest32-- = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *Source32--);
455               }
456             }
457             SourceBits += BltInfo->SourceSurface->lDelta;
458             DestBits += BltInfo->DestSurface->lDelta;
459           }
460         }
461         else
462         {
463           SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
464             + ((BltInfo->SourcePoint.y
465             + DestHeight - 1) * BltInfo->SourceSurface->lDelta)
466             + 4 * BltInfo->SourcePoint.x;
467           DestBits = (PBYTE)BltInfo->DestSurface->pvScan0
468             + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta)
469             + 4 * BltInfo->DestRect.left;
470           for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
471           {
472             if (BltInfo->DestRect.left < BltInfo->SourcePoint.x)
473             {
474               Dest32 = (DWORD *) DestBits;
475               Source32 = (DWORD *) SourceBits;
476               for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
477               {
478                 *Dest32++ = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *Source32++);
479               }
480             }
481             else
482             {
483               Dest32 = (DWORD *) DestBits + (DestWidth - 1);
484               Source32 = (DWORD *) SourceBits + (DestWidth - 1);
485               for (i = BltInfo->DestRect.right - 1; BltInfo->DestRect.left <= i; i--)
486               {
487                 *Dest32-- = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *Source32--);
488               }
489             }
490             SourceBits -= BltInfo->SourceSurface->lDelta;
491             DestBits -= BltInfo->DestSurface->lDelta;
492           }
493         }
494       }
495       else
496       {
497         /* Buffering for source and destination flip overlaps. Fixes KHMZ MirrorTest CORE-16642 */
498         BOOL TopToBottomDone = FALSE;
499 
500         /* No need to flip a LeftToRight bitmap only one pixel wide */
501         if ((bLeftToRight) && (DestWidth > 1))
502         {
503           DPRINT("Flip is bLeftToRight.\n");
504 
505           /* Allocate enough pixels for a row in DWORD's */
506           DWORD *store = ExAllocatePoolWithTag(NonPagedPool,
507             (DestWidth + 1) * 4, TAG_DIB);
508           if (store == NULL)
509           {
510             DPRINT1("Storage Allocation Failed.\n");
511             return FALSE;
512           }
513 
514           /* This sets SourceBits to the bottom line */
515           SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
516             + ((BltInfo->SourcePoint.y + DestHeight - 1)
517             * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
518 
519           /* This sets DestBits to the bottom line */
520           DestBits = (PBYTE)BltInfo->DestSurface->pvScan0
521            + (BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta
522            + 4 * BltInfo->DestRect.left;
523 
524           for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
525           {
526 
527               /* Set Dest32 to right pixel */
528               Dest32 = (DWORD *) DestBits + (DestWidth - 1);
529               Source32 = (DWORD *) SourceBits;
530 
531               Index = 0;
532 
533               /* Store pixels from left to right */
534               for (i = BltInfo->DestRect.right - 1; BltInfo->DestRect.left <= i; i--)
535               {
536                 store[Index] = *Source32++;
537                 Index++;
538               }
539 
540               Index = 0;
541 
542               /* Copy stored dat to pixels from right to left */
543               for (i = BltInfo->DestRect.right - 1; BltInfo->DestRect.left <= i; i--)
544               {
545                 *Dest32-- = store[Index];
546                 Index++;
547               }
548             SourceBits -= BltInfo->SourceSurface->lDelta;
549             DestBits -= BltInfo->DestSurface->lDelta;
550           }
551           ExFreePoolWithTag(store, TAG_DIB);
552           TopToBottomDone = TRUE;
553         }
554 
555         /* Top to Botoom Handling if bitmap more than one pixel high */
556         if ((bTopToBottom) && (DestHeight > 1))
557          {
558           /* Note: It is very important that this code remain optimized for time used.
559            *   Otherwise you will have random crashes in ReactOS that are undesirable.
560            *   For an example of this just try executing the code here two times.
561            */
562 
563           DPRINT("Flip is bTopToBottom.\n");
564 
565           /* Allocate enough pixels for a row in DWORD's */
566           DWORD *store = ExAllocatePoolWithTag(NonPagedPool,
567             (DestWidth + 1) * 4, TAG_DIB);
568           if (store == NULL)
569           {
570             DPRINT1("Storage Allocation Failed.\n");
571             return FALSE;
572           }
573 
574           /* This set DestBitsT to the top line */
575           DestBitsT = (PBYTE)BltInfo->DestSurface->pvScan0
576             + ((BltInfo->DestRect.top) * BltInfo->DestSurface->lDelta)
577             + 4 * BltInfo->DestRect.left;
578 
579           /* This sets DestBitsB to the bottom line */
580           DestBitsB = (PBYTE)BltInfo->DestSurface->pvScan0
581            + (BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta
582            + 4 * BltInfo->DestRect.left;
583 
584           /* The TopToBottomDone flag indicates that we are flipping for bTopToBottom and bLeftToRight
585            * and have already completed the bLeftToRight. So we will lose our first flip output
586            * unless we work with its output which is at the destination site. So in this case
587            * our new Source becomes the previous outputs Destination.
588            * Also in we use the same logic when we have corrected for negative lDelta's above
589            * and already completed a flip from Source to Destination for the first step
590            */
591 
592           if (TopToBottomDone || blDeltaAdjustDone)
593           {
594             /* This sets SourceBitsB to the bottom line */
595             SourceBitsB = DestBitsB;
596 
597             /* This sets SourceBitsT to the top line */
598             SourceBitsT = DestBitsT;
599           }
600           else
601           {
602             /* This sets SourceBitsB to the bottom line */
603             SourceBitsB = (PBYTE)BltInfo->SourceSurface->pvScan0
604               + ((BltInfo->SourcePoint.y + DestHeight - 1)
605               * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
606 
607             /* This sets SourceBitsT to the top line */
608             SourceBitsT = (PBYTE)BltInfo->SourceSurface->pvScan0
609               + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
610           }
611 
612           /* Overlaps and Vertical flips do not mix well. So we test for this and handle it
613            * by using two operations. First we just do a copy of the source to the destination.
614            * Then we do a flip in place at the destination location and we are done.
615            */
616           if ((BltInfo->SourcePoint.y != BltInfo->DestRect.top) &&                        // The values are not equal and
617              (abs(BltInfo->SourcePoint.y - BltInfo->DestRect.top) < (DestHeight + 2)) &&  // they are NOT seperated by > DestHeight
618              (BltInfo->SourceSurface->pvScan0 == BltInfo->DestSurface->pvScan0))          // and same surface (probably screen)
619           {
620             DPRINT("Flips Need Adjustments, so do move here.\n");
621 
622             if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
623             {
624               /* SourceBits points to top-left pixel for lDelta < 0 and bottom-left for lDelta > 0 */
625               SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
626                 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
627                 + 4 * BltInfo->SourcePoint.x;
628               for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
629               {
630                 RtlMoveMemory(DestBits, SourceBits, 4 * DestWidth);
631                 SourceBits += BltInfo->SourceSurface->lDelta;
632                 DestBits += BltInfo->DestSurface->lDelta;
633               }
634             }
635             else
636             {
637               /* SourceBits points to bottom-left pixel for lDelta < 0 and top-left for lDelta > 0 */
638               SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
639                 + ((BltInfo->SourcePoint.y
640                 + DestHeight - 1) * BltInfo->SourceSurface->lDelta)
641                 + 4 * BltInfo->SourcePoint.x;
642               /* SourceBits points to bottom-left pixel for lDelta < 0 and top-left for lDelta > 0 */
643               DestBits = (PBYTE)BltInfo->DestSurface->pvScan0
644                 + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta)
645                 + 4 * BltInfo->DestRect.left;
646               for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
647               {
648                 RtlMoveMemory(DestBits, SourceBits, 4 * DestWidth);
649                 SourceBits -= BltInfo->SourceSurface->lDelta;
650                 DestBits -= BltInfo->DestSurface->lDelta;
651               }
652             }
653 
654             /* This sets SourceBitsB to the bottom line */
655             SourceBitsB = DestBitsB;
656 
657             /* This sets SourceBitsT to the top line */
658             SourceBitsT = DestBitsT;
659           }
660 
661           /* Vertical Flip code starts here */
662           for (j = 0; j < DestHeight / 2 ; j++)
663           {
664             /* Store bottom row of Source pixels */
665             RtlMoveMemory(store, SourceBitsB, 4 * DestWidth);
666 
667             /* Copy top Source row to bottom Destination row overwriting it */
668             RtlMoveMemory(DestBitsB, SourceBitsT, 4 * DestWidth);
669 
670             /* Copy stored bottom row of Source pixels to Destination top row of pixels */
671             RtlMoveMemory(DestBitsT, store, 4 * DestWidth);
672 
673             /* Index top rows down and bottom rows up */
674             SourceBitsT += BltInfo->SourceSurface->lDelta;
675             SourceBitsB -= BltInfo->SourceSurface->lDelta;
676 
677             DestBitsT += BltInfo->DestSurface->lDelta;
678             DestBitsB -= BltInfo->DestSurface->lDelta;
679           }
680           if (DestHeight % 2)
681           {
682             /* If we had an odd number of lines we handle the center one here */
683             DPRINT("Handling Top To Bottom with Odd Number of lines.\n");
684             RtlMoveMemory(DestBitsB, SourceBitsT, 4 * DestWidth);
685           }
686           ExFreePoolWithTag(store, TAG_DIB);
687         }
688       }
689     }
690     break;
691 
692   default:
693     DPRINT1("DIB_32BPP_BitBltSrcCopy: Unhandled Source BPP: %u\n", BitsPerFormat(BltInfo->SourceSurface->iBitmapFormat));
694     return FALSE;
695   }
696 
697   return TRUE;
698 }
699 
700 BOOLEAN
701 DIB_32BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
702                          RECTL*  DestRect,  RECTL *SourceRect,
703                          XLATEOBJ *ColorTranslation, ULONG iTransColor)
704 {
705   LONG X, Y, SourceX, SourceY = 0, wd;
706   ULONG *DestBits, Source = 0;
707 
708   LONG DstHeight;
709   LONG DstWidth;
710   LONG SrcHeight;
711   LONG SrcWidth;
712 
713   DstHeight = DestRect->bottom - DestRect->top;
714   DstWidth = DestRect->right - DestRect->left;
715   SrcHeight = SourceRect->bottom - SourceRect->top;
716   SrcWidth = SourceRect->right - SourceRect->left;
717 
718   DestBits = (ULONG*)((PBYTE)DestSurf->pvScan0 +
719     (DestRect->left << 2) +
720     DestRect->top * DestSurf->lDelta);
721   wd = DestSurf->lDelta - ((DestRect->right - DestRect->left) << 2);
722 
723   for (Y = DestRect->top; Y < DestRect->bottom; Y++)
724   {
725     SourceY = SourceRect->top+(Y - DestRect->top) * SrcHeight / DstHeight;
726     for (X = DestRect->left; X < DestRect->right; X++, DestBits++)
727     {
728       SourceX = SourceRect->left+(X - DestRect->left) * SrcWidth / DstWidth;
729       if (SourceX >= 0 && SourceY >= 0 &&
730         SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
731       {
732         Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
733         if ((0x00FFFFFF & Source) != (0x00FFFFFF & iTransColor))
734         {
735           *DestBits = XLATEOBJ_iXlate(ColorTranslation, Source);
736         }
737       }
738     }
739 
740     DestBits = (ULONG*)((ULONG_PTR)DestBits + wd);
741   }
742 
743   return TRUE;
744 }
745 
746 typedef union {
747   ULONG ul;
748   struct {
749     UCHAR red;
750     UCHAR green;
751     UCHAR blue;
752     UCHAR alpha;
753   } col;
754 } NICEPIXEL32;
755 
756 static __inline UCHAR
757 Clamp8(ULONG val)
758 {
759   return (val > 255) ? 255 : (UCHAR)val;
760 }
761 
762 BOOLEAN
763 DIB_32BPP_AlphaBlend(SURFOBJ* Dest, SURFOBJ* Source, RECTL* DestRect,
764                      RECTL* SourceRect, CLIPOBJ* ClipRegion,
765                      XLATEOBJ* ColorTranslation, BLENDOBJ* BlendObj)
766 {
767   INT Rows, Cols, SrcX, SrcY;
768   register PULONG Dst;
769   BLENDFUNCTION BlendFunc;
770   register NICEPIXEL32 DstPixel, SrcPixel;
771   UCHAR Alpha, SrcBpp;
772 
773   DPRINT("DIB_32BPP_AlphaBlend: SourceRect: (%d,%d)-(%d,%d), DestRect: (%d,%d)-(%d,%d)\n",
774     SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
775     DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
776 
777   BlendFunc = BlendObj->BlendFunction;
778   if (BlendFunc.BlendOp != AC_SRC_OVER)
779   {
780     DPRINT1("BlendOp != AC_SRC_OVER\n");
781     return FALSE;
782   }
783   if (BlendFunc.BlendFlags != 0)
784   {
785     DPRINT1("BlendFlags != 0\n");
786     return FALSE;
787   }
788   if ((BlendFunc.AlphaFormat & ~AC_SRC_ALPHA) != 0)
789   {
790     DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendFunc.AlphaFormat);
791     return FALSE;
792   }
793   if ((BlendFunc.AlphaFormat & AC_SRC_ALPHA) != 0 &&
794        BitsPerFormat(Source->iBitmapFormat) != 32)
795   {
796     DPRINT1("Source bitmap must be 32bpp when AC_SRC_ALPHA is set\n");
797     return FALSE;
798   }
799 
800   Dst = (PULONG)((ULONG_PTR)Dest->pvScan0 + (DestRect->top * Dest->lDelta) +
801     (DestRect->left << 2));
802   SrcBpp = BitsPerFormat(Source->iBitmapFormat);
803 
804   Rows = 0;
805    SrcY = SourceRect->top;
806    while (++Rows <= DestRect->bottom - DestRect->top)
807   {
808     Cols = 0;
809     SrcX = SourceRect->left;
810     while (++Cols <= DestRect->right - DestRect->left)
811     {
812       SrcPixel.ul = DIB_GetSource(Source, SrcX, SrcY, ColorTranslation);
813       SrcPixel.col.red = (SrcPixel.col.red * BlendFunc.SourceConstantAlpha) / 255;
814       SrcPixel.col.green = (SrcPixel.col.green * BlendFunc.SourceConstantAlpha)  / 255;
815       SrcPixel.col.blue = (SrcPixel.col.blue * BlendFunc.SourceConstantAlpha) / 255;
816       SrcPixel.col.alpha = (32 == SrcBpp) ?
817                         (SrcPixel.col.alpha * BlendFunc.SourceConstantAlpha) / 255 :
818                         BlendFunc.SourceConstantAlpha ;
819 
820       Alpha = ((BlendFunc.AlphaFormat & AC_SRC_ALPHA) != 0) ?
821            SrcPixel.col.alpha : BlendFunc.SourceConstantAlpha ;
822 
823       DstPixel.ul = *Dst;
824       DstPixel.col.red = Clamp8((DstPixel.col.red * (255 - Alpha)) / 255 + SrcPixel.col.red) ;
825       DstPixel.col.green = Clamp8((DstPixel.col.green * (255 - Alpha)) / 255 + SrcPixel.col.green) ;
826       DstPixel.col.blue = Clamp8((DstPixel.col.blue * (255 - Alpha)) / 255 + SrcPixel.col.blue) ;
827       DstPixel.col.alpha = Clamp8((DstPixel.col.alpha * (255 - Alpha)) / 255 + SrcPixel.col.alpha) ;
828       *Dst++ = DstPixel.ul;
829       SrcX = SourceRect->left + (Cols*(SourceRect->right - SourceRect->left))/(DestRect->right - DestRect->left);
830     }
831     Dst = (PULONG)((ULONG_PTR)Dest->pvScan0 + ((DestRect->top + Rows) * Dest->lDelta) +
832                 (DestRect->left << 2));
833     SrcY = SourceRect->top + (Rows*(SourceRect->bottom - SourceRect->top))/(DestRect->bottom - DestRect->top);
834   }
835 
836   return TRUE;
837 }
838 
839 /* EOF */
840