summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog54
-rw-r--r--ChangeLog.pre-2-1054
-rw-r--r--ChangeLog.pre-2-854
-rw-r--r--gdk/win32/gdkdrawable-win32.c248
-rw-r--r--gdk/win32/gdkgc-win32.c315
-rw-r--r--gdk/win32/gdkprivate-win32.h4
6 files changed, 431 insertions, 298 deletions
diff --git a/ChangeLog b/ChangeLog
index b7adf589f..d8fdbadf3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,57 @@
+2005-06-23 Tor Lillqvist <tml@novell.com>
+
+ Improve and simplify line segment rendering on Win32, especially
+ the implementation of GDK_CAP_NOT_LAST, and dashed lines. Fixes
+ bug #306396.
+
+ * gdk/win32/gdkprivate-win32.h (GdkGCWin32): Save the GdkGC's
+ line_style, cap_style and join_style as such in the
+ GdkGCWin32. Don't need to keep the pen_double_dash flag, we can
+ check the line_style.
+
+ * gdk/win32/gdkgc-win32.c (fixup_pen): New internal function. Sets
+ up the GDI pen type, style, end cap and join attributes to use
+ based on the pen width, GDK line style, end cap style, and join
+ style.
+
+ For a narrow (zero-width) GDK pen with the GDK_CAP_NOT_LAST end
+ cap style, which typically are used for XOR drawing where it is
+ essential that the last pixel is not drawn, use a GDI cosmetic
+ pen. Only for a cosmetic pen does GDI not draw the last pixel. I
+ deduced this by experimetation, the documentation is rather vague.
+
+ For other GDK pens use a geometric GDI pen. If the width is 0 or 1
+ and the GDK end cap style is GDK_CAP_BUTT, and the line style is
+ GDK_LINE_SOLID, use PS_ENDCAP_ROUND. This ensures that also
+ single-pixel length lines are drawn. (For sngle-pixel width lines
+ roundness as such is of course irrelevant.) For dashed lines, use
+ PS_ENDCAP_FLAT.
+
+ For wide lines use PS_ENDCAP_FLAT, _ROUND or _SQUARE,
+ respectively, for GDK_CAP_BUTT, GDK_CAP_ROUND and GDK_CAP_PROJECTING.
+
+ For one pixel on-off dashed lines, use PS_ALTERNATE, it seems to
+ work better than PS_USERSTYLE. For other dashed lines, use
+ PS_USERSTYLE and the dashes as set by the user (or the default
+ four-pixel on-off style).
+
+ (gdk_win32_gc_values_to_win32values, gdk_win32_gc_set_dashes):
+ Call fixup_pen() to do the pen settings after modifying some of
+ the GDK GC attributes that affect pens.
+
+ * gdk/win32/gdkdrawable-win32.c (render_line_horizontal,
+ render_line_vertical, draw_segments): Check GdkGCWin32::line_style
+ instead of the the removed pen_double_dash member. Don't use
+ PATCOPY unconditionally in the PatBlt() call, use a raster ope
+ code that depends on the GC function in use.
+
+ (draw_rectangle, draw_segments, draw_lines): Be more careful in
+ deciding when to do the manual dash rendering.
+
+ (draw_segments): Don't do any manual "last point" drawing at
+ all. The above changes takes care of narrow line segments being
+ drawn correctly in most cases, at least on NT-based Windows.
+
2005-06-23 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkfilesystemunix.c (gtk_file_system_unix_get_folder):
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index b7adf589f..d8fdbadf3 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,57 @@
+2005-06-23 Tor Lillqvist <tml@novell.com>
+
+ Improve and simplify line segment rendering on Win32, especially
+ the implementation of GDK_CAP_NOT_LAST, and dashed lines. Fixes
+ bug #306396.
+
+ * gdk/win32/gdkprivate-win32.h (GdkGCWin32): Save the GdkGC's
+ line_style, cap_style and join_style as such in the
+ GdkGCWin32. Don't need to keep the pen_double_dash flag, we can
+ check the line_style.
+
+ * gdk/win32/gdkgc-win32.c (fixup_pen): New internal function. Sets
+ up the GDI pen type, style, end cap and join attributes to use
+ based on the pen width, GDK line style, end cap style, and join
+ style.
+
+ For a narrow (zero-width) GDK pen with the GDK_CAP_NOT_LAST end
+ cap style, which typically are used for XOR drawing where it is
+ essential that the last pixel is not drawn, use a GDI cosmetic
+ pen. Only for a cosmetic pen does GDI not draw the last pixel. I
+ deduced this by experimetation, the documentation is rather vague.
+
+ For other GDK pens use a geometric GDI pen. If the width is 0 or 1
+ and the GDK end cap style is GDK_CAP_BUTT, and the line style is
+ GDK_LINE_SOLID, use PS_ENDCAP_ROUND. This ensures that also
+ single-pixel length lines are drawn. (For sngle-pixel width lines
+ roundness as such is of course irrelevant.) For dashed lines, use
+ PS_ENDCAP_FLAT.
+
+ For wide lines use PS_ENDCAP_FLAT, _ROUND or _SQUARE,
+ respectively, for GDK_CAP_BUTT, GDK_CAP_ROUND and GDK_CAP_PROJECTING.
+
+ For one pixel on-off dashed lines, use PS_ALTERNATE, it seems to
+ work better than PS_USERSTYLE. For other dashed lines, use
+ PS_USERSTYLE and the dashes as set by the user (or the default
+ four-pixel on-off style).
+
+ (gdk_win32_gc_values_to_win32values, gdk_win32_gc_set_dashes):
+ Call fixup_pen() to do the pen settings after modifying some of
+ the GDK GC attributes that affect pens.
+
+ * gdk/win32/gdkdrawable-win32.c (render_line_horizontal,
+ render_line_vertical, draw_segments): Check GdkGCWin32::line_style
+ instead of the the removed pen_double_dash member. Don't use
+ PATCOPY unconditionally in the PatBlt() call, use a raster ope
+ code that depends on the GC function in use.
+
+ (draw_rectangle, draw_segments, draw_lines): Be more careful in
+ deciding when to do the manual dash rendering.
+
+ (draw_segments): Don't do any manual "last point" drawing at
+ all. The above changes takes care of narrow line segments being
+ drawn correctly in most cases, at least on NT-based Windows.
+
2005-06-23 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkfilesystemunix.c (gtk_file_system_unix_get_folder):
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index b7adf589f..d8fdbadf3 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,57 @@
+2005-06-23 Tor Lillqvist <tml@novell.com>
+
+ Improve and simplify line segment rendering on Win32, especially
+ the implementation of GDK_CAP_NOT_LAST, and dashed lines. Fixes
+ bug #306396.
+
+ * gdk/win32/gdkprivate-win32.h (GdkGCWin32): Save the GdkGC's
+ line_style, cap_style and join_style as such in the
+ GdkGCWin32. Don't need to keep the pen_double_dash flag, we can
+ check the line_style.
+
+ * gdk/win32/gdkgc-win32.c (fixup_pen): New internal function. Sets
+ up the GDI pen type, style, end cap and join attributes to use
+ based on the pen width, GDK line style, end cap style, and join
+ style.
+
+ For a narrow (zero-width) GDK pen with the GDK_CAP_NOT_LAST end
+ cap style, which typically are used for XOR drawing where it is
+ essential that the last pixel is not drawn, use a GDI cosmetic
+ pen. Only for a cosmetic pen does GDI not draw the last pixel. I
+ deduced this by experimetation, the documentation is rather vague.
+
+ For other GDK pens use a geometric GDI pen. If the width is 0 or 1
+ and the GDK end cap style is GDK_CAP_BUTT, and the line style is
+ GDK_LINE_SOLID, use PS_ENDCAP_ROUND. This ensures that also
+ single-pixel length lines are drawn. (For sngle-pixel width lines
+ roundness as such is of course irrelevant.) For dashed lines, use
+ PS_ENDCAP_FLAT.
+
+ For wide lines use PS_ENDCAP_FLAT, _ROUND or _SQUARE,
+ respectively, for GDK_CAP_BUTT, GDK_CAP_ROUND and GDK_CAP_PROJECTING.
+
+ For one pixel on-off dashed lines, use PS_ALTERNATE, it seems to
+ work better than PS_USERSTYLE. For other dashed lines, use
+ PS_USERSTYLE and the dashes as set by the user (or the default
+ four-pixel on-off style).
+
+ (gdk_win32_gc_values_to_win32values, gdk_win32_gc_set_dashes):
+ Call fixup_pen() to do the pen settings after modifying some of
+ the GDK GC attributes that affect pens.
+
+ * gdk/win32/gdkdrawable-win32.c (render_line_horizontal,
+ render_line_vertical, draw_segments): Check GdkGCWin32::line_style
+ instead of the the removed pen_double_dash member. Don't use
+ PATCOPY unconditionally in the PatBlt() call, use a raster ope
+ code that depends on the GC function in use.
+
+ (draw_rectangle, draw_segments, draw_lines): Be more careful in
+ deciding when to do the manual dash rendering.
+
+ (draw_segments): Don't do any manual "last point" drawing at
+ all. The above changes takes care of narrow line segments being
+ drawn correctly in most cases, at least on NT-based Windows.
+
2005-06-23 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkfilesystemunix.c (gtk_file_system_unix_get_folder):
diff --git a/gdk/win32/gdkdrawable-win32.c b/gdk/win32/gdkdrawable-win32.c
index 2d45a40f5..5d4883751 100644
--- a/gdk/win32/gdkdrawable-win32.c
+++ b/gdk/win32/gdkdrawable-win32.c
@@ -45,6 +45,12 @@
#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,
@@ -230,7 +236,51 @@ gdk_win32_set_colormap (GdkDrawable *drawable,
/* Drawing
*/
-static DWORD default_double_dashes[] = { 3, 3 };
+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)
@@ -259,70 +309,58 @@ align_with_dash_offset (int a, DWORD *dashes, int num_dashes, GdkGCWin32 *gcwin3
*/
static inline gboolean
render_line_horizontal (GdkGCWin32 *gcwin32,
- int x1,
- int x2,
- int y)
+ int x1,
+ int x2,
+ int y)
{
- int n = 0;
- HDC hdc = gcwin32->hdc;
- int pen_width = gcwin32->pen_width;
- DWORD *dashes;
- int num_dashes;
- int _x1 = x1;
-
- if (gcwin32->pen_dashes)
- {
- dashes = gcwin32->pen_dashes;
- num_dashes = gcwin32->pen_num_dashes;
- x1 = align_with_dash_offset (x1, dashes, num_dashes, gcwin32);
- }
- else
- {
- dashes = default_double_dashes;
- num_dashes = G_N_ELEMENTS (default_double_dashes);
- }
+ 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 && x1 + len > _x1)
- if (!GDI_CALL (PatBlt, (hdc,
+ 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->pen_double_dash)
+ if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
{
HBRUSH hbr;
- if ((hbr = SelectObject (hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
+ if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
return FALSE;
x1 = _x1;
- if (gcwin32->pen_dashes)
- x1 += gcwin32->pen_dash_offset;
+ x1 += gcwin32->pen_dash_offset;
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)
- if (!GDI_CALL (PatBlt, (hdc, x1, y - pen_width / 2,
+ if (!GDI_CALL (PatBlt, (gcwin32->hdc, 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 (SelectObject (hdc, hbr) == HGDI_ERROR)
+ if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
return FALSE;
}
@@ -331,67 +369,54 @@ render_line_horizontal (GdkGCWin32 *gcwin32,
static inline gboolean
render_line_vertical (GdkGCWin32 *gcwin32,
- int x,
- int y1,
- int y2)
+ int x,
+ int y1,
+ int y2)
{
- int n;
- HDC hdc = gcwin32->hdc;
- int pen_width = gcwin32->pen_width;
- DWORD *dashes;
- int num_dashes;
- int _y1 = y1;
-
- if (gcwin32->pen_dashes)
- {
- dashes = gcwin32->pen_dashes;
- num_dashes = gcwin32->pen_num_dashes;
- y1 = align_with_dash_offset (y1, dashes, num_dashes, gcwin32);
- }
- else
- {
- dashes = default_double_dashes;
- num_dashes = G_N_ELEMENTS (default_double_dashes);
- }
+ 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 && y1 + len > _y1)
- if (!GDI_CALL (PatBlt, (hdc, x - pen_width / 2,
+ 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->pen_double_dash)
+ if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
{
HBRUSH hbr;
- if ((hbr = SelectObject (hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
+ if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
return FALSE;
y1 = _y1;
- if (gcwin32->pen_dashes)
- y1 += gcwin32->pen_dash_offset;
+ y1 += gcwin32->pen_dash_offset;
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)
- if (!GDI_CALL (PatBlt, (hdc, x - pen_width / 2, y1,
+ if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2, 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 (SelectObject (hdc, hbr) == HGDI_ERROR)
+ if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
return FALSE;
}
@@ -485,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,
@@ -835,9 +832,7 @@ draw_rectangle (GdkGCWin32 *gcwin32,
x -= x_offset;
y -= y_offset;
- if (!filled && (gcwin32->pen_double_dash ||
- (gcwin32->pen_dashes && (gcwin32->pen_dash_offset ||
- !G_WIN32_IS_NT_BASED ()))))
+ 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) &&
@@ -1284,9 +1279,7 @@ draw_segments (GdkGCWin32 *gcwin32,
}
}
- if (gcwin32->pen_double_dash ||
- (gcwin32->pen_dashes && (gcwin32->pen_dash_offset ||
- !G_WIN32_IS_NT_BASED ())))
+ if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
{
for (i = 0; i < nsegs; i++)
{
@@ -1315,42 +1308,22 @@ draw_segments (GdkGCWin32 *gcwin32,
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);
@@ -1393,8 +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 | GDK_GC_FOREGROUND |
- LINE_ATTRIBUTES,
+ generic_draw (drawable, gc, GDK_GC_FOREGROUND | LINE_ATTRIBUTES,
draw_segments, region, segs, nsegs);
gdk_region_destroy (region);
@@ -1421,9 +1393,7 @@ draw_lines (GdkGCWin32 *gcwin32,
pts[i].y -= y_offset;
}
- if (gcwin32->pen_double_dash ||
- (gcwin32->pen_dashes && (gcwin32->pen_dash_offset ||
- !G_WIN32_IS_NT_BASED ())))
+ if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
{
for (i = 0; i < npoints - 1; i++)
{
diff --git a/gdk/win32/gdkgc-win32.c b/gdk/win32/gdkgc-win32.c
index 73f001f19..f1cc6c3c1 100644
--- a/gdk/win32/gdkgc-win32.c
+++ b/gdk/win32/gdkgc-win32.c
@@ -114,6 +114,115 @@ gdk_gc_win32_finalize (GObject *object)
}
static void
+fixup_pen (GdkGCWin32 *win32_gc)
+{
+ win32_gc->pen_style = 0;
+
+ /* First look at GDK width and end cap style, set GDI pen type and
+ * end cap.
+ */
+ if (win32_gc->pen_width == 0 &&
+ win32_gc->cap_style == GDK_CAP_NOT_LAST)
+ {
+ /* Use a cosmetic pen, always width 1 */
+ win32_gc->pen_style |= PS_COSMETIC;
+ }
+ else if (win32_gc->pen_width <= 1 &&
+ win32_gc->cap_style == GDK_CAP_BUTT)
+ {
+ /* For 1 pixel wide lines PS_ENDCAP_ROUND means draw both ends,
+ * even for one pixel length lines. But if we are drawing dashed
+ * lines we can't use PS_ENDCAP_ROUND.
+ */
+ if (win32_gc->line_style == GDK_LINE_SOLID)
+ win32_gc->pen_style |= PS_GEOMETRIC | PS_ENDCAP_ROUND;
+ else
+ win32_gc->pen_style |= PS_GEOMETRIC | PS_ENDCAP_FLAT;
+ }
+ else
+ {
+ win32_gc->pen_style |= PS_GEOMETRIC;
+ switch (win32_gc->cap_style)
+ {
+ /* For non-zero-width lines X11's CapNotLast works like CapButt */
+ case GDK_CAP_NOT_LAST:
+ case GDK_CAP_BUTT:
+ win32_gc->pen_style |= PS_ENDCAP_FLAT;
+ break;
+ case GDK_CAP_ROUND:
+ win32_gc->pen_style |= PS_ENDCAP_ROUND;
+ break;
+ case GDK_CAP_PROJECTING:
+ win32_gc->pen_style |= PS_ENDCAP_SQUARE;
+ break;
+ }
+ }
+
+ /* Next look at GDK line style, set GDI pen style attribute */
+ switch (win32_gc->line_style)
+ {
+ case GDK_LINE_SOLID:
+ win32_gc->pen_style |= PS_SOLID;
+ break;
+ case GDK_LINE_ON_OFF_DASH:
+ case GDK_LINE_DOUBLE_DASH:
+ if (win32_gc->pen_dashes == NULL)
+ {
+ win32_gc->pen_dashes = g_new (DWORD, 1);
+ win32_gc->pen_dashes[0] = 4;
+ win32_gc->pen_num_dashes = 1;
+ }
+ if (G_WIN32_IS_NT_BASED ())
+ {
+ if (!(win32_gc->pen_style & PS_TYPE_MASK) == PS_GEOMETRIC &&
+ win32_gc->pen_dashes[0] == 1 &&
+ (win32_gc->pen_num_dashes == 1 ||
+ (win32_gc->pen_num_dashes == 2 && win32_gc->pen_dashes[0] == 1)))
+ win32_gc->pen_style |= PS_ALTERNATE;
+ else
+ win32_gc->pen_style |= PS_USERSTYLE;
+ }
+ else
+ {
+ /* Render "short" on-off dashes drawn with R2_COPYPEN and a
+ * cosmetic pen using PS_DOT
+ */
+ if (win32_gc->line_style == GDK_LINE_ON_OFF_DASH &&
+ win32_gc->rop2 == R2_COPYPEN &&
+ (win32_gc->pen_style & PS_TYPE_MASK) == PS_COSMETIC &&
+ win32_gc->pen_dashes[0] <= 2 &&
+ (win32_gc->pen_num_dashes == 1 ||
+ (win32_gc->pen_num_dashes == 2 && win32_gc->pen_dashes[1] <= 2)))
+ win32_gc->pen_style |= PS_DOT;
+ else
+ /* Otherwise render opaque lines solid, horizontal or
+ * vertical ones will be dashed manually, see
+ * gdkdrawable-win32.c.
+ */
+ win32_gc->pen_style |= PS_SOLID;
+ }
+ break;
+ }
+
+ /* Last, for if the GDI pen is geometric, set the join attribute */
+ if ((win32_gc->pen_style & PS_TYPE_MASK) == PS_GEOMETRIC)
+ {
+ switch (win32_gc->join_style)
+ {
+ case GDK_JOIN_MITER:
+ win32_gc->pen_style |= PS_JOIN_MITER;
+ break;
+ case GDK_JOIN_ROUND:
+ win32_gc->pen_style |= PS_JOIN_ROUND;
+ break;
+ case GDK_JOIN_BEVEL:
+ win32_gc->pen_style |= PS_JOIN_BEVEL;
+ break;
+ }
+ }
+}
+
+static void
gdk_win32_gc_values_to_win32values (GdkGCValues *values,
GdkGCValuesMask mask,
GdkGCWin32 *win32_gc)
@@ -217,45 +326,6 @@ gdk_win32_gc_values_to_win32values (GdkGCValues *values,
{
if (values->stipple != NULL)
{
-#if 0 /* HB: this size limitation is disabled to make radio and check
- * buttons work. I got the impression from the API docs, that
- * it shouldn't be necessary at all, but win9x would do the clipping
- *
- * This code will need some work if reenabled since the stipple is
- * now stored in the backend-independent code.
- */
- gint sw, sh;
-
- gdk_drawable_get_size (values->stipple, &sw, &sh);
-
- if ( (sw != 8 || sh != 8)
- && !G_WIN32_IS_NT_BASED ()) /* HB: the MSDN says it's a Win95 limitation */
- {
- /* It seems that it *must* be 8x8, at least on my machine.
- * Thus, tile an 8x8 bitmap with the stipple in case it is
- * smaller, or simply use just the top left 8x8 in case it is
- * larger.
- */
- gchar dummy[8];
- GdkPixmap *bm = gdk_bitmap_create_from_data (NULL, dummy, 8, 8);
- GdkGC *gc = gdk_gc_new (bm);
- gint i, j;
-
- i = 0;
- while (i < 8)
- {
- j = 0;
- while (j < 8)
- {
- gdk_draw_drawable (bm, gc, values->stipple, 0, 0, i, j, sw, sh);
- j += sh;
- }
- i += sw;
- }
- win32_gc->stipple = bm;
- gdk_gc_unref (gc);
- }
-#endif
win32_gc->values_mask |= GDK_GC_STIPPLE;
GDK_NOTE (GC,
(g_print ("%sstipple=%p", s,
@@ -343,78 +413,32 @@ gdk_win32_gc_values_to_win32values (GdkGCValues *values,
if (mask & GDK_GC_LINE_STYLE)
{
- switch (values->line_style)
- {
- case GDK_LINE_SOLID:
- if (win32_gc->pen_dashes)
- {
- g_free (win32_gc->pen_dashes);
- win32_gc->pen_dashes = NULL;
- win32_gc->pen_num_dashes = 0;
- }
- win32_gc->pen_style &= ~(PS_STYLE_MASK);
- win32_gc->pen_style |= PS_SOLID;
- win32_gc->pen_double_dash = FALSE;
- break;
- case GDK_LINE_ON_OFF_DASH:
- case GDK_LINE_DOUBLE_DASH:
- if (!win32_gc->pen_dashes)
- {
- /* setting to PS_DASH probably isn't correct. If I understand the
- * xlib docs correctly it should influence the handling of
- * line endings ? --hb
- */
- win32_gc->pen_style &= ~(PS_STYLE_MASK);
- win32_gc->pen_style |= PS_DASH;
- }
- win32_gc->pen_double_dash = values->line_style == GDK_LINE_DOUBLE_DASH;
- break;
- }
- GDK_NOTE (GC, (g_print ("%sps|=PS_STYLE_%s", s, _gdk_win32_psstyle_to_string (win32_gc->pen_style)),
- s = ","));
+ win32_gc->line_style = values->line_style;
win32_gc->values_mask |= GDK_GC_LINE_STYLE;
}
if (mask & GDK_GC_CAP_STYLE)
{
- win32_gc->pen_style &= ~(PS_ENDCAP_MASK);
- switch (values->cap_style)
- {
- case GDK_CAP_NOT_LAST: /* ??? */
- case GDK_CAP_BUTT:
- win32_gc->pen_style |= PS_ENDCAP_FLAT;
- break;
- case GDK_CAP_ROUND:
- win32_gc->pen_style |= PS_ENDCAP_ROUND;
- break;
- case GDK_CAP_PROJECTING:
- win32_gc->pen_style |= PS_ENDCAP_SQUARE;
- break;
- }
- GDK_NOTE (GC, (g_print ("%sps|=PS_ENDCAP_%s", s, _gdk_win32_psendcap_to_string (win32_gc->pen_style)),
- s = ","));
+ win32_gc->cap_style = values->cap_style;
win32_gc->values_mask |= GDK_GC_CAP_STYLE;
}
if (mask & GDK_GC_JOIN_STYLE)
{
- win32_gc->pen_style &= ~(PS_JOIN_MASK);
- switch (values->join_style)
- {
- case GDK_JOIN_MITER:
- win32_gc->pen_style |= PS_JOIN_MITER;
- break;
- case GDK_JOIN_ROUND:
- win32_gc->pen_style |= PS_JOIN_ROUND;
- break;
- case GDK_JOIN_BEVEL:
- win32_gc->pen_style |= PS_JOIN_BEVEL;
- break;
- }
- GDK_NOTE (GC, (g_print ("%sps|=PS_JOIN_%s", s, _gdk_win32_psjoin_to_string (win32_gc->pen_style)),
- s = ","));
+ win32_gc->join_style = values->join_style;
win32_gc->values_mask |= GDK_GC_JOIN_STYLE;
}
+
+ if (mask & (GDK_GC_LINE_WIDTH|GDK_GC_LINE_STYLE|GDK_GC_CAP_STYLE|GDK_GC_JOIN_STYLE))
+ {
+ fixup_pen (win32_gc);
+ GDK_NOTE (GC, (g_print ("%sps|=PS_STYLE_%s|PS_ENDCAP_%s|PS_JOIN_%s", s,
+ _gdk_win32_psstyle_to_string (win32_gc->pen_style),
+ _gdk_win32_psendcap_to_string (win32_gc->pen_style),
+ _gdk_win32_psjoin_to_string (win32_gc->pen_style)),
+ s = ","));
+ }
+
GDK_NOTE (GC, g_print ("} mask=(%s)", _gdk_win32_gcvalues_mask_to_string (win32_gc->values_mask)));
}
@@ -443,11 +467,17 @@ _gdk_win32_gc_new (GdkDrawable *drawable,
win32_gc->subwindow_mode = GDK_CLIP_BY_CHILDREN;
win32_gc->graphics_exposures = TRUE;
win32_gc->pen_width = 0;
- win32_gc->pen_style = PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_JOIN_MITER;
+ /* Don't get confused by the PS_ENDCAP_ROUND. For narrow GDI pens
+ * (width == 1), PS_GEOMETRIC|PS_ENDCAP_ROUND works like X11's
+ * CapButt.
+ */
+ win32_gc->pen_style = PS_GEOMETRIC|PS_ENDCAP_ROUND|PS_JOIN_MITER;
+ win32_gc->line_style = GDK_LINE_SOLID;
+ win32_gc->cap_style = GDK_CAP_BUTT;
+ win32_gc->join_style = GDK_JOIN_MITER;
win32_gc->pen_dashes = NULL;
win32_gc->pen_num_dashes = 0;
win32_gc->pen_dash_offset = 0;
- win32_gc->pen_double_dash = FALSE;
win32_gc->pen_hbrbg = NULL;
win32_gc->values_mask = GDK_GC_FUNCTION | GDK_GC_FILL;
@@ -522,29 +552,9 @@ gdk_win32_gc_get_values (GdkGC *gc,
values->graphics_exposures = win32_gc->graphics_exposures;
values->line_width = win32_gc->pen_width;
- if (win32_gc->pen_style & PS_SOLID)
- values->line_style = GDK_LINE_SOLID;
- else if (win32_gc->pen_style & PS_DASH)
- values->line_style = win32_gc->pen_double_dash ? GDK_LINE_DOUBLE_DASH :
- GDK_LINE_ON_OFF_DASH;
- else
- values->line_style = GDK_LINE_SOLID;
-
- /* PS_ENDCAP_ROUND is zero */
- if (win32_gc->pen_style & PS_ENDCAP_FLAT)
- values->cap_style = GDK_CAP_BUTT;
- else if (win32_gc->pen_style & PS_ENDCAP_SQUARE)
- values->cap_style = GDK_CAP_PROJECTING;
- else
- values->cap_style = GDK_CAP_ROUND;
-
- /* PS_JOIN_ROUND is zero */
- if (win32_gc->pen_style & PS_JOIN_MITER)
- values->join_style = GDK_JOIN_MITER;
- else if (win32_gc->pen_style & PS_JOIN_BEVEL)
- values->join_style = GDK_JOIN_BEVEL;
- else
- values->join_style = GDK_JOIN_ROUND;
+ values->line_style = win32_gc->line_style;
+ values->cap_style = win32_gc->cap_style;
+ values->join_style = win32_gc->join_style;
}
static void
@@ -573,19 +583,13 @@ gdk_win32_gc_set_dashes (GdkGC *gc,
win32_gc = GDK_GC_WIN32 (gc);
- /* mark as set, see gdk_win32_gc_values_to_win32values () for the reason */
- win32_gc->values_mask |= GDK_GC_LINE_STYLE;
-
- win32_gc->pen_style &= ~(PS_STYLE_MASK);
-
- win32_gc->pen_style |= (PS_GEOMETRIC | PS_USERSTYLE);
win32_gc->pen_num_dashes = n;
- if (win32_gc->pen_dashes != NULL)
- g_free (win32_gc->pen_dashes);
+ g_free (win32_gc->pen_dashes);
win32_gc->pen_dashes = g_new (DWORD, n);
for (i = 0; i < n; i++)
win32_gc->pen_dashes[i] = dash_list[i];
win32_gc->pen_dash_offset = dash_offset;
+ fixup_pen (win32_gc);
}
void
@@ -659,13 +663,16 @@ _gdk_windowing_gc_copy (GdkGC *dst_gc,
dst_win32_gc->graphics_exposures = src_win32_gc->graphics_exposures;
dst_win32_gc->pen_width = src_win32_gc->pen_width;
dst_win32_gc->pen_style = src_win32_gc->pen_style;
- dst_win32_gc->pen_dashes = src_win32_gc->pen_dashes;
- if (dst_win32_gc->pen_dashes)
+ dst_win32_gc->line_style = src_win32_gc->line_style;
+ dst_win32_gc->cap_style = src_win32_gc->cap_style;
+ dst_win32_gc->join_style = src_win32_gc->join_style;
+ if (src_win32_gc->pen_dashes)
dst_win32_gc->pen_dashes = g_memdup (src_win32_gc->pen_dashes,
sizeof (DWORD) * src_win32_gc->pen_num_dashes);
+ else
+ dst_win32_gc->pen_dashes = NULL;
dst_win32_gc->pen_num_dashes = src_win32_gc->pen_num_dashes;
dst_win32_gc->pen_dash_offset = src_win32_gc->pen_dash_offset;
- dst_win32_gc->pen_double_dash = src_win32_gc->pen_double_dash;
dst_win32_gc->hdc = NULL;
@@ -825,7 +832,6 @@ gdk_win32_hdc_get (GdkDrawable *drawable,
GdkDrawableImplWin32 *impl = NULL;
gboolean ok = TRUE;
COLORREF fg = RGB (0, 0, 0), bg = RGB (255, 255, 255);
- LOGBRUSH logbrush;
HPEN hpen;
HBRUSH hbr;
@@ -858,7 +864,7 @@ gdk_win32_hdc_get (GdkDrawable *drawable,
if (ok && (usage & LINE_ATTRIBUTES))
{
/* For drawing GDK_LINE_DOUBLE_DASH */
- if ((usage & GDK_GC_BACKGROUND) && win32_gc->pen_double_dash)
+ if ((usage & GDK_GC_BACKGROUND) && win32_gc->line_style == GDK_LINE_DOUBLE_DASH)
{
bg = _gdk_win32_colormap_color (impl->colormap, _gdk_gc_get_bg_pixel (gc));
if ((win32_gc->pen_hbrbg = CreateSolidBrush (bg)) == NULL)
@@ -867,33 +873,26 @@ gdk_win32_hdc_get (GdkDrawable *drawable,
if (ok)
{
+ LOGBRUSH logbrush;
+ DWORD style_count = 0;
+ const DWORD *style = NULL;
+
/* Create and select pen */
logbrush.lbStyle = BS_SOLID;
logbrush.lbColor = fg;
logbrush.lbHatch = 0;
-
- if (win32_gc->pen_num_dashes > 0 && !G_WIN32_IS_NT_BASED ())
- {
- /* The Win9x GDI is rather limited so we either draw dashed
- * lines ourselves (only horizontal and vertical) or let them be
- * drawn solid to avoid implementing a whole line renderer.
- */
- if ((hpen = ExtCreatePen (
- (win32_gc->pen_style & ~(PS_STYLE_MASK)) | PS_SOLID,
- MAX (win32_gc->pen_width, 1),
- &logbrush,
- 0, NULL)) == NULL)
- WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
- }
- else
+
+ if ((win32_gc->pen_style & PS_STYLE_MASK) == PS_USERSTYLE)
{
- if ((hpen = ExtCreatePen (win32_gc->pen_style,
- MAX (win32_gc->pen_width, 1),
- &logbrush,
- win32_gc->pen_num_dashes,
- win32_gc->pen_dashes)) == NULL)
- WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
+ style_count = win32_gc->pen_num_dashes;
+ style = win32_gc->pen_dashes;
}
+
+ if ((hpen = ExtCreatePen (win32_gc->pen_style,
+ MAX (win32_gc->pen_width, 1),
+ &logbrush,
+ style_count, style)) == NULL)
+ WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
if (ok && SelectObject (win32_gc->hdc, hpen) == NULL)
WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index a2764a2b9..d76c8cb51 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -274,10 +274,12 @@ struct _GdkGCWin32
gint graphics_exposures;
gint pen_width;
DWORD pen_style;
+ GdkLineStyle line_style;
+ GdkCapStyle cap_style;
+ GdkJoinStyle join_style;
DWORD *pen_dashes; /* use for PS_USERSTYLE or step-by-step rendering */
gint pen_num_dashes;
gint pen_dash_offset;
- gboolean pen_double_dash;
HBRUSH pen_hbrbg;
/* Following fields are valid while the GC exists as a Windows DC */