BUGFIX: EngCreateBitmap() - don't call GDIOBJ_SetOwnerShip() with invalid handle
[reactos.git] / reactos / subsys / win32k / eng / surface.c
index 758fb6d..952aa01 100644 (file)
@@ -1,4 +1,23 @@
 /*
+ *  ReactOS W32 Subsystem
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id: surface.c,v 1.47 2004/12/18 17:12:32 royce Exp $
+ * 
  * COPYRIGHT:         See COPYING in the top level directory
  * PROJECT:           ReactOS kernel
  * PURPOSE:           GDI Driver Surace Functions
  * PROGRAMER:         Jason Filby
  * REVISION HISTORY:
  *                 3/7/1999: Created
+ *                 9/11/2000: Updated to handle real pixel packed bitmaps (UPDATE TO DATE COMPLETED)
+ * TESTING TO BE DONE:
+ * - Create a GDI bitmap with all formats, perform all drawing operations on them, render to VGA surface
+ *   refer to \test\microwin\src\engine\devdraw.c for info on correct pixel plotting for various formats
+ */
+#include <w32k.h>
+
+enum Rle_EscapeCodes
+{
+  RLE_EOL   = 0, /* End of line */
+  RLE_END   = 1, /* End of bitmap */
+  RLE_DELTA = 2  /* Delta */
+};
+
+INT FASTCALL BitsPerFormat(ULONG Format)
+{
+  switch(Format)
+  {
+    case BMF_1BPP: return 1;
+    case BMF_4BPP:
+    case BMF_4RLE: return 4;
+    case BMF_8BPP:
+    case BMF_8RLE: return 8;
+    case BMF_16BPP: return 16;
+    case BMF_24BPP: return 24;
+    case BMF_32BPP: return 32;
+    default: return 0;
+  }
+}
+
+ULONG FASTCALL BitmapFormat(WORD Bits, DWORD Compression)
+{
+  switch(Compression)
+  {
+    case BI_RGB:
+      switch(Bits)
+      {
+        case 1: return BMF_1BPP;
+        case 4: return BMF_4BPP;
+        case 8: return BMF_8BPP;
+        case 16: return BMF_16BPP;
+        case 24: return BMF_24BPP;
+        case 32: return BMF_32BPP;
+      }
+      return 0;
+
+    case BI_RLE4: return BMF_4RLE;
+    case BI_RLE8: return BMF_8RLE;
+
+    default: return 0;
+  }
+}
+
+/*
+ * @implemented
  */
+HBITMAP STDCALL
+EngCreateDeviceBitmap(IN DHSURF dhsurf,
+                     IN SIZEL Size,
+                     IN ULONG Format)
+{
+  HBITMAP NewBitmap;
+  SURFOBJ *SurfObj;
+
+  NewBitmap = EngCreateBitmap(Size, DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(Format)), Format, 0, NULL);
+  SurfObj = EngLockSurface((HSURF)NewBitmap);
+  SurfObj->dhsurf = dhsurf;
+  EngUnlockSurface(SurfObj);
 
