mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-18 09:00:34 +00:00
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.
This commit is contained in:
parent
36f2f822f2
commit
2ae574ab6d
@ -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;
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
/* 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 */
|
||||
|
||||
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;
|
||||
|
||||
bmi.bmiHeader.biSizeImage = 0;
|
||||
bmi.bmiHeader.biXPelsPerMeter =
|
||||
bmi.bmiHeader.biYPelsPerMeter = 0;
|
||||
bmi.bmiHeader.biClrUsed = 0;
|
||||
bmi.bmiHeader.biClrImportant = 0;
|
||||
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user