From e34f0452b4726ca49fb2fd664749f31650943f93 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 12 Jan 2005 21:28:03 +0000 Subject: [PATCH] Fix for #162790, by Iwan Wong: 2005-01-12 Tor Lillqvist Fix for #162790, by Iwan Wong: * gdk/win32/gdkdrawable-win32.c: Implement dashed lines correctly. Simplify the interface to render_line_horizontal() and render_line_vertical(). Need to draw lines "manually" also on NT-based Windowses if we have a dash offset or are drawing double-dashed lines. * gdk/win32/gdkprivate-win32.h: Keep also the dash offset, double-dash flag, and a brush for the background colour (used by the odd dashes in the double-dash line style) in the GdkGCWin32 struct. * gdk/win32/gdkgc-win32.c: Set up above new fields. --- ChangeLog | 17 ++++ ChangeLog.pre-2-10 | 17 ++++ ChangeLog.pre-2-8 | 17 ++++ gdk/win32/gdkdrawable-win32.c | 175 +++++++++++++++++++++++----------- gdk/win32/gdkgc-win32.c | 115 +++++++++++++--------- gdk/win32/gdkprivate-win32.h | 3 + 6 files changed, 243 insertions(+), 101 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0d2f06a1e3..a8759281b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2005-01-12 Tor Lillqvist + + Fix for #162790, by Iwan Wong: + + * gdk/win32/gdkdrawable-win32.c: Implement dashed lines + correctly. Simplify the interface to render_line_horizontal() and + render_line_vertical(). Need to draw lines "manually" also on + NT-based Windowses if we have a dash offset or are drawing + double-dashed lines. + + * gdk/win32/gdkprivate-win32.h: Keep also the dash offset, + double-dash flag, and a brush for the background colour (used by + the odd dashes in the double-dash line style) in the GdkGCWin32 + struct. + + * gdk/win32/gdkgc-win32.c: Set up above new fields. + 2005-01-10 Federico Mena Quintero Fix #162617. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 0d2f06a1e3..a8759281b8 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,20 @@ +2005-01-12 Tor Lillqvist + + Fix for #162790, by Iwan Wong: + + * gdk/win32/gdkdrawable-win32.c: Implement dashed lines + correctly. Simplify the interface to render_line_horizontal() and + render_line_vertical(). Need to draw lines "manually" also on + NT-based Windowses if we have a dash offset or are drawing + double-dashed lines. + + * gdk/win32/gdkprivate-win32.h: Keep also the dash offset, + double-dash flag, and a brush for the background colour (used by + the odd dashes in the double-dash line style) in the GdkGCWin32 + struct. + + * gdk/win32/gdkgc-win32.c: Set up above new fields. + 2005-01-10 Federico Mena Quintero Fix #162617. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 0d2f06a1e3..a8759281b8 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,20 @@ +2005-01-12 Tor Lillqvist + + Fix for #162790, by Iwan Wong: + + * gdk/win32/gdkdrawable-win32.c: Implement dashed lines + correctly. Simplify the interface to render_line_horizontal() and + render_line_vertical(). Need to draw lines "manually" also on + NT-based Windowses if we have a dash offset or are drawing + double-dashed lines. + + * gdk/win32/gdkprivate-win32.h: Keep also the dash offset, + double-dash flag, and a brush for the background colour (used by + the odd dashes in the double-dash line style) in the GdkGCWin32 + struct. + + * gdk/win32/gdkgc-win32.c: Set up above new fields. + 2005-01-10 Federico Mena Quintero Fix #162617. diff --git a/gdk/win32/gdkdrawable-win32.c b/gdk/win32/gdkdrawable-win32.c index 5f7b472000..3d53e7febb 100644 --- a/gdk/win32/gdkdrawable-win32.c +++ b/gdk/win32/gdkdrawable-win32.c @@ -239,20 +239,35 @@ gdk_win32_set_colormap (GdkDrawable *drawable, /* Drawing */ -/* - * Render a dashed line 'by hand' cause the Win9x GDI is - * too limited to do so +static DWORD default_double_dashes[] = { 3, 3 }; + +/* 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, +render_line_horizontal (GdkGCWin32 *gcwin32, int x1, int x2, - int y, - int pen_width, - DWORD *dashes, - int num_dashes) + int y) { - int n; + int n; + 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 += gcwin32->pen_dash_offset; + } + else + { + dashes = default_double_dashes; + num_dashes = G_N_ELEMENTS (default_double_dashes); + } for (n = 0; x1 < x2; n++) { @@ -269,19 +284,60 @@ render_line_horizontal (HDC hdc, x1 += dashes[n % num_dashes]; } + if (gcwin32->pen_double_dash) + { + HBRUSH hbr; + + if ((hbr = SelectObject (hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR) + return FALSE; + x1 = _x1; + if (gcwin32->pen_dashes) + x1 += gcwin32->pen_dash_offset; + for (n = 0; x1 < x2; n++) + { + int len = dashes[n % num_dashes]; + if (x1 + len > x2) + len = x2 - x1; + + if (n % 2) + if (!GDI_CALL (PatBlt, (hdc, x1, y - pen_width / 2, + len, pen_width, + PATCOPY))) + return FALSE; + + x1 += dashes[n % num_dashes]; + } + if (SelectObject (hdc, hbr) == HGDI_ERROR) + return FALSE; + } + return TRUE; } static inline gboolean -render_line_vertical (HDC hdc, +render_line_vertical (GdkGCWin32 *gcwin32, int x, int y1, - int y2, - int pen_width, - DWORD *dashes, - int num_dashes) + int y2) { - int n; + 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 += gcwin32->pen_dash_offset; + } + else + { + dashes = default_double_dashes; + num_dashes = G_N_ELEMENTS (default_double_dashes); + } for (n = 0; y1 < y2; n++) { @@ -297,6 +353,32 @@ render_line_vertical (HDC hdc, y1 += dashes[n % num_dashes]; } + if (gcwin32->pen_double_dash) + { + HBRUSH hbr; + + if ((hbr = SelectObject (hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR) + return FALSE; + y1 = _y1; + if (gcwin32->pen_dashes) + y1 += gcwin32->pen_dash_offset; + for (n = 0; y1 < y2; n++) + { + int len = dashes[n % num_dashes]; + if (y1 + len > y2) + len = y2 - y1; + if (n % 2) + if (!GDI_CALL (PatBlt, (hdc, x - pen_width / 2, y1, + pen_width, len, + PATCOPY))) + return FALSE; + + y1 += dashes[n % num_dashes]; + } + if (SelectObject (hdc, hbr) == HGDI_ERROR) + return FALSE; + } + return TRUE; } @@ -736,24 +818,14 @@ draw_rectangle (GdkGCWin32 *gcwin32, x -= x_offset; y -= y_offset; - if (!filled && gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ()) + if (!filled && (gcwin32->pen_double_dash || + (gcwin32->pen_dashes && (gcwin32->pen_dash_offset || + !G_WIN32_IS_NT_BASED ())))) { - 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 { @@ -796,7 +868,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); @@ -1196,7 +1269,9 @@ draw_segments (GdkGCWin32 *gcwin32, } } - if (gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ()) + if (gcwin32->pen_double_dash || + (gcwin32->pen_dashes && (gcwin32->pen_dash_offset || + !G_WIN32_IS_NT_BASED ()))) { for (i = 0; i < nsegs; i++) { @@ -1209,11 +1284,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,11 +1295,7 @@ 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)) && @@ -1311,7 +1378,8 @@ 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 | GDK_GC_FOREGROUND | + LINE_ATTRIBUTES, draw_segments, region, segs, nsegs); gdk_region_destroy (region); @@ -1338,7 +1406,9 @@ draw_lines (GdkGCWin32 *gcwin32, pts[i].y -= y_offset; } - if (gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ()) + if (gcwin32->pen_double_dash || + (gcwin32->pen_dashes && (gcwin32->pen_dash_offset || + !G_WIN32_IS_NT_BASED ()))) { for (i = 0; i < npoints - 1; i++) { @@ -1350,10 +1420,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 +1430,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,7 +1482,8 @@ 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); diff --git a/gdk/win32/gdkgc-win32.c b/gdk/win32/gdkgc-win32.c index 49beed4569..1c58ba34f4 100644 --- a/gdk/win32/gdkgc-win32.c +++ b/gdk/win32/gdkgc-win32.c @@ -366,6 +366,7 @@ gdk_win32_gc_values_to_win32values (GdkGCValues *values, } 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: @@ -378,6 +379,7 @@ gdk_win32_gc_values_to_win32values (GdkGCValues *values, 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)), @@ -462,6 +464,9 @@ _gdk_win32_gc_new (GdkDrawable *drawable, win32_gc->pen_style = PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_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; @@ -540,7 +545,8 @@ gdk_win32_gc_get_values (GdkGC *gc, if (win32_gc->pen_style & PS_SOLID) values->line_style = GDK_LINE_SOLID; else if (win32_gc->pen_style & PS_DASH) - values->line_style = GDK_LINE_ON_OFF_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; @@ -599,6 +605,7 @@ gdk_win32_gc_set_dashes (GdkGC *gc, 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; } void @@ -751,12 +758,15 @@ gdk_gc_copy (GdkGC *dst_gc, dst_win32_gc->pen_dashes = g_memdup (src_win32_gc->pen_dashes, sizeof (DWORD) * src_win32_gc->pen_num_dashes); 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; dst_win32_gc->saved_dc = FALSE; dst_win32_gc->hwnd = NULL; dst_win32_gc->holdpal = NULL; + dst_win32_gc->pen_hbrbg = NULL; } GdkScreen * @@ -807,15 +817,14 @@ _gdk_win32_colormap_color (GdkColormap *colormap, } } -static COLORREF -predraw_set_foreground (GdkGC *gc, - GdkColormap *colormap, - gboolean *ok) +gboolean +predraw (GdkGC *gc, + GdkColormap *colormap) { - COLORREF fg; GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc; GdkColormapPrivateWin32 *colormap_private; gint k; + gboolean ok = TRUE; if (colormap && (colormap->visual->type == GDK_VISUAL_PSEUDO_COLOR || @@ -826,18 +835,15 @@ predraw_set_foreground (GdkGC *gc, g_assert (colormap_private != NULL); if (!(win32_gc->holdpal = SelectPalette (win32_gc->hdc, colormap_private->hpal, FALSE))) - WIN32_GDI_FAILED ("SelectPalette"), *ok = FALSE; + WIN32_GDI_FAILED ("SelectPalette"), ok = FALSE; else if ((k = RealizePalette (win32_gc->hdc)) == GDI_ERROR) - WIN32_GDI_FAILED ("RealizePalette"), *ok = FALSE; + WIN32_GDI_FAILED ("RealizePalette"), ok = FALSE; else if (k > 0) - GDK_NOTE (COLORMAP, g_print ("predraw_set_foreground: realized %p: %d colors\n", + GDK_NOTE (COLORMAP, g_print ("predraw: realized %p: %d colors\n", colormap_private->hpal, k)); } - fg = _gdk_win32_colormap_color (colormap, win32_gc->foreground); - - GDK_NOTE (GC, g_print ("predraw_set_foreground: fg=%06lx\n", fg)); - return fg; + return ok; } /** @@ -898,7 +904,7 @@ gdk_win32_hdc_get (GdkDrawable *drawable, GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc; GdkDrawableImplWin32 *impl = NULL; gboolean ok = TRUE; - COLORREF fg = RGB (0, 0, 0); + COLORREF fg = RGB (0, 0, 0), bg = RGB (255, 255, 255); LOGBRUSH logbrush; HPEN hpen; HBRUSH hbr; @@ -935,11 +941,14 @@ gdk_win32_hdc_get (GdkDrawable *drawable, if (ok && (win32_gc->saved_dc = SaveDC (win32_gc->hdc)) == 0) WIN32_GDI_FAILED ("SaveDC"); } - + + if (ok && (usage & (GDK_GC_FOREGROUND | GDK_GC_BACKGROUND))) + ok = predraw (gc, impl->colormap); + if (ok && (usage & GDK_GC_FOREGROUND)) { - fg = predraw_set_foreground (gc, impl->colormap, &ok); - if (ok && (hbr = CreateSolidBrush (fg)) == NULL) + fg = _gdk_win32_colormap_color (impl->colormap, win32_gc->foreground); + if ((hbr = CreateSolidBrush (fg)) == NULL) WIN32_GDI_FAILED ("CreateSolidBrush"), ok = FALSE; if (ok && SelectObject (win32_gc->hdc, hbr) == NULL) @@ -951,36 +960,47 @@ gdk_win32_hdc_get (GdkDrawable *drawable, if (ok && (usage & LINE_ATTRIBUTES)) { - /* 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; + /* For drawing GDK_LINE_DOUBLE_DASH */ + if ((usage & GDK_GC_BACKGROUND) && win32_gc->pen_double_dash) + { + bg = _gdk_win32_colormap_color (impl->colormap, win32_gc->background); + if ((win32_gc->pen_hbrbg = CreateSolidBrush (bg)) == NULL) + WIN32_GDI_FAILED ("CreateSolidBrush"), ok = FALSE; + } + + if (ok) + { + /* 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 ((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; + } + + if (ok && SelectObject (win32_gc->hdc, hpen) == NULL) + WIN32_GDI_FAILED ("SelectObject"), ok = FALSE; } - else - { - 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; - } - - if (ok && SelectObject (win32_gc->hdc, hpen) == NULL) - WIN32_GDI_FAILED ("SelectObject"), ok = FALSE; } if (ok && (usage & GDK_GC_FONT)) @@ -1085,6 +1105,9 @@ gdk_win32_hdc_release (GdkDrawable *drawable, if (hbr != NULL) GDI_CALL (DeleteObject, (hbr)); + if (win32_gc->pen_hbrbg != NULL) + GDI_CALL (DeleteObject, (win32_gc->pen_hbrbg)); + win32_gc->hdc = NULL; } diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 188401b4a2..f614aadbaf 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -282,6 +282,9 @@ struct _GdkGCWin32 DWORD pen_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 */ HDC hdc;