[gtk+/gtk-2-24] win32: Let cairo create DIBs for GdkPixmap



commit 2ae574ab6dd1f9810c4667920f9984ed1e95d0f7
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Nov 9 13:25:02 2011 +0100

    win32: Let cairo create DIBs for GdkPixmap
    
    The win32 code for GdkPixmap dib creation workes as such, but
    when creating a cairo surface for it with cairo_win32_surface_create
    from the HDC it fails for any bitmap format than RGB24, due to
    assumptions in cairo.
    
    In order to create a cairo surface for e.g. A1 formats we need
    to let cairo create the surface via cairo_win32_surface_create_with_dib.
    Additionally, we must then make sure to use this surface in
    gdk_drawable_ref_cairo_surface, and to not create a new HDC for
    it but reuse the cairo one (as only one HDC can write to a bitmap).
    
    Even with this fixed there are some issues with current cairo, as
    cairo A1 format isn't quite the same as win32 monochrome bitmaps.
    Fixes for cairo will be submitted.

 gdk/win32/gdkpixmap-win32.c |  166 +++++++++++-------------------------------
 1 files changed, 44 insertions(+), 122 deletions(-)
---
diff --git a/gdk/win32/gdkpixmap-win32.c b/gdk/win32/gdkpixmap-win32.c
index c8b33b4..30b9c8a 100644
--- a/gdk/win32/gdkpixmap-win32.c
+++ b/gdk/win32/gdkpixmap-win32.c
@@ -35,6 +35,7 @@
 #include "gdkscreen.h"
 
 #include "gdkprivate-win32.h"
+#include <cairo-win32.h>
 
 static void gdk_pixmap_impl_win32_get_size   (GdkDrawable        *drawable,
 					      gint               *width,
@@ -109,9 +110,10 @@ gdk_pixmap_impl_win32_finalize (GObject *object)
   GDK_NOTE (PIXMAP, g_print ("gdk_pixmap_impl_win32_finalize: %p\n",
 			     GDK_PIXMAP_HBITMAP (wrapper)));
 
-  _gdk_win32_drawable_finish (GDK_DRAWABLE (object));  
+  if (!impl->is_foreign)
+    GDK_DRAWABLE_IMPL_WIN32 (impl)->hdc_count--;
 
-  GDI_CALL (DeleteObject, (GDK_PIXMAP_HBITMAP (wrapper)));
+  _gdk_win32_drawable_finish (GDK_DRAWABLE (object));
 
   gdk_win32_handle_table_remove (GDK_PIXMAP_HBITMAP (wrapper));
 
@@ -135,26 +137,16 @@ _gdk_pixmap_new (GdkDrawable *drawable,
 		gint         height,
 		gint         depth)
 {
-  struct {
-    BITMAPINFOHEADER bmiHeader;
-    union {
-      WORD bmiIndices[256];
-      DWORD bmiMasks[3];
-      RGBQUAD bmiColors[256];
-    } u;
-  } bmi;
-  UINT iUsage;
   HDC hdc;
-  HWND hwnd;
   HPALETTE holdpal = NULL;
   HBITMAP hbitmap;
   GdkPixmap *pixmap;
   GdkDrawableImplWin32 *drawable_impl;
   GdkPixmapImplWin32 *pixmap_impl;
   GdkColormap *cmap;
-  guchar *bits;
-  gint i;
   gint window_depth;
+  cairo_surface_t *dib_surface, *image_surface;
+  cairo_format_t format;
 
   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
   g_return_val_if_fail ((drawable != NULL) || (depth != -1), NULL);
@@ -173,6 +165,27 @@ _gdk_pixmap_new (GdkDrawable *drawable,
   GDK_NOTE (PIXMAP, g_print ("gdk_pixmap_new: %dx%dx%d drawable=%p\n",
 			     width, height, depth, drawable));
 
+  switch (depth)
+    {
+    case 1:
+      format = CAIRO_FORMAT_A1;
+      break;
+
+    case 8:
+      format = CAIRO_FORMAT_A8;
+      break;
+
+    case 24:
+    case 32:
+      format = CAIRO_FORMAT_RGB24;
+      break;
+
+    default:
+      g_warning ("gdk_win32_pixmap_new: depth = %d not supported", depth);
+      return NULL;
+      break;
+    }
+
   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
   drawable_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
   pixmap_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
@@ -189,123 +202,32 @@ _gdk_pixmap_new (GdkDrawable *drawable,
       if (cmap)
         gdk_drawable_set_colormap (pixmap, cmap);
     }
-  
-  if (GDK_IS_WINDOW (drawable))
-    hwnd = GDK_WINDOW_HWND (drawable);
-  else
-    hwnd = GetDesktopWindow ();
-  if ((hdc = GetDC (hwnd)) == NULL)
+
+  dib_surface = cairo_win32_surface_create_with_dib (format, width, height);
+  if (dib_surface == NULL)
     {
-      WIN32_GDI_FAILED ("GetDC");
       g_object_unref ((GObject *) pixmap);
       return NULL;
     }
 
-  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
-  bmi.bmiHeader.biWidth = width;
-  bmi.bmiHeader.biHeight = -height;
-  bmi.bmiHeader.biPlanes = 1;
-  switch (depth)
-    {
-    case 1:
-    case 24:
-    case 32:
-      bmi.bmiHeader.biBitCount = _gdk_windowing_get_bits_for_depth (gdk_display_get_default (), depth);
-      break;
-
-    case 4:
-      bmi.bmiHeader.biBitCount = 4;
-      break;
-      
-    case 5:
-    case 6:
-    case 7:
-    case 8:
-      bmi.bmiHeader.biBitCount = 8;
-      break;
-      
-    case 15:
-    case 16:
-      bmi.bmiHeader.biBitCount = 16;
-      break;
-
-    default:
-      g_warning ("gdk_win32_pixmap_new: depth = %d", depth);
-      g_assert_not_reached ();
-    }
-
-  if (bmi.bmiHeader.biBitCount == 16)
-    bmi.bmiHeader.biCompression = BI_BITFIELDS;
-  else
-    bmi.bmiHeader.biCompression = BI_RGB;
+  /* We need to have cairo create the dibsection for us, because
+     creating a cairo surface from a hdc only works for rgb24 format */
+  hdc = cairo_win32_surface_get_dc (dib_surface);
 
-  bmi.bmiHeader.biSizeImage = 0;
-  bmi.bmiHeader.biXPelsPerMeter =
-    bmi.bmiHeader.biYPelsPerMeter = 0;
-  bmi.bmiHeader.biClrUsed = 0;
-  bmi.bmiHeader.biClrImportant = 0;
+  /* We need to use the same hdc, because only one hdc
+     can render to the same bitmap */
+  drawable_impl->hdc = hdc;
+  drawable_impl->hdc_count = 1; /* Ensure we never free the cairo surface HDC */
 
-  iUsage = DIB_RGB_COLORS;
-  if (depth == 1)
-    {
-      bmi.u.bmiColors[0].rgbBlue =
-	bmi.u.bmiColors[0].rgbGreen =
-	bmi.u.bmiColors[0].rgbRed = 0x00;
-      bmi.u.bmiColors[0].rgbReserved = 0x00;
-
-      bmi.u.bmiColors[1].rgbBlue =
-	bmi.u.bmiColors[1].rgbGreen =
-	bmi.u.bmiColors[1].rgbRed = 0xFF;
-      bmi.u.bmiColors[1].rgbReserved = 0x00;
-    }
-  else
-    {
-      if (depth <= 8 && drawable_impl->colormap != NULL)
-	{
-	  GdkColormapPrivateWin32 *cmapp =
-	    GDK_WIN32_COLORMAP_DATA (drawable_impl->colormap);
-	  gint k;
-
-	  if ((holdpal = SelectPalette (hdc, cmapp->hpal, FALSE)) == NULL)
-	    WIN32_GDI_FAILED ("SelectPalette");
-	  else if ((k = RealizePalette (hdc)) == GDI_ERROR)
-	    WIN32_GDI_FAILED ("RealizePalette");
-	  else if (k > 0)
-	    GDK_NOTE (PIXMAP_OR_COLORMAP, g_print ("_gdk_win32_pixmap_new: realized %p: %d colors\n",
-						   cmapp->hpal, k));
-
-	  iUsage = DIB_PAL_COLORS;
-	  for (i = 0; i < 256; i++)
-	    bmi.u.bmiIndices[i] = i;
-	}
-      else if (bmi.bmiHeader.biBitCount == 16)
-	{
-	  GdkVisual *visual = gdk_visual_get_system ();
-
-	  bmi.u.bmiMasks[0] = visual->red_mask;
-	  bmi.u.bmiMasks[1] = visual->green_mask;
-	  bmi.u.bmiMasks[2] = visual->blue_mask;
-	}
-    }
-
-  hbitmap = CreateDIBSection (hdc, (BITMAPINFO *) &bmi,
-			      iUsage, (PVOID *) &bits, NULL, 0);
-  if (holdpal != NULL)
-    SelectPalette (hdc, holdpal, FALSE);
-
-  GDI_CALL (ReleaseDC, (hwnd, hdc));
-
-  GDK_NOTE (PIXMAP, g_print ("... =%p bits=%p pixmap=%p\n", hbitmap, bits, pixmap));
-
-  if (hbitmap == NULL)
-    {
-      WIN32_GDI_FAILED ("CreateDIBSection");
-      g_object_unref ((GObject *) pixmap);
-      return NULL;
-    }
+  /* No need to create a new surface when needed, as we have one already */
+  drawable_impl->cairo_surface = dib_surface;
 
+  /* Get the bitmap from the cairo hdc */
+  hbitmap = GetCurrentObject (hdc, OBJ_BITMAP);
   drawable_impl->handle = hbitmap;
-  pixmap_impl->bits = bits;
+
+  image_surface = cairo_win32_surface_get_image (dib_surface);
+  pixmap_impl->bits = cairo_image_surface_get_data (image_surface);
 
   gdk_win32_handle_table_insert (&GDK_PIXMAP_HBITMAP (pixmap), pixmap);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]