Bug 32215

Summary: Large gradients do not render
Product: cairo Reporter: Krzysztof Kosiński <tweenk.pl>
Component: image backendAssignee: Carl Worth <cworth>
Status: RESOLVED FIXED QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: major    
Priority: medium    
Version: 1.10.0   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments: Large gradient testcase
Output of "./precision 20000"
Output of "./precision 300000"
Pathological large gradient testcase
Output of "./radial-prec 1.8"

Description Krzysztof Kosiński 2010-12-08 00:02:32 UTC
When a gradient is larger than roughly 32ki units in the gradient space (not device space), it fails to render. Such gradients are frequently encountered in SVG, as well as when working at large zoom factors in e.g. Inkscape. The fundamental cause is the use of fixed point coordinates in pixman.
Comment 1 Krzysztof Kosiński 2010-12-08 00:06:43 UTC
Created attachment 40899 [details]
Large gradient testcase

This is a very simple test case. The program takes a single integer parameter and tries to render a radial gradient with this radius, scaled down to the area of the image surface used (500x500). On my system, the program works correctly only as long as the parameter is <= 32702. Any higher value causes a blank image to be saved to the PNG file.
Comment 2 Krzysztof Kosiński 2010-12-08 00:07:57 UTC
Created attachment 40900 [details]
Output of "./precision 20000"
Comment 3 Krzysztof Kosiński 2010-12-08 00:09:07 UTC
Created attachment 40901 [details]
Output of "./precision 300000"
Comment 4 Andrea Canciani 2010-12-17 03:45:36 UTC
(In reply to comment #0)
> When a gradient is larger than roughly 32ki units in the gradient space (not
> device space), it fails to render. Such gradients are frequently encountered in
> SVG, as well as when working at large zoom factors in e.g. Inkscape. The
> fundamental cause is the use of fixed point coordinates in pixman.

Actually the fundamental cause is the incorrect handling of gradients coordinates in Cairo.
Cairo is already trying to rescale gradients to fit withing the range accepted by pixman,
but it is only doing this for linear gradients and (worse) is doing it incorrectly and inconsistently
across different backends.

I pushed a branch which improves the handling of gradient coordinates:
http://cgit.freedesktop.org/~ranma42/cairo/log/?h=wip/doublepattern

Could you test it and check if it fixes your problem?
Comment 5 Krzysztof Kosiński 2010-12-17 13:28:07 UTC
This improves the situation a lot - I need to create absurdly large gradients to force them not to render. There are still some pathological cases which are not handled correctly though. I attach one of them - it's taken from a gradient definition in a SVG file encountered in the wild.
Comment 6 Krzysztof Kosiński 2010-12-17 13:30:35 UTC
Created attachment 41223 [details]
Pathological large gradient testcase

Testcase with an extreme transformation matrix. Such data is known to occur in some Inkscape documents encountered on the web. The gradient appears when I run the program as "./radial-prec 1.8", but disappears with "./radial-prec 1.9".
Comment 7 Krzysztof Kosiński 2010-12-17 13:31:38 UTC
Created attachment 41224 [details]
Output of "./radial-prec 1.8"
Comment 8 Andrea Canciani 2010-12-17 13:36:23 UTC
(In reply to comment #6)
> Created an attachment (id=41223) [details]
> Pathological large gradient testcase
> 
> Testcase with an extreme transformation matrix. Such data is known to occur in
> some Inkscape documents encountered on the web. The gradient appears when I run
> the program as "./radial-prec 1.8", but disappears with "./radial-prec 1.9".

This is not a gradient-specific problem.

Cairo is not handling  the transform matrix in a sufficiently solid way,
but you would likely have the same problem with surface patterns.
Comment 9 Krzysztof Kosiński 2010-12-17 13:40:05 UTC
> This is not a gradient-specific problem.
> 
> Cairo is not handling  the transform matrix in a sufficiently solid way,
> but you would likely have the same problem with surface patterns.

Should I file this as another bug?
Comment 10 Andrea Canciani 2010-12-17 14:53:02 UTC
(In reply to comment #9)
> > This is not a gradient-specific problem.
> > 
> > Cairo is not handling  the transform matrix in a sufficiently solid way,
> > but you would likely have the same problem with surface patterns.
> 
> Should I file this as another bug?

I'm not sure about it.

It looks like your second test case is not actually having problems with
the transform matrix but simply with the translation so it can be handled
correctly by improving my patches. I will update my branch soon.
Comment 11 Andrea Canciani 2010-12-29 07:57:26 UTC
I pushed a new branch fixing the second problem you noticed:
http://cgit.freedesktop.org/~ranma42/cairo/log/?h=wip/doublepattern2

It was actually caused by an incorrect conversion from the cairo matrix to the pixman transformation/offset.

This branch should make the handling of transformations in image, xlib and xcb more safe, but there are more overflows to be handled (two of them are easy to fix, so I do it before cleaning up for master).

This doesn't make all possible cairo matrices work on pixman (which is basically impossible), but should allow for a much wider range.

Would this be enough for inkscape to work correctly? Do you have other patterns failing?
Comment 12 Krzysztof Kosiński 2010-12-31 12:45:58 UTC
(In reply to comment #11)
> Would this be enough for inkscape to work correctly? Do you have other patterns
> failing?

At the moment, no other failing test cases. Thanks a lot!
Comment 13 Andrea Canciani 2011-01-02 10:12:57 UTC
(In reply to comment #12)
> (In reply to comment #11)
> > Would this be enough for inkscape to work correctly? Do you have other patterns
> > failing?
> 
> At the moment, no other failing test cases. Thanks a lot!

I just pushed to master a branch containing basically the same changes as the branch you tested.

The three "interesting" commits are:

commit 51594d9787905618de608a367c3a5fc0544c52e3
Author: Andrea Canciani <ranma42@gmail.com>
Date:   Fri Dec 17 11:04:41 2010 +0100

    matrix: Cairo matrix to pixman transform/offset conversion
    
    Xlib, XCB and image use the same code to convert a cairo_matrix_t to a
    backend-specific transform.
    
    The code did not handle correctly some matrices, thus a new function
    that performs the conversion in a more generic way was added and used
    in the backends instead of fixing the repeated code.
    
    Fixes part of https://bugs.freedesktop.org/show_bug.cgi?id=32215

commit 38dce5d14473e1106c8ea7a67b9be0f400d442a2
Author: Andrea Canciani <ranma42@gmail.com>
Date:   Fri Dec 17 11:03:03 2010 +0100

    pattern: Factor out pattern rescaling
    
    The same code was duplicated (incorrectly and with some minor
    differences) in pattern, image, xlib and xcb.
    
    _cairo_gradient_pattern_max_val() abstracts that code in a function
    that can be used whenever a gradients extremes need to be rescaled to
    fit within a given range.
    
    Fixes huge-linear, huge-radial.
    
    Fixes part of https://bugs.freedesktop.org/show_bug.cgi?id=32215


commit 200e147322a7a17dec91ad5f678a07fdfaf38de2
Author: Andrea Canciani <ranma42@gmail.com>
Date:   Fri Dec 17 11:04:53 2010 +0100

    pattern: Use double precision for gradient extreme objects
    
    Using double precision for gradient extreme objects ensures that they
    are preserved as specified when constructing the gradient pattern.
    
    Fixes huge-linear, huge-radial.
    
    Fixes part of https://bugs.freedesktop.org/show_bug.cgi?id=32215


Together they make it possible for backends that can handle the full double range to have any gradient and for pixman-based backends (image,xlib,xcb,fallbacks) to handle a much wider range of gradients and transformation matrices.

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.