fixed working strechblt for all dibxx now. do not say it does not take offset of...
[reactos.git] / reactos / subsys / win32k / dib / dib24bpp.c
index 5ec3ca9..30493e1 100644 (file)
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 /* $Id$ */
+
 #include <w32k.h>
 
+#define NDEBUG
+#include <debug.h>
+
 VOID
 DIB_24BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
 {
-  PBYTE addr = SurfObj->pvScan0 + (y * SurfObj->lDelta) + (x << 1) + x;
+  PBYTE addr = (PBYTE)SurfObj->pvScan0 + (y * SurfObj->lDelta) + (x << 1) + x;
   *(PUSHORT)(addr) = c & 0xFFFF;
   *(addr + 2) = (c >> 16) & 0xFF;
 }
@@ -30,30 +34,114 @@ DIB_24BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
 ULONG
 DIB_24BPP_GetPixel(SURFOBJ *SurfObj, LONG x, LONG y)
 {
-  PBYTE addr = SurfObj->pvScan0 + y * SurfObj->lDelta + (x << 1) + x;
+  PBYTE addr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + (x << 1) + x;
   return *(PUSHORT)(addr) + (*(addr + 2) << 16);
 }
 
 VOID
 DIB_24BPP_HLine(SURFOBJ *SurfObj, LONG x1, LONG x2, LONG y, ULONG c)
 {
-  PBYTE addr = SurfObj->pvScan0 + y * SurfObj->lDelta + (x1 << 1) + x1;
-  LONG cx = x1;
-
-  c &= 0xFFFFFF;
-  while(cx < x2) {
-    *(PUSHORT)(addr) = c & 0xFFFF;
-    addr += 2;
-    *(addr) = c >> 16;
-    addr += 1;
-    ++cx;
-  }
+  PBYTE addr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + (x1 << 1) + x1;
+  ULONG Count = x2 - x1;
+#ifndef _M_IX86
+  ULONG MultiCount;
+  ULONG Fill[3];
+#endif
+
+  if (Count < 8)
+    {
+      /* For small fills, don't bother doing anything fancy */
+      while (Count--)
+        {
+          *(PUSHORT)(addr) = c;
+          addr += 2;
+          *(addr) = c >> 16;
+          addr += 1;
+        }
+    }
+  else
+    {
+      /* Align to 4-byte address */
+      while (0 != ((ULONG_PTR) addr & 0x3))
+        {
+          *(PUSHORT)(addr) = c;
+          addr += 2;
+          *(addr) = c >> 16;
+          addr += 1;
+          Count--;
+        }
+      /* If the color we need to fill with is 0ABC, then the final mem pattern
+       * (note little-endianness) would be:
+       *
+       * |C.B.A|C.B.A|C.B.A|C.B.A|   <- pixel borders
+       * |C.B.A.C|B.A.C.B|A.C.B.A|   <- ULONG borders
+       *
+       * So, taking endianness into account again, we need to fill with these
+       * ULONGs: CABC BCAB ABCA */
+#ifdef _M_IX86
+       /* This is about 30% faster than the generic C code below */
+       __asm__ __volatile__ (
+"      movl %1, %%ecx\n"
+"      andl $0xffffff, %%ecx\n"         /* 0ABC */
+"      movl %%ecx, %%ebx\n"             /* Construct BCAB in ebx */
+"      shrl $8, %%ebx\n"
+"      movl %%ecx, %%eax\n"
+"      shll $16, %%eax\n"
+"      orl  %%eax, %%ebx\n"
+"      movl %%ecx, %%edx\n"             /* Construct ABCA in edx */
+"      shll $8, %%edx\n"
+"      movl %%ecx, %%eax\n"
+"      shrl $16, %%eax\n"
+"      orl  %%eax, %%edx\n"
+"      movl %%ecx, %%eax\n"             /* Construct CABC in eax */
+"      shll $24, %%eax\n"
+"      orl  %%ecx, %%eax\n"
+"      movl %2, %%ecx\n"                /* Load count */
+"      shr  $2, %%ecx\n"
+"      movl %3, %%edi\n"                /* Load dest */
+"0:\n"
+"      movl %%eax, (%%edi)\n"           /* Store 4 pixels, 12 bytes */
+"      movl %%ebx, 4(%%edi)\n"
+"      movl %%edx, 8(%%edi)\n"
+"      addl $12, %%edi\n"
+"      dec  %%ecx\n"
+"      jnz  0b\n"
+"      movl %%edi, %0\n"
+  : "=m"(addr)
+  : "m"(c), "m"(Count), "m"(addr)
+  : "%eax", "%ebx", "%ecx", "%edx", "%edi");
+#else
+      c = c & 0xffffff;                /* 0ABC */
+      Fill[0] = c | (c << 24);         /* CABC */
+      Fill[1] = (c >> 8) | (c << 16);  /* BCAB */
+      Fill[2] = (c << 8) | (c >> 16);  /* ABCA */
+      MultiCount = Count / 4;
+      do
+        {
+          *(PULONG)addr = Fill[0];
+          addr += 4;
+          *(PULONG)addr = Fill[1];
+          addr += 4;
+          *(PULONG)addr = Fill[2];
+          addr += 4;
+        }
+      while (0 != --MultiCount);
+#endif
+      Count = Count & 0x03;
+      while (0 != Count--)
+        {
+          *(PUSHORT)(addr) = c;
+          addr += 2;
+          *(addr) = c >> 16;
+          addr += 1;
+        }
+    }
 }
 
 VOID
 DIB_24BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
 {
-  PBYTE addr = SurfObj->pvScan0 + y1 * SurfObj->lDelta + (x << 1) + x;
+  PBYTE addr = (PBYTE)SurfObj->pvScan0 + y1 * SurfObj->lDelta + (x << 1) + x;
   LONG lDelta = SurfObj->lDelta;
 
   c &= 0xFFFFFF;
@@ -73,7 +161,7 @@ DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
   PBYTE    SourceBits_4BPP, SourceLine_4BPP;
   PWORD    SourceBits_16BPP, SourceLine_16BPP;
 
-  DestBits = BltInfo->DestSurface->pvScan0 + (BltInfo->DestRect.top * BltInfo->DestSurface->lDelta) + BltInfo->DestRect.left * 3;
+  DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + (BltInfo->DestRect.top * BltInfo->DestSurface->lDelta) + BltInfo->DestRect.left * 3;
 
   switch(BltInfo->SourceSurface->iBitmapFormat)
   {
@@ -99,7 +187,7 @@ DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
       break;
 
     case BMF_4BPP:
-      SourceBits_4BPP = BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + (BltInfo->SourcePoint.x >> 1);
+      SourceBits_4BPP = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + (BltInfo->SourcePoint.x >> 1);
 
       for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
       {
@@ -125,7 +213,7 @@ DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
       break;
 
     case BMF_8BPP:
-      SourceLine = BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
+      SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
       DestLine = DestBits;
 
       for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
@@ -148,7 +236,7 @@ DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
       break;
 
     case BMF_16BPP:
-      SourceBits_16BPP = BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 2 * BltInfo->SourcePoint.x;
+      SourceBits_16BPP = (PWORD)((PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 2 * BltInfo->SourcePoint.x);
 
       for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
       {
@@ -174,7 +262,7 @@ DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
       {
        if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
          {
-           SourceBits = BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
+           SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
            for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
              {
                RtlMoveMemory(DestBits, SourceBits, 3 * (BltInfo->DestRect.right - BltInfo->DestRect.left));
@@ -184,8 +272,8 @@ DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
          }
        else
          {
-           SourceBits = BltInfo->SourceSurface->pvScan0 + ((BltInfo->SourcePoint.y + BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1) * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
-           DestBits = BltInfo->DestSurface->pvScan0 + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta) + 3 * BltInfo->DestRect.left;
+           SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + ((BltInfo->SourcePoint.y + BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1) * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
+           DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta) + 3 * BltInfo->DestRect.left;
            for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
              {
                RtlMoveMemory(DestBits, SourceBits, 3 * (BltInfo->DestRect.right - BltInfo->DestRect.left));
@@ -203,7 +291,7 @@ DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
       break;
 
     case BMF_32BPP:
-      SourceLine = BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
+      SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
       DestLine = DestBits;
 
       for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
@@ -249,7 +337,7 @@ DIB_24BPP_BitBlt(PBLTINFO BltInfo)
 
    SourceY = BltInfo->SourcePoint.y;
    DestBits = (PBYTE)(
-      BltInfo->DestSurface->pvScan0 +
+      (PBYTE)BltInfo->DestSurface->pvScan0 +
       (BltInfo->DestRect.left << 1) + BltInfo->DestRect.left +
       BltInfo->DestRect.top * BltInfo->DestSurface->lDelta);
 
@@ -302,14 +390,247 @@ DIB_24BPP_BitBlt(PBLTINFO BltInfo)
    return TRUE;
 }
 
+/* BitBlt Optimize */
+BOOLEAN 
+DIB_24BPP_ColorFill(SURFOBJ* DestSurface, RECTL* DestRect, ULONG color)
+{
+  ULONG DestY; 
+
+#ifdef _M_IX86
+  PBYTE xaddr = (PBYTE)DestSurface->pvScan0 + DestRect->top * DestSurface->lDelta + (DestRect->left << 1) + DestRect->left;
+  PBYTE addr;
+  ULONG Count;
+  ULONG xCount=DestRect->right - DestRect->left;
+
+  for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
+  {
+    Count = xCount;
+    addr = xaddr;    
+    xaddr = (PBYTE)((ULONG_PTR)addr + DestSurface->lDelta);
+
+    if (Count < 8)
+    {
+      /* For small fills, don't bother doing anything fancy */
+      while (Count--)
+        {
+          *(PUSHORT)(addr) = color;
+          addr += 2;
+          *(addr) = color >> 16;
+          addr += 1;
+        }
+    }
+  else
+    {
+      /* Align to 4-byte address */
+      while (0 != ((ULONG_PTR) addr & 0x3))
+        {
+          *(PUSHORT)(addr) = color;
+          addr += 2;
+          *(addr) = color >> 16;
+          addr += 1;
+          Count--;
+        }
+      /* If the color we need to fill with is 0ABC, then the final mem pattern
+       * (note little-endianness) would be:
+       *
+       * |C.B.A|C.B.A|C.B.A|C.B.A|   <- pixel borders
+       * |C.B.A.C|B.A.C.B|A.C.B.A|   <- ULONG borders
+       *
+       * So, taking endianness into account again, we need to fill with these
+       * ULONGs: CABC BCAB ABCA */
+
+       /* This is about 30% faster than the generic C code below */
+       __asm__ __volatile__ (
+"      movl %1, %%ecx\n"
+"      andl $0xffffff, %%ecx\n"         /* 0ABC */
+"      movl %%ecx, %%ebx\n"             /* Construct BCAB in ebx */
+"      shrl $8, %%ebx\n"
+"      movl %%ecx, %%eax\n"
+"      shll $16, %%eax\n"
+"      orl  %%eax, %%ebx\n"
+"      movl %%ecx, %%edx\n"             /* Construct ABCA in edx */
+"      shll $8, %%edx\n"
+"      movl %%ecx, %%eax\n"
+"      shrl $16, %%eax\n"
+"      orl  %%eax, %%edx\n"
+"      movl %%ecx, %%eax\n"             /* Construct CABC in eax */
+"      shll $24, %%eax\n"
+"      orl  %%ecx, %%eax\n"
+"      movl %2, %%ecx\n"                /* Load count */
+"      shr  $2, %%ecx\n"
+"      movl %3, %%edi\n"                /* Load dest */
+".FL1:\n"
+"      movl %%eax, (%%edi)\n"           /* Store 4 pixels, 12 bytes */
+"      movl %%ebx, 4(%%edi)\n"
+"      movl %%edx, 8(%%edi)\n"
+"      addl $12, %%edi\n"
+"      dec  %%ecx\n"
+"      jnz  .FL1\n"
+"      movl %%edi, %0\n"
+  : "=m"(addr)
+  : "m"(color), "m"(Count), "m"(addr)
+  : "%eax", "%ebx", "%ecx", "%edx", "%edi");
+   Count = Count & 0x03;
+      while (0 != Count--)
+        {
+          *(PUSHORT)(addr) = color;
+          addr += 2;
+          *(addr) = color >> 16;
+          addr += 1;
+        }
+    }
+  }
+#else
+
+  for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
+    {                                                  
+      DIB_24BPP_HLine(DestSurface, DestRect->left, DestRect->right, DestY, color);                                                     
+    }
+#endif
+  return TRUE;
+}
+
+//NOTE: If you change something here, please do the same in other dibXXbpp.c files!
 BOOLEAN DIB_24BPP_StretchBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
                             RECTL* DestRect, RECTL *SourceRect,
                             POINTL* MaskOrigin, POINTL BrushOrigin,
                             CLIPOBJ *ClipRegion, XLATEOBJ *ColorTranslation,
                             ULONG Mode)
 {
-  DbgPrint("DIB_24BPP_StretchBlt: Source BPP: %u\n", BitsPerFormat(SourceSurf->iBitmapFormat));
-  return FALSE;
+   LONG SrcSizeY;
+   LONG SrcSizeX;
+   LONG DesSizeY;
+   LONG DesSizeX;      
+   LONG sx;
+   LONG sy;
+   LONG DesX;
+   LONG DesY;
+   LONG color;
+  
+   SrcSizeY = SourceRect->bottom - SourceRect->top;
+   SrcSizeX = SourceRect->right - SourceRect->left;
+  
+   DesSizeY = DestRect->bottom - DestRect->top;
+   DesSizeX = DestRect->right - DestRect->left;
+
+   switch(SourceSurf->iBitmapFormat)
+   {
+      case BMF_1BPP:
+         /* FIXME :  MaskOrigin, BrushOrigin, ClipRegion, Mode ? */
+      /* This is a reference implementation, it hasn't been optimized for speed */
+                      
+       for (DesY=DestRect->top; DesY<DestRect->bottom; DesY++)
+       {                        
+           sy = (((DesY - DestRect->top) * SrcSizeY) / DesSizeY) + SourceRect->top;
+                     
+            for (DesX=DestRect->left; DesX<DestRect->right; DesX++)
+            {                  
+                  sx = (((DesX - DestRect->left) * SrcSizeX) / DesSizeX) + SourceRect->left;
+                               
+                  if(DIB_1BPP_GetPixel(SourceSurf, sx, sy) == 0)
+                                 {
+                                       DIB_24BPP_PutPixel(DestSurf, DesX, DesY, XLATEOBJ_iXlate(ColorTranslation, 0));
+                  } 
+                                 else 
+                                 {
+                    DIB_24BPP_PutPixel(DestSurf, DesX, DesY, XLATEOBJ_iXlate(ColorTranslation, 1));
+                  }
+            }
+       }               
+
+         break;
+
+      case BMF_4BPP:           
+      /* FIXME :  MaskOrigin, BrushOrigin, ClipRegion, Mode ? */
+      /* This is a reference implementation, it hasn't been optimized for speed */
+                      
+       for (DesY=DestRect->top; DesY<DestRect->bottom; DesY++)
+       {                        
+           sy = (((DesY - DestRect->top) * SrcSizeY) / DesSizeY) + SourceRect->top;
+                     
+            for (DesX=DestRect->left; DesX<DestRect->right; DesX++)
+            {                  
+                 sx = (((DesX - DestRect->left) * SrcSizeX) / DesSizeX) + SourceRect->left;            
+                 color = DIB_4BPP_GetPixel(SourceSurf, sx, sy);
+                 DIB_24BPP_PutPixel(DestSurf, DesX, DesY, XLATEOBJ_iXlate(ColorTranslation, color));
+            }
+       }                  
+      break;
+
+      case BMF_8BPP:           
+      /* FIXME :  MaskOrigin, BrushOrigin, ClipRegion, Mode ? */
+      /* This is a reference implementation, it hasn't been optimized for speed */
+                      
+       for (DesY=DestRect->top; DesY<DestRect->bottom; DesY++)
+       {                        
+           sy = (((DesY - DestRect->top) * SrcSizeY) / DesSizeY) + SourceRect->top;
+                     
+            for (DesX=DestRect->left; DesX<DestRect->right; DesX++)
+            {                  
+                 sx = (((DesX - DestRect->left) * SrcSizeX) / DesSizeX) + SourceRect->left;            
+                 color = DIB_8BPP_GetPixel(SourceSurf, sx, sy);
+                 DIB_24BPP_PutPixel(DestSurf, DesX, DesY, XLATEOBJ_iXlate(ColorTranslation, color));
+            }
+       }                  
+      break;
+
+      case BMF_16BPP:          
+      /* FIXME :  MaskOrigin, BrushOrigin, ClipRegion, Mode ? */
+      /* This is a reference implementation, it hasn't been optimized for speed */
+                      
+       for (DesY=DestRect->top; DesY<DestRect->bottom; DesY++)
+       {                        
+           sy = (((DesY - DestRect->top) * SrcSizeY) / DesSizeY) + SourceRect->top;
+                     
+            for (DesX=DestRect->left; DesX<DestRect->right; DesX++)
+            {                  
+                 sx = (((DesX - DestRect->left) * SrcSizeX) / DesSizeX) + SourceRect->left;            
+                 color = DIB_16BPP_GetPixel(SourceSurf, sx, sy);
+                 DIB_24BPP_PutPixel(DestSurf, DesX, DesY, XLATEOBJ_iXlate(ColorTranslation, color));
+            }
+       }                  
+      break;
+
+      case BMF_24BPP:          
+      /* FIXME :  MaskOrigin, BrushOrigin, ClipRegion, Mode ? */
+      /* This is a reference implementation, it hasn't been optimized for speed */
+                      
+       for (DesY=DestRect->top; DesY<DestRect->bottom; DesY++)
+       {                        
+           sy = (((DesY - DestRect->top) * SrcSizeY) / DesSizeY) + SourceRect->top;
+                     
+            for (DesX=DestRect->left; DesX<DestRect->right; DesX++)
+            {                  
+                 sx = (((DesX - DestRect->left) * SrcSizeX) / DesSizeX) + SourceRect->left;            
+                 color = DIB_24BPP_GetPixel(SourceSurf, sx, sy);
+                 DIB_24BPP_PutPixel(DestSurf, DesX, DesY, XLATEOBJ_iXlate(ColorTranslation, color));
+            }
+       }                  
+      break;
+
+      case BMF_32BPP:          
+      /* FIXME :  MaskOrigin, BrushOrigin, ClipRegion, Mode ? */
+      /* This is a reference implementation, it hasn't been optimized for speed */
+                      
+       for (DesY=DestRect->top; DesY<DestRect->bottom; DesY++)
+       {                        
+           sy = (((DesY - DestRect->top) * SrcSizeY) / DesSizeY) + SourceRect->top;
+                     
+            for (DesX=DestRect->left; DesX<DestRect->right; DesX++)
+            {                  
+                 sx = (((DesX - DestRect->left) * SrcSizeX) / DesSizeX) + SourceRect->left;            
+                 color = DIB_32BPP_GetPixel(SourceSurf, sx, sy);
+                 DIB_24BPP_PutPixel(DestSurf, DesX, DesY, XLATEOBJ_iXlate(ColorTranslation, color));
+            }
+       }                  
+      break;
+
+      default:
+      //DPRINT1("DIB_24BPP_StretchBlt: Unhandled Source BPP: %u\n", BitsPerFormat(SourceSurf->iBitmapFormat));
+      return FALSE;
+    }
+  
+  return TRUE;
 }
 
 BOOLEAN
@@ -321,7 +642,7 @@ DIB_24BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
   BYTE *DestBits;
 
   SourceY = SourcePoint->y;
-  DestBits = (BYTE*)(DestSurf->pvScan0 +
+  DestBits = (BYTE*)((PBYTE)DestSurf->pvScan0 +
                       (DestRect->left << 2) +
                       DestRect->top * DestSurf->lDelta);
   wd = DestSurf->lDelta - ((DestRect->right - DestRect->left) << 2);
@@ -347,4 +668,98 @@ DIB_24BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
   return TRUE;
 }
 
+typedef union {
+   ULONG ul;
+   struct {
+      UCHAR red;
+      UCHAR green;
+      UCHAR blue;
+      UCHAR alpha;
+   } col;
+} NICEPIXEL32;
+
+STATIC inline UCHAR
+Clamp8(ULONG val)
+{
+   return (val > 255) ? 255 : val;
+}
+
+BOOLEAN
+DIB_24BPP_AlphaBlend(SURFOBJ* Dest, SURFOBJ* Source, RECTL* DestRect,
+                     RECTL* SourceRect, CLIPOBJ* ClipRegion,
+                     XLATEOBJ* ColorTranslation, BLENDOBJ* BlendObj)
+{
+   INT Rows, Cols, SrcX, SrcY;
+   register PUCHAR Dst;
+   ULONG DstDelta;
+   BLENDFUNCTION BlendFunc;
+   register NICEPIXEL32 DstPixel, SrcPixel;
+   UCHAR Alpha, SrcBpp;
+
+   DPRINT("DIB_24BPP_AlphaBlend: srcRect: (%d,%d)-(%d,%d), dstRect: (%d,%d)-(%d,%d)\n",
+          SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
+          DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
+
+   ASSERT(DestRect->bottom - DestRect->top == SourceRect->bottom - SourceRect->top &&
+          DestRect->right - DestRect->left == SourceRect->right - SourceRect->left);
+
+   BlendFunc = BlendObj->BlendFunction;
+   if (BlendFunc.BlendOp != AC_SRC_OVER)
+   {
+      DPRINT1("BlendOp != AC_SRC_OVER\n");
+      return FALSE;
+   }
+   if (BlendFunc.BlendFlags != 0)
+   {
+      DPRINT1("BlendFlags != 0\n");
+      return FALSE;
+   }
+   if ((BlendFunc.AlphaFormat & ~AC_SRC_ALPHA) != 0)
+   {
+      DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendFunc.AlphaFormat);
+      return FALSE;
+   }
+   if ((BlendFunc.AlphaFormat & AC_SRC_ALPHA) != 0 &&
+       BitsPerFormat(Source->iBitmapFormat) != 32)
+   {
+      DPRINT1("Source bitmap must be 32bpp when AC_SRC_ALPHA is set\n");
+      return FALSE;
+   }
+
+   Dst = (PUCHAR)((ULONG_PTR)Dest->pvScan0 + (DestRect->top * Dest->lDelta) +
+                             (DestRect->left * 3));
+   DstDelta = Dest->lDelta - ((DestRect->right - DestRect->left) * 3);
+   SrcBpp = BitsPerFormat(Source->iBitmapFormat);
+
+   Rows = DestRect->bottom - DestRect->top;
+   SrcY = SourceRect->top;
+   while (--Rows >= 0)
+   {
+      Cols = DestRect->right - DestRect->left;
+      SrcX = SourceRect->left;
+      while (--Cols >= 0)
+      {
+         SrcPixel.ul = DIB_GetSource(Source, SrcX++, SrcY, ColorTranslation);
+         SrcPixel.col.red = SrcPixel.col.red * BlendFunc.SourceConstantAlpha / 255;
+         SrcPixel.col.green = SrcPixel.col.green * BlendFunc.SourceConstantAlpha / 255;
+         SrcPixel.col.blue = SrcPixel.col.blue * BlendFunc.SourceConstantAlpha / 255;
+         SrcPixel.col.alpha = (SrcBpp == 32) ? (SrcPixel.col.alpha * BlendFunc.SourceConstantAlpha / 255) : BlendFunc.SourceConstantAlpha;
+
+         Alpha = ((BlendFunc.AlphaFormat & AC_SRC_ALPHA) != 0) ?
+                 SrcPixel.col.alpha : BlendFunc.SourceConstantAlpha;
+
+         DstPixel.ul = *Dst;
+         DstPixel.col.red = Clamp8(DstPixel.col.red * (255 - Alpha) / 255 + SrcPixel.col.red);
+         DstPixel.col.green = Clamp8(DstPixel.col.green * (255 - Alpha) / 255 + SrcPixel.col.green);
+         DstPixel.col.blue = Clamp8(DstPixel.col.blue * (255 - Alpha) / 255 + SrcPixel.col.blue);
+         *Dst = DstPixel.ul;
+         Dst = (PUCHAR)((ULONG_PTR)Dst + 3);
+      }
+      Dst = (PUCHAR)((ULONG_PTR)Dst + DstDelta);
+      SrcY++;
+   }
+
+   return TRUE;
+}
+
 /* EOF */