Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[filter-effects][css-masking][fill-stroke] clarify userSpaceOnUse / objectBoundingBox applied to non-SVG elements #249

Open
AmeliaBR opened this issue Jan 24, 2018 · 5 comments

Comments

@AmeliaBR
Copy link

filter, mask, clip-path, and the proposed extension of fill and stroke all support SVG graphical effects applied to CSS layout boxes.

The problem: none of these specs clearly define how the SVG effect-scaling attributes ( objectBoundingBox versus userSpaceOnUse for filterUnits, primitiveUnits, maskUnits, maskContentUnits, clipPathUnits, gradientUnits, patternUnits, and patternContentUnits) map to the CSS box model.

I think we've got fairly consistent implementations when it comes to objectBoundingBox effects (but I haven't tested carefully), by mapping it to border-box. This is despite the fact that definitions in masking and filters just link to the SVG spec's definition of bounding box units. And fill & stroke has text trying to get border-box to match stroke-box.

I know we don't have consistency for userSpaceOnUse effects. Definitions in the spec link to CSS Transforms' definition of the user coordinate system, which has now been updated to be defined as the transform-box width and height and position, with 1 unit = 1 CSS px. (I haven't tested whether any browsers that implement transform-box for SVG elements also change how userSpaceOnUse effects work in SVG. But my guess is no.)

Of course, to make it even more confusing, only Firefox matches the spec definition of userSpaceOnUse for SVG elements. Everyone is else is broken in a very unhelpful way.

(PS, Sorry for not bringing this up before. It's only as we've been working through FXTF issues that I realized there wasn't already an open issue for something I knew as one of the biggest issues with these specs!)

@AmeliaBR
Copy link
Author

AmeliaBR commented Jan 24, 2018

An initial test case, with filters, for people to start exploring: https://codepen.io/AmeliaBR/pen/qpGQyQ

Summary of the test:

  • The three filters each paint a flood color in the defined filter region, and then layer the original element over top. The original element will also be clipped to the filter region.

    • The blue and green filters are objectBoundingBox filters; the filter region is set to 2px wide (in scaled coordinates, this means 2 times the bounding box width) and 50% high (meaning 50% of the bounding box), measured from the 0,0 point of the reference box. The two filters are identical except for the flood color (they're used to distinguish different elements: the blue on normal elements and the green on elements with a rotational transform).
    • The purple and red filters are both userSpaceOnUse filters, with a filter region set to 100px wide (in the user coordinate system) and 50% high (of the user coordinate system's height), measured from the 0,0 point of the reference coordinate system. The purple is used on normal elements and the red on transformed elements.
  • The SVG containing the filter definitions is absolutely positioned offscreen, and set to 1px square, but with a 20x20 viewBox, because if we made it smaller elements would disappear in certain browsers and that wouldn't be very useful, now would it?

  • A series of 200x50px inline SVGs, each containing a 100%x100% rectangle (with yellow dotted stroke) that has the filter effects applied (and a transform applied, for the green & orange filters). All the SVGs have visible overflow; the cropping you see is from the filter region.

  • A series of 200x50px divs (with yellow dotted border), with the filter effects and transforms applied. The transform-origin is set to 0 0 to match SVG transform behavior.

Summary of results:

SVG elements:

  • All browsers tested are consistent & to-spec for rendering the objectBoundingBox effect on untransformed SVG elements (blue flood). The filter region is 1.5 times the rect fill-box width and half its height. Strokes are cropped where they fall outside the fill-box.

  • Most browsers are consistent & to-spec for objectBoundingBox on a transformed SVG element: the transform affects the filter region, so this looks like the previous element but rotated. MS Edge calculates the bounding box of the transformed rect in its parent's untransformed coordinate system before applying the filter.

  • As mentioned, Firefox is the only browser that is to-spec for userSpaceOnUse applied to SVG elements (purple), cropping the filtered rectangle to 100px wide and 50% of its user space height (aka, 25px). All the others calculate the 50% height relative to the 20-unit viewBox height of the SVG where the filters were defined, instead of the SVG where the effect is being used. (But they do scale the units back up to full px height, according to the local coordinate system.)

  • I'm not quite sure what Edge is doing with the user-space, transformed SVG element (red). All the other browsers are consistent with their results for the untransformed case, and then apply the transform to the filtered element.

CSS boxes:

  • MS Edge doesn't apply SVG filters to CSS boxes at all, so we don't know how they'd scale them if they did. However, there still seems to be weird rendering issues when both filter and transform are applied to the same box, and some elements disappear.

  • Safari ignores all filter-region parameters for SVG filters applied to CSS boxes, and instead clips the flood exactly to the border-box.

  • For objectBoundingBox (blue and green), Firefox & Chrome are consistent with each other, using the border-box as the bounding box, and creating a filter region that is 1.5 times the border-box width and half its height, and adjusting the box for transforms.

  • For userSpaceOnUse, Chrome and Firefox are each consistent with what they do for SVG when it comes to percentages (AKA, they disagree with each other), but are otherwise are using the border-box as the user-space reference box with 1px having its normal meaning.

    Which means Firefox is consistent with the spec as I'd interpret it (linking to the CSS transforms definition of local coordinate system) for CSS boxes: the reference box is the transform-box, which is always border-box for elements without SVG layout. (But I tested separately, and they don't adjust userSpace for SVG elements when you change transform-box to fill-box. So need to decide what to do there.)

Screenshots of results

Chrome (v63):
Screenshot, as described in the text

Firefox (v59):
Screenshot

Safari (v11 on OSX 10.13):
Screenshot

MS Edge (EdgeHTML v16):
Screenshot

@dirkschulze
Copy link
Contributor

@AmeliaBR Could you add this to the Agenda of the CSS WG? Do you think it should be discussed during the current F2F or can this be done in a regular telconf?

@AmeliaBR
Copy link
Author

AmeliaBR commented Apr 9, 2018

Hi @dirkschulze,

I'm not at the Face to Face, but it would be good to get a wider discussion, since this affects so many specs. If it could be scheduled for late afternoon Berlin time, I could call in and give a background/overview of the issue. But it might help if you're ready with some demos / whiteboard examples of all the different cases & options.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Clarify how userSpaceOnUse and objectBoundingBox apply to non-SVG elements.

The full IRC log of that discussion <TabAtkins> Topic: Clarify how userSpaceOnUse and objectBoundingBox apply to non-SVG elements
<astearns> github: https://github.com//issues/249
<TabAtkins> AmeliaBR: Mega issue that affects everything in SVG graphical effects that we support applying to CSS boxes
<TabAtkins> AmeliaBR: svg effects (gradients, patterns, clips) have a switch for how they're scaled and positioned
<TabAtkins> AmeliaBR: So when you apply it to a rect, it can either be scaled to that rect, or to the svg as a whole so a gradient spreads smoothly across multiple rects, etc.
<TabAtkins> AmeliaBR: When we added the specs for applying masks/clip-paths/filters to CSS boxes, it was never defined how they map to CSS coordinate spaces
<TabAtkins> AmeliaBR: Actual impls are inconsistent
<TabAtkins> AmeliaBR: I periodically get bug reports about how this is supposed to work
<astearns> TabAtkins: roc had a proposal
<astearns> TabAtkins: both anchor position according to CSS coordinate space, (and some other stuff)
<astearns> TabAtkins: you at least get consistent sizing
<TabAtkins> AmeliaBR: Yes, that's tehe simplest approach that still has sensible results
<TabAtkins> AmeliaBR: So boxes are always the size of the css box
<dbaron> s/consistent sizing/consistent sizing, but don't have the ability to have multiple boxes with views into the same gradient/
<TabAtkins> AmeliaBR: And OBB, which assumes the effect is scaled 0->1 gets that, and USOU gets normal px measurements
<dbaron> (I think that's right?)
<dbaron> (Tab says it is)
<TabAtkins> AmeliaBR: Other possiblity is that you map USOU to the ICB (or nearest CB). Firefox does one of these, don't remember which CB.
<TabAtkins> AmeliaBR: This doesn't match roc's proposal.
<TabAtkins> AmeliaBR: So ncan we get more eyeballs on this? It prevents us from getting a reasonable spec on several of our fxtf specs.
<fantasai> ScribeNick: fantasai

@mstange
Copy link

mstange commented Jun 6, 2019

  • For objectBoundingBox (blue and green), Firefox & Chrome are consistent with each other, using the border-box as the bounding box, and creating a filter region that is 1.5 times the border-box width and half its height, and adjusting the box for transforms.

There is actually a Firefox bug here which means that this is not entirely true: If the element has overflow, e.g. due to box-shadow, then Firefox enlarges the objectBoundingBox to include that overflow. This is tracked in bug 1067355.

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

No branches or pull requests

4 participants