-#include <ddk/winddi.h>
+  return NewBitmap;
+}
+
+VOID Decompress4bpp(SIZEL Size, BYTE *CompressedBits, BYTE *UncompressedBits, LONG Delta) 
+{
+       int x = 0;
+       int y = Size.cy - 1;
+       int c;
+       int length;
+       int width = ((Size.cx+1)/2);
+       int height = Size.cy - 1;
+       BYTE *begin = CompressedBits;
+       BYTE *bits = CompressedBits;
+       BYTE *temp;
+       while (y >= 0)
+       {
+               length = *bits++ / 2;
+               if (length)
+               {
+                       c = *bits++;
+                       while (length--)
+                       {
+                               if (x >= width) break;
+                               temp = UncompressedBits + (((height - y) * Delta) + x);
+                               x++;
+                               *temp = c;
+                       }
+               } else {
+                       length = *bits++;
+                       switch (length)
+                       {
+                       case RLE_EOL:
+                               x = 0;
+                               y--;
+                               break;
+                       case RLE_END:
+                               return;
+                       case RLE_DELTA:
+                               x += (*bits++)/2;
+                               y -= (*bits++)/2;
+                               break;
+                       default:
+                               length /= 2;
+                               while (length--)
+                               {
+                                       c = *bits++;
+                                       if (x < width)
+                                       {
+                                               temp = UncompressedBits + (((height - y) * Delta) + x);
+                                               x++;
+                                               *temp = c;
+                                       }
+                               }
+                               if ((bits - begin) & 1)
+                                       bits++;
+                       }
+               }
+       }
+}
+
+VOID Decompress8bpp(SIZEL Size, BYTE *CompressedBits, BYTE *UncompressedBits, LONG Delta) 
+{
+       int x = 0;
+       int y = Size.cy - 1;
+       int c;
+       int length;
+       int width = Size.cx;
+       int height = Size.cy - 1;
+       BYTE *begin = CompressedBits;
+       BYTE *bits = CompressedBits;
+       BYTE *temp;
+       while (y >= 0)
+       {
+               length = *bits++;
+               if (length)
+               {
+                       c = *bits++;
+                       while (length--)
+                       {
+                               if (x >= width) break;
+                               temp = UncompressedBits + (((height - y) * Delta) + x);
+                               x++;
+                               *temp = c;
+                       }
+               } else {
+                       length = *bits++;
+                       switch (length)
+                       {
+                       case RLE_EOL:
+                               x = 0;
+                               y--;
+                               break;
+                       case RLE_END:
+                               return;
+                       case RLE_DELTA:
+                               x += *bits++;
+                               y -= *bits++;
+                               break;
+                       default:
+                               while (length--)
+                               {
+                                       c = *bits++;
+                                       if (x < width)
+                                       {
+                                               temp = UncompressedBits + (((height - y) * Delta) + x);
+                                               x++;
+                                               *temp = c;
+                                       }
+                               }
+                               if ((bits - begin) & 1)
+                                       bits++;
+                       }
+               }
+       }
+}
 
-BOOL EngAssociateSurface(IN HSURF  Surface,
-                         IN HDEV  Dev,
-                         IN ULONG  Hooks)
+HBITMAP FASTCALL
+IntCreateBitmap(IN SIZEL Size,
+               IN LONG Width,
+               IN ULONG Format,
+               IN ULONG Flags,
+               IN PVOID Bits)
 {
-   SURFOBJ *Surfobj;
+  HBITMAP NewBitmap;
+  SURFOBJ *SurfObj;
+  BITMAPOBJ *BitmapObj;
+  PVOID UncompressedBits;
+  ULONG UncompressedFormat;
+
+  if (Format == 0)
+       return 0;
+
+  NewBitmap = BITMAPOBJ_AllocBitmap();
+  if (NewBitmap == NULL)
+       return 0;
+
+  BitmapObj = BITMAPOBJ_LockBitmap(NewBitmap);
+  SurfObj = &BitmapObj->SurfObj;
+
+  if (Format == BMF_4RLE)
+    {
+      SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(BMF_4BPP));
+      SurfObj->cjBits = SurfObj->lDelta * Size.cy;
+      UncompressedFormat = BMF_4BPP;
+      UncompressedBits = EngAllocMem(FL_ZERO_MEMORY, SurfObj->cjBits, 0);
+      Decompress4bpp(Size, (BYTE *)Bits, (BYTE *)UncompressedBits, SurfObj->lDelta);
+    }
+  else if (Format == BMF_8RLE)
+    {
+      SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(BMF_8BPP));
+      SurfObj->cjBits = SurfObj->lDelta * Size.cy;
+      UncompressedFormat = BMF_8BPP;
+      UncompressedBits = EngAllocMem(FL_ZERO_MEMORY, SurfObj->cjBits, 0);
+      Decompress8bpp(Size, (BYTE *)Bits, (BYTE *)UncompressedBits, SurfObj->lDelta);
+    }
+  else
+    {
+      SurfObj->lDelta = abs(Width);
+      SurfObj->cjBits = SurfObj->lDelta * Size.cy;
+      UncompressedBits = Bits;
+      UncompressedFormat = Format;
+    }
+
+  if (UncompressedBits != NULL)
+    {
+      SurfObj->pvBits = UncompressedBits;
+    }
+  else
+    {
+      if (SurfObj->cjBits == 0)
+        {
+          SurfObj->pvBits = NULL;
+        }
+      else
+        {
+          if (0 != (Flags & BMF_USERMEM))
+            {
+              SurfObj->pvBits = EngAllocUserMem(SurfObj->cjBits, 0);
+            }
+          else
+            {
+              SurfObj->pvBits = EngAllocMem(0 != (Flags & BMF_NOZEROINIT) ? 0 : FL_ZERO_MEMORY,
+                                            SurfObj->cjBits, 0);
+            }
+          if (SurfObj->pvBits == NULL)
+            {
+              BITMAPOBJ_UnlockBitmap(NewBitmap);
+              BITMAPOBJ_FreeBitmap(NewBitmap);
+              return 0;
+            }
+        }
+     }
 
