]> Pileus Git - ~andy/gtk/blobdiff - gdk/win32/gdkdrawable-win32.c
Rename from blit_inside_window(), as it now does blitting inside a bitmap,
[~andy/gtk] / gdk / win32 / gdkdrawable-win32.c
index 5f7b472000500f044d1ed0c21ab51641b2cd12cc..31d6a4195752e11333a5862862647aca79173540 100644 (file)
@@ -1,7 +1,7 @@
 /* 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-2004 Hans Breuer
+ * 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
@@ -32,6 +32,7 @@
 #include <glib.h>
 
 #include <pango/pangowin32.h>
+#include <cairo-win32.h>
 
 #include "gdkscreen.h" /* gdk_screen_get_default() */
 #include "gdkregion-generic.h"
 #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,
                                      gboolean        filled,
@@ -100,19 +107,6 @@ static void gdk_win32_draw_lines     (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_glyphs_transformed (GdkDrawable      *drawable,
-                                            GdkGC            *gc,
-                                            PangoMatrix      *matrix,
-                                            PangoFont        *font,
-                                            gint              x,
-                                            gint              y,
-                                            PangoGlyphString *glyphs);
 static void gdk_win32_draw_image     (GdkDrawable     *drawable,
                                      GdkGC           *gc,
                                      GdkImage        *image,
@@ -123,6 +117,8 @@ static void gdk_win32_draw_image     (GdkDrawable     *drawable,
                                      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);
 
@@ -139,6 +135,7 @@ 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)
@@ -188,10 +185,10 @@ gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass)
   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_glyphs_transformed = gdk_win32_draw_glyphs_transformed;
   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;
 
