[GDI32]
[reactos.git] / reactos / dll / win32 / gdi32 / objects / bitmap.c
index 969beb6..9e5aaeb 100644 (file)
@@ -3,6 +3,9 @@
 #define NDEBUG
 #include <debug.h>
 
+// From Yuan, ScanLineSize = (Width * bitcount + 31)/32
+#define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3)
+
 /*
  *           DIB_BitmapInfoSize
  *
@@ -41,30 +44,6 @@ INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
 UINT
 FASTCALL
 DIB_BitmapMaxBitsSize( PBITMAPINFO Info, UINT ScanLines )
-{
-    UINT MaxBits = 0;
-
-    if (!Info) return 0;
-
-    if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
-    {
-        PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER)Info;
-        MaxBits = Core->bcBitCount * Core->bcPlanes * Core->bcWidth;
-    }
-    else  /* assume BITMAPINFOHEADER */
-    {
-        if ((Info->bmiHeader.biCompression) && (Info->bmiHeader.biCompression != BI_BITFIELDS))
-            return Info->bmiHeader.biSizeImage;
-        // Planes are over looked by Yuan. I guess assumed always 1.
-        MaxBits = Info->bmiHeader.biBitCount * Info->bmiHeader.biPlanes * Info->bmiHeader.biWidth;
-    }
-    MaxBits = ((MaxBits + 31) & ~31 ) / 8; // From Yuan, ScanLineSize = (Width * bitcount + 31)/32
-    return (MaxBits * ScanLines);  // ret the full Size.
-}
-
-UINT
-FASTCALL
-DIB_BitmapBitsSize( CONST BITMAPINFO* Info )
 {
     UINT Ret;
 
@@ -73,22 +52,22 @@ DIB_BitmapBitsSize( CONST BITMAPINFO* Info )
     if ( Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
     {
         PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER)Info;
-        Ret = Core->bcHeight *
-              ((Core->bcWidth * Core->bcPlanes * Core->bcBitCount  + 31) & ~31 ) / 8;
+        Ret = WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes, Core->bcBitCount) * ScanLines;
     }
     else /* assume BITMAPINFOHEADER */
     {
-        if ((Info->bmiHeader.biCompression) &&
-                (Info->bmiHeader.biCompression != BI_BITFIELDS))
-            return Info->bmiHeader.biSizeImage;
-        // Make Height positive always....
-        Ret = abs(Info->bmiHeader.biHeight) *
-              ((Info->bmiHeader.biWidth * Info->bmiHeader.biPlanes * Info->bmiHeader.biBitCount + 31) & ~31 ) / 8;
+        if (!(Info->bmiHeader.biCompression) || (Info->bmiHeader.biCompression == BI_BITFIELDS))
+        {
+           Ret = WIDTH_BYTES_ALIGN32(Info->bmiHeader.biWidth * Info->bmiHeader.biPlanes, Info->bmiHeader.biBitCount) * ScanLines;
+        }
+        else
+        {
+           Ret = Info->bmiHeader.biSizeImage;
+        }
     }
     return Ret;
 }
 
-
 /*
  * DIB_GetBitmapInfo is complete copy of wine cvs 2/9-2006
  * from file dib.c from gdi32.dll or orginal version
@@ -161,39 +140,27 @@ int
 WINAPI
 GdiGetBitmapBitsSize(BITMAPINFO *lpbmi)
 {
-    int retSize;
+    UINT Ret;
+
+    if (!lpbmi) return 0;
 
-    if (lpbmi->bmiHeader.biSize == FIELD_OFFSET(BITMAPINFOHEADER, biPlanes))
+    if ( lpbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
     {
-        /* Calc the bits Size and align it*/
-        retSize = HIWORD(lpbmi->bmiHeader.biWidth) * ((LOWORD(lpbmi->bmiHeader.biWidth) *
-                  LOWORD(lpbmi->bmiHeader.biHeight) * HIWORD(lpbmi->bmiHeader.biHeight) + 31)
-                  & -32) / 8;
+        PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER)lpbmi;
+        Ret = WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes, Core->bcBitCount) * Core->bcHeight;
     }
-    else
+    else /* assume BITMAPINFOHEADER */
     {
-        if ( (lpbmi->bmiHeader.biCompression == BI_BITFIELDS) ||
-                (lpbmi->bmiHeader.biCompression == BI_RGB))
+        if (!(lpbmi->bmiHeader.biCompression) || (lpbmi->bmiHeader.biCompression == BI_BITFIELDS))
         {
-            if (lpbmi->bmiHeader.biHeight >=0 )
-            {
-                /* Calc the bits Size and align it*/
-                retSize = lpbmi->bmiHeader.biHeight * ((lpbmi->bmiHeader.biWidth *
-                                                        lpbmi->bmiHeader.biPlanes * lpbmi->bmiHeader.biBitCount + 31) & -32) / 8;
-            }
-            else
-            {
-                /* Make height postiive if it negitve then calc the bits Size and align it*/
-                retSize = (-lpbmi->bmiHeader.biHeight) * ((lpbmi->bmiHeader.biWidth *
-                          lpbmi->bmiHeader.biPlanes * lpbmi->bmiHeader.biBitCount + 31) & -32) / 8;
-            }
+           Ret = WIDTH_BYTES_ALIGN32(lpbmi->bmiHeader.biWidth * lpbmi->bmiHeader.biPlanes, lpbmi->bmiHeader.biBitCount) * abs(lpbmi->bmiHeader.biHeight);
         }
         else
         {
-            retSize = lpbmi->bmiHeader.biSizeImage;
+           Ret = lpbmi->bmiHeader.biSizeImage;
         }
     }
-    return retSize;
+    return Ret;
 }
 
 /*
@@ -316,7 +283,7 @@ StretchBlt(
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 HBITMAP WINAPI
 CreateBitmap(INT  Width,
@@ -325,7 +292,6 @@ CreateBitmap(INT  Width,
              UINT  BitsPixel,
              CONST VOID* pUnsafeBits)
 {
-    /* FIXME some part should be done in user mode */
     if (Width && Height)
     {
         return NtGdiCreateBitmap(Width, Height, Planes, BitsPixel, (LPBYTE) pUnsafeBits);
@@ -382,8 +348,6 @@ CreateCompatibleBitmap(
     INT  Height)
 {
     PDC_ATTR pDc_Attr;
-    HBITMAP hBmp = NULL;
-    DIBSECTION dibs;
 
     if (!GdiGetHandleUserData(hDC, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr))
         return NULL;
@@ -395,19 +359,26 @@ CreateCompatibleBitmap(
     {
         return  NtGdiCreateCompatibleBitmap(hDC, Width, Height);
     }
+    else
+    {
+        HBITMAP hBmp = NULL;
+        char buffer[sizeof(DIBSECTION) + 256*sizeof(RGBQUAD)];
+        DIBSECTION* pDIBs = (DIBSECTION*)buffer;
 
-    hBmp = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_BITMAP);
+        hBmp = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_BITMAP);
 
-    if ( GetObjectA(hBmp, sizeof(DIBSECTION), &dibs) != sizeof(DIBSECTION) )
-        return NULL;
+        if ( GetObjectA(hBmp, sizeof(DIBSECTION), pDIBs) != sizeof(DIBSECTION) )
+            return NULL;
 
-    if ( dibs.dsBm.bmBitsPixel <= 8 )
-        GetDIBColorTable(hDC, 0, 256, (RGBQUAD *)&dibs.dsBitfields);
+        if ( pDIBs->dsBm.bmBitsPixel <= 8 )
+            GetDIBColorTable(hDC, 0, 256, (RGBQUAD *)&pDIBs->dsBitfields[0]);
 
-    dibs.dsBmih.biWidth = Width;
-    dibs.dsBmih.biHeight = Height;
+        pDIBs->dsBmih.biWidth = Width;
+        pDIBs->dsBmih.biHeight = Height;
 
-    return CreateDIBSection(hDC, (CONST BITMAPINFO *)&dibs.dsBmih, 0, NULL, NULL, 0);
+        return CreateDIBSection(hDC, (CONST BITMAPINFO *)&pDIBs->dsBmih, 0, NULL, NULL, 0);
+    }
+    return NULL;
 }
 
 
@@ -493,7 +464,7 @@ CreateDIBitmap( HDC hDC,
     {
         _SEH2_TRY
         {
-            cjBmpScanSize = DIB_BitmapBitsSize(Data);
+            cjBmpScanSize = GdiGetBitmapBitsSize((BITMAPINFO *)Data);
             CalculateColorTableSize(&Data->bmiHeader, &ColorUse, &InfoSize);
             InfoSize += Data->bmiHeader.biSize;
         }
@@ -531,7 +502,6 @@ CreateDIBitmap( HDC hDC,
     return hBmp;
 }
 
-#if 0 // FIXME!!! This is a victim of the Win32k Initialization BUG!!!!!
 /*
  * @implemented
  */
@@ -567,9 +537,9 @@ SetDIBits(HDC hDC,
         }
     }
 
-    hDCc = NtGdiGetDCforBitmap(hBitmap);
+    hDCc = NtGdiGetDCforBitmap(hBitmap); // hDC can be NULL, so, get it from the bitmap.
     SavehDC = hDCc;
-    if ( !hDCc )
+    if ( !hDCc ) // No DC associated with bitmap, Clone or Create one.
     {
         nhDC = CreateCompatibleDC(hDC);
         if ( !nhDC ) return 0;
@@ -623,60 +593,6 @@ SetDIBits(HDC hDC,
 
     return LinesCopied;
 }
-#endif
-
-INT
-WINAPI
-SetDIBits(HDC hdc,
-          HBITMAP hbmp,
-          UINT uStartScan,
-          UINT cScanLines,
-          CONST VOID *lpvBits,
-          CONST BITMAPINFO *lpbmi,
-          UINT fuColorUse)
-{
-    PBITMAPINFO pConvertedInfo;
-    UINT ConvertedInfoSize;
-    INT LinesCopied = 0;
-    UINT cjBmpScanSize = 0;
-    PVOID pvSafeBits = (PVOID)lpvBits;
-
-// This needs to be almost the sames as SetDIBitsToDevice
-
-    if ( !cScanLines || !lpbmi || !lpvBits || (GDI_HANDLE_GET_TYPE(hbmp) != GDI_OBJECT_TYPE_BITMAP))
-        return 0;
-
-    if ( fuColorUse && fuColorUse != DIB_PAL_COLORS && fuColorUse != DIB_PAL_COLORS+1 )
-        return 0;
-
-    pConvertedInfo = ConvertBitmapInfo(lpbmi, fuColorUse,
-                                       &ConvertedInfoSize, FALSE);
-    if (!pConvertedInfo)
-        return 0;
-
-    cjBmpScanSize = DIB_BitmapMaxBitsSize((LPBITMAPINFO)lpbmi, cScanLines);
-
-    if ( lpvBits )
-    {
-        pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize);
-        if (pvSafeBits)
-            RtlCopyMemory( pvSafeBits, lpvBits, cjBmpScanSize);
-    }
-
-    LinesCopied = NtGdiSetDIBits( hdc,
-                                  hbmp,
-                                  uStartScan,
-                                  cScanLines,
-                                  pvSafeBits,
-                                  pConvertedInfo,
-                                  fuColorUse);
-
-    if ( lpvBits != pvSafeBits)
-        RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits);
-    if (lpbmi != pConvertedInfo)
-        RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo);
-    return LinesCopied;
-}
 
 /*
  * @implemented
@@ -703,6 +619,7 @@ SetDIBitsToDevice(
     UINT ConvertedInfoSize;
     INT LinesCopied = 0;
     UINT cjBmpScanSize = 0;
+    BOOL Hit = FALSE;
     PVOID pvSafeBits = (PVOID)Bits;
 
     if ( !ScanLines || !lpbmi || !Bits )
@@ -766,7 +683,26 @@ SetDIBitsToDevice(
     {
         pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize);
         if (pvSafeBits)
-            RtlCopyMemory( pvSafeBits, Bits, cjBmpScanSize);
+        {
+            _SEH2_TRY
+            {
+                RtlCopyMemory( pvSafeBits, Bits, cjBmpScanSize);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Hit = TRUE;
+            }
+            _SEH2_END
+
+            if (Hit)
+            {
+                // We don't die, we continue on with a allocated safe pointer to kernel
+                // space.....
+                DPRINT1("SetDIBitsToDevice fail to read BitMapInfo: %x or Bits: %x & Size: %d\n",pConvertedInfo,Bits,cjBmpScanSize);
+            }
+            DPRINT("SetDIBitsToDevice Allocate Bits %d!!!\n", cjBmpScanSize);
+        }
+
     }
 
     if (!GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr))
@@ -775,7 +711,8 @@ SetDIBitsToDevice(
         return 0;
     }
     /*
-      if ( !pDc_Attr ||
+      if ( !pDc_Attr || // DC is Public
+            ColorUse == DIB_PAL_COLORS ||
            ((pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
            (pConvertedInfo->bmiHeader.biCompression == BI_JPEG ||
             pConvertedInfo->bmiHeader.biCompression  == BI_PNG )) )*/
@@ -888,7 +825,7 @@ StretchDIBits(HDC hdc,
         return 0;
     }
 
-    cjBmpScanSize = DIB_BitmapBitsSize((LPBITMAPINFO)pConvertedInfo);
+    cjBmpScanSize = GdiGetBitmapBitsSize((BITMAPINFO *)pConvertedInfo);
 
     if ( lpBits )
     {
@@ -922,6 +859,7 @@ StretchDIBits(HDC hdc,
     }
     /*
       if ( !pDc_Attr ||
+            iUsage == DIB_PAL_COLORS ||
            ((pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
            (pConvertedInfo->bmiHeader.biCompression == BI_JPEG ||
             pConvertedInfo->bmiHeader.biCompression  == BI_PNG )) )*/