/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-2004 Tor Lillqvist
+ * Copyright (C) 2001-2005 Hans Breuer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#include <config.h>
#include <math.h>
+#include <stdio.h>
#include <glib.h>
#include <pango/pangowin32.h>
+#include <cairo-win32.h>
+#include "gdkscreen.h" /* gdk_screen_get_default() */
+#include "gdkregion-generic.h"
#include "gdkprivate-win32.h"
+#define ROP3_D 0x00AA0029
+#define ROP3_DSna 0x00220326
+#define ROP3_DSPDxax 0x00E20746
+
+#define LINE_ATTRIBUTES (GDK_GC_LINE_WIDTH|GDK_GC_LINE_STYLE| \
+ GDK_GC_CAP_STYLE|GDK_GC_JOIN_STYLE)
+
+#define MUST_RENDER_DASHES_MANUALLY(gcwin32) \
+ (gcwin32->line_style == GDK_LINE_DOUBLE_DASH || \
+ (gcwin32->line_style == GDK_LINE_ON_OFF_DASH && \
+ (gcwin32->pen_dash_offset || \
+ (!G_WIN32_IS_NT_BASED () && (gcwin32->pen_style & PS_STYLE_MASK) == PS_SOLID))))
+
static void gdk_win32_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
- gint filled,
+ gboolean filled,
gint x,
gint y,
gint width,
gint height);
static void gdk_win32_draw_arc (GdkDrawable *drawable,
GdkGC *gc,
- gint filled,
+ gboolean filled,
gint x,
gint y,
gint width,
gint angle2);
static void gdk_win32_draw_polygon (GdkDrawable *drawable,
GdkGC *gc,
- gint filled,
+ gboolean filled,
GdkPoint *points,
gint npoints);
static void gdk_win32_draw_text (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints);
-static void gdk_win32_draw_glyphs (GdkDrawable *drawable,
- GdkGC *gc,
- PangoFont *font,
- gint x,
- gint y,
- PangoGlyphString *glyphs);
static void gdk_win32_draw_image (GdkDrawable *drawable,
GdkGC *gc,
GdkImage *image,
gint width,
gint height);
+static cairo_surface_t *gdk_win32_ref_cairo_surface (GdkDrawable *drawable);
+
static void gdk_win32_set_colormap (GdkDrawable *drawable,
GdkColormap *colormap);
static gint gdk_win32_get_depth (GdkDrawable *drawable);
+static GdkScreen * gdk_win32_get_screen (GdkDrawable *drawable);
+
static GdkVisual* gdk_win32_get_visual (GdkDrawable *drawable);
static void gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass);
static void gdk_drawable_impl_win32_finalize (GObject *object);
static gpointer parent_class = NULL;
+static const cairo_user_data_key_t gdk_win32_cairo_key;
GType
gdk_drawable_impl_win32_get_type (void)
drawable_class->draw_points = gdk_win32_draw_points;
drawable_class->draw_segments = gdk_win32_draw_segments;
drawable_class->draw_lines = gdk_win32_draw_lines;
- drawable_class->draw_glyphs = gdk_win32_draw_glyphs;
drawable_class->draw_image = gdk_win32_draw_image;
+ drawable_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
+
drawable_class->set_colormap = gdk_win32_set_colormap;
drawable_class->get_colormap = gdk_win32_get_colormap;
drawable_class->get_depth = gdk_win32_get_depth;
+ drawable_class->get_screen = gdk_win32_get_screen;
drawable_class->get_visual = gdk_win32_get_visual;
- drawable_class->get_image = _gdk_win32_get_image;
-
drawable_class->_copy_to_image = _gdk_win32_copy_to_image;
}
static GdkColormap*
gdk_win32_get_colormap (GdkDrawable *drawable)
{
- GdkDrawableImplWin32 *impl;
-
- impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
-
- return impl->colormap;
+ return GDK_DRAWABLE_IMPL_WIN32 (drawable)->colormap;
}
static void
gdk_win32_set_colormap (GdkDrawable *drawable,
GdkColormap *colormap)
{
- GdkDrawableImplWin32 *impl;
-
- impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
if (impl->colormap == colormap)
return;
/* Drawing
*/
+static int
+rop2_to_rop3 (int rop2)
+{
+ switch (rop2)
+ {
+ /* Oh, Microsoft's silly names for binary and ternary rops. */
+#define CASE(rop2,rop3) case R2_##rop2: return rop3
+ CASE (BLACK, BLACKNESS);
+ CASE (NOTMERGEPEN, NOTSRCERASE);
+ CASE (MASKNOTPEN, 0x00220326);
+ CASE (NOTCOPYPEN, NOTSRCCOPY);
+ CASE (MASKPENNOT, SRCERASE);
+ CASE (NOT, DSTINVERT);
+ CASE (XORPEN, SRCINVERT);
+ CASE (NOTMASKPEN, 0x007700E6);
+ CASE (MASKPEN, SRCAND);
+ CASE (NOTXORPEN, 0x00990066);
+ CASE (NOP, 0x00AA0029);
+ CASE (MERGENOTPEN, MERGEPAINT);
+ CASE (COPYPEN, SRCCOPY);
+ CASE (MERGEPENNOT, 0x00DD0228);
+ CASE (MERGEPEN, SRCPAINT);
+ CASE (WHITE, WHITENESS);
+#undef CASE
+ default: return SRCCOPY;
+ }
+}
+
+static int
+rop2_to_patblt_rop (int rop2)
+{
+ switch (rop2)
+ {
+#define CASE(rop2,patblt_rop) case R2_##rop2: return patblt_rop
+ CASE (COPYPEN, PATCOPY);
+ CASE (XORPEN, PATINVERT);
+ CASE (NOT, DSTINVERT);
+ CASE (BLACK, BLACKNESS);
+ CASE (WHITE, WHITENESS);
+#undef CASE
+ default:
+ g_warning ("Unhandled rop2 in GC to be used in PatBlt: %#x", rop2);
+ return PATCOPY;
+ }
+}
+
+static inline int
+align_with_dash_offset (int a, DWORD *dashes, int num_dashes, GdkGCWin32 *gcwin32)
+{
+ int n = 0;
+ int len_sum = 0;
+ /*
+ * We can't simply add the dashoffset, it can be an arbitrary larger
+ * or smaller value not even between x1 and x2. It just says use the
+ * dash pattern aligned to the offset. So ensure x1 is smaller _x1
+ * and we start with the appropriate dash.
+ */
+ for (n = 0; n < num_dashes; n++)
+ len_sum += dashes[n];
+ if ( len_sum > 0 /* pathological api usage? */
+ && gcwin32->pen_dash_offset > a)
+ a -= (((gcwin32->pen_dash_offset/len_sum - a/len_sum) + 1) * len_sum);
+ else
+ a = gcwin32->pen_dash_offset;
+
+ return a;
+}
+
+/* Render a dashed line 'by hand'. Used for all dashes on Win9x (where
+ * GDI is way too limited), and for double dashes on all Windowses.
+ */
+static inline gboolean
+render_line_horizontal (GdkGCWin32 *gcwin32,
+ int x1,
+ int x2,
+ int y)
+{
+ int n = 0;
+ const int pen_width = MAX (gcwin32->pen_width, 1);
+ const int _x1 = x1;
+
+ g_assert (gcwin32->pen_dashes);
+
+ x1 = align_with_dash_offset (x1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
+
+ for (n = 0; x1 < x2; n++)
+ {
+ int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+ if (x1 + len > x2)
+ len = x2 - x1;
+
+ if (n % 2 == 0 && x1 + len > _x1)
+ if (!GDI_CALL (PatBlt, (gcwin32->hdc,
+ x1 < _x1 ? _x1 : x1,
+ y - pen_width / 2,
+ len, pen_width,
+ rop2_to_patblt_rop (gcwin32->rop2))))
+ return FALSE;
+
+ x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+ }
+
+ if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
+ {
+ HBRUSH hbr;
+
+ if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
+ return FALSE;
+ x1 = _x1;
+ x1 += gcwin32->pen_dash_offset;
+ for (n = 0; x1 < x2; n++)
+ {
+ int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+ if (x1 + len > x2)
+ len = x2 - x1;
+
+ if (n % 2)
+ if (!GDI_CALL (PatBlt, (gcwin32->hdc, x1, y - pen_width / 2,
+ len, pen_width,
+ rop2_to_patblt_rop (gcwin32->rop2))))
+ return FALSE;
+
+ x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+ }
+ if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static inline gboolean
+render_line_vertical (GdkGCWin32 *gcwin32,
+ int x,
+ int y1,
+ int y2)
+{
+ int n;
+ const int pen_width = MAX (gcwin32->pen_width, 1);
+ const int _y1 = y1;
+
+ g_assert (gcwin32->pen_dashes);
+
+ y1 = align_with_dash_offset (y1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
+ for (n = 0; y1 < y2; n++)
+ {
+ int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+ if (y1 + len > y2)
+ len = y2 - y1;
+ if (n % 2 == 0 && y1 + len > _y1)
+ if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2,
+ y1 < _y1 ? _y1 : y1,
+ pen_width, len,
+ rop2_to_patblt_rop (gcwin32->rop2))))
+ return FALSE;
+
+ y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+ }
+
+ if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
+ {
+ HBRUSH hbr;
+
+ if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
+ return FALSE;
+ y1 = _y1;
+ y1 += gcwin32->pen_dash_offset;
+ for (n = 0; y1 < y2; n++)
+ {
+ int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+ if (y1 + len > y2)
+ len = y2 - y1;
+ if (n % 2)
+ if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2, y1,
+ pen_width, len,
+ rop2_to_patblt_rop (gcwin32->rop2))))
+ return FALSE;
+
+ y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+ }
+ if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void
-gdk_win32_draw_rectangle (GdkDrawable *drawable,
- GdkGC *gc,
- gint filled,
- gint x,
- gint y,
- gint width,
- gint height)
+draw_tiles_lowlevel (HDC dest,
+ HDC tile,
+ int rop3,
+ gint dest_x,
+ gint dest_y,
+ gint tile_x_origin,
+ gint tile_y_origin,
+ gint width,
+ gint height,
+ gint tile_width,
+ gint tile_height)
{
- GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
- const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
- HDC hdc;
- HGDIOBJ old_pen_or_brush;
- POINT pts[4];
- gboolean ok = TRUE;
+ gint x, y;
- GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %#x (%p) %s%dx%d@+%d+%d\n",
- (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle,
- gc_private,
- (filled ? "fill " : ""),
- width, height, x, y));
-
- if (filled
- && (gc_private->tile)
- && (gc_private->values_mask & GDK_GC_TILE)
- && (gc_private->values_mask & GDK_GC_FILL))
+ GDK_NOTE (MISC, g_print ("draw_tiles_lowlevel: %p %+d%+d tile=%p:%dx%d@%+d%+d %dx%d\n",
+ dest,
+ dest_x, dest_y,
+ tile, tile_width, tile_height,
+ tile_x_origin, tile_y_origin,
+ width, height));
+
+ y = tile_y_origin % tile_height;
+ if (y > 0)
+ y -= tile_height;
+ while (y < dest_y + height)
{
- _gdk_win32_draw_tiles (drawable, gc, gc_private->tile, x, y, width, height);
- return;
+ if (y + tile_height >= dest_y)
+ {
+ x = tile_x_origin % tile_width;
+ if (x > 0)
+ x -= tile_width;
+ while (x < dest_x + width)
+ {
+ if (x + tile_width >= dest_x)
+ {
+ gint src_x = MAX (0, dest_x - x);
+ gint src_y = MAX (0, dest_y - y);
+
+ if (!GDI_CALL (BitBlt, (dest, x + src_x, y + src_y,
+ MIN (tile_width, dest_x + width - (x + src_x)),
+ MIN (tile_height, dest_y + height - (y + src_y)),
+ tile,
+ src_x, src_y,
+ rop3)))
+ return;
+ }
+ x += tile_width;
+ }
+ }
+ y += tile_height;
}
+}
- hdc = gdk_win32_hdc_get (drawable, gc, mask);
+static void
+draw_tiles (GdkDrawable *drawable,
+ GdkGC *gc,
+ int rop3,
+ GdkPixmap *tile,
+ gint dest_x,
+ gint dest_y,
+ gint tile_x_origin,
+ gint tile_y_origin,
+ gint width,
+ gint height)
+{
+ const GdkGCValuesMask mask = GDK_GC_FOREGROUND;
+ gint tile_width, tile_height;
+ GdkGC *gc_copy;
+ HDC dest_hdc, tile_hdc;
-#if 0
- {
- HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
- HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
- LOGBRUSH lbr;
- LOGPEN lpen;
- GetObject (hbr, sizeof (lbr), &lbr);
- GetObject (hpen, sizeof (lpen), &lpen);
-
- g_print ("current brush: style = %s, color = 0x%.08x\n",
- (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
- lbr.lbColor);
- g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
- (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
- lpen.lopnWidth,
- lpen.lopnColor);
- }
-#endif
+ gc_copy = gdk_gc_new (tile);
+ gdk_gc_copy (gc_copy, gc);
+ dest_hdc = gdk_win32_hdc_get (drawable, gc, mask);
+ tile_hdc = gdk_win32_hdc_get (tile, gc_copy, mask);
+
+ gdk_drawable_get_size (tile, &tile_width, &tile_height);
+
+ draw_tiles_lowlevel (dest_hdc, tile_hdc, rop3,
+ dest_x, dest_y, tile_x_origin, tile_y_origin,
+ width, height, tile_width, tile_height);
+
+ gdk_win32_hdc_release (drawable, gc, mask);
+ gdk_win32_hdc_release (tile, gc_copy, mask);
+ gdk_gc_unref (gc_copy);
+}
+
+static void
+generic_draw (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkGCValuesMask mask,
+ void (*function) (GdkGCWin32 *, HDC, gint, gint, va_list),
+ const GdkRegion *region,
+ ...)
+{
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+ GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
+ HDC hdc;
+ va_list args;
+ GdkFill fill_style = _gdk_gc_get_fill (gc);
- if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
+ va_start (args, region);
+
+ /* If tiled or stippled, draw to a temp pixmap and do blitting magic.
+ */
+
+ if (gcwin32->values_mask & GDK_GC_FILL &&
+ ((fill_style == GDK_TILED &&
+ gcwin32->values_mask & GDK_GC_TILE &&
+ _gdk_gc_get_tile (gc) != NULL)
+ ||
+ ((fill_style == GDK_OPAQUE_STIPPLED ||
+ fill_style == GDK_STIPPLED) &&
+ gcwin32->values_mask & GDK_GC_STIPPLE &&
+ _gdk_gc_get_stipple (gc) != NULL)))
{
- if (!BeginPath (hdc))
- WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
+ const GdkGCValuesMask blitting_mask = 0;
+ GdkGCValuesMask drawing_mask = GDK_GC_FOREGROUND;
+ gint ts_x_origin = 0, ts_y_origin = 0;
+
+ gint width = region->extents.x2 - region->extents.x1;
+ gint height = region->extents.y2 - region->extents.y1;
+
+ GdkPixmap *mask_pixmap =
+ gdk_pixmap_new (drawable, width, height, 1);
+ GdkPixmap *tile_pixmap =
+ gdk_pixmap_new (drawable, width, height, -1);
+ GdkPixmap *stipple_bitmap = NULL;
+ GdkColor fg;
+
+ GdkGC *mask_gc = gdk_gc_new (mask_pixmap);
+ GdkGC *tile_gc = gdk_gc_new (tile_pixmap);
- /* Win9x doesn't support Rectangle calls in a path,
- * thus use Polyline.
+ HDC mask_hdc;
+ HDC tile_hdc;
+
+ HGDIOBJ old_mask_hbm;
+ HGDIOBJ old_tile_hbm;
+
+ GdkGCValues gcvalues;
+
+ hdc = gdk_win32_hdc_get (drawable, gc, blitting_mask);
+ tile_hdc = CreateCompatibleDC (hdc);
+
+ if (gcwin32->values_mask & GDK_GC_TS_X_ORIGIN)
+ ts_x_origin = gc->ts_x_origin;
+ if (gcwin32->values_mask & GDK_GC_TS_Y_ORIGIN)
+ ts_y_origin = gc->ts_y_origin;
+
+ ts_x_origin -= region->extents.x1;
+ ts_y_origin -= region->extents.y1;
+
+ /* Fill mask bitmap with zeros */
+ gdk_gc_set_function (mask_gc, GDK_CLEAR);
+ gdk_draw_rectangle (mask_pixmap, mask_gc, TRUE,
+ 0, 0, width, height);
+
+ /* Paint into mask bitmap, drawing ones */
+ gdk_gc_set_function (mask_gc, GDK_COPY);
+ fg.pixel = 1;
+ gdk_gc_set_foreground (mask_gc, &fg);
+
+ /* If the drawing function uses line attributes, set them as in
+ * the real GC.
*/
-
- pts[0].x = x;
- pts[0].y = y;
- pts[1].x = x + width + 1;
- pts[1].y = y;
- pts[2].x = x + width + 1;
- pts[2].y = y + height + 1;
- pts[3].x = x;
- pts[3].y = y + height + 1;
-
- if (ok)
- MoveToEx (hdc, x, y, NULL);
+ if (mask & LINE_ATTRIBUTES)
+ {
+ gdk_gc_get_values (gc, &gcvalues);
+ if (gcvalues.line_width != 0 ||
+ gcvalues.line_style != GDK_LINE_SOLID ||
+ gcvalues.cap_style != GDK_CAP_BUTT ||
+ gcvalues.join_style != GDK_JOIN_MITER)
+ gdk_gc_set_line_attributes (mask_gc,
+ gcvalues.line_width,
+ gcvalues.line_style,
+ gcvalues.cap_style,
+ gcvalues.join_style);
+ drawing_mask |= LINE_ATTRIBUTES;
+ }
+
+ /* Ditto, if the drawing function draws text, set up for that. */
+ if (mask & GDK_GC_FONT)
+ drawing_mask |= GDK_GC_FONT;
+
+ mask_hdc = gdk_win32_hdc_get (mask_pixmap, mask_gc, drawing_mask);
+ (*function) (GDK_GC_WIN32 (mask_gc), mask_hdc,
+ region->extents.x1, region->extents.y1, args);
+ gdk_win32_hdc_release (mask_pixmap, mask_gc, drawing_mask);
+
+ if (fill_style == GDK_TILED)
+ {
+ /* Tile pixmap with tile */
+ draw_tiles (tile_pixmap, tile_gc, SRCCOPY,
+ _gdk_gc_get_tile (gc),
+ 0, 0, ts_x_origin, ts_y_origin,
+ width, height);
+ }
+ else
+ {
+ /* Tile with stipple */
+ GdkGC *stipple_gc;
+
+ stipple_bitmap = gdk_pixmap_new (NULL, width, height, 1);
+ stipple_gc = gdk_gc_new (stipple_bitmap);
+
+ /* Tile stipple bitmap */
+ draw_tiles (stipple_bitmap, stipple_gc, SRCCOPY,
+ _gdk_gc_get_stipple (gc),
+ 0, 0, ts_x_origin, ts_y_origin,
+ width, height);
+
+ if (fill_style == GDK_OPAQUE_STIPPLED)
+ {
+ /* Fill tile pixmap with background */
+ fg.pixel = _gdk_gc_get_bg_pixel (gc);
+ gdk_gc_set_foreground (tile_gc, &fg);
+ gdk_draw_rectangle (tile_pixmap, tile_gc, TRUE,
+ 0, 0, width, height);
+ }
+ gdk_gc_unref (stipple_gc);
+ }
+
+ gdk_gc_unref (mask_gc);
+ gdk_gc_unref (tile_gc);
+
+ mask_hdc = CreateCompatibleDC (hdc);
+
+ if ((old_mask_hbm = SelectObject (mask_hdc, GDK_PIXMAP_HBITMAP (mask_pixmap))) == NULL)
+ WIN32_GDI_FAILED ("SelectObject");
+
+ if ((old_tile_hbm = SelectObject (tile_hdc, GDK_PIXMAP_HBITMAP (tile_pixmap))) == NULL)
+ WIN32_GDI_FAILED ("SelectObject");
+
+ if (fill_style == GDK_STIPPLED ||
+ fill_style == GDK_OPAQUE_STIPPLED)
+ {
+ HDC stipple_hdc;
+ HGDIOBJ old_stipple_hbm;
+ HBRUSH fg_brush;
+ HGDIOBJ old_tile_brush;
+
+ if ((stipple_hdc = CreateCompatibleDC (hdc)) == NULL)
+ WIN32_GDI_FAILED ("CreateCompatibleDC");
+
+ if ((old_stipple_hbm =
+ SelectObject (stipple_hdc,
+ GDK_PIXMAP_HBITMAP (stipple_bitmap))) == NULL)
+ WIN32_GDI_FAILED ("SelectObject");
+
+ if ((fg_brush = CreateSolidBrush
+ (_gdk_win32_colormap_color (impl->colormap,
+ _gdk_gc_get_fg_pixel (gc)))) == NULL)
+ WIN32_GDI_FAILED ("CreateSolidBrush");
+
+ if ((old_tile_brush = SelectObject (tile_hdc, fg_brush)) == NULL)
+ WIN32_GDI_FAILED ("SelectObject");
+
+ /* Paint tile with foreround where stipple is one
+ *
+ * Desired ternary ROP: (P=foreground, S=stipple, D=destination)
+ * P S D ?
+ * 0 0 0 0
+ * 0 0 1 1
+ * 0 1 0 0
+ * 0 1 1 0
+ * 1 0 0 0
+ * 1 0 1 1
+ * 1 1 0 1
+ * 1 1 1 1
+ *
+ * Reading bottom-up: 11100010 = 0xE2. PSDK docs say this is
+ * known as DSPDxax, with hex value 0x00E20746.
+ */
+ GDI_CALL (BitBlt, (tile_hdc, 0, 0, width, height,
+ stipple_hdc, 0, 0, ROP3_DSPDxax));
+
+ if (fill_style == GDK_STIPPLED)
+ {
+ /* Punch holes in mask where stipple is zero */
+ GDI_CALL (BitBlt, (mask_hdc, 0, 0, width, height,
+ stipple_hdc, 0, 0, SRCAND));
+ }
+
+ GDI_CALL (SelectObject, (tile_hdc, old_tile_brush));
+ GDI_CALL (DeleteObject, (fg_brush));
+ GDI_CALL (SelectObject, (stipple_hdc, old_stipple_hbm));
+ GDI_CALL (DeleteDC, (stipple_hdc));
+ g_object_unref (stipple_bitmap);
+ }
+
+ /* Tile pixmap now contains the pattern that we should paint in
+ * the areas where mask is one. (It is filled with said pattern.)
+ */
+
+ if (G_WIN32_IS_NT_BASED ())
+ {
+ GDI_CALL (MaskBlt, (hdc, region->extents.x1, region->extents.y1,
+ width, height,
+ tile_hdc, 0, 0,
+ GDK_PIXMAP_HBITMAP (mask_pixmap), 0, 0,
+ MAKEROP4 (rop2_to_rop3 (gcwin32->rop2), ROP3_D)));
+ }
+ else
+ {
+ GdkPixmap *temp1_pixmap =
+ gdk_pixmap_new (drawable, width, height, -1);
+ GdkPixmap *temp2_pixmap =
+ gdk_pixmap_new (drawable, width, height, -1);
+ HDC temp1_hdc = CreateCompatibleDC (hdc);
+ HDC temp2_hdc = CreateCompatibleDC (hdc);
+ HGDIOBJ old_temp1_hbm =
+ SelectObject (temp1_hdc, GDK_PIXMAP_HBITMAP (temp1_pixmap));
+ HGDIOBJ old_temp2_hbm =
+ SelectObject (temp2_hdc, GDK_PIXMAP_HBITMAP (temp2_pixmap));
+
+ /* Grab copy of dest region to temp1 */
+ GDI_CALL (BitBlt,(temp1_hdc, 0, 0, width, height,
+ hdc, region->extents.x1, region->extents.y1, SRCCOPY));
+
+ /* Paint tile to temp1 using correct function */
+ GDI_CALL (BitBlt, (temp1_hdc, 0, 0, width, height,
+ tile_hdc, 0, 0, rop2_to_rop3 (gcwin32->rop2)));
+
+ /* Mask out temp1 where function didn't paint */
+ GDI_CALL (BitBlt, (temp1_hdc, 0, 0, width, height,
+ mask_hdc, 0, 0, SRCAND));
+
+ /* Grab another copy of dest region to temp2 */
+ GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
+ hdc, region->extents.x1, region->extents.y1, SRCCOPY));
+
+ /* Mask out temp2 where function did paint */
+ GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
+ mask_hdc, 0, 0, ROP3_DSna));
+
+ /* Combine temp1 with temp2 */
+ GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
+ temp1_hdc, 0, 0, SRCPAINT));
+
+ /* Blit back */
+ GDI_CALL (BitBlt, (hdc, region->extents.x1, region->extents.y1, width, height,
+ temp2_hdc, 0, 0, SRCCOPY));
+
+ /* Cleanup */
+ GDI_CALL (SelectObject, (temp1_hdc, old_temp1_hbm));
+ GDI_CALL (SelectObject, (temp2_hdc, old_temp2_hbm));
+ GDI_CALL (DeleteDC, (temp1_hdc));
+ GDI_CALL (DeleteDC, (temp2_hdc));
+ g_object_unref (temp1_pixmap);
+ g_object_unref (temp2_pixmap);
+ }
- if (ok && !Polyline (hdc, pts, 4))
- WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
-
- if (ok && !CloseFigure (hdc))
- WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
+ /* Cleanup */
+ GDI_CALL (SelectObject, (mask_hdc, old_mask_hbm));
+ GDI_CALL (SelectObject, (tile_hdc, old_tile_hbm));
+ GDI_CALL (DeleteDC, (mask_hdc));
+ GDI_CALL (DeleteDC, (tile_hdc));
+ g_object_unref (mask_pixmap);
+ g_object_unref (tile_pixmap);
+
+ gdk_win32_hdc_release (drawable, gc, blitting_mask);
+ }
+ else
+ {
+ hdc = gdk_win32_hdc_get (drawable, gc, mask);
+ (*function) (gcwin32, hdc, 0, 0, args);
+ gdk_win32_hdc_release (drawable, gc, mask);
+ }
+ va_end (args);
+}
- if (ok && !EndPath (hdc))
- WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
-
- if (ok && !filled)
- if (!WidenPath (hdc))
- WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
-
- if (ok && !FillPath (hdc))
- WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
+static GdkRegion *
+widen_bounds (GdkRectangle *bounds,
+ gint pen_width)
+{
+ if (pen_width == 0)
+ pen_width = 1;
+
+ bounds->x -= pen_width;
+ bounds->y -= pen_width;
+ bounds->width += 2 * pen_width;
+ bounds->height += 2 * pen_width;
+
+ return gdk_region_rectangle (bounds);
+}
+
+static void
+draw_rectangle (GdkGCWin32 *gcwin32,
+ HDC hdc,
+ gint x_offset,
+ gint y_offset,
+ va_list args)
+{
+ HGDIOBJ old_pen_or_brush;
+ gboolean filled;
+ gint x;
+ gint y;
+ gint width;
+ gint height;
+
+ filled = va_arg (args, gboolean);
+ x = va_arg (args, gint);
+ y = va_arg (args, gint);
+ width = va_arg (args, gint);
+ height = va_arg (args, gint);
+
+ x -= x_offset;
+ y -= y_offset;
+
+ if (!filled && MUST_RENDER_DASHES_MANUALLY (gcwin32))
+ {
+ render_line_vertical (gcwin32, x, y, y+height+1) &&
+ render_line_horizontal (gcwin32, x, x+width+1, y) &&
+ render_line_vertical (gcwin32, x+width+1, y, y+height+1) &&
+ render_line_horizontal (gcwin32, x, x+width+1, y+height+1);
}
else
{
old_pen_or_brush = SelectObject (hdc, GetStockObject (NULL_PEN));
else
old_pen_or_brush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
-
- if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
- WIN32_GDI_FAILED ("Rectangle");
-
- SelectObject (hdc, old_pen_or_brush);
- }
+ if (old_pen_or_brush == NULL)
+ WIN32_GDI_FAILED ("SelectObject");
+ else
+ GDI_CALL (Rectangle, (hdc, x, y, x+width+1, y+height+1));
- gdk_win32_hdc_release (drawable, gc, mask);
+ if (old_pen_or_brush != NULL)
+ GDI_CALL (SelectObject, (hdc, old_pen_or_brush));
+ }
}
static void
-gdk_win32_draw_arc (GdkDrawable *drawable,
- GdkGC *gc,
- gint filled,
- gint x,
- gint y,
- gint width,
- gint height,
- gint angle1,
- gint angle2)
+gdk_win32_draw_rectangle (GdkDrawable *drawable,
+ GdkGC *gc,
+ gboolean filled,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
{
- const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
- HDC hdc;
- int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
+ GdkRectangle bounds;
+ GdkRegion *region;
- GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x %d,%d,%d,%d %d %d\n",
- (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle,
- x, y, width, height, angle1, angle2));
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %s (%p) %s%dx%d@%+d%+d\n",
+ _gdk_win32_drawable_description (drawable),
+ gc,
+ (filled ? "fill " : ""),
+ width, height, x, y));
+
+ bounds.x = x;
+ bounds.y = y;
+ bounds.width = width;
+ bounds.height = height;
+ region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+ generic_draw (drawable, gc,
+ GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
+ (filled ? 0 : LINE_ATTRIBUTES),
+ draw_rectangle, region, filled, x, y, width, height);
+
+ gdk_region_destroy (region);
+}
- /* Seems that drawing arcs with width or height <= 2 fails, at least
- * with my TNT card.
- */
- if (width <= 2 || height <= 2 || angle2 == 0)
- return;
+static void
+draw_arc (GdkGCWin32 *gcwin32,
+ HDC hdc,
+ gint x_offset,
+ gint y_offset,
+ va_list args)
+{
+ HGDIOBJ old_pen;
+ gboolean filled;
+ gint x, y;
+ gint width, height;
+ gint angle1, angle2;
+ int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
- hdc = gdk_win32_hdc_get (drawable, gc, mask);
+ filled = va_arg (args, gboolean);
+ x = va_arg (args, gint);
+ y = va_arg (args, gint);
+ width = va_arg (args, gint);
+ height = va_arg (args, gint);
+ angle1 = va_arg (args, gint);
+ angle2 = va_arg (args, gint);
+ x -= x_offset;
+ y -= y_offset;
+
if (angle2 >= 360*64)
{
nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
}
else if (angle2 > 0)
{
- /* The 100. is just an arbitrary value */
- nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
- nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
- nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
- nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
+ nXStartArc = x + width/2 + width * cos(angle1/64.*2.*G_PI/360.);
+ nYStartArc = y + height/2 + -height * sin(angle1/64.*2.*G_PI/360.);
+ nXEndArc = x + width/2 + width * cos((angle1+angle2)/64.*2.*G_PI/360.);
+ nYEndArc = y + height/2 + -height * sin((angle1+angle2)/64.*2.*G_PI/360.);
}
else
{
- nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
- nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
- nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
- nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
+ nXEndArc = x + width/2 + width * cos(angle1/64.*2.*G_PI/360.);
+ nYEndArc = y + height/2 + -height * sin(angle1/64.*2.*G_PI/360.);
+ nXStartArc = x + width/2 + width * cos((angle1+angle2)/64.*2.*G_PI/360.);
+ nYStartArc = y + height/2 + -height * sin((angle1+angle2)/64.*2.*G_PI/360.);
}
- /* GDK_OPAQUE_STIPPLED arcs not implemented. */
-
if (filled)
{
- GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
- x, y, x+width, y+height,
- nXStartArc, nYStartArc,
- nXEndArc, nYEndArc));
- if (!Pie (hdc, x, y, x+width, y+height,
- nXStartArc, nYStartArc, nXEndArc, nYEndArc))
- WIN32_GDI_FAILED ("Pie");
+ old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
+ GDK_NOTE (MISC, g_print ("... Pie(%p,%d,%d,%d,%d,%d,%d,%d,%d)\n",
+ hdc, x, y, x+width, y+height,
+ nXStartArc, nYStartArc, nXEndArc, nYEndArc));
+ GDI_CALL (Pie, (hdc, x, y, x+width, y+height,
+ nXStartArc, nYStartArc, nXEndArc, nYEndArc));
+ GDI_CALL (SelectObject, (hdc, old_pen));
}
else
{
- GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
- x, y, x+width, y+height,
- nXStartArc, nYStartArc,
- nXEndArc, nYEndArc));
- if (!Arc (hdc, x, y, x+width, y+height,
- nXStartArc, nYStartArc, nXEndArc, nYEndArc))
- WIN32_GDI_FAILED ("Arc");
+ GDK_NOTE (MISC, g_print ("... Arc(%p,%d,%d,%d,%d,%d,%d,%d,%d)\n",
+ hdc, x, y, x+width, y+height,
+ nXStartArc, nYStartArc, nXEndArc, nYEndArc));
+ GDI_CALL (Arc, (hdc, x, y, x+width, y+height,
+ nXStartArc, nYStartArc, nXEndArc, nYEndArc));
}
- gdk_win32_hdc_release (drawable, gc, mask);
+}
+
+static void
+gdk_win32_draw_arc (GdkDrawable *drawable,
+ GdkGC *gc,
+ gboolean filled,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ gint angle1,
+ gint angle2)
+{
+ GdkRectangle bounds;
+ GdkRegion *region;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_arc: %s %d,%d,%d,%d %d %d\n",
+ _gdk_win32_drawable_description (drawable),
+ x, y, width, height, angle1, angle2));
+
+ if (width <= 2 || height <= 2 || angle2 == 0)
+ return;
+
+ bounds.x = x;
+ bounds.y = y;
+ bounds.width = width;
+ bounds.height = height;
+ region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+ generic_draw (drawable, gc,
+ GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
+ draw_arc, region, filled, x, y, width, height, angle1, angle2);
+
+ gdk_region_destroy (region);
+}
+
+static void
+draw_polygon (GdkGCWin32 *gcwin32,
+ HDC hdc,
+ gint x_offset,
+ gint y_offset,
+ va_list args)
+{
+ gboolean filled;
+ POINT *pts;
+ HPEN old_pen;
+ gint npoints;
+ gint i;
+
+ filled = va_arg (args, gboolean);
+ pts = va_arg (args, POINT *);
+ npoints = va_arg (args, gint);
+
+ if (x_offset != 0 || y_offset != 0)
+ for (i = 0; i < npoints; i++)
+ {
+ pts[i].x -= x_offset;
+ pts[i].y -= y_offset;
+ }
+
+ if (filled)
+ {
+ old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
+ if (old_pen == NULL)
+ WIN32_GDI_FAILED ("SelectObject");
+ GDI_CALL (Polygon, (hdc, pts, npoints));
+ if (old_pen != NULL)
+ GDI_CALL (SelectObject, (hdc, old_pen));
+ }
+ else
+ GDI_CALL (Polyline, (hdc, pts, npoints));
}
static void
gdk_win32_draw_polygon (GdkDrawable *drawable,
GdkGC *gc,
- gint filled,
+ gboolean filled,
GdkPoint *points,
gint npoints)
{
- GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
- const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
- HDC hdc;
+ GdkRectangle bounds;
+ GdkRegion *region;
POINT *pts;
- gboolean ok = TRUE;
int i;
- GDK_NOTE (MISC, g_print ("gdk_win32_draw_polygon: %#x (%p) %d\n",
- (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle,
- gc_private,
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_polygon: %s %d points\n",
+ _gdk_win32_drawable_description (drawable),
npoints));
if (npoints < 2)
return;
- hdc = gdk_win32_hdc_get (drawable, gc, mask);
+ bounds.x = G_MAXINT;
+ bounds.y = G_MAXINT;
+ bounds.width = 0;
+ bounds.height = 0;
+
pts = g_new (POINT, npoints+1);
for (i = 0; i < npoints; i++)
{
+ bounds.x = MIN (bounds.x, points[i].x);
+ bounds.y = MIN (bounds.y, points[i].y);
pts[i].x = points[i].x;
pts[i].y = points[i].y;
}
-
- if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
- {
- if (!BeginPath (hdc))
- WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
-
- if (ok)
- MoveToEx (hdc, points[0].x, points[0].y, NULL);
-
- if (pts[0].x == pts[npoints-1].x && pts[0].y == pts[npoints-1].y)
- npoints--;
- if (ok && !Polyline (hdc, pts, 4))
- WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
-
- if (ok && !CloseFigure (hdc))
- WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
-
- if (ok && !EndPath (hdc))
- WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
-
- if (ok && !filled)
- if (!WidenPath (hdc))
- WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
-
- if (ok && !FillPath (hdc))
- WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
+ for (i = 0; i < npoints; i++)
+ {
+ bounds.width = MAX (bounds.width, points[i].x - bounds.x);
+ bounds.height = MAX (bounds.height, points[i].y - bounds.y);
}
- else
+
+ if (points[0].x != points[npoints-1].x ||
+ points[0].y != points[npoints-1].y)
{
- if (points[0].x != points[npoints-1].x
- || points[0].y != points[npoints-1].y)
- {
- pts[npoints].x = points[0].x;
- pts[npoints].y = points[0].y;
- npoints++;
- }
-
- if (filled)
- {
- if (!Polygon (hdc, pts, npoints))
- WIN32_GDI_FAILED ("Polygon");
- }
- else
- {
- if (!Polyline (hdc, pts, npoints))
- WIN32_GDI_FAILED ("Polyline");
- }
+ pts[npoints].x = points[0].x;
+ pts[npoints].y = points[0].y;
+ npoints++;
}
+
+ region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+ generic_draw (drawable, gc,
+ GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
+ draw_polygon, region, filled, pts, npoints);
+
+ gdk_region_destroy (region);
g_free (pts);
- gdk_win32_hdc_release (drawable, gc, mask);
}
typedef struct
{
const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
wchar_t *wcstr, wc;
- gint wlen;
+ glong wlen;
gdk_draw_text_arg arg;
if (text_length == 0)
arg.y = y;
arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
- GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n",
- (guint) GDK_DRAWABLE_HANDLE (drawable),
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_text: %s (%d,%d) \"%.*s\" (len %d)\n",
+ _gdk_win32_drawable_description (drawable),
x, y,
(text_length > 10 ? 10 : text_length),
text, text_length));
}
else
{
- wcstr = g_new (wchar_t, text_length);
- if ((wlen = _gdk_utf8_to_ucs2 (wcstr, text, text_length, text_length)) == -1)
- g_warning ("gdk_win32_draw_text: _gdk_utf8_to_ucs2 failed");
- else
- _gdk_wchar_text_handle (font, wcstr, wlen, gdk_draw_text_handler, &arg);
+ wcstr = g_utf8_to_utf16 (text, text_length, NULL, &wlen, NULL);
+ _gdk_wchar_text_handle (font, wcstr, wlen, gdk_draw_text_handler, &arg);
g_free (wcstr);
}
-
gdk_win32_hdc_release (drawable, gc, mask);
}
arg.y = y;
arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
- GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
- (guint) GDK_DRAWABLE_HANDLE (drawable),
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_text_wc: %s (%d,%d) len: %d\n",
+ _gdk_win32_drawable_description (drawable),
x, y, text_length));
if (sizeof (wchar_t) != sizeof (GdkWChar))
gint width,
gint height)
{
- HDC hdc;
- HDC srcdc;
- HGDIOBJ hgdiobj;
- HRGN src_rgn, draw_rgn, outside_rgn;
- RECT r;
- gint src_width, src_height;
- gboolean ok = TRUE;
- GdkDrawableImplWin32 *impl;
- HANDLE src_handle;
-
- impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
- if (GDK_IS_DRAWABLE_IMPL_WIN32(src))
- src_handle = GDK_DRAWABLE_IMPL_WIN32 (src)->handle;
- else
- src_handle = GDK_DRAWABLE_HANDLE (src);
+ g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
- GDK_NOTE (MISC, g_print ("gdk_win32_draw_drawable: dest: %#x @+%d+%d"
- " src: %#x %dx%d@+%d+%d\n",
- (guint) impl->handle,
- xdest, ydest,
- (guint) src_handle,
- width, height, xsrc, ysrc));
+ _gdk_win32_blit (FALSE, (GdkDrawableImplWin32 *) drawable,
+ gc, src, xsrc, ysrc,
+ xdest, ydest, width, height);
+}
- hdc = gdk_win32_hdc_get (drawable, gc, 0);
+static void
+gdk_win32_draw_points (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPoint *points,
+ gint npoints)
+{
+ HDC hdc;
+ HGDIOBJ old_pen;
+ int i;
- gdk_drawable_get_size (src, &src_width, &src_height);
- src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1);
- draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
+ hdc = gdk_win32_hdc_get (drawable, gc, GDK_GC_FOREGROUND);
-#if 0 /* HB: I dont't see reason to do this ... */
- if (GDK_IS_WINDOW_IMPL_WIN32 (drawable))
- {
- /* If we are drawing on a window, calculate the region that is
- * outside the source pixmap, and invalidate that, causing it to
- * be cleared. XXX
- */
- SetRectEmpty (&r);
- outside_rgn = CreateRectRgnIndirect (&r);
- if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
- {
- if (ERROR == OffsetRgn (outside_rgn, xdest, ydest))
- WIN32_GDI_FAILED ("OffsetRgn");
- GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
- g_print ("...calling InvalidateRgn, "
- "bbox: %ldx%ld@+%ld+%ld\n",
- r.right - r.left - 1, r.bottom - r.top - 1,
- r.left, r.top)));
- if (!InvalidateRgn (impl->handle, outside_rgn, TRUE))
- WIN32_GDI_FAILED ("InvalidateRgn");
- }
- if (!DeleteObject (outside_rgn))
- WIN32_GDI_FAILED ("DeleteObject");
- }
-#endif
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_points: %s %d points\n",
+ _gdk_win32_drawable_description (drawable),
+ npoints));
-#if 1 /* Don't know if this is necessary */
- if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
- g_warning ("gdk_win32_draw_drawable: CombineRgn returned a COMPLEXREGION");
+ /* The X11 version uses XDrawPoint(), which doesn't use the fill
+ * mode, so don't use generic_draw. But we should use the current
+ * function, so we can't use SetPixel(). Draw single-pixel
+ * rectangles (sigh).
+ */
- if (0 == GetRgnBox (draw_rgn, &r))
- WIN32_GDI_FAILED("GetRgnBox");
- if (r.left != xsrc
- || r.top != ysrc
- || r.right != xsrc + width + 1
- || r.bottom != ysrc + height + 1)
- {
- xdest += r.left - xsrc;
- xsrc = r.left;
- ydest += r.top - ysrc;
- ysrc = r.top;
- width = r.right - xsrc - 1;
- height = r.bottom - ysrc - 1;
-
- GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
- "dest: @+%d+%d\n",
- width, height, xsrc, ysrc,
- xdest, ydest));
- }
-#endif
+ old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
+ for (i = 0; i < npoints; i++)
+ Rectangle (hdc, points[i].x, points[i].y,
+ points[i].x + 2, points[i].y + 2);
- if (!DeleteObject (src_rgn))
- WIN32_GDI_FAILED ("DeleteObject");
- if (!DeleteObject (draw_rgn))
- WIN32_GDI_FAILED ("DeleteObject");
+ SelectObject (hdc, old_pen);
+ gdk_win32_hdc_release (drawable, gc, GDK_GC_FOREGROUND);
+}
- /* This function is called also to bitblt from a window.
- */
- if (GDK_IS_PIXMAP_IMPL_WIN32 (src) || GDK_IS_PIXMAP(src))
+static void
+draw_segments (GdkGCWin32 *gcwin32,
+ HDC hdc,
+ gint x_offset,
+ gint y_offset,
+ va_list args)
+{
+ GdkSegment *segs;
+ gint nsegs;
+ gint i;
+
+ segs = va_arg (args, GdkSegment *);
+ nsegs = va_arg (args, gint);
+
+ if (x_offset != 0 || y_offset != 0)
{
- if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
- WIN32_GDI_FAILED ("CreateCompatibleDC"), ok = FALSE;
-
- if (ok && (hgdiobj = SelectObject (srcdc, src_handle)) == NULL)
- WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
-
- if (ok && !BitBlt (hdc, xdest, ydest, width, height,
- srcdc, xsrc, ysrc, SRCCOPY))
- WIN32_GDI_FAILED ("BitBlt");
-
- if (ok && (SelectObject (srcdc, hgdiobj) == NULL))
- WIN32_GDI_FAILED ("SelectObject");
-
- if (srcdc != NULL && !DeleteDC (srcdc))
- WIN32_GDI_FAILED ("DeleteDC");
+ /* must not modify in place, but could splice in the offset all below */
+ segs = g_memdup (segs, nsegs * sizeof (GdkSegment));
+ for (i = 0; i < nsegs; i++)
+ {
+ segs[i].x1 -= x_offset;
+ segs[i].y1 -= y_offset;
+ segs[i].x2 -= x_offset;
+ segs[i].y2 -= y_offset;
+ }
}
- else if (impl->handle == src_handle)
+
+ if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
{
- /* Blitting inside a window, use ScrollDC */
- RECT scrollRect, clipRect, emptyRect;
- HRGN updateRgn;
-
- scrollRect.left = MIN (xsrc, xdest);
- scrollRect.top = MIN (ysrc, ydest);
- scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
- scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
-
- clipRect.left = xdest;
- clipRect.top = ydest;
- clipRect.right = xdest + width + 1;
- clipRect.bottom = ydest + height + 1;
-
- SetRectEmpty (&emptyRect);
- updateRgn = CreateRectRgnIndirect (&emptyRect);
- if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
- &scrollRect, &clipRect,
- updateRgn, NULL))
- WIN32_GDI_FAILED ("ScrollDC"), ok = FALSE;
- if (ok && !InvalidateRgn (impl->handle, updateRgn, FALSE))
- WIN32_GDI_FAILED ("InvalidateRgn"), ok = FALSE;
- if (ok && !UpdateWindow (impl->handle))
- WIN32_GDI_FAILED ("UpdateWindow");
- if (!DeleteObject (updateRgn))
- WIN32_GDI_FAILED ("DeleteObject");
+ for (i = 0; i < nsegs; i++)
+ {
+ if (segs[i].x1 == segs[i].x2)
+ {
+ int y1, y2;
+
+ if (segs[i].y1 <= segs[i].y2)
+ y1 = segs[i].y1, y2 = segs[i].y2;
+ else
+ y1 = segs[i].y2, y2 = segs[i].y1;
+
+ render_line_vertical (gcwin32, segs[i].x1, y1, y2);
+ }
+ else if (segs[i].y1 == segs[i].y2)
+ {
+ int x1, x2;
+
+ if (segs[i].x1 <= segs[i].x2)
+ x1 = segs[i].x1, x2 = segs[i].x2;
+ else
+ x1 = segs[i].x2, x2 = segs[i].x1;
+
+ render_line_horizontal (gcwin32, x1, x2, segs[i].y1);
+ }
+ else
+ GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
+ GDI_CALL (LineTo, (hdc, segs[i].x2, segs[i].y2));
+ }
}
else
{
- if ((srcdc = GetDC (src_handle)) == NULL)
- WIN32_GDI_FAILED ("GetDC"), ok = FALSE;
-
- if (ok && !BitBlt (hdc, xdest, ydest, width, height,
- srcdc, xsrc, ysrc, SRCCOPY))
- WIN32_GDI_FAILED ("BitBlt");
- if (ok && !ReleaseDC (src_handle, srcdc))
- WIN32_GDI_FAILED ("ReleaseDC");
+ for (i = 0; i < nsegs; i++)
+ {
+ const GdkSegment *ps = &segs[i];
+ const int x1 = ps->x1, y1 = ps->y1;
+ int x2 = ps->x2, y2 = ps->y2;
+
+ GDK_NOTE (MISC, g_print (" +%d+%d..+%d+%d", x1, y1, x2, y2));
+ GDI_CALL (MoveToEx, (hdc, x1, y1, NULL)) &&
+ GDI_CALL (LineTo, (hdc, x2, y2));
+ }
+
+ GDK_NOTE (MISC, g_print ("\n"));
}
- gdk_win32_hdc_release (drawable, gc, 0);
+ if (x_offset != 0 || y_offset != 0)
+ g_free (segs);
}
-void
-_gdk_win32_draw_tiles (GdkDrawable *drawable,
- GdkGC *gc,
- GdkPixmap *tile,
- gint x_from,
- gint y_from,
- gint max_width,
- gint max_height)
+static void
+gdk_win32_draw_segments (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkSegment *segs,
+ gint nsegs)
{
- gint x = x_from, y = y_from;
- gint tile_width, tile_height;
- gint width, height;
-
- gdk_drawable_get_size (drawable, &width, &height);
- gdk_drawable_get_size (tile, &tile_width, &tile_height);
+ GdkRectangle bounds;
+ GdkRegion *region;
+ gint i;
- width = MIN (width, max_width);
- height = MIN (height, max_height);
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %s %d segs\n",
+ _gdk_win32_drawable_description (drawable),
+ nsegs));
- tile_width = MIN (tile_width, max_width);
- tile_height = MIN (tile_height, max_height);
+ bounds.x = G_MAXINT;
+ bounds.y = G_MAXINT;
+ bounds.width = 0;
+ bounds.height = 0;
- while (y < height)
+ for (i = 0; i < nsegs; i++)
{
- x = x_from;
- while (x < width)
- {
- gdk_win32_draw_drawable (drawable, gc, tile,
- x % tile_width, /* xsrc */
- y % tile_height, /* ysrc */
- x, y, /* dest */
- tile_width, tile_height);
- x += tile_width;
- }
- y += tile_height;
+ bounds.x = MIN (bounds.x, segs[i].x1);
+ bounds.x = MIN (bounds.x, segs[i].x2);
+ bounds.y = MIN (bounds.y, segs[i].y1);
+ bounds.y = MIN (bounds.y, segs[i].y2);
}
-}
-static void
-gdk_win32_draw_points (GdkDrawable *drawable,
- GdkGC *gc,
- GdkPoint *points,
- gint npoints)
-{
- HDC hdc;
- COLORREF fg;
- GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
- GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
- int i;
-
- hdc = gdk_win32_hdc_get (drawable, gc, 0);
-
- fg = _gdk_win32_colormap_color (impl->colormap, gc_private->foreground);
+ for (i = 0; i < nsegs; i++)
+ {
+ bounds.width = MAX (bounds.width, segs[i].x1 - bounds.x);
+ bounds.width = MAX (bounds.width, segs[i].x2 - bounds.x);
+ bounds.height = MAX (bounds.height, segs[i].y1 - bounds.y);
+ bounds.height = MAX (bounds.height, segs[i].y2 - bounds.y);
+ }
- GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x %dx%.06x\n",
- (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle,
- npoints, (guint) fg));
+ region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
- for (i = 0; i < npoints; i++)
- SetPixel (hdc, points[i].x, points[i].y, fg);
+ generic_draw (drawable, gc, GDK_GC_FOREGROUND | LINE_ATTRIBUTES,
+ draw_segments, region, segs, nsegs);
- gdk_win32_hdc_release (drawable, gc, 0);
+ gdk_region_destroy (region);
}
static void
-gdk_win32_draw_segments (GdkDrawable *drawable,
- GdkGC *gc,
- GdkSegment *segs,
- gint nsegs)
+draw_lines (GdkGCWin32 *gcwin32,
+ HDC hdc,
+ gint x_offset,
+ gint y_offset,
+ va_list args)
{
- GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
- const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
- HDC hdc;
- gboolean ok = TRUE;
- int i;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %#x nsegs: %d\n",
- (guint) GDK_DRAWABLE_IMPL_WIN32 (drawable)->handle, nsegs));
-
- hdc = gdk_win32_hdc_get (drawable, gc, mask);
+ POINT *pts;
+ gint npoints;
+ gint i;
- if (gc_private->fill_style == GDK_OPAQUE_STIPPLED)
- {
- if (!BeginPath (hdc))
- WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
-
- for (i = 0; ok && i < nsegs; i++)
- {
- if (ok && !MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
- WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
- if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
- WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
-
- /* Draw end pixel */
- if (ok && gc_private->pen_width <= 1)
- if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
- WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
- }
+ pts = va_arg (args, POINT *);
+ npoints = va_arg (args, gint);
- if (ok && !EndPath (hdc))
- WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
-
- if (ok && !WidenPath (hdc))
- WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
-
- if (ok && !FillPath (hdc))
- WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
- }
- else
+ if (x_offset != 0 || y_offset != 0)
+ for (i = 0; i < npoints; i++)
+ {
+ pts[i].x -= x_offset;
+ pts[i].y -= y_offset;
+ }
+
+ if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
{
- const gboolean maybe_patblt =
- gc_private->rop2 == R2_COPYPEN &&
- gc_private->pen_width <= 1 &&
- (gc_private->pen_style & PS_STYLE_MASK) == PS_SOLID;
-
- for (i = 0; ok && i < nsegs; i++)
- {
- /* PatBlt() is much faster than LineTo(), says
- * jpe@archaeopteryx.com. Hmm. Use it if we have a solid
- * colour pen, then we know that the brush is also solid and
- * of the same colour.
- */
- if (maybe_patblt && segs[i].x1 == segs[i].x2)
- {
+ for (i = 0; i < npoints - 1; i++)
+ {
+ if (pts[i].x == pts[i+1].x)
+ {
int y1, y2;
-
- if (segs[i].y1 <= segs[i].y2)
- y1 = segs[i].y1, y2 = segs[i].y2;
+ if (pts[i].y > pts[i+1].y)
+ y1 = pts[i+1].y, y2 = pts[i].y;
else
- y1 = segs[i].y2, y2 = segs[i].y1;
-
- if (!PatBlt (hdc, segs[i].x1, y1,
- 1, y2 - y1 + 1, PATCOPY))
- WIN32_GDI_FAILED ("PatBlt"), ok = FALSE;
- }
- else if (maybe_patblt && segs[i].y1 == segs[i].y2)
- {
+ y1 = pts[i].y, y2 = pts[i+1].y;
+
+ render_line_vertical (gcwin32, pts[i].x, y1, y2);
+ }
+ else if (pts[i].y == pts[i+1].y)
+ {
int x1, x2;
-
- if (segs[i].x1 <= segs[i].x2)
- x1 = segs[i].x1, x2 = segs[i].x2;
+ if (pts[i].x > pts[i+1].x)
+ x1 = pts[i+1].x, x2 = pts[i].x;
else
- x1 = segs[i].x2, x2 = segs[i].x1;
+ x1 = pts[i].x, x2 = pts[i+1].x;
- if (!PatBlt (hdc, x1, segs[i].y1,
- x2 - x1 + 1, 1, PATCOPY))
- WIN32_GDI_FAILED ("PatBlt"), ok = FALSE;
- }
- else
- {
- if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
- WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
- if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
- WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
-
- /* Draw end pixel */
- if (ok && gc_private->pen_width <= 1)
- if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
- WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
- }
+ render_line_horizontal (gcwin32, x1, x2, pts[i].y);
+ }
+ else
+ GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
+ GDI_CALL (LineTo, (hdc, pts[i+1].x, pts[i+1].y));
}
}
- gdk_win32_hdc_release (drawable, gc, mask);
+ else
+ GDI_CALL (Polyline, (hdc, pts, npoints));
}
static void
GdkPoint *points,
gint npoints)
{
- GdkGCWin32 *gc_private = GDK_GC_WIN32 (gc);
- const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND;
- HDC hdc;
+ GdkRectangle bounds;
+ GdkRegion *region;
POINT *pts;
int i;
- gboolean ok = TRUE;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_lines: %s %d points\n",
+ _gdk_win32_drawable_description (drawable),
+ npoints));
if (npoints < 2)
return;
- hdc = gdk_win32_hdc_get (drawable, gc, mask);
+ bounds.x = G_MAXINT;
+ bounds.y = G_MAXINT;
+ bounds.width = 0;
+ bounds.height = 0;
pts = g_new (POINT, npoints);
for (i = 0; i < npoints; i++)
{
+ bounds.x = MIN (bounds.x, points[i].x);
+ bounds.y = MIN (bounds.y, points[i].y);
pts[i].x = points[i].x;
pts[i].y = points[i].y;
}
-
- if (!Polyline (hdc, pts, npoints))
- WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
-
+
+ for (i = 0; i < npoints; i++)
+ {
+ bounds.width = MAX (bounds.width, points[i].x - bounds.x);
+ bounds.height = MAX (bounds.height, points[i].y - bounds.y);
+ }
+
+ region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+ generic_draw (drawable, gc, GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
+ LINE_ATTRIBUTES,
+ draw_lines, region, pts, npoints);
+
+ gdk_region_destroy (region);
g_free (pts);
+}
+
+static void
+blit_from_pixmap (gboolean use_fg_bg,
+ GdkDrawableImplWin32 *dest,
+ HDC hdc,
+ GdkPixmapImplWin32 *src,
+ GdkGC *gc,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height)
+{
+ GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
+ HDC srcdc;
+ HBITMAP holdbitmap;
+ RGBQUAD oldtable[256], newtable[256];
+ COLORREF bg, fg;
+
+ gint newtable_size = 0, oldtable_size = 0;
+ gboolean ok = TRUE;
- /* Draw end pixel */
- if (ok && gc_private->pen_width <= 1)
+ GDK_NOTE (MISC, g_print ("blit_from_pixmap\n"));
+
+ srcdc = _gdk_win32_drawable_acquire_dc (GDK_DRAWABLE (src));
+ if (!srcdc)
+ return;
+
+ if (!(holdbitmap = SelectObject (srcdc, ((GdkDrawableImplWin32 *) src)->handle)))
+ WIN32_GDI_FAILED ("SelectObject");
+ else
{
- MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
- if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
- WIN32_GDI_FAILED ("LineTo");
+ if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth <= 8)
+ {
+ /* Blitting from a 1, 4 or 8-bit pixmap */
+
+ if ((oldtable_size = GetDIBColorTable (srcdc, 0, 256, oldtable)) == 0)
+ WIN32_GDI_FAILED ("GetDIBColorTable");
+ else if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth == 1)
+ {
+ /* Blitting from an 1-bit pixmap */
+
+ gint bgix, fgix;
+
+ if (use_fg_bg)
+ {
+ bgix = _gdk_gc_get_bg_pixel (gc);
+ fgix = _gdk_gc_get_fg_pixel (gc);
+ }
+ else
+ {
+ bgix = 0;
+ fgix = 1;
+ }
+
+ if (GDK_IS_PIXMAP_IMPL_WIN32 (dest) &&
+ GDK_PIXMAP_OBJECT (dest->wrapper)->depth <= 8)
+ {
+ /* Destination is also pixmap, get fg and bg from
+ * its palette. Either use the foreground and
+ * background pixel values in the GC (only in the
+ * case of gdk_image_put(), cf. XPutImage()), or 0
+ * and 1 to index the palette.
+ */
+ if (!GDI_CALL (GetDIBColorTable, (hdc, bgix, 1, newtable)) ||
+ !GDI_CALL (GetDIBColorTable, (hdc, fgix, 1, newtable+1)))
+ ok = FALSE;
+ }
+ else
+ {
+ /* Destination is a window, get fg and bg from its
+ * colormap
+ */
+
+ bg = _gdk_win32_colormap_color (dest->colormap, bgix);
+ fg = _gdk_win32_colormap_color (dest->colormap, fgix);
+ newtable[0].rgbBlue = GetBValue (bg);
+ newtable[0].rgbGreen = GetGValue (bg);
+ newtable[0].rgbRed = GetRValue (bg);
+ newtable[0].rgbReserved = 0;
+ newtable[1].rgbBlue = GetBValue (fg);
+ newtable[1].rgbGreen = GetGValue (fg);
+ newtable[1].rgbRed = GetRValue (fg);
+ newtable[1].rgbReserved = 0;
+ }
+ if (ok)
+ GDK_NOTE (MISC, g_print ("bg: %02x %02x %02x "
+ "fg: %02x %02x %02x\n",
+ newtable[0].rgbRed,
+ newtable[0].rgbGreen,
+ newtable[0].rgbBlue,
+ newtable[1].rgbRed,
+ newtable[1].rgbGreen,
+ newtable[1].rgbBlue));
+ newtable_size = 2;
+ }
+ else if (GDK_IS_PIXMAP_IMPL_WIN32 (dest))
+ {
+ /* Destination is pixmap, get its color table */
+
+ if ((newtable_size = GetDIBColorTable (hdc, 0, 256, newtable)) == 0)
+ WIN32_GDI_FAILED ("GetDIBColorTable"), ok = FALSE;
+ }
+
+ /* If blitting between pixmaps, set source's color table */
+ if (ok && newtable_size > 0)
+ {
+ GDK_NOTE (MISC_OR_COLORMAP,
+ g_print ("blit_from_pixmap: set color table"
+ " hdc=%p count=%d\n",
+ srcdc, newtable_size));
+ if (!GDI_CALL (SetDIBColorTable, (srcdc, 0, newtable_size, newtable)))
+ ok = FALSE;
+ }
+ }
+
+ if (ok)
+ GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
+ srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
+
+ /* Restore source's color table if necessary */
+ if (ok && newtable_size > 0 && oldtable_size > 0)
+ {
+ GDK_NOTE (MISC_OR_COLORMAP,
+ g_print ("blit_from_pixmap: reset color table"
+ " hdc=%p count=%d\n",
+ srcdc, oldtable_size));
+ GDI_CALL (SetDIBColorTable, (srcdc, 0, oldtable_size, oldtable));
+ }
+
+ GDI_CALL (SelectObject, (srcdc, holdbitmap));
}
- gdk_win32_hdc_release (drawable, gc, mask);
+
+ _gdk_win32_drawable_release_dc (GDK_DRAWABLE (src));
+}
+
+static void
+blit_inside_drawable (HDC hdc,
+ GdkGCWin32 *gcwin32,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height)
+
+{
+ GDK_NOTE (MISC, g_print ("blit_inside_drawable\n"));
+
+ GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
+ hdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
}
static void
-gdk_win32_draw_glyphs (GdkDrawable *drawable,
- GdkGC *gc,
- PangoFont *font,
- gint x,
- gint y,
- PangoGlyphString *glyphs)
+blit_from_window (HDC hdc,
+ GdkGCWin32 *gcwin32,
+ GdkDrawableImplWin32 *src,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height)
+{
+ HDC srcdc;
+ HPALETTE holdpal = NULL;
+ GdkColormap *cmap = gdk_colormap_get_system ();
+
+ GDK_NOTE (MISC, g_print ("blit_from_window\n"));
+
+ if ((srcdc = GetDC (src->handle)) == NULL)
+ {
+ WIN32_GDI_FAILED ("GetDC");
+ return;
+ }
+
+ if (cmap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
+ cmap->visual->type == GDK_VISUAL_STATIC_COLOR)
+ {
+ gint k;
+
+ if (!(holdpal = SelectPalette (srcdc, GDK_WIN32_COLORMAP_DATA (cmap)->hpal, FALSE)))
+ WIN32_GDI_FAILED ("SelectPalette");
+ else if ((k = RealizePalette (srcdc)) == GDI_ERROR)
+ WIN32_GDI_FAILED ("RealizePalette");
+ else if (k > 0)
+ GDK_NOTE (MISC_OR_COLORMAP,
+ g_print ("blit_from_window: realized %d\n", k));
+ }
+
+ GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
+ srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
+
+ if (holdpal != NULL)
+ GDI_CALL (SelectPalette, (srcdc, holdpal, FALSE));
+
+ GDI_CALL (ReleaseDC, (src->handle, srcdc));
+}
+
+void
+_gdk_win32_blit (gboolean use_fg_bg,
+ GdkDrawableImplWin32 *draw_impl,
+ GdkGC *gc,
+ GdkDrawable *src,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height)
{
- const GdkGCValuesMask mask = GDK_GC_FOREGROUND;
HDC hdc;
+ HRGN src_rgn, draw_rgn, outside_rgn;
+ RECT r;
+ GdkDrawableImplWin32 *src_impl = NULL;
+ gint src_width, src_height;
+
+ GDK_NOTE (MISC, g_print ("_gdk_win32_blit: src:%s %dx%d@%+d%+d\n"
+ " dst:%s @%+d%+d use_fg_bg=%d\n",
+ _gdk_win32_drawable_description (src),
+ width, height, xsrc, ysrc,
+ _gdk_win32_drawable_description (&draw_impl->parent_instance),
+ xdest, ydest,
+ use_fg_bg));
- hdc = gdk_win32_hdc_get (drawable, gc, mask);
+ /* If blitting from the root window, take the multi-monitor offset
+ * into account.
+ */
+ if (src == ((GdkWindowObject *)_gdk_root)->impl)
+ {
+ GDK_NOTE (MISC, g_print ("... offsetting src coords\n"));
+ xsrc -= _gdk_offset_x;
+ ysrc -= _gdk_offset_y;
+ }
- /* HB: Maybe there should be a GDK_GC_PANGO flag for hdc_get */
- /* default write mode is transparent (leave background) */
- if (SetBkMode (hdc, TRANSPARENT) == 0)
- WIN32_GDI_FAILED ("SetBkMode");
+ if (GDK_IS_DRAWABLE_IMPL_WIN32 (src))
+ src_impl = (GdkDrawableImplWin32 *) src;
+ else if (GDK_IS_WINDOW (src))
+ src_impl = (GdkDrawableImplWin32 *) GDK_WINDOW_OBJECT (src)->impl;
+ else if (GDK_IS_PIXMAP (src))
+ src_impl = (GdkDrawableImplWin32 *) GDK_PIXMAP_OBJECT (src)->impl;
+ else
+ g_assert_not_reached ();
- if (GDI_ERROR == SetTextAlign (hdc, TA_LEFT|TA_BASELINE|TA_NOUPDATECP))
- WIN32_GDI_FAILED ("SetTextAlign");
+ hdc = gdk_win32_hdc_get (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
- pango_win32_render (hdc, font, glyphs, x, y);
+ gdk_drawable_get_size (src, &src_width, &src_height);
- gdk_win32_hdc_release (drawable, gc, mask);
+ if ((src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1)) == NULL)
+ WIN32_GDI_FAILED ("CreateRectRgn");
+ else if ((draw_rgn = CreateRectRgn (xsrc, ysrc,
+ xsrc + width + 1,
+ ysrc + height + 1)) == NULL)
+ WIN32_GDI_FAILED ("CreateRectRgn");
+ else
+ {
+ if (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl))
+ {
+ int comb;
+
+ /* If we are drawing on a window, calculate the region that is
+ * outside the source pixmap, and invalidate that, causing it to
+ * be cleared. Not completely sure whether this is always needed. XXX
+ */
+ SetRectEmpty (&r);
+ outside_rgn = CreateRectRgnIndirect (&r);
+
+ if ((comb = CombineRgn (outside_rgn,
+ draw_rgn, src_rgn,
+ RGN_DIFF)) == ERROR)
+ WIN32_GDI_FAILED ("CombineRgn");
+ else if (comb != NULLREGION)
+ {
+ OffsetRgn (outside_rgn, xdest, ydest);
+ GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
+ g_print ("... InvalidateRgn "
+ "bbox: %ldx%ld@%+ld%+ld\n",
+ r.right - r.left - 1, r.bottom - r.top - 1,
+ r.left, r.top)));
+ InvalidateRgn (draw_impl->handle, outside_rgn, TRUE);
+ }
+ GDI_CALL (DeleteObject, (outside_rgn));
+ }
+
+#if 1 /* Don't know if this is necessary XXX */
+ if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
+ g_warning ("gdk_win32_blit: CombineRgn returned a COMPLEXREGION");
+
+ GetRgnBox (draw_rgn, &r);
+ if (r.left != xsrc || r.top != ysrc ||
+ r.right != xsrc + width + 1 || r.bottom != ysrc + height + 1)
+ {
+ xdest += r.left - xsrc;
+ xsrc = r.left;
+ ydest += r.top - ysrc;
+ ysrc = r.top;
+ width = r.right - xsrc - 1;
+ height = r.bottom - ysrc - 1;
+
+ GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@%+d%+d, "
+ "dest: @%+d%+d\n",
+ width, height, xsrc, ysrc,
+ xdest, ydest));
+ }
+#endif
+
+ GDI_CALL (DeleteObject, (src_rgn));
+ GDI_CALL (DeleteObject, (draw_rgn));
+ }
+
+ if (draw_impl->handle == src_impl->handle)
+ blit_inside_drawable (hdc, GDK_GC_WIN32 (gc), xsrc, ysrc, xdest, ydest, width, height);
+ else if (GDK_IS_PIXMAP_IMPL_WIN32 (src_impl))
+ blit_from_pixmap (use_fg_bg, draw_impl, hdc,
+ (GdkPixmapImplWin32 *) src_impl, gc,
+ xsrc, ysrc, xdest, ydest, width, height);
+ else
+ blit_from_window (hdc, GDK_GC_WIN32 (gc), src_impl, xsrc, ysrc, xdest, ydest, width, height);
+ gdk_win32_hdc_release (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
}
static void
gint width,
gint height)
{
- GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
- GdkImagePrivateWin32 *image_private = IMAGE_PRIVATE_DATA (image);
- GdkColormapPrivateWin32 *colormap_private = (GdkColormapPrivateWin32 *) impl->colormap;
- HDC hdc, memdc;
- HGDIOBJ oldbitmap;
- DIBSECTION ds;
- static struct {
- BITMAPINFOHEADER bmiHeader;
- WORD bmiIndices[256];
- } bmi;
- static gboolean bmi_inited = FALSE;
- gboolean ok = TRUE;
- int i;
+ g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
- hdc = gdk_win32_hdc_get (drawable, gc, 0);
+ _gdk_win32_blit (TRUE, (GdkDrawableImplWin32 *) drawable,
+ gc, (GdkPixmap *) image->windowing_data,
+ xsrc, ysrc, xdest, ydest, width, height);
+}
- if (image->visual && image->visual->type == GDK_VISUAL_PSEUDO_COLOR &&
- colormap_private && colormap_private->xcolormap->rc_palette)
+/**
+ * _gdk_win32_drawable_acquire_dc
+ * @drawable: a Win32 #GdkDrawable implementation
+ *
+ * Gets a DC with the given drawable selected into
+ * it.
+ *
+ * Return value: The DC, on success. Otherwise
+ * %NULL. If this function succeeded
+ * _gdk_win32_drawable_release_dc() must be called
+ * release the DC when you are done using it.
+ **/
+HDC
+_gdk_win32_drawable_acquire_dc (GdkDrawable *drawable)
+{
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+
+ if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
+ GDK_WINDOW_DESTROYED (impl->wrapper))
+ return NULL;
+
+ if (!impl->hdc)
{
- if (!bmi_inited)
+ if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
{
- for (i = 0; i < 256; i++)
- bmi.bmiIndices[i] = i;
- bmi_inited = TRUE;
+ impl->hdc = CreateCompatibleDC (NULL);
+ if (!impl->hdc)
+ WIN32_GDI_FAILED ("CreateCompatibleDC");
+
+ if (impl->hdc)
+ {
+ impl->saved_dc_bitmap = SelectObject (impl->hdc,
+ impl->handle);
+ if (!impl->saved_dc_bitmap)
+ {
+ WIN32_GDI_FAILED ("CreateCompatibleDC");
+ DeleteDC (impl->hdc);
+ impl->hdc = NULL;
+ }
+ }
}
+ else
+ {
+ impl->hdc = GetDC (impl->handle);
+ if (!impl->hdc)
+ WIN32_GDI_FAILED ("GetDC");
+ }
+ }
- if (GetObject (image_private->hbitmap, sizeof (DIBSECTION),
- &ds) != sizeof (DIBSECTION))
- WIN32_GDI_FAILED ("GetObject"), ok = FALSE;
-#if 0
- g_print("xdest = %d, ydest = %d, xsrc = %d, ysrc = %d, width = %d, height = %d\n",
- xdest, ydest, xsrc, ysrc, width, height);
- g_print("bmWidth = %d, bmHeight = %d, bmBitsPixel = %d, bmBits = %p\n",
- ds.dsBm.bmWidth, ds.dsBm.bmHeight, ds.dsBm.bmBitsPixel, ds.dsBm.bmBits);
- g_print("biWidth = %d, biHeight = %d, biBitCount = %d, biClrUsed = %d\n",
- ds.dsBmih.biWidth, ds.dsBmih.biHeight, ds.dsBmih.biBitCount, ds.dsBmih.biClrUsed);
-#endif
- bmi.bmiHeader = ds.dsBmih;
- /* I have spent hours on getting the parameters to
- * SetDIBitsToDevice right. I wonder what drugs the guys in
- * Redmond were on when they designed this API.
- */
- if (ok && SetDIBitsToDevice (hdc,
- xdest, ydest,
- width, height,
- xsrc, (-ds.dsBmih.biHeight)-height-ysrc,
- 0, -ds.dsBmih.biHeight,
- ds.dsBm.bmBits,
- (CONST BITMAPINFO *) &bmi,
- DIB_PAL_COLORS) == 0)
- WIN32_GDI_FAILED ("SetDIBitsToDevice");
+ if (impl->hdc)
+ {
+ impl->hdc_count++;
+ return impl->hdc;
}
else
+ return NULL;
+}
+
+/**
+ * _gdk_win32_drawable_release_dc
+ * @drawable: a Win32 #GdkDrawable implementation
+ *
+ * Releases the reference count for the DC
+ * from _gdk_win32_drawable_acquire_dc()
+ **/
+void
+_gdk_win32_drawable_release_dc (GdkDrawable *drawable)
+{
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+
+ g_return_if_fail (impl->hdc_count > 0);
+
+ impl->hdc_count--;
+ if (impl->hdc_count == 0)
{
+ if (impl->saved_dc_bitmap)
+ {
+ GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
+ impl->saved_dc_bitmap = NULL;
+ }
+
+ if (impl->hdc)
+ {
+ GDI_CALL (DeleteDC, (impl->hdc));
+ impl->hdc = NULL;
+ }
+ }
+}
- if ((memdc = CreateCompatibleDC (hdc)) == NULL)
- WIN32_GDI_FAILED ("CreateCompatibleDC"), ok = FALSE;
+static void
+gdk_win32_cairo_surface_destroy (void *data)
+{
+ GdkDrawableImplWin32 *impl = data;
- if (ok && (oldbitmap = SelectObject (memdc, image_private->hbitmap)) == NULL)
- WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
+ _gdk_win32_drawable_release_dc (GDK_DRAWABLE (impl));
+ impl->cairo_surface = NULL;
+}
- if (ok && !BitBlt (hdc, xdest, ydest, width, height,
- memdc, xsrc, ysrc, SRCCOPY))
- WIN32_GDI_FAILED ("BitBlt");
+static cairo_surface_t *
+gdk_win32_ref_cairo_surface (GdkDrawable *drawable)
+{
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
- if (oldbitmap != NULL && SelectObject (memdc, oldbitmap) == NULL)
- WIN32_GDI_FAILED ("SelectObject");
+ if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
+ GDK_WINDOW_DESTROYED (impl->wrapper))
+ return NULL;
- if (memdc != NULL && !DeleteDC (memdc))
- WIN32_GDI_FAILED ("DeleteDC");
+ if (!impl->cairo_surface)
+ {
+ HDC hdc = _gdk_win32_drawable_acquire_dc (drawable);
+ if (!hdc)
+ return NULL;
+
+ impl->cairo_surface = cairo_win32_surface_create (hdc);
+
+ cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
+ drawable, gdk_win32_cairo_surface_destroy);
}
- gdk_win32_hdc_release (drawable, gc, 0);
+ else
+ cairo_surface_reference (impl->cairo_surface);
+
+ return impl->cairo_surface;
}
static gint
return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
}
+static GdkScreen*
+gdk_win32_get_screen (GdkDrawable *drawable)
+{
+ return gdk_screen_get_default ();
+}
+
static GdkVisual*
gdk_win32_get_visual (GdkDrawable *drawable)
{
return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
}
-HWND
+HGDIOBJ
gdk_win32_drawable_get_handle (GdkDrawable *drawable)
{
- return GDK_DRAWABLE_HANDLE(drawable);
+ return GDK_DRAWABLE_HANDLE (drawable);
}
+
+/**
+ * _gdk_win32_drawable_finish
+ * @drawable: a Win32 #GdkDrawable implementation
+ *
+ * Releases any resources allocated internally for the drawable.
+ * This is called when the drawable becomes unusable
+ * (gdk_window_destroy() for a window, or the refcount going to
+ * zero for a pixmap.)
+ **/
+void
+_gdk_win32_drawable_finish (GdkDrawable *drawable)
+{
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+
+ if (impl->cairo_surface)
+ {
+ cairo_surface_finish (impl->cairo_surface);
+ cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
+ NULL, NULL);
+ }
+
+ g_assert (impl->hdc_count == 0);
+}
+