Created attachment 132628 [details] cairo_rel_curve_to(cr, 100, 100, 100, 100, 0, 0) Trying to render the bezier curve which has the end point same as start point and both control points are also matching, for example: cairo_move_to(cr, 100, 100); cairo_rel_curve_to(cr, 100, 100, 100, 100, 0, 0); Results in wrong image. Expected result: For the example above, I would expect a 45 degrees diagonal line is drawn. Actual result: A dot at the current point location is drawn. Note, that if make control points slightly differ the line is drawn. See attachments for: 1) cairo_rel_curve_to(cr, 100, 100, 100, 100, 0, 0); 2) cairo_rel_curve_to(cr, 100, 100, 101, 100, 0, 0);
Created attachment 132630 [details] cairo_rel_curve_to(cr, 100, 100, 101, 100, 0, 0)
Created attachment 132671 [details] Reproducer I can reproduce with the attached program and, as already said, adding an offset of 1 makes "things work". Are such degenerate curves even well-defined (the two control points coincide and so do the two end points)?
I can say that in some other vector graphics implementations this case works as I described in expected result. I can define the SVG image which essentially draws such Bezier curve and Firefox displays such SVG correctly, i.e. diagonal line is drawn. So, I assume cairo is not behaving naturally in this case.
What happens is: _cairo_path_fixed_stroke_to_polygon is called and in its curve_to() callback it calls _cairo_spline_decompose() on this curve. The original curve is (100,100)->(200,200)->(200,200)->(100,100) (these are its four control points) and it is decomposed into the following two curves: (100,100)->(150,150)->(175,175)->(175,175) (175,175)->(175,175)->(150,150)->(100,100) The error now is 0 so points are added. The add_point callback of the spline is spline_to() and it gets the following arguments: spline to (175,175) with tangent (0,0) spline to (100,100) with tangent (-100,-100) The problem is the tangent (0,0), which means that spline_to() just calls add_fan(). At this point I am lost on what is going on. This code ignores the point argument and only uses the passed-in point. Thus, only "things around (100,100)" happen. With the following patch, things work as expected. Since I have no clue about the algorithm, I'm not sure how incorrect this is. I guess that the thought here was "tangent (0,0) can only happen if the points are all the same", which this example shows is wrong. However, since this is just a guess, I'll hope that someone with more of a clue looks at this. Oh and: The test suite should be checked for regressions. Chris? Andrea? Anyone with some clue about this?
Created attachment 132696 [details] [review] This patch makes the reproducer work correctly. No idea what other side-effects it might have.
-- GitLab Migration Automatic Message -- This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/cairo/cairo/issues/191.
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.