summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Lillqvist <tml@novell.com>2005-06-24 13:00:05 +0000
committerTor Lillqvist <tml@src.gnome.org>2005-06-24 13:00:05 +0000
commitbaad14eee091cc643fa8371dd2fb79219a4aaf88 (patch)
treeea243bf9e6c2b4c0eb4caf0fd6a239dc9f54cfc4
parent621f16a4429b39a7ecce88b77c9c79aab389769b (diff)
downloadgdk-pixbuf-baad14eee091cc643fa8371dd2fb79219a4aaf88.tar.gz
Improve and simplify line segment rendering on Win32, especially the
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.
-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 */