xref: /reactos/win32ss/gdi/dib/dib32bpp.c (revision 6924b8ff)
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;
62   LONG     DestWidth, DestHeight;
63   BOOLEAN  bTopToBottom, bLeftToRight;
64   BOOLEAN  blDeltaSrcNeg, blDeltaDestNeg;
65   BOOLEAN  blDeltaAdjustDone = FALSE;
66 
67   DPRINT("DIB_32BPP_BitBltSrcCopy: SourcePoint (%d, %d), SourceSurface cx/cy (%d/%d), "
68          "DestSurface cx/cy (%d/%d) DestRect: (%d,%d)-(%d,%d)\n",
69          BltInfo->SourcePoint.x, BltInfo->SourcePoint.y,
70          BltInfo->SourceSurface->sizlBitmap.cx, BltInfo->SourceSurface->sizlBitmap.cy,
71          BltInfo->DestSurface->sizlBitmap.cx, BltInfo->DestSurface->sizlBitmap.cy,
72          BltInfo->DestRect.left, BltInfo->DestRect.top, BltInfo->DestRect.right, BltInfo->DestRect.bottom);
73 
74   DPRINT("BltInfo->DestSurface->lDelta is '%d' and BltInfo->SourceSurface->lDelta is '%d'.\n",
75            BltInfo->DestSurface->lDelta,  BltInfo->SourceSurface->lDelta);
76 
77   DPRINT("iBitmapFormat is %d and width,height is (%d,%d).\n", BltInfo->SourceSurface->iBitmapFormat,
78          BltInfo->DestRect.right - BltInfo->DestRect.left, BltInfo->DestRect.bottom - BltInfo->DestRect.top);
79 
80   DPRINT("BltInfo->SourcePoint.x is '%d' and BltInfo->SourcePoint.y is '%d'.\n",
81          BltInfo->SourcePoint.x, BltInfo->SourcePoint.y);
82 
83   /* Do not deal with negative numbers for these values */
84   if ((BltInfo->DestRect.left < 0) || (BltInfo->DestRect.top < 0) ||
85       (BltInfo->DestRect.right < 0) || (BltInfo->DestRect.bottom < 0))
86     return FALSE;
87 
88   /* Detect negative lDelta's meaning Bottom-Up bitmaps */
89   blDeltaSrcNeg = BltInfo->SourceSurface->lDelta < 0;
90   blDeltaDestNeg = BltInfo->DestSurface->lDelta < 0;
91 
92   /* Get back left to right flip here */
93   bLeftToRight = BltInfo->DestRect.left > BltInfo->DestRect.right;
94 
95   /* Check for top to bottom flip needed. */
96   bTopToBottom = BltInfo->DestRect.top > BltInfo->DestRect.bottom;
97 
98   DPRINT("bTopToBottom is '%d' and DestSurface->lDelta < 0 is '%d' and SourceSurface->lDelta < 0 is '%d'.\n",
99            bTopToBottom, BltInfo->DestSurface->lDelta < 0 ? 1 : 0,  BltInfo->SourceSurface->lDelta < 0 ? 1 : 0);
100 
101   /* Make WellOrdered with top < bottom and left < right */
102   RECTL_vMakeWellOrdered(&BltInfo->DestRect);
103 
104   DestWidth = BltInfo->DestRect.right - BltInfo->DestRect.left;
105   DestHeight = BltInfo->DestRect.bottom - BltInfo->DestRect.top;
106 
107   DestBits = (PBYTE)BltInfo->DestSurface->pvScan0
108     + (BltInfo->DestRect.top * BltInfo->DestSurface->lDelta)
109     + 4 * BltInfo->DestRect.left;
110 
111   DPRINT("iBitmapFormat is %d and width,height is (%d,%d).\n", BltInfo->SourceSurface->iBitmapFormat,
112          DestWidth, DestHeight);
113 
114   switch (BltInfo->SourceSurface->iBitmapFormat)
115   {
116   case BMF_1BPP:
117     DPRINT("1BPP Case Selected with DestRect Width of '%d'.\n",
118            DestWidth);
119 
120     if (bLeftToRight || bTopToBottom)
121     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
122 
123     sx = BltInfo->SourcePoint.x;
124 
125     /* This sets sy to the top line */
126     sy = BltInfo->SourcePoint.y;
127 
128     if (bTopToBottom)
129     {
130       /* This sets sy to the bottom line */
131       sy += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
132     }
133 
134     for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
135     {
136       sx = BltInfo->SourcePoint.x;
137 
138       if (bLeftToRight)
139       {
140         /* This sets the sx to the rightmost pixel */
141         sx += (DestWidth - 1);
142       }
143 
144       for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
145       {
146         if (DIB_1BPP_GetPixel(BltInfo->SourceSurface, sx, sy) == 0)
147         {
148           DIB_32BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 0));
149         }
150         else
151         {
152           DIB_32BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 1));
153         }
154 
155         DEC_OR_INC(sx, bLeftToRight, 1);
156       }
157       DEC_OR_INC(sy, bTopToBottom, 1);
158     }
159     break;
160 
161   case BMF_4BPP:
162     DPRINT("4BPP Case Selected with DestRect Width of '%d'.\n",
163            DestWidth);
164 
165     if (bLeftToRight || bTopToBottom)
166     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
167 
168     /* This sets SourceBits_4BPP to the top line */
169     SourceBits_4BPP = (PBYTE)BltInfo->SourceSurface->pvScan0
170       + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
171       + (BltInfo->SourcePoint.x >> 1);
172 
173     if (bTopToBottom)
174     {
175       /* This sets SourceBits_4BPP to the bottom line */
176       SourceBits_4BPP += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
177     }
178 
179     for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
180     {
181       SourceLine_4BPP = SourceBits_4BPP;
182       sx = BltInfo->SourcePoint.x;
183 
184       if (bLeftToRight)
185       {
186         /* This sets sx to the rightmost pixel */
187         sx += (DestWidth - 1);
188       }
189 
190       f1 = sx & 1;
191 
192       for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
193       {
194         xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest,
195           (*SourceLine_4BPP & altnotmask[f1]) >> (4 * (1 - f1)));
196         DIB_32BPP_PutPixel(BltInfo->DestSurface, i, j, xColor);
197         if (f1 == 1) {
198           DEC_OR_INC(SourceLine_4BPP, bLeftToRight, 1);
199           f1 = 0;
200         } else {
201           f1 = 1;
202         }
203         DEC_OR_INC(sx, bLeftToRight, 1);
204       }
205       DEC_OR_INC(SourceBits_4BPP, bTopToBottom, BltInfo->SourceSurface->lDelta);
206     }
207     break;
208 
209   case BMF_8BPP:
210     DPRINT("8BPP Case Selected with DestRect Width of '%d'.\n",
211            DestWidth);
212 
213     if (bLeftToRight || bTopToBottom)
214     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
215 
216     /* This sets SourceLine to the top line */
217     SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0
218       + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
219       + BltInfo->SourcePoint.x;
220     DestLine = DestBits;
221 
222     if (bTopToBottom)
223     {
224       /* This sets SourceLine to the bottom line */
225       SourceLine += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
226     }
227 
228     for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
229     {
230       SourceBits = SourceLine;
231       DestBits = DestLine;
232 
233       if (bLeftToRight)
234       {
235         /* This sets the SourceBits to the rightmost pixel */
236         SourceBits += (DestWidth - 1);
237       }
238 
239       for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
240       {
241         xColor = *SourceBits;
242         *((PDWORD) DestBits) = (DWORD)XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
243         DEC_OR_INC(SourceBits, bLeftToRight, 1);
244         DestBits += 4;
245       }
246       DEC_OR_INC(SourceLine, bTopToBottom, BltInfo->SourceSurface->lDelta);
247       DestLine += BltInfo->DestSurface->lDelta;
248     }
249     break;
250 
251   case BMF_16BPP:
252     DPRINT("16BPP Case Selected with DestRect Width of '%d'.\n",
253             DestWidth);
254 
255     if (bLeftToRight || bTopToBottom)
256     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
257 
258     /* This sets SourceLine to the top line */
259     SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0
260       + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
261       + 2 * BltInfo->SourcePoint.x;
262     DestLine = DestBits;
263 
264     if (bTopToBottom)
265     {
266       /* This sets SourceLine to the bottom line */
267       SourceLine += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
268     }
269 
270     for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
271     {
272       SourceBits = SourceLine;
273       DestBits = DestLine;
274 
275       if (bLeftToRight)
276       {
277         /* This sets the SourceBits to the rightmost pixel */
278         SourceBits += (DestWidth - 1) * 2;
279       }
280 
281       for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
282       {
283         xColor = *((PWORD) SourceBits);
284         *((PDWORD) DestBits) = (DWORD)XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
285         DEC_OR_INC(SourceBits, bLeftToRight, 2);
286         DestBits += 4;
287       }
288 
289       DEC_OR_INC(SourceLine, bTopToBottom, BltInfo->SourceSurface->lDelta);
290       DestLine += BltInfo->DestSurface->lDelta;
291     }
292     break;
293 
294   case BMF_24BPP:
295     DPRINT("24BPP Case Selected with DestRect Width of '%d'.\n",
296       DestWidth);
297 
298     if (bLeftToRight || bTopToBottom)
299     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
300 
301     /* This sets SourceLine to the top line */
302     SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0
303       + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
304       + 3 * BltInfo->SourcePoint.x;
305 
306     if (bTopToBottom)
307     {
308       /* This sets SourceLine to the bottom line */
309       SourceLine += BltInfo->SourceSurface->lDelta * (DestHeight - 1);
310     }
311 
312     DestLine = DestBits;
313 
314     for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
315     {
316       SourceBits = SourceLine;
317       DestBits = DestLine;
318 
319       if (bLeftToRight)
320       {
321         /* This sets the SourceBits to the rightmost pixel */
322         SourceBits += (DestWidth - 1) * 3;
323       }
324 
325       for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
326       {
327         xColor = (*(SourceBits + 2) << 0x10) +
328           (*(SourceBits + 1) << 0x08) +
329           (*(SourceBits));
330         *((PDWORD)DestBits) = (DWORD)XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, xColor);
331         DEC_OR_INC(SourceBits, bLeftToRight, 3);
332         DestBits += 4;
333       }
334 
335       DEC_OR_INC(SourceLine, bTopToBottom, BltInfo->SourceSurface->lDelta);
336       DestLine += BltInfo->DestSurface->lDelta;
337     }
338     break;
339 
340   case BMF_32BPP:
341     DPRINT("32BPP Case Selected with SourcePoint (%d,%d) and DestRect Width/height of '%d/%d' DestRect: (%d,%d)-(%d,%d).\n",
342            BltInfo->SourcePoint.x, BltInfo->SourcePoint.y, DestWidth, DestHeight,
343            BltInfo->DestRect.left, BltInfo->DestRect.top, BltInfo->DestRect.right, BltInfo->DestRect.bottom);
344 
345     if (bLeftToRight || bTopToBottom)
346     DPRINT("bLeftToRight is '%d' and bTopToBottom is '%d'.\n", bLeftToRight, bTopToBottom);
347 
348     /* This handles the negative lDelta's which represent Top-to-Bottom bitmaps */
349     if (((blDeltaSrcNeg || blDeltaDestNeg) && !(blDeltaSrcNeg && blDeltaDestNeg)) && bTopToBottom)
350     {
351       DPRINT("Adjusting for lDelta's here.\n");
352       if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
353       {
354         /* SourceBits points to top-left pixel for lDelta < 0 and bottom-left for lDelta > 0 */
355         SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
356           + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta)
357           + 4 * BltInfo->SourcePoint.x;
358         for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
359         {
360           RtlMoveMemory(DestBits, SourceBits, 4 * DestWidth);
361           SourceBits += BltInfo->SourceSurface->lDelta;
362           DestBits += BltInfo->DestSurface->lDelta;
363         }
364       }
365       else
366       {
367         /* SourceBits points to bottom-left pixel for lDelta < 0 and top-left for lDelta > 0 */
368         SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0
369           + ((BltInfo->SourcePoint.y + DestHeight - 1) * BltInfo->SourceSurface->lDelta)
370           + 4 * BltInfo->SourcePoint.x;
371         /* DestBits 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