w3c / fxtf-drafts

Mirror of https://hg.fxtf.org/drafts
https://drafts.fxtf.org/
Other
71 stars 50 forks source link

[css-masking-1] stroke-bounding-box and non-scaling-stroke #279

Open dirkschulze opened 6 years ago

dirkschulze commented 6 years ago

Currently, the stroke bounding box does not take the CSS property vector-effects with the value non-scaling-stroke into account.

Though browsers do support non-scaling-stroke, the implementation can be very different and SVG does not require a specific way. Computing the actual stroke-width depending on the different applied transforms and the vector-effects is non trivial. (Note that even browsers currently do not compute the stroke-with for non-scaling-stroke but rather do it as part of the painting process.)

I'd like to propose to keep the algorithm as is and mention that vector-effects do not affect the stroke bounding box.

css-meeting-bot commented 6 years ago

The Working Group just discussed stroke-bounding-box and non-scaling-stroke.

The full IRC log of that discussion <BogdanBrinza> topic: stroke-bounding-box and non-scaling-stroke
<BogdanBrinza> GitHub: https://github.com/w3c/fxtf-drafts/issues/279
<chris> krit: referencing stroke bbox more now, and this does not take into account non scaling stroke. Is it the bbox or some hueristic of the stroke. We resolved on hueristic in the past to be comparable in all browsers. otherwise result is library dependent.
<chris> ... some cannot compute at all, others do not give a tight bbox
<AmeliaBR> Current definition/algorithms for the different bounding boxes: https://svgwg.org/svg2-draft/coords.html#BoundingBoxes
<chris> ... agreed to use hueristics, more consistent and easier for developers
<chris> ... if we keep it we need to clarify effect of NSS
<chris> chris: sounds like we should stay with the hueristic
<chris> tav: what is the hueristic?
<krit> https://drafts.fxtf.org/css-masking-1/#compute-stroke-bounding-box
<chris> krit: (looks for link) object bbox and then extending based on stroke properties
<chris> AmeliaBR: should check for mitred corners, but should use effective stroke width after NSS
<chris> krit: NSS graphical effect so not really geometric
<liam> [ https://svgwg.org/svg2-draft/painting.html#TermStrokeShape "Authors should be aware that the shape of a stroke may in some cases, such as at extremely tight curves, differ across platforms." ]
<chris> liam: spec says stroke shape may differ across platforms. same in PostScript. depends on precision of floating point.
<liam> [hence arguably not testable]
<chris> AmeliaBR: also non uniform scales, which mess up the coordinate system for stroke bbox on unscaled stroke
<chris> krit: yes, need to do in viewport coordinate space
<chris> ... but do we want to, or leave it entirely up to browsers? Affects masking, wll be incosistent
<chris> AmeliaBR: should not depend on parent coordinate space. if we integrate NSS then it depends on parent context as well
<chris> Tav: authors would not expect things to change with NSS
<chris> AmeliaBR: warn authors that using these together will not be useful
<chris> Tav: what situation would make them do that
<chris> AmeliaBR: like a mask image sized to the drawn area of the shape, then when scaled you expect the mask to scale too but it does not, with NSS
<chris> krit: need to specify what happens anyway
<chris> AmeliaBR: small intersection of effects, ok to say not supported, but needs a clear warning where they are defined
<chris> Tav: ok, good. lets not spend much time, little practical use
<chris> AmeliaBR: most important is consistent implementations
<chris> liam: and with stroke bounding box. will not be pixel fidelity
<chris> krit: give hueristic as a fallback, or say it must be used. in both cases, computing NSS bbox geometrically is not easy
<chris> ... prefer to get consistency, so not a tight bbox
<chris> chris: i would prefer we exclude it
<chris> AmeliaBR: exact computation or a generous hueristic (over rather than under-estimate)
<chris> krit: already in the masking spec
<chris> AmeliaBR: examples of cases where the mask is a worst case?
<chris> krit: will add to the issue
<chris> AmeliaBR: would like to see some diagrams. and feedback from other implementors
<chris> AmeliaBR: other implementors please give your opinions
<chris> BogdanBrinza: Microsoft does not have a strong opinion, but want it to be easy for implementors
<chris> krit: differences between the graphics libraries
<chris> BogdanBrinza: we don't support NSS yet
<chris> krit: this comes up even for ordinary stroke
<chris> rrsagent, make minutes
<RRSAgent> I have made the request to generate https://www.w3.org/2018/06/04-svg-minutes.html chris
<chris> rrsagent, make logs public
<RRSAgent> I have made the request, chris
<chris> rrsagent, make minutes
<RRSAgent> I have made the request to generate https://www.w3.org/2018/06/04-svg-minutes.html chris
dirkschulze commented 6 years ago

@dstorey @boggydigital @AmeliaBR Here an example of the different computed boxes w/o looking at non-scaling-stroke.

The first shape is the extreme case with the worst outcome of the heuristic. The second shape is the regular outcome for many shapes in real life.

The tight stroke box in the image is the idealistic outcome. A few implementations are able to compute it correctly in all cases... including paths with cubic curves.

screen shot 2018-06-05 at 06 54 52
Tavmjong commented 5 years ago

I would actually argue that the bounding box should be calculated assuming a non-dashing stroke.

AmeliaBR commented 5 years ago

I would actually argue that the bounding box should be calculated assuming a non-dashing stroke.

And that's currently specified in both algorithms for calculating it: in CSS masking, and in SVG 2.

Where the two algorithms differ is in how they handle mitered corners and line caps. The SVG 2 algorithm uses the actual stroke shape for painting (assuming no dashing), while the CSS Masking algorithm (which explicitly warns that it may be overridden by SVG 2) uses a set of heuristics that add on a little bit extra to the stroke bounding box for path, polygon and polyline based on the value of the line join/cap properties, without actually checking for whether those properties cause the stroke to extend outside the box by (object bounding box + 1/2 stroke width padding).

If we're using the actual stroke shape, then maybe it makes sense to use the shape as painted, with vector effects included. (But that still creates complications of translating that shape back into the current coordinate system.) If we're using the heuristics, then definitely keep it simple.

Has anyone actually implemented any of these algorithms for properties that use a stroke-box value?

svgeesus commented 5 years ago

I would actually argue that the bounding box should be calculated assuming a non-dashing stroke.

Yes, otherwise it changes if stroke dash, or offset, is animated.

css-meeting-bot commented 5 years ago

The SVG Working Group just discussed [css-masking-1] stroke-bounding-box and non-scaling-stroke, and agreed to the following:

The full IRC log of that discussion <myles> Topic: [css-masking-1] stroke-bounding-box and non-scaling-stroke
<myles> GitHub: https://github.com/w3c/fxtf-drafts/issues/279
<myles> krit: We have the stroke bounding box and for various limitations in implementations and difficulties in rendering, masking is having some heuristics for the bounding box. These heuristics don't say anything about the non scaling stroke property. In some cases it makes it smaller, and in some bigger.
<myles> krit: So what happens? Does it affect the bounding box?
<myles> chris: It should take it into account. CSS masking allows SVG to override it, so this affects CSS. There's a question about dashing - it takes dashing into account, then the stroke bounding box will change depending on dashing, and the bounding box can change on every iteration from, so it should take all the largest possible stroke that could be painted, and it may not be the tightest box
<myles> krit: WebKit does use tight stroke bounding box at the moment.
<myles> chris: It does the tight boudning box including the dashing?
<myles> krit: yes
<myles> chris: That's correct. It's probably easier for implementors too
<myles> krit: It's expensive to compute.
<myles> krit: However, the difficulty is the differences between the implementations depending on how they compute it.
<myles> krit: That's why we need heuristics in the first place.
<myles> chris: Is that about miter limits?
<myles> krit: yes, mostly.
<myles> krit: I did a patch for WebKit to include it. It is possible to compute it correctly and include it into the heuristic. It can be done. I can put it in the spec.
<myles> chris: I don't think it affects very much. You work out what the width really is, and then proceed.
<myles> AmeliaBR: It becomes an issue if you have weird transforms. In the coordinate system for the shape, your stroke that is an even width line on the screen, it isn't even in the unevenly scaled coordinate system.
<myles> myles: You would implement it by computing it and passing it through a transform.
<myles> AmeliaBR: Yes. Figure out what the shape should be in the screen coordinate system, and stroke it there. But bbox needs to be in local coordinate system. So it needs to round-trip
<myles> krit: AmeliaBR, myles, should we integrate it?
<myles> AmeliaBR: Either make it really simple or really accurate. I don't like CSS masking because it's in-between. It has weird extra heuristics that complicate things that gives you weird results that aren't what you want. Let's keep it really simple that are the fill bounding box padded by half the stroke width, or let's be accurate.
<myles> krit: What about miter?
<myles> AmeliaBR: In CSS masking, you get a different stroke bounding box for a rectangle and for a polygon with the same corners as the rectange. That's unfortunate.
<myles> krit: We can make it consistent ... <missed>
<myles> AmeliaBR: The heuristic assumes there might be a sharp corner, but there might not be. They're rough approximations.
<myles> krit: I uploaded an image that the heuristic can be wrong, depending on the miter limit.
<myles> myles: what do authors want?
<myles> krit: Heuristics are for giving the same experience in every browser.
<myles> chris: The other thing is that the bbox should include all the stroke. If it includes more, that's probably okay
<myles> chris: but if it includes less, then that's worse.
<myles> chris: you typically want to apply a filter to that region or use that region for pointer events. If you missing some, that's visually intrusive.
<myles> myles: given we're already passing these paths through transforms, we should probably just do the right thing
<myles> krit: What is the "correct thing"? The tight stroke box without dashing?
<myles> myles: no opinion
<myles> myles: (about dashing)
<myles> krit: You want it to entirely contain, but in some examples, the heuristic can do bad things
<myles> AmeliaBR: My main concern is that you can end up changing the bounding box by changing a shape to a path. If we can address that, so we leave room for those miter corners even on a circle that never has miter corners, that would address the issue. I don't like the idea of convering a shape to a path and the bbox changes and now your effects are no longer aligned.
<myles> krit: So, you would rather prefer to have the red box than the correct one for non-rects and symbols?
<myles> AmeliaBR: yes
<myles> AmeliaBR: It's better to be overly generous. The main reason in the first place is authoring complaints that the default bounding box doesn't include the stroke (it's too small)
<myles> krit: Do people agree?
<myles> krit: chris?
<myles> chris: I'm fine with that.
<myles> krit: proposed resolution: Don't include non-scaling stroke in the bounding box
<myles> krit: proposed resolution: use the same heuristic regardless of what shape it is
<myles> krit: Let's start with the second one. Then we can do the first one and see if we can work out how to do it
<myles> AmeliaBR: Try to see if we can come up with a reasonable heuristic for incorporating non-scaling stroke
<myles> AmeliaBR: Proposed resolution: Use the same heuristic as CSS masking, but modify it to make it apply equally to all shapes, and modify it to incorporate non-scaling stroke
<myles> chris: and if we can't?
<myles> AmeliaBR: If we can't do anything useful, do nothing
<myles> chris: If we can't, we can err on the side of exactness
<myles> krit: I'll make a proposal.
<myles> AmeliaBR: "Use the same heuristic as CSS masking, but modify it to make it apply equally to all shapes, and modify it to incorporate non-scaling stroke" but make it clear we will revisit when we have proposed text
<myles> RESOLVED: Desire to use the same heuristic as CSS masking, but modify it to make it apply equally to all shapes, and modify it to incorporate non-scaling stroke. Revisit this once we have specific text