-   // Point our new Surfobj to hsurf (assumes hsurf is value returned by
-   // ExAllocatePool)
-   Surfobj = Surface;
 
-   // Associate the hdev
-   Surfobj->hdev = Dev;
+  if (0 == (Flags & BMF_TOPDOWN))
+    {
+      SurfObj->pvScan0 = (PVOID) ((ULONG_PTR) SurfObj->pvBits + SurfObj->cjBits - SurfObj->lDelta);
+      SurfObj->lDelta = - SurfObj->lDelta;
+    }
+  else
+    {
+      SurfObj->pvScan0 = SurfObj->pvBits;
+    }
 
-   // FIXME: Hook up the specified functions
+  SurfObj->dhsurf = 0; /* device managed surface */
+  SurfObj->hsurf = (HSURF)NewBitmap;
+  SurfObj->dhpdev = NULL;
+  SurfObj->hdev = NULL;
+  SurfObj->sizlBitmap = Size;
+  SurfObj->iBitmapFormat = UncompressedFormat;
+  SurfObj->iType = STYPE_BITMAP;
+  SurfObj->fjBitmap = Flags & (BMF_TOPDOWN | BMF_NOZEROINIT);
+  SurfObj->iUniq = 0;
+
+  BitmapObj->flHooks = 0;
+  BitmapObj->flFlags = 0;
+  BitmapObj->dimension.cx = 0;
+  BitmapObj->dimension.cy = 0;
+  BitmapObj->dib = NULL;
+
+  BITMAPOBJ_UnlockBitmap(NewBitmap);
+
+  return NewBitmap;
 }
 
-BOOL APIENTRY EngDeleteSurface(HSURF hsurf)
+/*
+ * @implemented
+ */
+HBITMAP STDCALL
+EngCreateBitmap(IN SIZEL Size,
+               IN LONG Width,
+               IN ULONG Format,
+               IN ULONG Flags,
+               IN PVOID Bits)
 {
-   // Assume the hsurf was the value returned by ExAllocatePool
-   ExFreePool(hsurf);
+  HBITMAP NewBitmap;
+  
+  NewBitmap = IntCreateBitmap(Size, Width, Format, Flags, Bits);
+  if ( !NewBitmap )
+         return 0;
+
+  GDIOBJ_SetOwnership(NewBitmap, NULL);
+
+  return NewBitmap;
 }
 
-SURFOBJ *EngLockSurface(IN HSURF hsurf)
+/*
+ * @unimplemented
+ */
+HSURF STDCALL
+EngCreateDeviceSurface(IN DHSURF dhsurf,
+                      IN SIZEL Size,
+                      IN ULONG Format)
 {
-  /* We assume that hsurf is the value returned from ExAllocatePool */
-  return EngAllocUserMem(NULL, sizeof(SURFOBJ), "");
+  HSURF NewSurface;
+  SURFOBJ *SurfObj;
+  BITMAPOBJ *BitmapObj;
+
+  NewSurface = (HSURF)BITMAPOBJ_AllocBitmap();
+  if (NewSurface == NULL)
+       return 0;
+
+  GDIOBJ_SetOwnership(NewSurface, NULL);
+
+  BitmapObj = BITMAPOBJ_LockBitmap(NewSurface);
+  SurfObj = &BitmapObj->SurfObj;
+
+  SurfObj->dhsurf = dhsurf;
+  SurfObj->hsurf = NewSurface;
+  SurfObj->sizlBitmap = Size;
+  SurfObj->iBitmapFormat = Format;
+  SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(Format));
+  SurfObj->iType = STYPE_DEVICE;
+  SurfObj->iUniq = 0;
+
+  BitmapObj->flHooks = 0;
+
+  BITMAPOBJ_UnlockBitmap(NewSurface);
+
+  return NewSurface;
 }
 
-VOID EngUnlockSurface(IN SURFOBJ *pso)
+PFN FASTCALL DriverFunction(DRVENABLEDATA *DED, ULONG DriverFunc)
+{
+  ULONG i;
+
+  for(i=0; i<DED->c; i++)
+  {
+    if(DED->pdrvfn[i].iFunc == DriverFunc)
+      return DED->pdrvfn[i].pfn;
+  }
+  return NULL;
+}
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+EngAssociateSurface(IN HSURF Surface,
+                   IN HDEV Dev,
+                   IN ULONG Hooks)
+{
+  SURFOBJ *SurfObj;
+  BITMAPOBJ *BitmapObj;
+  GDIDEVICE* Device;
+
+  Device = (GDIDEVICE*)Dev;
+
+  BitmapObj = BITMAPOBJ_LockBitmap(Surface);
+  ASSERT(BitmapObj);
+  SurfObj = &BitmapObj->SurfObj;
+
+  /* Associate the hdev */
+  SurfObj->hdev = Dev;
+  SurfObj->dhpdev = Device->PDev;
+
+  /* Hook up specified functions */
+  BitmapObj->flHooks = Hooks;
+
+  BITMAPOBJ_UnlockBitmap(Surface);
+
+  return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+EngModifySurface(
+   IN HSURF hsurf,
+   IN HDEV hdev,
+   IN FLONG flHooks,
+   IN FLONG flSurface,
+   IN DHSURF dhsurf,
+   OUT VOID *pvScan0,
+   IN LONG lDelta,
+   IN VOID *pvReserved)
+{
+   SURFOBJ *pso;
+
+   pso = EngLockSurface(hsurf);
+   if (pso == NULL)
+   {
+      return FALSE;
+   }
+
+   if (!EngAssociateSurface(hsurf, hdev, flHooks))
+   {
+      EngUnlockSurface(pso);
+
+      return FALSE;
+   }
+
+   pso->dhsurf = dhsurf;
+   pso->lDelta = lDelta;
+   pso->pvScan0 = pvScan0;
+
+   EngUnlockSurface(pso);
+
+   return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+EngDeleteSurface(IN HSURF Surface)
+{
+   GDIOBJ_SetOwnership(Surface, PsGetCurrentProcess());
+   BITMAPOBJ_FreeBitmap(Surface);
+   return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+EngEraseSurface(SURFOBJ *Surface,
+               RECTL *Rect,
+               ULONG iColor)
+{
+  ASSERT(Surface);
+  ASSERT(Rect);
+  return FillSolid(Surface, Rect, iColor);
+}
+
+/*
+ * @implemented
+ */
+SURFOBJ * STDCALL
+EngLockSurface(IN HSURF Surface)
+{
+  BITMAPOBJ *bmp = (BITMAPOBJ*)BITMAPOBJ_LockBitmap(Surface);
+  if(bmp != NULL)
+  {
+    return &bmp->SurfObj;
+  }
+  
+  return NULL;
+}
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+EngUnlockSurface(IN SURFOBJ *Surface)
 {
-  EngFreeUserMem(sizeof(pso));
+  ASSERT (Surface);
+  BITMAPOBJ_UnlockBitmap (Surface->hsurf);
 }
+/* EOF */