[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / eng / surface.c
index 8ee3b0d..464e7d0 100644 (file)
@@ -191,6 +191,13 @@ EngCreateDeviceBitmap(IN DHSURF dhsurf,
     }
 
     pso = EngLockSurface((HSURF)NewBitmap);
+    if (!pso)
+    {
+        DPRINT1("EngLockSurface failed on newly created bitmap!\n");
+        GreDeleteObject(NewBitmap);
+        return NULL;
+    }
+
     pso->dhsurf = dhsurf;
     EngUnlockSurface(pso);
 
@@ -438,25 +445,270 @@ IntCreateBitmap(IN SIZEL Size,
     return hbmp;
 }
 
+/* Name gleaned from C++ symbol information for SURFMEM::bInitDIB */
+typedef struct _DEVBITMAPINFO
+{
+    ULONG Format;
+    ULONG Width;
+    ULONG Height;
+    ULONG Flags;
+    ULONG Size;
+} DEVBITMAPINFO, *PDEVBITMAPINFO;
+
+SURFOBJ*
+FASTCALL
+SURFMEM_bCreateDib(IN PDEVBITMAPINFO BitmapInfo,
+                   IN PVOID Bits)
+{
+    BOOLEAN Compressed = FALSE;
+    ULONG ScanLine = 0; // Compiler is dumb
+    ULONG Size;
+    SURFOBJ *pso;
+    PSURFACE psurf;
+    SIZEL LocalSize;
+    BOOLEAN AllocatedLocally = FALSE;
+
+    /*
+     * First, check the format so we can get the aligned scanline width.
+     * RLE and the newer fancy-smanshy JPG/PNG support do NOT have scanlines
+     * since they are compressed surfaces!
+     */
+    switch (BitmapInfo->Format)
+    {
+        case BMF_1BPP:
+            ScanLine = ((BitmapInfo->Width + 31) & ~31) >> 3;
+            break;
+
+        case BMF_4BPP:
+            ScanLine = ((BitmapInfo->Width + 7) & ~7) >> 1;
+            break;
+
+        case BMF_8BPP:
+            ScanLine = (BitmapInfo->Width + 3) & ~3;
+            break;
+
+        case BMF_16BPP:
+            ScanLine = ((BitmapInfo->Width + 1) & ~1) << 1;
+            break;
+
+        case BMF_24BPP:
+            ScanLine = ((BitmapInfo->Width * 3) + 3) & ~3;
+            break;
+
+        case BMF_32BPP:
+            ScanLine = BitmapInfo->Width << 2;
+            break;
+
+        case BMF_8RLE:
+        case BMF_4RLE:
+        case BMF_JPEG:
+        case BMF_PNG:
+            Compressed = TRUE;
+            break;
+
+        default:
+            DPRINT1("Invalid bitmap format\n");
+            return NULL;
+    }
+
+    /* Does the device manage its own surface? */
+    if (!Bits)
+    {
+        /* We need to allocate bits for the caller, figure out the size */
+        if (Compressed)
+        {
+            /* Note: we should not be seeing this scenario from ENGDDI */
+            ASSERT(FALSE);
+            Size = BitmapInfo->Size;
+        }
+        else
+        {
+            /* The height times the bytes for each scanline */
+            Size = BitmapInfo->Height * ScanLine;
+        }
+        
+        if (Size)
+        {
+            /* Check for allocation flag */
+            if (BitmapInfo->Flags & BMF_USERMEM)
+            {
+                /* Get the bits from user-mode memory */
+                Bits = EngAllocUserMem(Size, 'mbuG');
+            }
+            else
+            {
+                /* Get kernel bits (zeroed out if requested) */
+                Bits = EngAllocMem((BitmapInfo->Flags & BMF_NOZEROINIT) ? 0 : FL_ZERO_MEMORY,
+                                   Size,
+                                   TAG_DIB);
+            }
+            AllocatedLocally = TRUE;
+            /* Bail out if that failed */
+            if (!Bits) return NULL;
+        }
+    }
+    else
+    {
+        /* Should not have asked for user memory */
+        ASSERT((BitmapInfo->Flags & BMF_USERMEM) == 0);
+    }
+
+    /* Allocate the actual surface object structure */
+    psurf = SURFACE_AllocSurfaceWithHandle();
+    if (!psurf)
+    {
+        if(Bits && AllocatedLocally)
+        {
+            if(BitmapInfo->Flags & BMF_USERMEM)
+                EngFreeUserMem(Bits);
+            else
+                EngFreeMem(Bits);
+        }
+        return NULL;
+    }
+
+    /* Lock down the surface */
+    if (!SURFACE_InitBitsLock(psurf))
+    {
+        /* Bail out if that failed */
+        SURFACE_UnlockSurface(psurf);
+        SURFACE_FreeSurfaceByHandle(psurf->BaseObject.hHmgr);
+        return NULL;
+    }
+
+    /* We should now have our surface object */
+    pso = &psurf->SurfObj;
+
+    /* Save format and flags */
+    pso->iBitmapFormat = BitmapInfo->Format;
+    pso->fjBitmap = BitmapInfo->Flags & (BMF_TOPDOWN | BMF_UMPDMEM | BMF_USERMEM);
+
+    /* Save size and type */
+    LocalSize.cy = BitmapInfo->Height;
+    LocalSize.cx = BitmapInfo->Width;
+    pso->sizlBitmap = LocalSize;
+    pso->iType = STYPE_BITMAP;
+    
+    /* Device-managed surface, no flags or dimension */
+    pso->dhsurf = 0;
+    pso->dhpdev = NULL;
+    pso->hdev = NULL;
+    psurf->flFlags = 0;
+    psurf->dimension.cx = 0;
+    psurf->dimension.cy = 0;
+    psurf->hSecure = NULL;
+    psurf->hDIBSection = NULL;
+    psurf->flHooks = 0;
+    
+    /* Set bits */
+    pso->pvBits = Bits;
+    
+    /* Check for bitmap type */
+    if (!Compressed)
+    {
+        /* Number of bits is based on the height times the scanline */
+        pso->cjBits = BitmapInfo->Height * ScanLine;
+        if (BitmapInfo->Flags & BMF_TOPDOWN)
+        {
+            /* For topdown, the base address starts with the bits */
+            pso->pvScan0 = pso->pvBits;
+            pso->lDelta = ScanLine;
+        }
+        else
+        {
+            /* Otherwise we start with the end and go up */
+            pso->pvScan0 = (PVOID)((ULONG_PTR)pso->pvBits + pso->cjBits - ScanLine);
+            pso->lDelta = -ScanLine;
+        }
+    }
+    else
+    {
+        /* Compressed surfaces don't have scanlines! */
+        ASSERT(FALSE); // Should not get here on ENGDDI
+        pso->lDelta = 0;
+        pso->cjBits = BitmapInfo->Size;
+        
+        /* Check for JPG or PNG */
+        if ((BitmapInfo->Format != BMF_JPEG) && (BitmapInfo->Format != BMF_PNG))
+        {
+            /* Wherever the bit data is */
+            pso->pvScan0 = pso->pvBits;
+        }
+        else
+        {
+            /* Fancy formats don't use a base address */
+            pso->pvScan0 = NULL;
+            ASSERT(FALSE); // ENGDDI shouldn't be creating PNGs for drivers ;-)
+        }
+    }
+    
+    /* Finally set the handle and uniq */
+    pso->hsurf = (HSURF)psurf->BaseObject.hHmgr;
+    pso->iUniq = 0;
+    
+    /* Unlock and return the surface */
+    SURFACE_UnlockSurface(psurf);
+    return pso;
+}
+
 /*
  * @implemented
  */
-HBITMAP APIENTRY
+HBITMAP
+APIENTRY
 EngCreateBitmap(IN SIZEL Size,
                 IN LONG Width,
                 IN ULONG Format,
                 IN ULONG Flags,
                 IN PVOID Bits)
 {
-    HBITMAP hNewBitmap;
-
-    hNewBitmap = IntCreateBitmap(Size, Width, Format, Flags, Bits);
-    if ( !hNewBitmap )
-        return 0;
-
-    GDIOBJ_SetOwnership(hNewBitmap, NULL);
+    SURFOBJ* Surface;
+    DEVBITMAPINFO BitmapInfo;
+    
+    /* Capture the parameters */
+    BitmapInfo.Format = Format;
+    BitmapInfo.Width = Size.cx;
+    BitmapInfo.Height = Size.cy;
+    BitmapInfo.Flags = Flags;
+
+    /*
+     * If the display driver supports framebuffer access, use the scanline width
+     * to determine the actual width of the bitmap, and convert it to pels instead
+     * of bytes.
+     */
+    if ((Bits) && (Width))
+    {
+        switch (BitmapInfo.Format)
+        {
+            /* Do the conversion for each bit depth we support */
+            case BMF_1BPP:
+                BitmapInfo.Width = Width * 8;
+                break;
+            case BMF_4BPP:
+                BitmapInfo.Width = Width * 2;
+                break;
+            case BMF_8BPP:
+                BitmapInfo.Width = Width;
+                break;
+            case BMF_16BPP:
+                BitmapInfo.Width = Width / 2;
+                break;
+            case BMF_24BPP:
+                BitmapInfo.Width = Width / 3;
+                break;
+            case BMF_32BPP:
+                BitmapInfo.Width = Width / 4;
+                break;
+        }
+    }
+    
+    /* Now create the surface */
+    Surface = SURFMEM_bCreateDib(&BitmapInfo, Bits);
+    if (!Surface) return 0;
 
-    return hNewBitmap;
+    /* Set public ownership and reutrn the handle */
+    GDIOBJ_SetOwnership(Surface->hsurf, NULL);
+    return Surface->hsurf;
 }
 
 /*
@@ -529,7 +781,7 @@ EngAssociateSurface(
 
     /* Associate the hdev */
     pso->hdev = hdev;
-    pso->dhpdev = ppdev->hPDev;
+    pso->dhpdev = ppdev->dhpdev;
 
     /* Hook up specified functions */
     psurf->flHooks = flHooks;
@@ -571,7 +823,7 @@ EngModifySurface(
 
     /* Associate the hdev */
     pso->hdev = hdev;
-    pso->dhpdev = ppdev->hPDev;
+    pso->dhpdev = ppdev->dhpdev;
 
     /* Hook up specified functions */
     psurf->flHooks = flHooks;