@@ -239,62 +236,188 @@ gdk_win32_set_colormap (GdkDrawable *drawable,
 /* Drawing
  */
 
-/*
- * Render a dashed line 'by hand' cause the Win9x GDI is 
- * too limited to do so
+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 (HDC    hdc,
-                        int    x1, 
-                        int    x2,
-                        int    y,
-                        int    pen_width,
-                        DWORD *dashes,
-                        int    num_dashes)
+render_line_horizontal (GdkGCWin32 *gcwin32,
+                        int         x1,
+                        int         x2,
+                        int         y)
 {
-  int n;
+  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 = dashes[n % num_dashes];
+      int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
       if (x1 + len > x2)
         len = x2 - x1;
 
-      if (n % 2 == 0)
-        if (!GDI_CALL (PatBlt, (hdc, x1, y - pen_width / 2, 
+      if (n % 2 == 0 && x1 + len > _x1)
+        if (!GDI_CALL (PatBlt, (gcwin32->hdc, 
+                               x1 < _x1 ? _x1 : x1, 
+                               y - pen_width / 2, 
                                len, pen_width, 
-                               PATCOPY)))
+                               rop2_to_patblt_rop (gcwin32->rop2))))
          return FALSE;
 
-      x1 += dashes[n % num_dashes];
+      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 (HDC    hdc,
-                     int    x, 
-                      int    y1,
-                      int    y2,
-                      int    pen_width,
-                      DWORD *dashes,
-                     int    num_dashes)
+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 = dashes[n % num_dashes];
+      int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
       if (y1 + len > y2)
         len = y2 - y1;
-      if (n % 2 == 0)
-        if (!GDI_CALL (PatBlt, (hdc, x - pen_width / 2, 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, 
-                               PATCOPY)))
+                               rop2_to_patblt_rop (gcwin32->rop2))))
          return FALSE;
 
-      y1 += dashes[n % num_dashes];
+      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;
@@ -315,7 +438,7 @@ draw_tiles_lowlevel (HDC  dest,
 {
   gint x, y;
 
-  GDK_NOTE (MISC, g_print ("draw_tiles_lowlevel: %p +%d+%d tile=%p:%dx%d@+%d+%d %dx%d\n",
+  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,
@@ -387,34 +510,6 @@ draw_tiles (GdkDrawable *drawable,
   gdk_gc_unref (gc_copy);
 }
 
-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 void
 generic_draw (GdkDrawable    *drawable,
              GdkGC          *gc,
@@ -427,6 +522,7 @@ generic_draw (GdkDrawable    *drawable,
   GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
   HDC hdc;
   va_list args;
+  GdkFill fill_style = _gdk_gc_get_fill (gc);
 
   va_start (args, region);
 
@@ -434,14 +530,14 @@ generic_draw (GdkDrawable    *drawable,
    */
 
   if (gcwin32->values_mask & GDK_GC_FILL &&
-      ((gcwin32->fill_style == GDK_TILED &&
+      ((fill_style == GDK_TILED &&
        gcwin32->values_mask & GDK_GC_TILE &&
-       gcwin32->tile != NULL)
+       _gdk_gc_get_tile (gc) != NULL)
        ||
-       ((gcwin32->fill_style == GDK_OPAQUE_STIPPLED ||
-        gcwin32->fill_style == GDK_STIPPLED) &&
+       ((fill_style == GDK_OPAQUE_STIPPLED ||
+        fill_style == GDK_STIPPLED) &&
        gcwin32->values_mask & GDK_GC_STIPPLE &&
-       gcwin32->stipple != NULL)))
+       _gdk_gc_get_stipple (gc) != NULL)))
     {
       const GdkGCValuesMask blitting_mask = 0;
       GdkGCValuesMask drawing_mask = GDK_GC_FOREGROUND;
@@ -516,11 +612,11 @@ generic_draw (GdkDrawable    *drawable,
                   region->extents.x1, region->extents.y1, args);
       gdk_win32_hdc_release (mask_pixmap, mask_gc, drawing_mask);
 
-      if (gcwin32->fill_style == GDK_TILED)
+      if (fill_style == GDK_TILED)
        {
          /* Tile pixmap with tile */
          draw_tiles (tile_pixmap, tile_gc, SRCCOPY,
-                     gcwin32->tile,
+                     _gdk_gc_get_tile (gc),
                      0, 0, ts_x_origin, ts_y_origin,
                      width, height);
        }
@@ -534,14 +630,14 @@ generic_draw (GdkDrawable    *drawable,
 
          /* Tile stipple bitmap */
          draw_tiles (stipple_bitmap, stipple_gc, SRCCOPY,
-                     gcwin32->stipple,
+                     _gdk_gc_get_stipple (gc),
                      0, 0, ts_x_origin, ts_y_origin,
                      width, height);
 
-         if (gcwin32->fill_style == GDK_OPAQUE_STIPPLED)
+         if (fill_style == GDK_OPAQUE_STIPPLED)
            {
              /* Fill tile pixmap with background */
-             fg.pixel = gcwin32->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);
@@ -560,8 +656,8 @@ generic_draw (GdkDrawable    *drawable,
       if ((old_tile_hbm = SelectObject (tile_hdc, GDK_PIXMAP_HBITMAP (tile_pixmap))) == NULL)
        WIN32_GDI_FAILED ("SelectObject");
 
-      if (gcwin32->fill_style == GDK_STIPPLED ||
-         gcwin32->fill_style == GDK_OPAQUE_STIPPLED)
+      if (fill_style == GDK_STIPPLED ||
+         fill_style == GDK_OPAQUE_STIPPLED)
        {
          HDC stipple_hdc;
          HGDIOBJ old_stipple_hbm;
@@ -578,7 +674,7 @@ generic_draw (GdkDrawable    *drawable,
 
          if ((fg_brush = CreateSolidBrush
               (_gdk_win32_colormap_color (impl->colormap,
-                                          gcwin32->foreground))) == NULL)
+                                          _gdk_gc_get_fg_pixel (gc)))) == NULL)
            WIN32_GDI_FAILED ("CreateSolidBrush");
 
          if ((old_tile_brush = SelectObject (tile_hdc, fg_brush)) == NULL)
@@ -603,7 +699,7 @@ generic_draw (GdkDrawable    *drawable,
          GDI_CALL (BitBlt, (tile_hdc, 0, 0, width, height,
                             stipple_hdc, 0, 0, ROP3_DSPDxax));
 
-         if (gcwin32->fill_style == GDK_STIPPLED)
+         if (fill_style == GDK_STIPPLED)
            {
              /* Punch holes in mask where stipple is zero */
              GDI_CALL (BitBlt, (mask_hdc, 0, 0, width, height,
@@ -736,24 +832,12 @@ draw_rectangle (GdkGCWin32 *gcwin32,
   x -= x_offset;
   y -= y_offset;
 
-  if (!filled && gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ())
+  if (!filled && MUST_RENDER_DASHES_MANUALLY (gcwin32))
     {
-      render_line_vertical (hdc, x, y, y+height+1,
-                           gcwin32->pen_width,
-                           gcwin32->pen_dashes,
-                           gcwin32->pen_num_dashes) &&
-      render_line_horizontal (hdc, x, x+width+1, y,
-                             gcwin32->pen_width,
-                             gcwin32->pen_dashes,
-                             gcwin32->pen_num_dashes) &&
-      render_line_vertical (hdc, x+width+1, y, y+height+1,
-                           gcwin32->pen_width,
-                           gcwin32->pen_dashes,
-                           gcwin32->pen_num_dashes) &&
-      render_line_horizontal (hdc, x, x+width+1, y+height+1,
-                             gcwin32->pen_width,
-                             gcwin32->pen_dashes,
-                             gcwin32->pen_num_dashes);
+      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
     {
@@ -783,7 +867,7 @@ gdk_win32_draw_rectangle (GdkDrawable *drawable,
   GdkRectangle bounds;
   GdkRegion *region;
 
-  GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %s (%p) %s%dx%d@+%d+%d\n",
+  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 " : ""),
@@ -796,7 +880,8 @@ gdk_win32_draw_rectangle (GdkDrawable *drawable,
   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
 
   generic_draw (drawable, gc,
-               GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
+               GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
+               (filled ? 0 : LINE_ATTRIBUTES),
                draw_rectangle, region, filled, x, y, width, height);
 
   gdk_region_destroy (region);
@@ -849,20 +934,18 @@ draw_arc (GdkGCWin32 *gcwin32,
   if (filled)
     {
       old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
-      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));
+      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));
+      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));
     }
@@ -1196,7 +1279,7 @@ draw_segments (GdkGCWin32 *gcwin32,
         }
     }
 
-  if (gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ())
+  if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
     {
       for (i = 0; i < nsegs; i++)
        {
@@ -1209,11 +1292,7 @@ draw_segments (GdkGCWin32 *gcwin32,
              else
                y1 = segs[i].y2, y2 = segs[i].y1;
              
-             render_line_vertical (hdc,
-                                   segs[i].x1, y1, y2,
-                                   gcwin32->pen_width,
-                                   gcwin32->pen_dashes,
-                                   gcwin32->pen_num_dashes);
+             render_line_vertical (gcwin32, segs[i].x1, y1, y2);
            }
          else if (segs[i].y1 == segs[i].y2)
            {
@@ -1224,51 +1303,27 @@ draw_segments (GdkGCWin32 *gcwin32,
              else
                x1 = segs[i].x2, x2 = segs[i].x1;
              
-             render_line_horizontal (hdc,
-                                     x1, x2, segs[i].y1,
-                                     gcwin32->pen_width,
-                                     gcwin32->pen_dashes,
-                                     gcwin32->pen_num_dashes);
+             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
     {
       for (i = 0; i < nsegs; i++)
-       GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
-         GDI_CALL (LineTo, (hdc, segs[i].x2, segs[i].y2));
-
-      /* not drawing the end pixel does produce a crippled mask, look 
-       * e.g. at xpm icons produced with gdk_pixbuf_new_from_xpm_data trough
-       * gdk_pixbuf_render_threshold_alpha (testgtk folder icon or
-       * Dia's toolbox icons) but only on win9x ... --hb
-       *
-       * Update : see bug #81895 and bug #126710 why this is finally
-       *          needed on any win32 platform ;-)
-       */
-      if (gcwin32->pen_width <= 1)
-        {
-          GdkSegment *ps = &segs[nsegs-1];
-          int xc = 0, yc = 0;
-
-          if (ps->y2 == ps->y1 && ps->x2 == ps->x1)
-            xc = 1; /* just a point */
-          else if (ps->y2 == ps->y1)
-            xc = (ps->x1 < ps->x2) ? 1 : -1; /* advance x only */
-          else if (ps->x2 == ps->x1)
-            yc = (ps->y1 < ps->y2) ? 1 : -1; /* advance y only */
-          else
-            {
-              xc = (ps->x1 < ps->x2) ? 1 : -1;
-              yc = (ps->y1 < ps->y2) ? 1 : -1;
-            }
-
-          GDI_CALL (LineTo, (hdc, ps->x2 + xc, ps->y2 + yc));
-        }
+       {
+         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"));
     }
   if (x_offset != 0 || y_offset != 0)
     g_free (segs);
@@ -1311,7 +1366,7 @@ gdk_win32_draw_segments (GdkDrawable *drawable,
 
   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
 
-  generic_draw (drawable, gc, GDK_GC_FOREGROUND|LINE_ATTRIBUTES,
+  generic_draw (drawable, gc, GDK_GC_FOREGROUND | LINE_ATTRIBUTES,
                draw_segments, region, segs, nsegs);
 
   gdk_region_destroy (region);
@@ -1338,7 +1393,7 @@ draw_lines (GdkGCWin32 *gcwin32,
        pts[i].y -= y_offset;
       }
   
-  if (gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ())
+  if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
     {
       for (i = 0; i < npoints - 1; i++)
         {
@@ -1350,10 +1405,7 @@ draw_lines (GdkGCWin32 *gcwin32,
              else
                y1 = pts[i].y, y2 = pts[i+1].y;
              
-             render_line_vertical (hdc, pts[i].x, y1, y2,
-                                   gcwin32->pen_width,
-                                   gcwin32->pen_dashes,
-                                   gcwin32->pen_num_dashes);
+             render_line_vertical (gcwin32, pts[i].x, y1, y2);
            }
          else if (pts[i].y == pts[i+1].y)
            {
@@ -1363,10 +1415,7 @@ draw_lines (GdkGCWin32 *gcwin32,
              else
                x1 = pts[i].x, x2 = pts[i+1].x;
 
-             render_line_horizontal (hdc, x1, x2, pts[i].y,
-                                     gcwin32->pen_width,
-                                     gcwin32->pen_dashes,
-                                     gcwin32->pen_num_dashes);
+             render_line_horizontal (gcwin32, x1, x2, pts[i].y);
            }
          else
            GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
@@ -1418,134 +1467,20 @@ gdk_win32_draw_lines (GdkDrawable *drawable,
 
   region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
 
-  generic_draw (drawable, gc, GDK_GC_FOREGROUND|LINE_ATTRIBUTES,
+  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
-draw_glyphs (GdkGCWin32 *gcwin32,
-            HDC         hdc,
-            gint        x_offset,
-            gint        y_offset,
-            va_list     args)
-{
-  PangoFont *font;
-  gint x;
-  gint y;
-  PangoGlyphString *glyphs;
-
-  font = va_arg (args, PangoFont *);
-  x = va_arg (args, gint);
-  y = va_arg (args, gint);
-  glyphs = va_arg (args, PangoGlyphString *);
-
-  x -= x_offset;
-  y -= y_offset;
-
-  pango_win32_render (hdc, font, glyphs, x, y);
-}
-
-static void
-draw_glyphs_transformed (GdkGCWin32 *gcwin32,
-                        HDC         hdc,
-                        gint        x_offset,
-                        gint        y_offset,
-                        va_list     args)
-{
-  PangoFont *font;
-  gint x;
-  gint y;
-  PangoGlyphString *glyphs;
-  PangoMatrix *matrix;
-
-  matrix = va_arg(args, PangoMatrix *);
-  font = va_arg (args, PangoFont *);
-  x = va_arg (args, gint);
-  y = va_arg (args, gint);
-  glyphs = va_arg (args, PangoGlyphString *);
-
-  x -= x_offset;
-  y -= y_offset;
-
-  pango_win32_render_transformed (hdc, matrix, font, glyphs, x, y);
-}
-
-static void
-gdk_win32_draw_glyphs (GdkDrawable      *drawable,
-                      GdkGC            *gc,
-                      PangoFont        *font,
-                      gint              x,
-                      gint              y,
-                      PangoGlyphString *glyphs)
-{
-  GdkRectangle bounds;
-  GdkRegion *region;
-  PangoRectangle ink_rect;
-
-  pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
-
-  bounds.x = x + PANGO_PIXELS (ink_rect.x) - 1;
-  bounds.y = y + PANGO_PIXELS (ink_rect.y) - 1;
-  bounds.width = PANGO_PIXELS (ink_rect.width) + 2;
-  bounds.height = PANGO_PIXELS (ink_rect.height) + 2;
-  region = gdk_region_rectangle (&bounds);
-  
-  generic_draw (drawable, gc, GDK_GC_FOREGROUND|GDK_GC_FONT,
-               draw_glyphs, region, font, x, y, glyphs);
-
-  gdk_region_destroy (region);
-}
-
-static void 
-gdk_win32_draw_glyphs_transformed (GdkDrawable      *drawable,
-                                  GdkGC            *gc,
-                                  PangoMatrix      *matrix,
-                                  PangoFont        *font,
-                                  gint              x,
-                                  gint              y,
-                                  PangoGlyphString *glyphs)
-{
-  GdkRectangle bounds;
-  GdkRegion *region;
-  PangoRectangle ink_rect;
-
-  pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
-
-  bounds.x = x + PANGO_PIXELS (ink_rect.x) - 1;
-  bounds.y = y + PANGO_PIXELS (ink_rect.y) - 1;
-  bounds.width = PANGO_PIXELS (ink_rect.width) + 2;
-  bounds.height = PANGO_PIXELS (ink_rect.height) + 2;
-  region = gdk_region_rectangle (&bounds);
-
-  if (matrix)
-    {
-      /* transform region */
-      bounds.x = bounds.x * matrix->xx + bounds.y * matrix->xy + matrix->x0;
-      bounds.y = bounds.x * matrix->yx + bounds.y * matrix->yy + matrix->x0;
-      bounds.width  = bounds.width  * matrix->xx + bounds.height * matrix->xy;
-      bounds.height = bounds.height * matrix->yx + bounds.width  * matrix->xy;
-      generic_draw (drawable, gc, GDK_GC_FOREGROUND|GDK_GC_FONT,
-                   draw_glyphs_transformed, region, matrix, font, x, y, glyphs);
-    }
-  else
-    { 
-       generic_draw (drawable, gc, GDK_GC_FOREGROUND|GDK_GC_FONT,
-                    draw_glyphs, region, font, x/PANGO_SCALE, y/PANGO_SCALE, glyphs);
-    }
-
-  gdk_region_destroy (region);
-}
-
 static void
 blit_from_pixmap (gboolean              use_fg_bg,
                  GdkDrawableImplWin32 *dest,
                  HDC                   hdc,
                  GdkPixmapImplWin32   *src,
-                 GdkGCWin32           *gcwin32,
+                 GdkGC                *gc,
                  gint                  xsrc,
                  gint                  ysrc,
                  gint                  xdest,
@@ -1553,6 +1488,7 @@ blit_from_pixmap (gboolean              use_fg_bg,
                  gint                  width,
                  gint                  height)
 {
+  GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
   HDC srcdc;
   HBITMAP holdbitmap;
   RGBQUAD oldtable[256], newtable[256];
@@ -1563,12 +1499,10 @@ blit_from_pixmap (gboolean              use_fg_bg,
   
   GDK_NOTE (MISC, g_print ("blit_from_pixmap\n"));
 
-  if (!(srcdc = CreateCompatibleDC (NULL)))
-    {
-      WIN32_GDI_FAILED ("CreateCompatibleDC");
-      return;
-    }
-      
+  srcdc = _gdk_win32_drawable_acquire_dc (GDK_DRAWABLE (src));
+  if (!srcdc)
+    return;
+  
   if (!(holdbitmap = SelectObject (srcdc, ((GdkDrawableImplWin32 *) src)->handle)))
     WIN32_GDI_FAILED ("SelectObject");
   else
@@ -1587,8 +1521,8 @@ blit_from_pixmap (gboolean              use_fg_bg,
              
              if (use_fg_bg)
                {
-                 bgix = gcwin32->background;
-                 fgix = gcwin32->foreground;
+                 bgix = _gdk_gc_get_bg_pixel (gc);
+                 fgix = _gdk_gc_get_fg_pixel (gc);
                }
              else
                {
@@ -1673,21 +1607,22 @@ blit_from_pixmap (gboolean              use_fg_bg,
       
       GDI_CALL (SelectObject, (srcdc, holdbitmap));
     }
-  GDI_CALL (DeleteDC, (srcdc));
+  
+  _gdk_win32_drawable_release_dc (GDK_DRAWABLE (src));
 }
 
 static void
-blit_inside_window (HDC        hdc,
-                   GdkGCWin32 *gcwin32,
-                   gint        xsrc,
-                   gint        ysrc,
-                   gint        xdest,
-                   gint        ydest,
-                   gint        width,
-                   gint        height)
+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_window\n"));
+  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)));
@@ -1741,7 +1676,7 @@ blit_from_window (HDC                   hdc,
 
 void
 _gdk_win32_blit (gboolean              use_fg_bg,
-                GdkDrawableImplWin32 *drawable,
+                GdkDrawableImplWin32 *draw_impl,
                 GdkGC                *gc,
                 GdkDrawable          *src,
                 gint                  xsrc,
@@ -1754,19 +1689,26 @@ _gdk_win32_blit (gboolean              use_fg_bg,
   HDC hdc;
   HRGN src_rgn, draw_rgn, outside_rgn;
   RECT r;
-  GdkDrawableImplWin32 *draw_impl;
   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_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 ((GdkDrawable *) drawable),
+                          _gdk_win32_drawable_description (&draw_impl->parent_instance),
                           xdest, ydest,
                           use_fg_bg));
 
-  draw_impl = (GdkDrawableImplWin32 *) drawable;
+  /* 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;
+    }
 
   if (GDK_IS_DRAWABLE_IMPL_WIN32 (src))
     src_impl = (GdkDrawableImplWin32 *) src;
@@ -1777,7 +1719,7 @@ _gdk_win32_blit (gboolean              use_fg_bg,
   else
     g_assert_not_reached ();
 
-  hdc = gdk_win32_hdc_get ((GdkDrawable *) drawable, gc, GDK_GC_FOREGROUND);
+  hdc = gdk_win32_hdc_get (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
 
   gdk_drawable_get_size (src, &src_width, &src_height);
 
@@ -1808,8 +1750,8 @@ _gdk_win32_blit (gboolean              use_fg_bg,
            {
              OffsetRgn (outside_rgn, xdest, ydest);
              GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
-                              g_print ("...calling InvalidateRgn, "
-                                       "bbox: %ldx%ld@+%ld+%ld\n",
+                              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);
@@ -1832,8 +1774,8 @@ _gdk_win32_blit (gboolean              use_fg_bg,
          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",
+         GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@%+d%+d, "
+                                  "dest: @%+d%+d\n",
                                   width, height, xsrc, ysrc,
                                   xdest, ydest));
        }
@@ -1843,15 +1785,15 @@ _gdk_win32_blit (gboolean              use_fg_bg,
       GDI_CALL (DeleteObject, (draw_rgn));
     }
 
-  if (GDK_IS_PIXMAP_IMPL_WIN32 (src_impl))
+  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, GDK_GC_WIN32 (gc),
+                     (GdkPixmapImplWin32 *) src_impl, gc,
                      xsrc, ysrc, xdest, ydest, width, height);
-  else if (draw_impl->handle == src_impl->handle)
-    blit_inside_window (hdc, GDK_GC_WIN32 (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 ((GdkDrawable *) drawable, gc, GDK_GC_FOREGROUND);
+  gdk_win32_hdc_release (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
 }
 
 static void
@@ -1872,6 +1814,130 @@ gdk_win32_draw_image (GdkDrawable     *drawable,
                   xsrc, ysrc, xdest, ydest, width, height);
 }
 
+/**
+ * _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 (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
+       {
+         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 (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;
+       }
+    }
+}
+
+static void
+gdk_win32_cairo_surface_destroy (void *data)
+{
+  GdkDrawableImplWin32 *impl = data;
+
+  _gdk_win32_drawable_release_dc (GDK_DRAWABLE (impl));
+  impl->cairo_surface = NULL;
+}
+
+static cairo_surface_t *
+gdk_win32_ref_cairo_surface (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->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);
+    }
+  else
+    cairo_surface_reference (impl->cairo_surface);
+
+  return impl->cairo_surface;
+}
+
 static gint
 gdk_win32_get_depth (GdkDrawable *drawable)
 {
@@ -1898,14 +1964,27 @@ gdk_win32_drawable_get_handle (GdkDrawable *drawable)
   return GDK_DRAWABLE_HANDLE (drawable);
 }
 
-gboolean
-gdk_draw_rectangle_alpha_libgtk_only (GdkDrawable *drawable,
-                                     gint         x,
-                                     gint         y,
-                                     gint         width,
-                                     gint         height,
-                                     GdkColor    *color,
-                                     guint16      alpha)
+/**
+ * _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)
 {
-  return FALSE;
+  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);
 }
+