[OS/2] Bug 395301: Move offscreen surface creation from gfxOS2Platform to gfxOS2Surface
authormozilla@weilbacher.org
Tue, 18 Sep 2007 14:20:25 -0700
changeset 6062 42bd5de5287262e71121bcaced42eae8ecffc520
parent 6061 07297a875093f0cc8e330fcbb7fc2fce8d6ba360
child 6063 5c27ea27d03cd9d61e0c5283d87d62bdffff0f0b
push idunknown
push userunknown
push dateunknown
bugs395301
milestone1.9a8pre
[OS/2] Bug 395301: Move offscreen surface creation from gfxOS2Platform to gfxOS2Surface
gfx/thebes/public/gfxOS2Platform.h
gfx/thebes/public/gfxOS2Surface.h
gfx/thebes/src/gfxOS2Platform.cpp
gfx/thebes/src/gfxOS2Surface.cpp
--- a/gfx/thebes/public/gfxOS2Platform.h
+++ b/gfx/thebes/public/gfxOS2Platform.h
@@ -66,16 +66,11 @@ public:
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, PRBool& aAborted);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
                                   const gfxFontStyle *aStyle);
 protected:
     static gfxFontconfigUtils *sFontconfigUtils;
-
-private:
-    HDC mDC;
-    HPS mPS;
-    HBITMAP mBitmap;
 };
 
 #endif /* GFX_OS2_PLATFORM_H */
--- a/gfx/thebes/public/gfxOS2Surface.h
+++ b/gfx/thebes/public/gfxOS2Surface.h
@@ -35,28 +35,37 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_OS2_SURFACE_H
 #define GFX_OS2_SURFACE_H
 
 #include "gfxASurface.h"
 
+#define INCL_GPIBITMAPS
 #include <os2.h>
 #include <cairo-os2.h>
 
 class THEBES_API gfxOS2Surface : public gfxASurface {
 
 public:
+    // constructor to create a cairo surface using an existing PS
     gfxOS2Surface(HPS aPS, const gfxIntSize& aSize);
+    // constructor used to create a memory surface of given size
+    gfxOS2Surface(const gfxIntSize& aSize,
+                  gfxASurface::gfxImageFormat aImageFormat);
+    // constructor for surface connected to an onscreen window
     gfxOS2Surface(HWND aWnd);
     virtual ~gfxOS2Surface();
 
     HPS GetPS() { return mPS; }
     gfxIntSize GetSize() { return mSize; }
 
 private:
     PRBool mOwnsPS;
-    HPS mPS;
-    gfxIntSize mSize;
+    PRBool mHasWnd; // indicates if created through the HWND constructor
+    HDC mDC; // memory device context
+    HPS mPS; // presentation space connected to window or memory device
+    HBITMAP mBitmap; // bitmap for initialization of memory surface
+    gfxIntSize mSize; // current size of the surface
 };
 
 #endif /* GFX_OS2_SURFACE_H */
--- a/gfx/thebes/src/gfxOS2Platform.cpp
+++ b/gfx/thebes/src/gfxOS2Platform.cpp
@@ -46,17 +46,16 @@
 //#include <fontconfig/fontconfig.h>
 
 /**********************************************************************
  * class gfxOS2Platform
  **********************************************************************/
 gfxFontconfigUtils *gfxOS2Platform::sFontconfigUtils = nsnull;
 
 gfxOS2Platform::gfxOS2Platform()
