xref: /reactos/win32ss/gdi/dib/dib24bpp.c (revision 98e8827a)
1 /*
2  * PROJECT:         Win32 subsystem
3  * LICENSE:         See COPYING in the top level directory
4  * FILE:            win32ss/gdi/dib/dib24bpp.c
5  * PURPOSE:         Device Independant Bitmap functions, 24bpp
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_24BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
22 {
23   PBYTE addr = (PBYTE)SurfObj->pvScan0 + (y * SurfObj->lDelta) + (x << 1) + x;
24   *(PUSHORT)(addr) = c & 0xFFFF;
25   *(addr + 2) = (c >> 16) & 0xFF;
26 }
27 
28 ULONG
29 DIB_24BPP_GetPixel(SURFOBJ *SurfObj, LONG x, LONG y)
30 {
31   PBYTE addr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + (x << 1) + x;
32   return *(PUSHORT)(addr) + (*(addr + 2) << 16);
33 }
34 
35 
36 
37 VOID
38 DIB_24BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
39 {
40   PBYTE addr = (PBYTE)SurfObj->pvScan0 + y1 * SurfObj->lDelta + (x << 1) + x;
41   LONG lDelta = SurfObj->lDelta;
42 
43   c &= 0xFFFFFF;
44   while(y1++ < y2)
45   {
46     *(PUSHORT)(addr) = c & 0xFFFF;
47     *(addr + 2) = (BYTE)(c >> 16);
48 
49     addr += lDelta;
50   }
51 }
52 
53 BOOLEAN
54 DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
55 {
56   LONG     i, j, sx, sy, xColor, f1;
57   PBYTE    SourceBits, DestBits, SourceLine, DestLine;
58   PBYTE    SourceBits_4BPP, SourceLine_4BPP;
59   PWORD    SourceBits_16BPP, SourceLine_16BPP;
60   BOOLEAN  bTopToBottom, bLeftToRight;
61 
62   DPRINT("DIB_24BPP_BitBltSrcCopy: SrcSurf cx/cy (%d/%d), DestSuft cx/cy (%d/%d) dstRect: (%d,%d)-(%d,%d)\n",
63          BltInfo->SourceSurface->sizlBitmap.cx, BltInfo->SourceSurface->sizlBitmap.cy,
64          BltInfo->DestSurface->sizlBitmap.cx, BltInfo->DestSurface->sizlBitmap.cy,
65          BltInfo->DestRect.left, BltInfo->DestRect.top, BltInfo->DestRect.right, BltInfo->DestRect.bottom);
66 
67   /* Get back left to right flip here */
68   bLeftToRight = (BltInfo->DestRect.left > BltInfo->DestRect.right);
69 
70   /* Check for top to bottom flip needed. */
71   bTopToBottom = BltInfo->DestRect.top > BltInfo->DestRect.bottom;
72 
73   DPRINT("BltInfo->SourcePoint.x is '%d' and BltInfo->SourcePoint.y is '%d'.\n",
74          BltInfo->SourcePoint.x, BltInfo->SourcePoint.y);
75 
76   /* Make WellOrdered by making top < bottom and left < right */
77   RECTL_vMakeWellOrdered(&BltInfo->DestRect);
78 
79   DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + (BltInfo->DestRect.top * BltInfo->DestSurface->lDelta) + BltInfo->DestRect.left * 3;
80 
81   switch(BltInfo->SourceSurface->iBitmapFormat)
82   {
83     case BMF_1BPP:
84       sx = BltInfo->SourcePoint.x;
85 
86       /* This sets sy to the top line */
87       sy = BltInfo->SourcePoint.y;
88 
89       if (bTopToBottom)
90       {
91         /* This sets sy to the bottom line */
92         sy += BltInfo->SourceSurface->lDelta * (BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1);
93       }
94 
95       for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
96       {
97         sx = BltInfo->SourcePoint.x;
98 
99         if (bLeftToRight)
100         {
101           /* This sets sx to the rightmost pixel */
102           sx += (BltInfo->DestRect.right - BltInfo->DestRect.left - 1);
103         }
104 
105         for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
106         {
107           if(DIB_1BPP_GetPixel(BltInfo->SourceSurface, sx, sy) == 0)
108           {
109             DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 0));
110           } else {
111             DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 1));
112           }
113           DEC_OR_INC(sx, bLeftToRight, 1);
114         }
115         DEC_OR_INC(sy, bTopToBottom, 1);
116       }
117       break;
118 
119     case BMF_4BPP:
120       DPRINT("4BPP Case Selected with DestRect Width of '%d'.\n",
121              BltInfo->DestRect.right - BltInfo->DestRect.left);
122 
123       /* This sets SourceBits_4BPP to the top line */
124       SourceBits_4BPP = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + (BltInfo->SourcePoint.x >> 1);
125 
126       if (bTopToBottom)
127       {
128         /* This sets SourceBits_4BPP to the bottom line */
129         SourceBits_4BPP += BltInfo->SourceSurface->lDelta * (BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1);
130       }
131 
132       for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
133       {
134         SourceLine_4BPP = SourceBits_4BPP;
135         DestLine = DestBits;
136         sx = BltInfo->SourcePoint.x;
137 
138         if (bLeftToRight)
139         {
140           /* This sets sx to the rightmost pixel */
141           sx += (BltInfo->DestRect.right - BltInfo->DestRect.left - 1);
142         }
143 
144         f1 = sx & 1;
145 
146         for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
147         {
148           xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest,
149               (*SourceLine_4BPP & altnotmask[f1]) >> (4 * (1 - f1)));
150           *DestLine++ = xColor & 0xff;
151           *(PWORD)DestLine = (WORD)(xColor >> 8);
152           DestLine += 2;
153           if(f1 == 1) {
154             DEC_OR_INC(SourceLine_4BPP, bLeftToRight, 1);
155             f1 = 0;
156           }
157           else
158           {
159             f1 = 1;
160           }
161           DEC_OR_INC(sx, bLeftToRight, 1);
162         }
163         DEC_OR_INC(SourceBits_4BPP, bTopToBottom, BltInfo->SourceSurface->lDelta);
164         DestBits += BltInfo->DestSurface->lDelta;
165       }
166       break;
167 
168     case BMF_8BPP:
169       DPRINT("8BPP Case Selected with DestRect Width of '%d'.\n",
170              BltInfo->DestRect.right - BltInfo->DestRect.left);
171 
172       /* This sets SourceLine to the top line */
173       SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
174 
175       if (bTopToBottom)
176       {
177         /* This sets SourceLine to the bottom line */
178         SourceLine += BltInfo->SourceSurface->lDelta * (BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1);
179       }
180       DestLine = DestBits;
181 
182       for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
183       {
184         SourceBits = SourceLine;
185         DestBits = DestLine;
186 
187         if (bLeftToRight)
188         {
189           /* This sets the SourceBits to the rightmost pixel */
190           SourceBits += (BltInfo->DestRect.right - BltInfo->DestRect.left - 1);
191         }
192 
193         for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
194         {
195           xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *SourceBits);
196           *DestBits = xColor & 0xff;
197           *(PWORD)(DestBits + 1) = (WORD)(xColor >> 8);
198           DEC_OR_INC(SourceBits, bLeftToRight, 1);
199           DestBits += 3;
200         }
201 
202         DEC_OR_INC(SourceLine, bTopToBottom, BltInfo->SourceSurface->lDelta);
203         DestLine += BltInfo->DestSurface->lDelta;
204       }
205       break;
206 
207     case BMF_16BPP:
208       DPRINT("16BPP Case Selected with DestRect Width of '%d'.\n",
209              BltInfo->DestRect.right - BltInfo->DestRect.left);
210 
211       /* This sets SourceBits_16BPP to the top line */
212       SourceBits_16BPP = (PWORD)((PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 2 * BltInfo->SourcePoint.x);
213 
214       if (bTopToBottom)
215       {
216         /* This sets SourceBits_16BPP to the bottom line */
217         SourceBits_16BPP += (BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1) * BltInfo->SourceSurface->lDelta;
218       }
219 
220       for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
221       {
222         SourceLine_16BPP = SourceBits_16BPP;
223         DestLine = DestBits;
224 
225         if (bLeftToRight)
226         {
227           /* This sets the SourceLine_16BPP to the rightmost pixel */
228           SourceLine_16BPP += (BltInfo->DestRect.right - BltInfo->DestRect.left - 1);
229         }
230 
231         for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
232         {
233           xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *SourceLine_16BPP);
234           *DestLine++ = xColor & 0xff;
235           *(PWORD)DestLine = (WORD)(xColor >> 8);
236           DestLine += 2;
237           DEC_OR_INC(SourceLine_16BPP, bLeftToRight, 1);
238         }
239         if (bTopToBottom)
240         {
241           SourceBits_16BPP = (PWORD)((PBYTE)SourceBits_16BPP - BltInfo->SourceSurface->lDelta);
242         }
243         else
244         {
245           SourceBits_16BPP = (PWORD)((PBYTE)SourceBits_16BPP + BltInfo->SourceSurface->lDelta);
246         }
247         DestBits += BltInfo->DestSurface->lDelta;
248       }
249       break;
250 
251     case BMF_24BPP:
252       DPRINT("24BPP Case Selected with DestRect Width of '%d'.\n",
253              BltInfo->DestRect.right - BltInfo->DestRect.left);
254 
255       /* Check for no flips here because we are about to use RtlMoveMemory and it can only do increasing src & dst */
256       if ((BltInfo->XlateSourceToDest == NULL ||
257         (BltInfo->XlateSourceToDest->flXlate & XO_TRIVIAL) != 0) &&
258         (!bTopToBottom && !bLeftToRight))
259       {
260         DPRINT("XO_TRIVIAL is TRUE.\n");
261         if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
262         {
263           /* This sets SourceBits to the top line */
264           SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
265           for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
266           {
267             RtlMoveMemory(DestBits, SourceBits, 3 * (BltInfo->DestRect.right - BltInfo->DestRect.left));
268             SourceBits += BltInfo->SourceSurface->lDelta;
269             DestBits += BltInfo->DestSurface->lDelta;
270           }
271         }
272         else
273         {
274           SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + ((BltInfo->SourcePoint.y + BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1) * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
275           DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta) + 3 * BltInfo->DestRect.left;
276           for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
277           {
278             RtlMoveMemory(DestBits, SourceBits, 3 * (BltInfo->DestRect.right - BltInfo->DestRect.left));
279             SourceBits -= BltInfo->SourceSurface->lDelta;
280             DestBits -= BltInfo->DestSurface->lDelta;
281           }
282         }
283       }
284       else
285       {
286         DPRINT("XO_TRIVIAL is NOT TRUE.\n");
287 
288         if (!bTopToBottom && !bLeftToRight)
289       /* **Note: Indent is purposefully less than desired to keep reviewable differences to a minimum for PR** */
290       {
291         sx = BltInfo->SourcePoint.x;
292         sy = BltInfo->SourcePoint.y;
293 
294         for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
295         {
296           sx = BltInfo->SourcePoint.x;
297           for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
298           {
299             DWORD pixel = DIB_24BPP_GetPixel(BltInfo->SourceSurface, sx, sy);
300             DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, pixel));
301             sx++;
302           }
303           sy++;
304         }
305       }
306         else
307         {
308           /* Buffering for source and destination flip overlaps. Fixes KHMZ MirrorTest CORE-16642 */
309           BOOL TopToBottomDone = FALSE;
310 
311           if (bLeftToRight)
312           {
313             DPRINT("Flip is bLeftToRight.\n");
314             DWORD  Index;
315 
316             /* Allocate enough pixels for a row in DWORD's */
317             DWORD *store = ExAllocatePoolWithTag(NonPagedPool,
318               (BltInfo->DestRect.right - BltInfo->DestRect.left + 1) * 4, TAG_DIB);
319             if (store == NULL)
320             {
321               DPRINT1("Storage Allocation Failed.\n");
322               return FALSE;
323             }
324 
325             sx = BltInfo->SourcePoint.x;
326             /* This sets sy to the top line */
327             sy = BltInfo->SourcePoint.y;
328 
329             /* This sets sx to the rightmost pixel */
330             sx = BltInfo->SourcePoint.x + (BltInfo->DestRect.right - BltInfo->DestRect.left - 1);
331 
332             for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
333             {
334 
335               /* This sets sx to the rightmost pixel */
336               sx = BltInfo->SourcePoint.x + (BltInfo->DestRect.right - BltInfo->DestRect.left - 1);
337 
338               Index = 0;
339 
340               // Read right to left and store
341               for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
342               {
343                 store[Index] = DIB_24BPP_GetPixel(BltInfo->SourceSurface, sx, sy);
344                 Index++;
345                 sx--;
346               }
347 
348               Index = 0;
349 
350               // Write left to right to pixel
351               for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
352               {
353                 DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, store[Index]));
354                 Index++;
355               }
356               sy++;
357             }
358             ExFreePoolWithTag(store, TAG_DIB);
359             TopToBottomDone = TRUE;
360           }
361 
362           if (bTopToBottom)
363           {
364             DPRINT("Flip is bTopToBottom.\n");
365             DWORD  Index;
366 
367             /* Allocate enough pixels for a column in DWORD's */
368             DWORD *store = ExAllocatePoolWithTag(NonPagedPool,
369               (BltInfo->DestRect.bottom - BltInfo->DestRect.top + 1) * 4, TAG_DIB);
370             if (store == NULL)
371             {
372               DPRINT1("Storage Allocation Failed.\n");
373               return FALSE;
374             }
375 
376             /* The TopToBottomDone flag indicates that we are flipping for bTopToBottom and bLeftToRight
377              * and have already completed the bLeftToRight. So we will lose our first flip output
378              * unless we work with its output which is at the destination site. So in this case
379              * our new Source becomes the previous outputs Destination.
380              */
381 
382             if (TopToBottomDone)
383             {
384              sx = BltInfo->DestRect.left;
385               sy = BltInfo->DestRect.top;
386 
387               /* This sets sy to the bottom line */
388               sy += (BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1);
389             }
390             else
391             {
392               sx = BltInfo->SourcePoint.x;
393 
394               /* This sets sy to the top line */
395               sy = BltInfo->SourcePoint.y;
396 
397               /* This sets sy to the bottom line */
398               sy = BltInfo->SourcePoint.y + (BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1);
399             }
400 
401             for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
402             {
403 
404               /* This sets sy to the bottom line */
405               sy = BltInfo->SourcePoint.y + (BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1);
406               Index = 0;
407 
408               /* Read bottom to top and store */
409               for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
410               {
411                 if (TopToBottomDone)
412                 {
413                   store[Index] = DIB_24BPP_GetPixel(BltInfo->DestSurface, sx, sy);
414                 }
415                 else
416                 {
417                   store[Index] = DIB_24BPP_GetPixel(BltInfo->SourceSurface, sx, sy);
418                 }
419                 Index++;
420                 sy--;
421               }
422 
423               Index = 0;
424 
425               for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
426               {
427                 DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, store[Index]));
428                 Index++;
429               }
430               sx++;
431             }
432             ExFreePoolWithTag(store, TAG_DIB);
433           }
434 
435         }
436       }
437       break;
438 
439     case BMF_32BPP:
440       DPRINT("32BPP Case Selected with DestRect Width of '%d'.\n",
441              BltInfo->DestRect.right - BltInfo->DestRect.left);
442 
443       SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
444 
445       if (bTopToBottom)
446       {
447         /* This sets SourceLine to the bottom line */
448         SourceLine += BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1;
449       }
450       DestLine = DestBits;
451 
452       for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
453       {
454         SourceBits = SourceLine;
455         DestBits = DestLine;
456 
457         if (bLeftToRight)
458         {
459           /* This sets SourceBits to the rightmost pixel */
460           SourceBits += (BltInfo->DestRect.right - BltInfo->DestRect.left - 1) * 4;
461         }
462         for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
463         {
464           xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *((PDWORD) SourceBits));
465           *DestBits = xColor & 0xff;
466           *(PWORD)(DestBits + 1) = (WORD)(xColor >> 8);
467           DEC_OR_INC(SourceBits, bLeftToRight, 4);
468           DestBits += 3;
469         }
470 
471         DEC_OR_INC(SourceLine, bTopToBottom, BltInfo->SourceSurface->lDelta);
472         DestLine += BltInfo->DestSurface->lDelta;
473       }
474       break;
475 
476     default:
477       DbgPrint("DIB_24BPP_Bitblt: Unhandled Source BPP: %u\n", BitsPerFormat(BltInfo->SourceSurface->iBitmapFormat));
478       return FALSE;
479   }
480 
481   return TRUE;
482 }
483 
484 BOOLEAN
485 DIB_24BPP_BitBlt(PBLTINFO BltInfo)
486 {
487    LONG DestX, DestY;
488    LONG SourceX, SourceY;
489    LONG PatternY = 0;
490    ULONG Dest, Source = 0, Pattern = 0;
491    BOOL UsesSource;
492    BOOL UsesPattern;
493    PBYTE DestBits;
494 
495    UsesSource = ROP4_USES_SOURCE(BltInfo->Rop4);
496    UsesPattern = ROP4_USES_PATTERN(BltInfo->Rop4);
497 
498    SourceY = BltInfo->SourcePoint.y;
499    DestBits = (PBYTE)(
500       (PBYTE)BltInfo->DestSurface->pvScan0 +
501       (BltInfo->DestRect.left << 1) + BltInfo->DestRect.left +
502       BltInfo->DestRect.top * BltInfo->DestSurface->lDelta);
503 
504    if (UsesPattern)
505    {
506       if (BltInfo->PatternSurface)
507       {
508          PatternY = (BltInfo->DestRect.top - BltInfo->BrushOrigin.y) %
509                     BltInfo->PatternSurface->sizlBitmap.cy;
510       }
511       else
512       {
513          if (BltInfo->Brush)
514          {
515             Pattern = BltInfo->Brush->iSolidColor;
516          }
517       }
518    }
519 
520    for (DestY = BltInfo->DestRect.top; DestY < BltInfo->DestRect.bottom; DestY++)
521    {
522       SourceX = BltInfo->SourcePoint.x;
523 
524       for (DestX = BltInfo->DestRect.left; DestX < BltInfo->DestRect.right; DestX++, DestBits += 3, SourceX++)
525       {
526          Dest = *((PUSHORT)DestBits) + (*(DestBits + 2) << 16);
527 
528          if (UsesSource)
529          {
530             Source = DIB_GetSource(BltInfo->SourceSurface, SourceX, SourceY, BltInfo->XlateSourceToDest);
531          }
532 
533          if (BltInfo->PatternSurface)
534          {
535             Pattern = DIB_GetSourceIndex(BltInfo->PatternSurface, (DestX - BltInfo->BrushOrigin.x) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY);
536          }
537 
538          Dest = DIB_DoRop(BltInfo->Rop4, Dest, Source, Pattern) & 0xFFFFFF;
539          *(PUSHORT)(DestBits) = Dest & 0xFFFF;
540          *(DestBits + 2) = (BYTE)(Dest >> 16);
541       }
542 
543       SourceY++;
544       if (BltInfo->PatternSurface)
545       {
546          PatternY++;
547          PatternY %= BltInfo->PatternSurface->sizlBitmap.cy;
548       }
549       DestBits -= (BltInfo->DestRect.right - BltInfo->DestRect.left) * 3;
550       DestBits += BltInfo->DestSurface->lDelta;
551    }
552 
553    return TRUE;
554 }
555 
556 /* BitBlt Optimize */
557 BOOLEAN
558 DIB_24BPP_ColorFill(SURFOBJ* DestSurface, RECTL* DestRect, ULONG color)
559 {
560   LONG DestY;
561 
562   /* Make WellOrdered by making top < bottom and left < right */
563   RECTL_vMakeWellOrdered(DestRect);
564 
565 #if defined(_M_IX86) && !defined(_MSC_VER)
566   PBYTE xaddr = (PBYTE)DestSurface->pvScan0 + DestRect->top * DestSurface->lDelta + (DestRect->left << 1) + DestRect->left;
567   PBYTE addr;
568   ULONG Count;
569   ULONG xCount=DestRect->right - DestRect->left;
570 
571   for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
572   {
573     Count = xCount;
574     addr = xaddr;
575     xaddr = (PBYTE)((ULONG_PTR)addr + DestSurface->lDelta);
576 
577     if (Count < 8)
578     {
579       /* For small fills, don't bother doing anything fancy */
580       while (Count--)
581         {
582           *(PUSHORT)(addr) = color;
583           addr += 2;
584           *(addr) = color >> 16;
585           addr += 1;
586         }
587     }
588     else
589     {
590       /* Align to 4-byte address */
591       while (0 != ((ULONG_PTR) addr & 0x3))
592       {
593         *(PUSHORT)(addr) = color;
594         addr += 2;
595         *(addr) = color >> 16;
596         addr += 1;
597         Count--;
598       }
599       /* If the color we need to fill with is 0ABC, then the final mem pattern
600        * (note little-endianness) would be:
601        *
602        * |C.B.A|C.B.A|C.B.A|C.B.A|   <- pixel borders
603        * |C.B.A.C|B.A.C.B|A.C.B.A|   <- ULONG borders
604        *
605        * So, taking endianness into account again, we need to fill with these
606        * ULONGs: CABC BCAB ABCA */
607 
608       /* This is about 30% faster than the generic C code below */
609       __asm__ __volatile__ (
610         "movl %1, %%ecx\n\t"
611         "andl $0xffffff, %%ecx\n\t"     /* 0ABC */
612         "movl %%ecx, %%ebx\n\t"         /* Construct BCAB in ebx */
613         "shrl $8, %%ebx\n\t"
614         "movl %%ecx, %%eax\n\t"
615         "shll $16, %%eax\n\t"
616         "orl  %%eax, %%ebx\n\t"
617         "movl %%ecx, %%edx\n\t"         /* Construct ABCA in edx */
618         "shll $8, %%edx\n\t"
619         "movl %%ecx, %%eax\n\t"
620         "shrl $16, %%eax\n\t"
621         "orl  %%eax, %%edx\n\t"
622         "movl %%ecx, %%eax\n\t"         /* Construct CABC in eax */
623         "shll $24, %%eax\n\t"
624         "orl  %%ecx, %%eax\n\t"
625         "movl %2, %%ecx\n\t"            /* Load count */
626         "shr  $2, %%ecx\n\t"
627         "movl %3, %%edi\n"              /* Load dest */
628         "1:\n\t"
629         "movl %%eax, (%%edi)\n\t"       /* Store 4 pixels, 12 bytes */
630         "movl %%ebx, 4(%%edi)\n\t"
631         "movl %%edx, 8(%%edi)\n\t"
632         "addl $12, %%edi\n\t"
633         "dec  %%ecx\n\t"
634         "jnz  1b\n\t"
635         "movl %%edi, %0"
636         : "=m"(addr)
637         : "m"(color), "m"(Count), "m"(addr)
638         : "%eax", "%ebx", "%ecx", "%edx", "%edi");
639       Count = Count & 0x03;
640       while (0 != Count--)
641       {
642         *(PUSHORT)(addr) = color;
643         addr += 2;
644         *(addr) = color >> 16;
645         addr += 1;
646       }
647     }
648   }
649 #else
650 
651   for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
652   {
653     DIB_24BPP_HLine(DestSurface, DestRect->left, DestRect->right, DestY, color);
654   }
655 #endif
656   return TRUE;
657 }
658 
659 BOOLEAN
660 DIB_24BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
661                          RECTL*  DestRect,  RECTL *SourceRect,
662                          XLATEOBJ *ColorTranslation, ULONG iTransColor)
663 {
664   LONG X, Y, SourceX, SourceY = 0, wd;
665   ULONG Source = 0, Dest;
666   BYTE *DestBits;
667 
668   LONG DstHeight;
669   LONG DstWidth;
670   LONG SrcHeight;
671   LONG SrcWidth;
672 
673   DstHeight = DestRect->bottom - DestRect->top;
674   DstWidth = DestRect->right - DestRect->left;
675   SrcHeight = SourceRect->bottom - SourceRect->top;
676   SrcWidth = SourceRect->right - SourceRect->left;
677 
678   DestBits = (BYTE*)((PBYTE)DestSurf->pvScan0 +
679                       (DestRect->left * 3) +
680                       DestRect->top * DestSurf->lDelta);
681   wd = DestSurf->lDelta - ((DestRect->right - DestRect->left) * 3);
682 
683   for(Y = DestRect->top; Y < DestRect->bottom; Y++)
684   {
685     SourceY = SourceRect->top+(Y - DestRect->top) * SrcHeight / DstHeight;
686     for(X = DestRect->left; X < DestRect->right; X++, DestBits += 3)
687     {
688       SourceX = SourceRect->left+(X - DestRect->left) * SrcWidth / DstWidth;
689       if (SourceX >= 0 && SourceY >= 0 &&
690           SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
691       {
692         Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
693         if(Source != iTransColor)
694         {
695           Dest = XLATEOBJ_iXlate(ColorTranslation, Source) & 0xFFFFFF;
696            *(PUSHORT)(DestBits) = Dest & 0xFFFF;
697            *(DestBits + 2) = (BYTE)(Dest >> 16);
698         }
699       }
700     }
701 
702     DestBits = (BYTE*)((ULONG_PTR)DestBits + wd);
703   }
704 
705   return TRUE;
706 }
707 
708 typedef union {
709    ULONG ul;
710    struct {
711       UCHAR red;
712       UCHAR green;
713       UCHAR blue;
714       UCHAR alpha;
715    } col;
716 } NICEPIXEL32;
717 
718 static __inline UCHAR
719 Clamp8(ULONG val)
720 {
721    return (val > 255) ? 255 : (UCHAR)val;
722 }
723 
724 BOOLEAN
725 DIB_24BPP_AlphaBlend(SURFOBJ* Dest, SURFOBJ* Source, RECTL* DestRect,
726                      RECTL* SourceRect, CLIPOBJ* ClipRegion,
727                      XLATEOBJ* ColorTranslation, BLENDOBJ* BlendObj)
728 {
729    INT Rows, Cols, SrcX, SrcY;
730    register PUCHAR Dst;
731    BLENDFUNCTION BlendFunc;
732    register NICEPIXEL32 DstPixel, SrcPixel;
733    UCHAR Alpha;
734    //UCHAR SrcBpp;
735 
736    DPRINT("DIB_24BPP_AlphaBlend: srcRect: (%d,%d)-(%d,%d), dstRect: (%d,%d)-(%d,%d)\n",
737           SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
738           DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
739 
740    BlendFunc = BlendObj->BlendFunction;
741    if (BlendFunc.BlendOp != AC_SRC_OVER)
742    {
743       DPRINT1("BlendOp != AC_SRC_OVER\n");
744       return FALSE;
745    }
746    if (BlendFunc.BlendFlags != 0)
747    {
748       DPRINT1("BlendFlags != 0\n");
749       return FALSE;
750    }
751    if ((BlendFunc.AlphaFormat & ~AC_SRC_ALPHA) != 0)
752    {
753       DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendFunc.AlphaFormat);
754       return FALSE;
755    }
756    if ((BlendFunc.AlphaFormat & AC_SRC_ALPHA) != 0 &&
757        BitsPerFormat(Source->iBitmapFormat) != 32)
758    {
759       DPRINT1("Source bitmap must be 32bpp when AC_SRC_ALPHA is set\n");
760       return FALSE;
761    }
762 
763    Dst = (PUCHAR)((ULONG_PTR)Dest->pvScan0 + (DestRect->top * Dest->lDelta) +
764                              (DestRect->left * 3));
765    //SrcBpp = BitsPerFormat(Source->iBitmapFormat);
766 
767    Rows = 0;
768    SrcY = SourceRect->top;
769    while (++Rows <= DestRect->bottom - DestRect->top)
770   {
771     Cols = 0;
772     SrcX = SourceRect->left;
773     while (++Cols <= DestRect->right - DestRect->left)
774     {
775       SrcPixel.ul = DIB_GetSource(Source, SrcX, SrcY, ColorTranslation);
776       SrcPixel.col.red = (SrcPixel.col.red * BlendFunc.SourceConstantAlpha) / 255;
777       SrcPixel.col.green = (SrcPixel.col.green * BlendFunc.SourceConstantAlpha) / 255;
778       SrcPixel.col.blue = (SrcPixel.col.blue * BlendFunc.SourceConstantAlpha) / 255;
779       if (!(BlendFunc.AlphaFormat & AC_SRC_ALPHA))
780       {
781           Alpha = BlendFunc.SourceConstantAlpha ;
782       }
783       else
784       {
785         Alpha = (SrcPixel.col.alpha * BlendFunc.SourceConstantAlpha) / 255;
786       }
787 
788       DstPixel.col.red = Clamp8((*Dst * (255 - Alpha)) / 255 + SrcPixel.col.red) ;
789       DstPixel.col.green = Clamp8((*(Dst+1) * (255 - Alpha) / 255 + SrcPixel.col.green)) ;
790       DstPixel.col.blue = Clamp8((*(Dst+2) * (255 - Alpha)) / 255 + SrcPixel.col.blue) ;
791       *Dst++ = DstPixel.col.red;
792       *Dst++ = DstPixel.col.green;
793       *Dst++ = DstPixel.col.blue;
794       SrcX = SourceRect->left + (Cols*(SourceRect->right - SourceRect->left))/(DestRect->right - DestRect->left);
795     }
796     Dst = (PUCHAR)((ULONG_PTR)Dest->pvScan0 + ((DestRect->top + Rows) * Dest->lDelta) +
797                 (DestRect->left*3));
798     SrcY = SourceRect->top + (Rows*(SourceRect->bottom - SourceRect->top))/(DestRect->bottom - DestRect->top);
799   }
800 
801    return TRUE;
802 }
803 
804 /* EOF */
805