bad rendering of rounded corners for small objects

Bug #1409520 reported by Stefan Bruens on 2015-01-11
32
This bug affects 5 people
Affects Status Importance Assigned to Milestone
Inkscape
Medium
Unassigned

Bug Description

When creating small rectangles or polygon shapes with rounded corners, some of the corners are badly rendered (sharp corner instead of rounded). See screenshot.

The attached svg was created the following way:
1. New document (A4)
2. create rectangle
3. scale down rectangle

Stefan Bruens (stefan-bruens) wrote :
Stefan Bruens (stefan-bruens) wrote :
su_v (suv-lp) wrote :

Please always add information about OS/platform and Inkscape version to bug reports, thx.

Based on the screenshot, this is a report about Inkscape 0.91+devel, or 0.91pre3.

On OS X 10.7.5:
- not reproduced with Inkscape 0.48.5 (independent of cairo version)
- not reproduced with Inkscape 0.91+devel r13847, using cairo 1.12.2
- reproduced with Inkscape 0.91+devel r13847, using cairo 1.12.14, 1.14.0, current master

tags: added: cairo renderer-cairo
su_v (suv-lp) wrote :

More cairo releases tested (on OS X 10.7.5):
- not reproduced with 1.12.0, 1.12.2
- reproduced with 1.12.4, 1.12.6, 1.12.8
(all tests done with libpixman unchanged @0.28.2)

Likely, this rendering issue seems triggered by an upstream change in cairo between 1.12.2 and 1.12.4.

su_v (suv-lp) on 2015-01-11
Changed in inkscape:
importance: Undecided → Low
status: New → Triaged
su_v (suv-lp) wrote :

The problem does not seem to be related to the size of the object itself, but to the stroke width (zoom in to the top-left corner in the attached variation of the test case - this file has no scaled viewBox, unit conversions or other transforms applied elsewhere).

su_v (suv-lp) wrote :

Screenshot comparing rendering in trunk with cairo 1.12.2 and 1.12.4

Stefan Bruens (stefan-bruens) wrote :

OS: openSUSE 13.2
inkscape: 0.91 branch, r13695
libcairo: 1.12.16

Matthew Woehlke (mw-triad) wrote :

I'm seeing this also. It appears to be a regression since 0.48, although I'd believe it's related to a cairo bump in the same time period.

I seem to be seeing this consistently on EVERY object (paths as well as rectangles), although I'll note that the only objects I am working with are usually stroke size 0.1 - 0.5 with overall size often 1 - 5, but sometimes larger. What I don't see mentioned already is that the problem appears to consistently manifest on the corner where an object is closed, i.e. the location of the first vertex in the path definition (equivalent to the upper left corner of an untransformed rectangle).

Beveled corners seem to be okay?

su_v (suv-lp) wrote :

On 2015-01-11 23:33 (+0200), ~suv wrote:
> Screenshot comparing rendering in trunk with cairo 1.12.2 and 1.12.4

Seems I mixed up the screenshots earlier - attaching new screenshots redone using latest trunk r14176 with cairo 1.12.2 (ok) and cairo 1.12.4 (not ok).

The reported issue also reproduces with current stable cairo 1.14.2; the incorrect rendering of the rounded corner occurs at the start/end node of a path closed with a 'z' or 'Z' segment (AFAICT it doesn't matter whether start and end node coincide (duplicate nodes) or not).

su_v (suv-lp) on 2015-10-13
tags: added: regression
Tavmjong Bah (tavmjong-free) wrote :

I've dumped out some of the Cairo calls to see how Inkscape is drawing the rectangle. It is using a series of lineto's. Converting the rectangle to a path gives exactly the same calls (as expected).

I then wrote a small C program that used the same Cairo calls. I see a change in behavior between a stroke width of 0.6 and 0.7. At 0.6, rounded corners are drawn as bevels while at 0.7 they are rendered rounded. Cairo may be attempting to optimize drawing the corners (if the two ends of the outer offset paths are less than a given distance apart, draw a bevel). This is confirmed by examining the source code (cairo-stroke-path.c). Changing the 'tolerance' from the default 0.1 to 0.05 (cairo_set_tolernace()) results in rounded corners when the stroke width is 0.5.

In Inkscape, converting the rectangle to a path and then dragging one of the adjacent corners (so that the enclosed angle changes) results in the join being drawn round when the angle is more acute... which makes the two ends of the offset paths be farther apart.

With the small C program all corners are effected, not just at the start of the path. I cannot reproduce the behavior in Inkscape where only the start/stop corner is incorrect. Using 'cairo_rectangle' instead of a path, the behavior is the same.

I've changed the default value of 'tolerance' inside Inkscape. If I increase the value to 0.5 or decrease the value to 0.05 the start/end corner is rendered correctly. The default value of 0.1 yields a bad corner. There is probably a subtle bug in Cairo.

I've attached a cleaned up test case.

Here is a snip-it of the Cairo code for the test image with scaling of 4000% (and with some debugging output):

  // Inkscape Path ----------------------------------------
  cairo_matrix_t cm;
  cm.xx = 40;
  cm.xy = 0;
  cm.x0 = 0;
  cm.yx = 0;
  cm.yy = 40;
  cm.y0 = -160;
  cairo_transform( c, &cm ); // ink_cairo_transform
  // calling prepareStroke()
  // called prepareStroke()
  // DrawingContext::path
  // feed_pathvector_to_cairo: entrance
  // feed_path_to_cairo: entrance
  // cairo_rectangle( c, 0.25, 0.25, 3, 2 );
  cairo_move_to( c, 0.25, 1.25);
  cairo_line_to( c, 3.75, 1.25); // Not optimized
  cairo_line_to( c, 3.75, 3.75); // Not optimized
  cairo_line_to( c, 0.25, 3.75); // Not optimized
  cairo_close_path( c );
  // has_stroke... calling applyStroke()
  cairo_set_line_width( c, 0.5);
  cairo_set_line_join( c, 1);
  // has_stroke... called applyStroke()
  cairo_stroke_preserve( c );
  cairo_new_path( c );

Tavmjong Bah (tavmjong-free) wrote :

I've confirmed that with the default tolerance of 0.1 the magic "width" where the behavior changes from drawing a bevel to a round line cap for a right angle join is 0.6828. There is also a bug in the Cairo code where a tolerance larger than the stroke width can result in round line caps (there is a squaring of a negative number in the calculation which leads to an invalid result).

Tavmjong Bah (tavmjong-free) wrote :

Oh, oh, oh....

I've built a debug version of Cairo with some print statements...

Findings:

1. Standalone Cairo program uses code in cairo-path-stroke-traps.c. This code applies the tolerance condition when constructing line joins, both in the middle of a path and when closing a path.

2. Inkscape uses code in cairo-path-stroke-polygon.c: This code applies tolerance only when when constructing a line-join for closing a path. When a path is being closed and the tolerance condition is not met, the path is closed with a miter (rather than a bevel as in cairo-path-stroke-traps.c).

3. The tolerance condition does not depend on the CTM matrix thus a path scaled up can have a visible defect (as we see in the SVG test case).

4. The tolerance condition is invalid if the 'tolerance' value is larger than the half the stroke width as this results in a negative number that is then squared. (For example, tolerance values of 5 and 0.05 result in rounded corners while a value of 0.1 results in bevel corners.

Questions:

1. What triggers following the traps vs polygon code?

2. Why is the tolerance condition only applied on closing a path in the polygon code?

Time to send email to the Cairo mailing list.

su_v (suv-lp) wrote :

On 2015-10-14 11:15 (+0200), Tavmjong Bah wrote:
> 3. The tolerance condition does not depend on the CTM matrix thus a path
> scaled up can have a visible defect (as we see in the SVG test case).

Raising bug importance to 'Medium'.

Changed in inkscape:
importance: Low → Medium
Geoff (gphillips) wrote :

I am using Inkscape 0.92 on Windows 10 and get a sharp top left rectangle corner despite setting the joins to rounded.
If I increase the stroke width, eventually the corner rounds, but at 0.3 mm, it is sharp!
This makes drawing rectangular prisms difficult if smooth corners are required.
I can't see any way around this bug.

Thomas Wiesner (wiesiwies) wrote :

Using Inkscape 0.92.2 (5c3e80d, 2017-08-06), 64 bit on Win7 SP1 64 bit, I'm affected by this bug, too.
I find it rather annoying, because I often draw diagrams with boxes that fall into the affected width range.

I've played around bit and noticed that the problem seems to appear only within a certain line width range. Here are the instructions for reproduction:

1) Start Inkscape.
2) Draw a rectangle. (A small one for better visibility of the problem.)
3) Set the join to "Round join" in the "Fill and Stroke" panel.
4) Set the stroke width to 1px. The result is step4.png. The upper left corner has no rounded join.
5) Decrease the stroke width. When reaching 0.442px (didn't test more decimals), the join is suddenly correct, see step5.png.
6) Increasing the width produces, again, the wrong result. When 2.581px are reached, the result is correct again, see step6.png.

So at least for me and this testcase, the problem appears for 0.442px <= width < 2.581px.

Hachmann (marenhachmann) wrote :

Still happens with Inkscape master from September 2018 + libcairo2 1.15.10-2

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Duplicates of this bug

Other bug subscribers