[WIN32SS][NTGDI] Alignment probe change in NtGdiSetBitmapBits (#1309)
[reactos.git] / win32ss / gdi / ntgdi / bitmaps.c
index 584dde5..c982599 100644 (file)
@@ -2,8 +2,9 @@
  * COPYRIGHT:        GNU GPL, See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Bitmap functions
- * FILE:             subsys/win32k/objects/bitmaps.c
- * PROGRAMER:        Timo Kreuzer <timo.kreuzer@reactos.org>
+ * FILE:             win32ss/gdi/ntgdi/bitmaps.c
+ * PROGRAMERS:       Timo Kreuzer <timo.kreuzer@reactos.org>
+ *                   Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
  */
 
 #include <win32k.h>
 #define NDEBUG
 #include <debug.h>
 
-void
+BOOL
+NTAPI
+GreSetBitmapOwner(
+    _In_ HBITMAP hbmp,
+    _In_ ULONG ulOwner)
+{
+    /* Check if we have the correct object type */
+    if (GDI_HANDLE_GET_TYPE(hbmp) != GDILoObjType_LO_BITMAP_TYPE)
+    {
+        DPRINT1("Incorrect type for hbmp: %p\n", hbmp);
+        return FALSE;
+    }
+
+    /// FIXME: this is a hack and doesn't handle a race condition properly.
+    /// It needs to be done in GDIOBJ_vSetObjectOwner atomically.
+
+    /* Check if we set public or none */
+    if ((ulOwner == GDI_OBJ_HMGR_PUBLIC) ||
+        (ulOwner == GDI_OBJ_HMGR_NONE))
+    {
+        /* Only allow this for owned objects */
+        if (GreGetObjectOwner(hbmp) != GDI_OBJ_HMGR_POWNED)
+        {
+            DPRINT1("Cannot change owner for non-powned hbmp\n");
+            return FALSE;
+        }
+    }
+
+    return GreSetObjectOwner(hbmp, ulOwner);
+}
+
+LONG
 NTAPI
 UnsafeSetBitmapBits(
-    PSURFACE psurf,
-    IN ULONG cjBits,
-    IN PVOID pvBits)
+    _Inout_ PSURFACE psurf,
+    _In_ ULONG cjBits,
+    _In_ const VOID *pvBits)
 {
-    PUCHAR pjDst, pjSrc;
+    PUCHAR pjDst;
+    const UCHAR *pjSrc;
     LONG lDeltaDst, lDeltaSrc;
-    ULONG nWidth, nHeight, cBitsPixel;
+    ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
+
+    NT_ASSERT(psurf->flags & API_BITMAP);
+    NT_ASSERT(psurf->SurfObj.iBitmapFormat <= BMF_32BPP);
 
     nWidth = psurf->SurfObj.sizlBitmap.cx;
-    nHeight = psurf->SurfObj.sizlBitmap.cy;
+    nHeight = labs(psurf->SurfObj.sizlBitmap.cy);
     cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
 
-    /* Get pointers */
     pjDst = psurf->SurfObj.pvScan0;
     pjSrc = pvBits;
     lDeltaDst = psurf->SurfObj.lDelta;
     lDeltaSrc = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
+    NT_ASSERT(lDeltaSrc <= labs(lDeltaDst));
+
+    cbDst = labs(lDeltaDst) * nHeight;
+    cbSrc = lDeltaSrc * nHeight;
+    cjBits = min(cjBits, cbSrc);
 
-    while (nHeight--)
+    iSrc = iDst = 0;
+    for (Y = 0; Y < nHeight; Y++)
     {
+        if (iSrc + lDeltaSrc > cjBits || iDst + labs(lDeltaDst) > cbDst)
+        {
+            LONG lDelta = min(cjBits - iSrc, cbDst - iDst);
+            NT_ASSERT(lDelta >= 0);
+            RtlCopyMemory(pjDst, pjSrc, lDelta);
+            iSrc += lDelta;
+            break;
+        }
+
         /* Copy one line */
-        memcpy(pjDst, pjSrc, lDeltaSrc);
+        RtlCopyMemory(pjDst, pjSrc, lDeltaSrc);
         pjSrc += lDeltaSrc;
         pjDst += lDeltaDst;
+        iSrc += lDeltaSrc;
+        iDst += labs(lDeltaDst);
     }
 
+    return iSrc;
 }
 
 HBITMAP
@@ -76,6 +129,7 @@ GreCreateBitmapEx(
                                  iFormat,
                                  fjBitmap,
                                  cjWidthBytes,
+                                 pvCompressedBits ? 0 : cjSizeImage,
                                  pvBits);
     if (!psurf)
     {
@@ -94,7 +148,7 @@ GreCreateBitmapEx(
         lDelta = WIDTH_BYTES_ALIGN32(nWidth, gajBitsPerFormat[iFormat]);
 
         pvBits = psurf->SurfObj.pvBits;
-        DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat);
+        DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat, cjSizeImage);
     }
 
     /* Get the handle for the bitmap */
@@ -142,7 +196,7 @@ NtGdiCreateBitmap(
     IN OPTIONAL LPBYTE pUnsafeBits)
 {
     HBITMAP hbmp;
-    ULONG cRealBpp, cjWidthBytes, iFormat, fjBitmap;
+    ULONG cRealBpp, cjWidthBytes, iFormat;
     ULONGLONG cjSize;
     PSURFACE psurf;
 
@@ -164,15 +218,13 @@ NtGdiCreateBitmap(
         return NULL;
     }
 
-    /* Allocations larger than PAGE_SIZE go into user mem */
-    fjBitmap = (cjSize > PAGE_SIZE) ? BMF_USERMEM : 0;
-
     /* Allocate the surface (but don't set the bits) */
     psurf = SURFACE_AllocSurface(STYPE_BITMAP,
                                  nWidth,
                                  nHeight,
                                  iFormat,
-                                 fjBitmap,
+                                 0,
+                                 0,
                                  0,
                                  NULL);
     if (!psurf)
@@ -191,7 +243,7 @@ NtGdiCreateBitmap(
         _SEH2_TRY
         {
             ProbeForRead(pUnsafeBits, (SIZE_T)cjSize, 1);
-            UnsafeSetBitmapBits(psurf, 0, pUnsafeBits);
+            UnsafeSetBitmapBits(psurf, cjSize, pUnsafeBits);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -220,7 +272,9 @@ HBITMAP FASTCALL
 IntCreateCompatibleBitmap(
     PDC Dc,
     INT Width,
-    INT Height)
+    INT Height,
+    UINT Planes,
+    UINT Bpp)
 {
     HBITMAP Bmp = NULL;
     PPALETTE ppal;
@@ -237,9 +291,15 @@ IntCreateCompatibleBitmap(
 
         Bmp = GreCreateBitmap(abs(Width),
                               abs(Height),
-                              1,
-                              Dc->ppdev->gdiinfo.cBitsPixel,
+                              Planes ? Planes : 1,
+                              Bpp ? Bpp : Dc->ppdev->gdiinfo.cBitsPixel,
                               NULL);
+        if (Bmp == NULL)
+        {
+            DPRINT1("Failed to allocate a bitmap!\n");
+            return NULL;
+        }
+
         psurf = SURFACE_ShareLockSurface(Bmp);
         ASSERT(psurf);
 
@@ -252,6 +312,7 @@ IntCreateCompatibleBitmap(
         /* Set flags */
         psurf->flags = API_BITMAP;
         psurf->hdc = NULL; // FIXME:
+        psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
         SURFACE_ShareUnlockSurface(psurf);
     }
     else
@@ -268,8 +329,8 @@ IntCreateCompatibleBitmap(
 
             Bmp = GreCreateBitmap(abs(Width),
                           abs(Height),
-                          1,
-                          dibs.dsBm.bmBitsPixel,
+                          Planes ? Planes : 1,
+                          Bpp ? Bpp : dibs.dsBm.bmBitsPixel,
                           NULL);
             psurfBmp = SURFACE_ShareLockSurface(Bmp);
             ASSERT(psurfBmp);
@@ -280,6 +341,7 @@ IntCreateCompatibleBitmap(
             /* Set flags */
             psurfBmp->flags = API_BITMAP;
             psurfBmp->hdc = NULL; // FIXME:
+            psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
             SURFACE_ShareUnlockSurface(psurfBmp);
         }
         else if (Count == sizeof(DIBSECTION))
@@ -292,8 +354,8 @@ IntCreateCompatibleBitmap(
             bi->bmiHeader.biSize          = sizeof(bi->bmiHeader);
             bi->bmiHeader.biWidth         = Width;
             bi->bmiHeader.biHeight        = Height;
-            bi->bmiHeader.biPlanes        = dibs.dsBmih.biPlanes;
-            bi->bmiHeader.biBitCount      = dibs.dsBmih.biBitCount;
+            bi->bmiHeader.biPlanes        = Planes ? Planes : dibs.dsBmih.biPlanes;
+            bi->bmiHeader.biBitCount      = Bpp ? Bpp : dibs.dsBmih.biBitCount;
             bi->bmiHeader.biCompression   = dibs.dsBmih.biCompression;
             bi->bmiHeader.biSizeImage     = 0;
             bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
@@ -374,20 +436,19 @@ NtGdiCreateCompatibleBitmap(
         return NULL;
     }
 
-    Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
+    Bmp = IntCreateCompatibleBitmap(Dc, Width, Height, 0, 0);
 
     DC_UnlockDc(Dc);
     return Bmp;
 }
 
 BOOL
-APIENTRY
-NtGdiGetBitmapDimension(
-    HBITMAP hBitmap,
-    LPSIZE psizDim)
+NTAPI
+GreGetBitmapDimension(
+    _In_ HBITMAP hBitmap,
+    _Out_ LPSIZE psizDim)
 {
     PSURFACE psurfBmp;
-    BOOL bResult = TRUE;
 
     if (hBitmap == NULL)
         return FALSE;
@@ -400,26 +461,42 @@ NtGdiGetBitmapDimension(
         return FALSE;
     }
 
+    *psizDim = psurfBmp->sizlDim;
+
+    /* Unlock the bitmap */
+    SURFACE_ShareUnlockSurface(psurfBmp);
+
+    return TRUE;
+}
+
+BOOL
+APIENTRY
+NtGdiGetBitmapDimension(
+    HBITMAP hBitmap,
+    LPSIZE psizDim)
+{
+    SIZE dim;
+
+    if (!GreGetBitmapDimension(hBitmap, &dim))
+        return FALSE;
+
     /* Use SEH to copy the data to the caller */
     _SEH2_TRY
     {
-        ProbeForWrite(psizDim, sizeof(SIZE), 1);
-        *psizDim = psurfBmp->sizlDim;
+        ProbeForWrite(psizDim, sizeof(*psizDim), 1);
+        *psizDim = dim;
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        bResult = FALSE;
+        _SEH2_YIELD(return FALSE);
     }
     _SEH2_END
 
-    /* Unlock the bitmap */
-    SURFACE_ShareUnlockSurface(psurfBmp);
-
-    return bResult;
+    return TRUE;
 }
 
 
-VOID
+LONG
 FASTCALL
 UnsafeGetBitmapBits(
     PSURFACE psurf,
@@ -428,10 +505,10 @@ UnsafeGetBitmapBits(
 {
     PUCHAR pjDst, pjSrc;
     LONG lDeltaDst, lDeltaSrc;
-    ULONG nWidth, nHeight, cBitsPixel;
+    ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
 
     nWidth = psurf->SurfObj.sizlBitmap.cx;
-    nHeight = psurf->SurfObj.sizlBitmap.cy;
+    nHeight = labs(psurf->SurfObj.sizlBitmap.cy);
     cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
 
     /* Get pointers */
@@ -439,14 +516,33 @@ UnsafeGetBitmapBits(
     pjDst = pvBits;
     lDeltaSrc = psurf->SurfObj.lDelta;
     lDeltaDst = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
+    NT_ASSERT(labs(lDeltaSrc) >= lDeltaDst);
 
-    while (nHeight--)
+    cbSrc = nHeight * labs(lDeltaSrc);
+    cbDst = nHeight * lDeltaDst;
+    Bytes = min(Bytes, cbDst);
+
+    iSrc = iDst = 0;
+    for (Y = 0; Y < nHeight; Y++)
     {
+        if (iSrc + labs(lDeltaSrc) > cbSrc || iDst + lDeltaDst > Bytes)
+        {
+            LONG lDelta = min(cbSrc - iSrc, Bytes - iDst);
+            NT_ASSERT(lDelta >= 0);
+            RtlCopyMemory(pjDst, pjSrc, lDelta);
+            iDst += lDelta;
+            break;
+        }
+
         /* Copy one line */
         RtlCopyMemory(pjDst, pjSrc, lDeltaDst);
         pjSrc += lDeltaSrc;
         pjDst += lDeltaDst;
+        iSrc += labs(lDeltaSrc);
+        iDst += lDeltaDst;
     }
+
+    return iDst;
 }
 
 LONG
@@ -493,8 +589,7 @@ NtGdiGetBitmapBits(
     _SEH2_TRY
     {
         ProbeForWrite(pUnsafeBits, cjBuffer, 1);
-        UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits);
-        ret = cjBuffer;
+        ret = UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -522,6 +617,11 @@ NtGdiSetBitmapBits(
         return 0;
     }
 
+    if (GDI_HANDLE_IS_STOCKOBJ(hBitmap))
+    {
+        return 0;
+    }
+
     psurf = SURFACE_ShareLockSurface(hBitmap);
     if (psurf == NULL)
     {
@@ -529,11 +629,22 @@ NtGdiSetBitmapBits(
         return 0;
     }
 
+    if (((psurf->flags & API_BITMAP) == 0) ||
+        (psurf->SurfObj.iBitmapFormat > BMF_32BPP))
+    {
+        DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n",
+                psurf->SurfObj.iBitmapFormat,
+                psurf->flags);
+        EngSetLastError(ERROR_INVALID_HANDLE);
+        SURFACE_ShareUnlockSurface(psurf);
+        return 0;
+    }
+
     _SEH2_TRY
     {
+        /* NOTE: Win2k3 doesn't check WORD alignment here. */
         ProbeForRead(pUnsafeBits, Bytes, 1);
-        UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
-        ret = 1;
+        ret = UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {