JDK-8160599 : Stroke rendered far off Shape's edge
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8,9
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_8
  • CPU: x86
  • Submitted: 2016-06-29
  • Updated: 2017-04-22
  • Resolved: 2017-04-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 10
10Fixed
Related Reports
Relates :  
Relates :  
Description
Bug reported by TeamFX on behalf of Dr Michael PAUS:

Under certain conditions it happens that a Stroke is rendered beyond a Shape's edge, i. e. the edge of the fill and the stroke itself are not aligned on screen. The attached program (courtesy of Dr Michael PAUS) proofs this.
Comments
This was fixed in JDK10 when we integrated the fix for JDK-8177985. For JDK9, there is a workaround which is to enable the double-precision Marlin rasterizer using "-Dprism.marlinrasterizer=true". (The double-precision version of Marlin is the default if you enable Marlin, but if you really want to make sure it is using the double-precision version as opposed to the float-precision version that still has the problem, then you can also add "-Dprism.marlin.double=true" as well.) I am marking this fixed in 10 as a result.
19-04-2017

MarlinFX was integrated in december 2016 with float and double precision variants (but MarlinFX is disabled by default in JFX9). MarlinFX with Double-precision fixes this rendering issue.
19-04-2017

We can integrate a work-around for this by enabling the double support in MarlinFX. See JDK-8171393 for more info...
16-12-2016

For long time, I want to use double instead of floats in the Pisces / Marlin pipeline to improve quality ie subpixel accuracy. I could try generating another pipeline (Transformer, Dasher, Stroker, Renderer) in MarlinFX with a sed script (quick and dirty) to see its impact on both quality but also performance. In MarlinFX, Renderer.addLine already uses double and long (32.32) values for DDA but the accuracy issue remains in the previous stages
29-11-2016

It looks like the new MarlinFX rasterizer inherits the same inaccuracies (probably because it was also based on Pisces).
29-11-2016

Based on my understanding of Jim's evaluation, this seems unlikely, given the extent of the change. Jim can comment further as to whether my understanding is correct.
09-08-2016

If a third party could provide the needed patch, would it make it in JDK 9 then or is it still a no-go due to the huge code review needed in turn?
06-08-2016

Yes, that would be a rather involved change, perhaps out of scope for JDK 9 at this point given the number of other bugs we have in the pipeline.
15-07-2016

I modified the dasher to subdivide in doubles and the dashed outline is now nice and stable across a wide variety of dash lengths, but it doesn't match the fill or the solid stroke (both of which remain in float). It looks like we will need to have a separate double-based rasterizer pipeline for when the path exceeds a certain size - a much bigger change than just patching the subdivision in the dasher... :(
15-07-2016

It looks like the issue is float precision combined with a lot of successive subdivision operations of the curves. If I add a slider that changes the length of the dashes we generally get better approximations as the lengths get longer (fewer dashes and thus fewer subdivision operations). One issue is that iterating the on/off dashes the code currently starts with the original curve and then slices off the first dash, then it uses the remainder from that subdivision to slice off the next dash or space, then it uses the remainder from that operation to slice off the next, iterating so that the "remainder" part of the curve has the round-off errors from N successive subdivision operations (where N == the number of dashes rendered on this curve so far). Doing a simple switch of the algorithm to always start with the original curve to subdivide it from t0 to t1 for each dash segment makes it much more accurate, but still the dashes don't always follow the outline. I'll have to try switching that part of the algorithm to double precision to see if that can bridge the gap.
14-07-2016

Attaching the "Circle as path" version of the test case...
12-07-2016

Another piece of evidence is that converting the circle to a path (which would go through the rasterizer for both parts) has no impact on the result. This is thus more likely to be an inaccuracy in the stroking engine somewhere. It's interesting to note that one of the visible segments in the rectangle case isn't even dashed, so the stroking engine got pretty far off base in that example to lose the dashing properties...
12-07-2016

Added comment by TeamFX on behalf of Dr Michael PAUS: Hi Jim. I doubt that the special approximation of circles is the real cause of this problem because I have the same problem with simple polygons too. See attached test program "ShapeOutlineBugRectangle". Polygons only contain straight line segments so there is no need for any approximation. In the test program the polygon is just a simple square which is rotated by 45 degrees. I noticed that the problem does not seem to show up if the axis of this square are instead aligned with the screen axis.
03-07-2016

The attached file "ShapeOutlineBugRectangle.java" proofs that this has nothing to do with circles: It also happens with simple rectangles, so the cause must be somewhere different.
03-07-2016

This is likely due to the error in approximating a large circle with a cubic. When we stroke a path with dashes we turn it into a path which only allows line, quad and cubic segments. When we render the filled part of the circle, though, we use a shader which evaluates x^2+y^2<r. The greatest differences between the cubic version of the circle that we use in paths is when we are at the 45-degree marks. If you modify the test case so that it shows the 0,90,180,270 degree parts of the circle then the stroke and the fill match very closely. There are alternate approximations of a circle to a cubic that have different error properties - another cubic constant minimizes the error at the 45 degree marks, but has greater error then at both 22.5 and 67.5 degrees. Cubics and circles will never be perfectly equal, though.
29-06-2016

I can confirm this bug on JDK 8 and JDK 9. This only appears to happen for extremely large objects (it would also happen at extreme scales). It looks like a precision issue. Lowering priority to P4.
29-06-2016