Bug 26380

Summary: SVG Filters and big sized filterRegions
Product: WebKit Reporter: Dirk Schulze <krit>
Component: SVGAssignee: Nobody <webkit-unassigned>
Status: RESOLVED FIXED    
Severity: Normal CC: eric, jeffschiller, oliver, simon.fraser, zimmermann
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: PC   
OS: OS X 10.5   
Bug Depends on:    
Bug Blocks: 68469, 26389    
Attachments:
Description Flags
big svg filter
oliver: review-
big svg filter
none
clip filter to viewport
simon.fraser: review-
Testcase with svg inside 3d transform
none
Better testcase none

Description Dirk Schulze 2009-06-13 22:35:36 PDT
We need to take care about very big filterRegions and itemSizes of filters. CI has problems with very big image size.
We could clip the filterRegion after a defined maximum size and don't support bigger filters.

Perhaps we can try to scale down the GraphicsContext and limit the size of all ImageBuffers for source input / filter effects. We could transform the filterRegion and itemsize too. But we will see every pixel. The size of every pixel gets bigger on bigger sized filters.
Or we give the CTM of the scaling to every filter effect and transform the context of every filter effect. But many filter effects need pixel manipulation. Don't know if that is a possible way.

Another way is maybe to just draw the visible area. But I don't have experience with that. And what to do on zooming out of the SVG?
Comment 1 Dirk Schulze 2009-06-14 11:46:11 PDT
Created attachment 31267 [details]
big svg filter 

This patch uses one of the solutions above. We scale the context down to a predefined maximum size and transform all necessary rects too. Apply the effects and scale back. It seems, that opera and firefox use simular solutions.
I haven't tested it on a mac. We might use a smaller size than 3000x3000. I'll set the review flag when i'am sure.
Comment 2 Dirk Schulze 2009-06-14 13:10:43 PDT
Comment on attachment 31267 [details]
big svg filter 

works on mac
Comment 3 Oliver Hunt 2009-06-18 01:52:51 PDT
Comment on attachment 31267 [details]
big svg filter 

Where does the 3000.0f maxSize come from? It looks like it's actually a constant so i believe you actually probably want a static const float kMaxFilterSize = 3000.0f; in the file, rather than scoped to the function.
Comment 4 Dirk Schulze 2009-08-04 12:49:02 PDT
Created attachment 34081 [details]
big svg filter

constant for maximum filter size. At ~3000x3000 px a difference at calculating is sensible.
Comment 5 Eric Seidel (no email) 2009-08-07 12:29:21 PDT
Comment on attachment 34081 [details]
big svg filter

Seems like this is an aspect ratio scaling problem which we've already solved in other parts of the code.  I wonder if we could just re-use the scaling code instead of writing it again here.
Comment 6 Dirk Schulze 2009-08-07 13:00:32 PDT
(In reply to comment #5)
> (From update of attachment 34081 [details])
> Seems like this is an aspect ratio scaling problem which we've already solved
> in other parts of the code.  I wonder if we could just re-use the scaling code
> instead of writing it again here.

where did we solve this problem?
Comment 7 Eric Seidel (no email) 2009-08-07 13:02:41 PDT
Certainly SVGPerserveAspectRatio solves this.
Comment 8 Eric Seidel (no email) 2009-08-07 13:02:59 PDT
There are probably less-complicated solutions in the Image code too.
Comment 9 Eric Seidel (no email) 2009-08-08 09:08:37 PDT
There was also a recent TransformationMatrix::rectToRect call added, but that won't handle aspect ratios for you.
Comment 10 Eric Seidel (no email) 2009-09-03 00:53:37 PDT
Comment on attachment 34081 [details]
big svg filter

So this is just about limiting the size of the intermediate buffers?  Doesn't SVG have some sort of attribute to control this kind of thing anyway?
Comment 11 Dirk Schulze 2009-09-03 05:52:26 PDT
(In reply to comment #10)
> (From update of attachment 34081 [details])
> So this is just about limiting the size of the intermediate buffers?  Doesn't
> SVG have some sort of attribute to control this kind of thing anyway?

The size of a filter can be as big as you wish. And it is neccessary to limit the size of a buffer, especially if you have many filters. But as far as I know, we don't have attributes or parameters to limit intermediate buffers with context scaling for big filters.

Another point to add limitations here is filterRes. This code can be used to add different resolutions for filters later.

> Certainly SVGPerserveAspectRatio solves this.
I looked at SVGPerserveAspectRatio during some experiments with feImage. It seems to be a bit to complex for this simple scaling of context and image with. I haven't looked at Image yet.
Comment 12 Simon Fraser (smfr) 2009-09-21 14:14:55 PDT
Won't scaling the graphics context down cause image aliasing artifacts etc?
Comment 13 Dirk Schulze 2009-09-21 23:03:58 PDT
(In reply to comment #12)
> Won't scaling the graphics context down cause image aliasing artifacts etc?
Images will loose quality, yes. But a filter size can be as big as you want. And scaling down the context on a pre defined size, makes it possible to calculate filter effects with pixel manipulation in an acceptable time. It makes it possible to draw the effect at all, if the size is bigger than some platform ImageBuffers are able to render.
Comment 14 Nikolas Zimmermann 2009-10-14 16:25:57 PDT
So what about this patch? I think we should settle on a solution.
I think we should introduce a maximum limit right now, given the fact you can easily blow up a target PC using a dozen masks at a large size :-)

When filterRes & friends is taken into account, we need to think about a more clever solution, but I'd vote for an initial "sanitization value", scaling larger filters down, yes with loosing quality.

After that I think we can enable SVG Filters as default, so finally pass SVG 1.0, and advertize ourselves as SVG 1.0 fully compilant, see the 'requiredFeatures' feature of SVG viewers.

Anyone with me?
Comment 15 Jeff Schiller 2009-10-14 16:59:23 PDT
> Anyone with me?

From an outsider's perspective:  um, yes please! :)
Comment 16 Dirk Schulze 2009-11-09 23:52:56 PST
Comment on attachment 34081 [details]
big svg filter

Clearing review flag. This would just limit the size of the filter surface but not of the effect surfaces.
Comment 17 Dirk Schulze 2009-11-10 10:37:23 PST
Created attachment 42876 [details]
clip filter to viewport

This patch clips the filter and all it's effects to the current viewport. This will limit the filter size to the current viewable window content. I'll upload the test results as soon as I have access to a Mac.
Comment 18 Simon Fraser (smfr) 2009-11-10 10:58:49 PST
Comment on attachment 42876 [details]
clip filter to viewport


> Index: WebCore/svg/SVGFilterElement.cpp
> ===================================================================

> @@ -125,6 +127,7 @@ void SVGFilterElement::buildFilter(const
>                                 filterRect.width() * targetRect.width(),
>                                 filterRect.height() * targetRect.height());
>  
> +    m_filter->setViewPort(document()->view()->visibleContentRect());

But is this rect in the same coordinate system as the rest of the filter rects? What if the filter is on a child of a transformed element?

> Index: WebCore/svg/graphics/SVGResourceFilter.cpp
> ===================================================================
> --- WebCore/svg/graphics/SVGResourceFilter.cpp	(revision 50732)
> +++ WebCore/svg/graphics/SVGResourceFilter.cpp	(working copy)
> @@ -63,6 +63,9 @@ void SVGResourceFilter::prepareFilter(Gr
>      FloatRect targetRect = object->objectBoundingBox();
>      m_ownerElement->buildFilter(targetRect);
>  
> +    // clip filterRect to viewPort
> +    m_filterBBox.intersect(m_viewPort);

This isn't going to do the right thing for filtered SVG inside a HTML with CSS 3D transforms; element content that is outside the viewport can be made visible with a rotateY(), for example. And, yes the visible filtered content may be arbitrarily large in that case.

> Index: WebCore/svg/graphics/SVGResourceFilter.h
> ===================================================================
> --- WebCore/svg/graphics/SVGResourceFilter.h	(revision 50732)
> +++ WebCore/svg/graphics/SVGResourceFilter.h	(working copy)
> @@ -65,6 +65,9 @@ public:
>      FloatRect filterBoundingBox() { return m_filterBBox; }
>      void setFilterBoundingBox(const FloatRect& rect) { m_filterBBox = rect; }
>  
> +    IntRect viewPort() { return m_viewPort; }
> +    void setViewPort(const IntRect& rect) { m_viewPort = rect; }

I question the need for these methods, but if you do have them, then viewPort() should be const.
Comment 19 Dirk Schulze 2009-11-10 11:11:59 PST
(In reply to comment #18)
> (From update of attachment 42876 [details])
> But is this rect in the same coordinate system as the rest of the filter rects?
> What if the filter is on a child of a transformed element?
Yes, it's the same coordinate space. I tested it on the W3C test suite, where SVG is embeded to html.
We already use this on pattern and others via clampImageBufferSizeToViewport.

> This isn't going to do the right thing for filtered SVG inside a HTML with CSS
> 3D transforms; element content that is outside the viewport can be made visible
> with a rotateY(), for example. And, yes the visible filtered content may be
> arbitrarily large in that case.
I don't like the idea of activating css transforms for SVG. What happens if we transform an SVG element with <animation>, JS and CSS transform (2D or 3D)?

> I question the need for these methods, but if you do have them, then viewPort()
> should be const.
Ok, viewPort() is not needed atm. setViewPort is needed to get the viewPort in SVGResourceFilter from SVGFilterElement.
Comment 20 Simon Fraser (smfr) 2009-11-10 11:20:40 PST
(In reply to comment #19)

> > This isn't going to do the right thing for filtered SVG inside a HTML with CSS
> > 3D transforms; element content that is outside the viewport can be made visible
> > with a rotateY(), for example. And, yes the visible filtered content may be
> > arbitrarily large in that case.
> I don't like the idea of activating css transforms for SVG. What happens if we
> transform an SVG element with <animation>, JS and CSS transform (2D or 3D)?

I'm not talking about CSS transforms on SVG. I'm concerned about SVG inside HTML, where the HTML has 3d transforms.
Comment 21 Dirk Schulze 2009-11-10 11:47:42 PST
(In reply to comment #20)
> (In reply to comment #19)
> 
> > > This isn't going to do the right thing for filtered SVG inside a HTML with CSS
> > > 3D transforms; element content that is outside the viewport can be made visible
> > > with a rotateY(), for example. And, yes the visible filtered content may be
> > > arbitrarily large in that case.
> > I don't like the idea of activating css transforms for SVG. What happens if we
> > transform an SVG element with <animation>, JS and CSS transform (2D or 3D)?
> 
> I'm not talking about CSS transforms on SVG. I'm concerned about SVG inside
> HTML, where the HTML has 3d transforms.
hm. I'm not familiar with 3d transform on CSS, but I made more tests after you comment. The viewPort size of the SVG, will depend on the <object> when you embed a SVG into a HTML. It will get the currently visible size when SVG is the root element (pure SVG).
Comment 22 Dirk Schulze 2009-11-10 11:49:25 PST
(In reply to comment #21)
> The viewPort size of the SVG, will depend on the <object> when you
> embed a SVG into a HTML.
This means, that the viewPort size is the size of the HTML-element <object>.
Comment 23 Simon Fraser (smfr) 2009-11-10 12:01:30 PST
(In reply to comment #22)
> (In reply to comment #21)
> > The viewPort size of the SVG, will depend on the <object> when you
> > embed a SVG into a HTML.
> This means, that the viewPort size is the size of the HTML-element <object>.

document()->view()->visibleContentRect() will return the content rect of the HTML document in the case of HTML with nested SVG.
Comment 24 Dirk Schulze 2009-11-10 12:12:54 PST
(In reply to comment #23)
> (In reply to comment #22)
> > (In reply to comment #21)
> > > The viewPort size of the SVG, will depend on the <object> when you
> > > embed a SVG into a HTML.
> > This means, that the viewPort size is the size of the HTML-element <object>.
> 
> document()->view()->visibleContentRect() will return the content rect of the
> HTML document in the case of HTML with nested SVG.
Well, this example:

<html>
<div style="margin: 20px;">
<object data="filter.svg" type="image/svg+xml" width="5000">
</div>
</body></html>

gives me 0,0,5000,150 as contentRect, is it that what you mean?
Comment 25 Simon Fraser (smfr) 2009-11-10 12:21:52 PST
Try xhtml with mixed SVG and HTML. <object> is different.
Comment 26 Dirk Schulze 2009-11-10 12:32:01 PST
(In reply to comment #25)
> Try xhtml with mixed SVG and HTML. <object> is different.

Don't we just support embeding svg into html with either <object>, <img> or <embed>?
Comment 27 Dirk Schulze 2009-11-10 12:42:02 PST
(In reply to comment #26)
> (In reply to comment #25)
> > Try xhtml with mixed SVG and HTML. <object> is different.
> 
> Don't we just support embeding svg into html with either <object>, <img> or
> <embed>?

Sorry. I noticed, that there is a difference, if I name the file with .xml or .html :-P Here the exmaple:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body id="body">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <linearGradient id="gradient" gradientUnits="objectBoundingBox"
                            x1="0" y1="0" x2="1" y2="1">
            <stop offset="0" stop-color="green" />
            <stop offset="0.01" stop-color="red" />
        </linearGradient>
        <filter id="filter">
            <feOffset/>
        </filter>
    </defs>
    <g>
        <rect x="0" y="0" width="5000" height="5000" style="fill:url(#gradient);filter:url(#filter);"/>
    </g>
</svg>
</body>
</html>

The viewport is now the visible area of the window and changes with resizing the window.
Comment 28 Dirk Schulze 2009-11-10 12:56:03 PST
(In reply to comment #25)
> Try xhtml with mixed SVG and HTML. <object> is different.
When I look at the exmaple above, I still think that the behavior is right, since the HML itself limits the size of the SVG. So clipping here is ok. And even with 3D transform, the SVG shouldn't get more content.
Comment 29 Simon Fraser (smfr) 2009-11-10 14:12:38 PST
Created attachment 42894 [details]
Testcase with svg inside 3d transform
Comment 30 Simon Fraser (smfr) 2009-11-10 14:20:52 PST
Created attachment 42897 [details]
Better testcase
Comment 31 Dirk Schulze 2009-11-10 14:33:38 PST
(In reply to comment #30)
> Created an attachment (id=42897) [details]
> Better testcase

Don't know if this is a bug on Cairo, but this example event don't work without filters. I added
<div style="background-color:green; width:5000px;height:50px"></div>
and the green box is longer than the green to red rect of the SVG (css transformation disabled). But this reflects a general problem with big sized SVG. We do clampImageBufferSizeToViewport on other parts of SVG and every time this could break CSS transformations :-/.

Who decided to combine this techniques ;-)
Comment 32 Dirk Schulze 2009-11-10 23:57:11 PST
I still believe that it is better to clip the filter to viewport for the moment. Even if it causes problems with big filters on CSS transforms. We should figure out a general solution for SVG to aboid this problem, since we clip the size on other parts of SVG too.
Or does someone have a better idea how to limit the calculation complexity?
Comment 33 Dirk Schulze 2009-11-23 09:30:28 PST
Fixed in bug 6021.