-    : mDC(NULL), mPS(NULL), mBitmap(NULL)
 {
 #ifdef DEBUG_thebes
     printf("gfxOS2Platform::gfxOS2Platform()\n");
 #endif
     // this seems to be reasonably early in the process and only once,
     // so it's a good place to initialize OS/2 cairo stuff
     cairo_os2_init();
 #ifdef DEBUG_thebes
@@ -70,26 +69,16 @@ gfxOS2Platform::gfxOS2Platform()
 gfxOS2Platform::~gfxOS2Platform()
 {
 #ifdef DEBUG_thebes
     printf("gfxOS2Platform::~gfxOS2Platform()\n");
 #endif
     gfxFontconfigUtils::Shutdown();
     sFontconfigUtils = nsnull;
 
-    if (mBitmap) {
-        GpiSetBitmap(mPS, NULL);
-        GpiDeleteBitmap(mBitmap);
-    }
-    if (mPS) {
-        GpiDestroyPS(mPS);
-    }
-    if (mDC) {
-        DevCloseDC(mDC);
-    }
     // clean up OS/2 cairo stuff
     cairo_os2_fini();
 #ifdef DEBUG_thebes
     printf("  cairo_os2_fini() was called\n");
 #endif
 }
 
 already_AddRefed<gfxASurface>
@@ -97,51 +86,22 @@ gfxOS2Platform::CreateOffscreenSurface(c
                                        gfxASurface::gfxImageFormat aImageFormat)
 {
 #ifdef DEBUG_thebes_2
     printf("gfxOS2Platform::CreateOffscreenSurface(%d/%d, %d)\n",
            aSize.width, aSize.height, aImageFormat);
 #endif
     gfxASurface *newSurface = nsnull;
 
-    // XXX we only ever seem to get aImageFormat=0 or ImageFormatARGB32 but
+    // we only ever seem to get aImageFormat=0 or ImageFormatARGB32 but
     // I don't really know if we need to differ between ARGB32 and RGB24 here
     if (aImageFormat == gfxASurface::ImageFormatARGB32 ||
         aImageFormat == gfxASurface::ImageFormatRGB24)
     {
-        // create a PS, partly taken from nsOffscreenSurface::Init(), i.e. nsDrawingSurfaceOS2.cpp
-        DEVOPENSTRUC dop = { 0, 0, 0, 0, 0 };
-        SIZEL sizel = { 0, 0 }; /* use same page size as device */
-        mDC = DevOpenDC(0, OD_MEMORY, "*", 5, (PDEVOPENDATA)&dop, NULLHANDLE);
-        if (mDC != DEV_ERROR) {
-            mPS = GpiCreatePS(0, mDC, &sizel, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
-            if (mPS != GPI_ERROR) {
-                // XXX: nsPaletteOS2::SelectGlobalPalette(mPS);
-                // perhaps implement the palette stuff at some point?!
-
-                // now create a bitmap of the right size
-                BITMAPINFOHEADER2 hdr = { 0 };
-                hdr.cbFix = sizeof(BITMAPINFOHEADER2);
-                hdr.cx = aSize.width;
-                hdr.cy = aSize.height;
-                hdr.cPlanes = 1;
-
-                // find bit depth, XXX this may not work here, use the aImageFormat instead?!
-                LONG lBitCount = 0;
-                DevQueryCaps(mDC, CAPS_COLOR_BITCOUNT, 1, &lBitCount);
-                hdr.cBitCount = (USHORT)lBitCount;
-
-                mBitmap = GpiCreateBitmap(mPS, &hdr, 0, 0, 0);
-                if (mBitmap != GPI_ERROR) {
-                    // set final stats & select bitmap into ps
-                    GpiSetBitmap(mPS, mBitmap);
-                }
-            } /* if mPS */
-        } /* if mDC */
-        newSurface = new gfxOS2Surface(mPS, aSize);
+        newSurface = new gfxOS2Surface(aSize, aImageFormat);
     } else if (aImageFormat == gfxASurface::ImageFormatA8 ||
                aImageFormat == gfxASurface::ImageFormatA1) {
         newSurface = new gfxImageSurface(aSize, aImageFormat);
     } else {
         return nsnull;
     }
 
     NS_IF_ADDREF(newSurface);
--- a/gfx/thebes/src/gfxOS2Surface.cpp
+++ b/gfx/thebes/src/gfxOS2Surface.cpp
@@ -39,61 +39,129 @@
 
 #include <stdio.h>
 
 /**********************************************************************
  * class gfxOS2Surface
  **********************************************************************/
 
 gfxOS2Surface::gfxOS2Surface(HPS aPS, const gfxIntSize& aSize)
-    : mOwnsPS(PR_FALSE), mPS(aPS), mSize(aSize)
+    : mOwnsPS(PR_FALSE), mHasWnd(PR_FALSE), mDC(nsnull), mPS(aPS), mBitmap(nsnull), mSize(aSize)
+{
+#ifdef DEBUG_thebes_2
+    printf("gfxOS2Surface[%#x]::gfxOS2Surface(HPS=%#x, Size=%dx%d)\n", (unsigned int)this,
+           (unsigned int)mPS, aSize.width, aSize.height);
+#endif
+
+    // create the cairo surface on the passed PS
+    cairo_surface_t *surf = cairo_os2_surface_create(mPS, mSize.width, mSize.height);
+#ifdef DEBUG_thebes_2
+    printf("  type(%#x)=%d (ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
+           cairo_surface_get_type(surf), (unsigned int)mPS, mSize.width, mSize.height);
+#endif
+    // XXX for now uncomment the mark_dirty function, see bug 371505
+    //cairo_surface_mark_dirty(surf);
+    Init(surf);
+}
+
+gfxOS2Surface::gfxOS2Surface(const gfxIntSize& aSize,
+                             gfxASurface::gfxImageFormat aImageFormat)
+    : mOwnsPS(PR_TRUE), mHasWnd(PR_FALSE), mSize(aSize)
 {
 #ifdef DEBUG_thebes_2
-    printf("gfxOS2Surface[%#x]::gfxOS2Surface(HPS=%#x, ...)\n",
-           (unsigned int)this, (unsigned int)aPS);
+    printf("gfxOS2Surface[%#x]::gfxOS2Surface(Size=%dx%d, %d)\n", (unsigned int)this,
+           aSize.width, aSize.height, aImageFormat);
 #endif
+    // in this case we don't have a window, so we create a memory presentation
+    // space to construct the cairo surface on
 
+    // create a PS, partly taken from nsOffscreenSurface::Init(), i.e. nsDrawingSurfaceOS2.cpp
+    DEVOPENSTRUC dop = { 0, 0, 0, 0, 0 };
+    SIZEL sizel = { 0, 0 }; // use same page size as device
+    mDC = DevOpenDC(0, OD_MEMORY, (PSZ)"*", 5, (PDEVOPENDATA)&dop, NULLHANDLE);
+    NS_ASSERTION(mDC != DEV_ERROR, "Could not create memory DC");
+
+    mPS = GpiCreatePS(0, mDC, &sizel, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
+    NS_ASSERTION(mPS != GPI_ERROR, "Could not create PS on memory DC!");
+
+    // now create a bitmap of the right size
+    BITMAPINFOHEADER2 hdr = { 0 };
+    hdr.cbFix = sizeof(BITMAPINFOHEADER2);
+    hdr.cx = mSize.width;
+    hdr.cy = mSize.height;
+    hdr.cPlanes = 1;
+
+    // find bit depth
+    LONG lBitCount = 0;
+    DevQueryCaps(mDC, CAPS_COLOR_BITCOUNT, 1, &lBitCount);
+    hdr.cBitCount = (USHORT)lBitCount;
+
+    mBitmap = GpiCreateBitmap(mPS, &hdr, 0, 0, 0);
+    NS_ASSERTION(mBitmap != GPI_ERROR, "Could not create bitmap in memory!");
+    // set final stats & select bitmap into PS
+    GpiSetBitmap(mPS, mBitmap);
+
+    // now we can finally create the cairo surface on the in-memory PS
     cairo_surface_t *surf = cairo_os2_surface_create(mPS, mSize.width, mSize.height);
 #ifdef DEBUG_thebes_2
-    printf("  type(%#x)=%d (own=%d, ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
-           cairo_surface_get_type(surf), mOwnsPS, (unsigned int)mPS, mSize.width, mSize.height);
+    printf("  type(%#x)=%d (ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
+           cairo_surface_get_type(surf), (unsigned int)mPS, mSize.width, mSize.height);
 #endif
     // XXX for now uncomment the mark_dirty function, see bug 371505
     //cairo_surface_mark_dirty(surf);
     Init(surf);
 }
 
 gfxOS2Surface::gfxOS2Surface(HWND aWnd)
-    : mOwnsPS(PR_TRUE)
+    : mOwnsPS(PR_TRUE), mHasWnd(PR_TRUE), mDC(nsnull), mBitmap(nsnull)
 {
 #ifdef DEBUG_thebes_2
-    printf("gfxOS2Surface[%#x]::gfxOS2Surface(HWND=%#x)\n",
-           (unsigned int)this, (unsigned int)aWnd);
+    printf("gfxOS2Surface[%#x]::gfxOS2Surface(HWND=%#x)\n", (unsigned int)this,
+           (unsigned int)aWnd);
 #endif
 
     mPS = WinGetPS(aWnd);
 
     RECTL rectl;
     WinQueryWindowRect(aWnd, &rectl);
     mSize.width = rectl.xRight - rectl.xLeft;
     mSize.height = rectl.yTop - rectl.yBottom;
     if (mSize.width == 0) mSize.width = 1;   // fake a minimal surface area to let
     if (mSize.height == 0) mSize.height = 1; // cairo_os2_surface_create() return something
     cairo_surface_t *surf = cairo_os2_surface_create(mPS, mSize.width, mSize.height);
 #ifdef DEBUG_thebes_2
-    printf("  type(%#x)=%d (own=%d, ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
-           cairo_surface_get_type(surf), mOwnsPS, (unsigned int)mPS, mSize.width, mSize.height);
+    printf("  type(%#x)=%d (ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
+           cairo_surface_get_type(surf), (unsigned int)mPS, mSize.width, mSize.height);
 #endif
-    cairo_os2_surface_set_hwnd(surf, aWnd); // XXX is this needed here??
+    // record the window handle in the cairo surface, so that refresh works
+    cairo_os2_surface_set_hwnd(surf, aWnd);
     // XXX for now uncomment the mark_dirty function, see bug 371505
     //cairo_surface_mark_dirty(surf);
     Init(surf);
 }
 
 gfxOS2Surface::~gfxOS2Surface()
 {
 #ifdef DEBUG_thebes_2
     printf("gfxOS2Surface[%#x]::~gfxOS2Surface()\n", (unsigned int)this);
 #endif
 
-    if (mOwnsPS)
-        WinReleasePS(mPS);
+    // Surfaces connected to a window were created using WinGetPS so we should
+    // release it again with WinReleasePS. Memory surfaces on the other
+    // hand were created on memory device contexts with the GPI functions, so
+    // use those to clean up stuff.
+    if (mHasWnd) {
+        if (mOwnsPS && mPS) {
+            WinReleasePS(mPS);
+        }
+    } else {
+        if (mBitmap) {
+            GpiSetBitmap(mPS, NULL);
+            GpiDeleteBitmap(mBitmap);
+        }
+        if (mOwnsPS && mPS) {
+            GpiDestroyPS(mPS);
+        }
+        if (mDC) {
+            DevCloseDC(mDC);
+        }
+    }
 }