Tk Source Code

View Ticket
Login
Ticket UUID: 2874226
Title: polygon and closed polylines in canvas don't fully honor -joinstyle on Windows and OS X
Type: Bug Version: obsolete: 8.4.19
Submitter: beric Created on: 2009-10-07 17:39:37
Subsystem: 82. X11 Emulation Assigned To: fvogel
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2017-08-24 19:32:03
Resolution: Fixed Closed By: fvogel
    Closed on: 2017-08-24 19:32:03
Description:
Under Windows, the following code:

pack [canvas .c]
set id [.c create polygon {20.0 20.0 50.0 50.0 30.0 80.0 20.0 50.0 20.0 30.0}]
.c itemconfigure $id -fill red -outline black -width 10 -joinstyle miter

shows a polygon with a round close point, while the -joinstyle is miter.

See the attached image: left is Unix, right is Windows.

Documentation of XDrawLines() says that it honors joinstyle if first and last point are identical.
The XDrawLines() implementation in tkWinDraw.c should do the same thing.

Or is it a limitation of GDI Polygon function?
User Comments: fvogel added on 2017-08-24 19:32:03:
Merged to core-8-6-branch and trunk.

fvogel added on 2017-08-21 12:42:14:
I have created a short demo script showing the "line" and "polygon" items of a canvas with different combinations of options. See "testcanvasitems.tcl" attached.

Rendering with this script before and after the fix (on Windows 7) can be compared through the two attachments "BEFOREtheFIX.png" and "BUGFIX BRANCH.png". The join styles "miter" and "bevel" are now correctly honored in all cases, and I cannot see any regression otherwise.

I think this is now ready for merging.

fvogel added on 2017-08-19 16:03:16:
I have analyzed the performance impact of the fix for Windows since I was unsure.

Details are in attachment "2874226 - -joinstyle - performance checks.tcl".

In conclusion, the fix does not create any loss of performance. It rather improves performance slightly (but the difference in measured figures are in the uncertainty margin).

fvogel added on 2017-08-17 21:06:34:

Propagated the Windows fix to all kind of lines (stippled and non-stippled). See [c441e73fea].

Rendering of all join styles is now correct on Windows when the first and last point of a polygon or polyline are the same, for both stippled and non stippled lines (and ditto for polygon outlines).


fvogel added on 2017-08-16 22:06:56:

Thinking a bit more, I have found a way to fix the problem on Windows as well, see [441f6fee93].

The given example script now renders correctly (for any join style) on all platforms.

Remaining <TODO>: fix the case of stippled lines on Windows.


fvogel added on 2017-08-16 20:26:47:
I have implemented the suggested workaround for Windows. It works indeed for the "miter" join style.

However it does not work for "bevel" join style (which can be readily checked through the workaround script I posted below when changing it to -joinstyle bevel).

Since there is no known solution for "bevel" joinstyle, I won't implement this workaround in win/tkWinDraw.c. Rendering on Windows is therefore unchanged.

Summing up:
- rendering was already OK on Linux
- incorrect rendering on OS X could be fixed
- incorrect rendering on Windows will not be fixed, being a limitation of the GDI function Polyline()

fvogel added on 2017-08-13 08:48:48:

For OS X I have pushed a proposed fix, see [abd26a6e99].

For the Windows case, I have found confirmation in the book "Windows Graphics Programming: Win32 GDI and DirectDraw" from Feng Yuan that an end cap is always applied to the first and last points drawn, even if their coordinates are exactly the same.

Even more interesting: This link also proposes a workaround consisting in adding an extra line segment from the first point to the second point at the end of the list of points. This looks like a clever trick because a figure drawn using a single Polyline call will not have pixels drawn twice, therefore there will be no performance impact from this workaround.

So the following draws correctly under Windows:

# Win workaround
package require Tk
pack [canvas .c]
set id [.c create polygon {20.0 20.0 50.0 50.0 30.0 80.0 20.0 50.0 20.0 30.0 20.0 20.0 50.0 50.0}]
.c itemconfigure $id -fill red -outline black -width 10 -joinstyle miter

I will have a look at whether I can implement such an automatic workaround in the Windows rendering code of Tk.


fvogel added on 2017-08-12 21:42:00:
Drawing of the polygon item of the canvas is performed in generic/tkCanvPoly.c through function TkFillPolygon(). This calls XFillPolygon() to draw the filled polygon, and then XDrawLines() to draw its border. So far this is platform-independent code.

On Linux, the Xlib function XDrawLines() indeeds honors the join-style embedded in the GC, and if the first and last points of the polyline are the same then they join according to the given join-style. Fine and OK (see attachment "OnLinux(OK).png").

On Windows, XDrawLines() in tkWinDraw.c correctly sets the PS_JOIN_MITER style to the pen set to function RenderObject(). This function correctly provides this pen to the device context (dc) through SelectObject(). And then the lines are drawn through a call to  func(dc, winPoints, npoints);  with func value being "Polyline". So the GDI function "Polyline()" is called, with the correct pen. In the MSDN documentation, nothing is said about what's happening when the first and last points sent to Polyline() are the same. What we obtain (see attachment "OnWindows(KO).png" apparently is a limitation of the GDI function Polyline(). So this will be a "Won't fix" for Windows.

On OS X, XDrawLines() in tkMacOSXDraw.c draws the polyline through calls to CGContextMoveToPoint() and then successive CGContextAddLineToPoint(). While CGContextAddLineToPoint() honors the join style, the drawing happens in a so-called path and during this line by line drawing there is no notion of closure of the polyline that would allow correct rendering in the first=end point. BUT specifically requesting the path to close (by adding a call to CGContextClosePath(dc.context);) provides the correctly rendered result. This needs however to be done only when the first and last points are the same. Patch will follow.

beric added on 2009-10-08 00:39:38:

File Added - 345661: polygon.png

Attachments: