Commit e34f0452 authored by Tor Lillqvist's avatar Tor Lillqvist Committed by Tor Lillqvist

Fix for #162790, by Iwan Wong:

2005-01-12  Tor Lillqvist  <tlillqvist@novell.com>

	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.
parent 698418d6
2005-01-12 Tor Lillqvist <tlillqvist@novell.com>
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 <federico@ximian.com>
Fix #162617.
......
2005-01-12 Tor Lillqvist <tlillqvist@novell.com>
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 <federico@ximian.com>
Fix #162617.
......
2005-01-12 Tor Lillqvist <tlillqvist@novell.com>
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 <federico@ximian.com>
Fix #162617.
......
......@@ -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);
......
......@@ -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;
}
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;
/* 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;
}
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;
}
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment