Define overflow:visible behavior for pattern tiles #129

Open
AmeliaBR opened this Issue May 4, 2016 · 12 comments

Projects

None yet

7 participants

@AmeliaBR
Contributor
AmeliaBR commented May 4, 2016

The effect of visible overflow for pattern tiles was not clearly defined in SVG 1, leading to non-interoperable implementations. In SVG 1.1, a warning was added:

Note that if the ‘overflow’ property is set to visible the rendering behavior for the pattern is undefined.

I would really like to remove this "officially undefined" behavior from SVG 2.

Relevant discussion from the mailing list in 2009 (thread starts here) includes this statement from @erikdahlstrom :

The SVG WG agrees that the rendering behavior for overflow="visible" on elements in SVG 1.1 is currently unspecified. For the second edition of SVG 1.1 the WG has resolved to leave the rendering behavior for overflowing pattern tiles as undefined[1] in order to fully address the issue in the next version of SVG[2].

That second link goes to this Tracker issue, which has no updates since 2009.

This is not a theoretical issue. I get complaints & confusion from authors about why patterns that work just the way they want in one browser don't work in another. Specifically, the issue comes up when the repeating element of the pattern doesn't fit in a neat rectangular tile.

Here's a recent example screenshot. The top image is from Firefox, showing clipping to the pattern tile despite the overflow value, the bottom image is from Chrome:
Two screenshots, top has distinct elements separated by whitespace, bottom has a continuous houndstooth pattern

My current best advice for the authors is to use <use> elements to create enough repetitions to completely fill in the rectangular tile. But that's far from ideal. Not only is it messy and repetitive code, it also opens up the possibility of edge effects in the rendering (revealing the edges of the pattern tiles).

As I understand it, the only aspect of overflowing pattern tiles that really needs to be defined is the rendering order. When overflowing content from pattern tiles overlaps, which tile is painted on top? E.g., are tiles painted in rows, left to right then top to bottom, or in columns? I don't see any theoretical reason to prefer one or the other, so this could be based on whatever is easiest for current implementations.

Next steps:

  • Create a test case of overlapping overflowing patterns
  • Gather data for current implementations: which ones clip vs draw the overflow, and if they draw the overflow, what rendering order do they use
  • Feedback from implementers about whether there are any other intrinsic obstacles to supporting overflowing patterns.
@dennisgaebel

Thanks for filing this for me @AmeliaBR Here is the test case I put together that shows it's implementation. http://codepen.io/grayghostvisuals/pen/0d8d57b976de9863a3e3949bb863232e

I would prefer the current method this pen demonstrates as using the other method of use multiple times is more work than really necessary.

@AmeliaBR
Contributor
AmeliaBR commented May 5, 2016

@dennisgaebel I seem to have led you astray. Playing with your code, the problem in Firefox isn't caused by the overflow: visible, but by the patternTransform on the secondary pattern. I've extracted both patterns here: https://jsbin.com/bugebisatu/1/edit?html,output for comparison

Now, duplicating patterns with href references is another section of the spec that isn't as well defined as it should be. But you might be safe just calling this a Firefox bug.

As for the overflow: visible issue, I created a simpler test case here: https://jsbin.com/zujekujaxo/edit?html,output

Alas, it looks like we have browser compatibility (Blink, Gecko, & Edge, all tested on Windows) for always clipping to the pattern tile regardless of the overflow value. Which isn't particularly useful from an authoring point of view, but at least it's consistent and should probably be defined in the spec.

@Tavmjong
Contributor
Tavmjong commented May 5, 2016

It would be a real shame not to get this fixed. It is a huge authoring problem.

In practice, handling overflow is not hard implement. A simple strategy it to creates a tile of the correct size and then draws into the tile repeatedly, stepping by the tile width/height each time as necessary until the tile contains the complete pattern including overlaps from neighboring tiles. Then one tiles as normal. This is the strategy we (Inkscape) uses to render hatches which can also overflow.

What is missing in the spec is the rendering order when there is overflowing. For hatches, the spec dictates that the hatch paths are drawn from left to right. For patterns, I would suggest we spec tiling a row from left to right then tiling rows from top to bottom.

@Emasoft
Emasoft commented May 5, 2016

Can this be fixed in time for SVG 2?

@AmeliaBR
Contributor
AmeliaBR commented May 6, 2016

It's easy enough to define how overflowing pattern tiles could behave (Tav's description makes sense), but we would need commitments from other implementers before including it in the spec.

@heycam
Contributor
heycam commented May 12, 2016

It's probably fine to require overflow:visible with overflowing content to make the final pattern tile size larger and to draw multiple copies of the <pattern> into it, but it would need to be clear how many copies of the <pattern> need to be rendered. For example consider a simple case that I think we want to make work:

<pattern width="10" height="10" overflow="visible">
  <circle cx="0" cy="0" r="4"/>
</pattern>

If you extend the pattern area like this:

[1][2][3]
[4][5][6]
[7][8][9]

where [5] is the original (0, 0) -> (10, 10) area, then it's clear that it's sufficient to paint the pattern content four times: once at the original [5] position, and then at [6], [8] and [9]. Can we determine that automatically? We can look at the bounding box of the <pattern> content, although given filters with possibly indefinite extents (like <feGaussianBlur>) it's hard to determine what exact areas would have pixels touched (though you could make a good guess).

You can easily create content that would require many paints of the pattern, too, such as:

<pattern width="10" height="10" overflow="visible">
  <rect x="-10000" y="-10000" width="20000" height="20000"
        fill="black" fill-opacity="0.01"/>
</pattern>

Should this be painted thousands of times to end up with a completely opaque black pattern? Maybe! But it would be good to avoid allowing authors to easily create slow rendering content like this.

My feeling is that the most useful case is where we paint slightly out of the pattern tile, so maybe we can – at least initially – require that the pattern only be repeated in the eight adjacent spaces to the original tile area. If we find it's useful to have a bigger intermediate area for rendering, maybe we can have an attribute for that.

Tav's suggestion to paint paint top to bottom, left to right, sounds good.

@AmeliaBR
Contributor

I'm not sure I'd want to specify "overflow, but only onto the immediately adjacent tiles". It should be straightforward to calculate the extent of overflow from the (decorated) bounding box of the pattern contents. Filters complicate it, but all implementations will have a means of calculating the maximum "dirty" area of a given block of SVG code.

Yes, in some cases the results could be horrible for performance, but I don't think that's reason enough to impose an arbitrary limit.

@BigBadaboom

I've done some experimenting and I have had trouble coming up with a use case where the extra repeats are useful. If the pattern has a simple opaque design, you get no benefit from the extra repeats. You can't achieve effects with +/-nS that you can't achieve with +/-S.

Filters or other translucent elements that extend further than +/-S mostly just result in messy results. For example, a large drop shadow just ends up casting multiple extra shadows over your original object, making it darker and muddier.

So maybe Cameron's suggestion of just overflowing to the immediately adjacent tiles is not too unreasonable.

But perhaps someone can come up with an example that does do something useful with the extra repeats.

@Tavmjong
Contributor

It's not too hard to come up with interesting tiling using simple shapes that require more than +/-S. The first example is a simple filled rotated rectangle (requires 4 copies). The second example is a circle with just a stroke (requires 5 copies). The third example is a squiggly line (requires 20 copies, but would probably be better done as a hatch).

pattern_tiling_4
pattern_tiling_5
pattern_tiling_20

@BigBadaboom
BigBadaboom commented May 12, 2016 edited

Yeah I see how some of those are a bit easier to create with more than +/-S, especially #2. But none would require much extra work if overflow was limited to the immediately adjacent tiles.

@Tavmjong How does Inkscape work out how many times it needs to tile? The BBox? Wouldn't you risk getting clipped results when the pattern uses stroked shapes? Or does the algorithm add a fudge factor?

@nikosandronikos
Contributor

We discussed this issue on the telcon this morning.
https://www.w3.org/2016/05/12-svg-minutes.html#item03

Given that there isn't consensus on the best approach to take (restrict max tile area or not) and the uncertainty of either option actually being implemented. We're going to leave the effect of overflow:visible undefined in SVG 2 and devote our time to other areas of the spec.

We will definitely look to improve this behaviour in future, as it's badly needed by authors.

@Tavmjong
Contributor

Pull request: #164 to clarify overflow behavior and to encourage implementers to render overflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment