-
Notifications
You must be signed in to change notification settings - Fork 693
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
[css-shapes] Specify algorithms for computing line-box intrusion into float's margin box. #2949
Comments
@bfgeek CSS2 just says that "line boxes are shortened" - you're looking for a more precise definition of this? You mentioned on today's call that you looked at Gecko's code and saw that it pretty much matched Blink's. I'm assuming whatever we define should be useful for both regular floats and floats with shape-outside. Right now, the shapes spec says "line boxes next to a float are shortened as necessary to avoid intersections with the float area" - is this wrong, or just imprecise? How would you change this? |
Basically because of subtle implementation differences, we'll end up with implementations that mostly match, but that get edges cases wrong. (see history of CSS2 :P). This is mozilla's entry point for the above algorithm: This algorithm I'm after is you have some float, for a given line-box, how far into that shape can I go? The algorithms in the implementations are similar, but not exactly the same. E.g. they apply shape-margins at different stages (probably leading to different results), testing intersection with images looks like they'll behave differently, etc. I realize this is a lot of work to write down, and make sure all the edge cases work correctly, but this will mean that implementations can work towards what's in the specification, and another implementation will be able to easily implement without spending many engineering hours coming up with similar (but perhaps subtlety different algorithms). If we write down these algorithms, it'll be easy to find answers to the questions on the call such as what happens when polygons create -ve area, etc, and easy for implementations to implement the desired behaviour. |
My naive answer is "you can't" - the line box and the float area cannot intersect. We will definitely need to spec how the shape and shape-margin build up the float area in point, line and inverted area cases. I'm not clear what we need to spec for a particular float area and line box beyond "don't intersect." |
Sorry that sentence should be "how far into the float's margin box can I go, e.g. based on the shape area". If we don't have an algorithm for this then different implementations will add/subtract things at different stages, causing different behaviour when things saturate. Additionally "don't intersect" isn't enough; a valid implementation then would be to simply position line-boxes based on a bounding-rect of the shape area. Defining an algorithm for above, while a lot of work, will ensure that implementations have exactly the same behaviour, and less work for future/current implementations looking to implement the spec correctly. |
What Ian's trying to say is that the precise algorithm for computing an inflated/deflated shape (due to shape-margin) aren't written into the spec, and they're non-trivial to figure out correctly. It would help a lot to produce these. (For example, is it correct to handle ellipse() by just growing/shrinking the axises? That does not produce the same thing as "the shape obtained by adding all points X distance away from the edge", which isn't an ellipse any longer.) |
I don't see how one could conclude from the spec that growing/shrinking the axes of an ellipse would be an appropriate way to apply shape-margin. The shape-margin definition doesn't allow it. And there's an example of applying positive shape-margin to a polygon that shows that the resulting shape is no longer a polygon. We can definitely add more precise wording than "don't intersect," but I don't think we're going to be able to get precise enough to (for instance) guarantee that implementations are going to achieve the same line breaks. |
Why not, tho? I don't see a particular reason why we need to allow differences in the result here, beyond trivial things like rounding? SVG implementations already have solutions for computing the desired shapes (just take the implementation of the stroking algorithm, with What's still needed beyond that is an explanation of how to find how far into the shape's bounding rect a linebox can penetrate without intersecting the shape. There are algorithms in the literature for doing this sort of line-sweep collision-finding for physics engines, but saying "it's defined in the literature, good luck!" isn't a very nice thing to do to implementors. (I tried that with something for gradients, and @SimonSapin made me actually define it. ^_^) A naive approach that doesn't work, for example, is to find where the top and bottom edges of the linebox would hit the shape, and use the one that's further out - this ignores the possibility of a "spike" between the two edges that should push the linebox even further. The actual efficient algorithm isn't particularly easy to puzzle out! |
To summarize: There are two algorithms that are imprecise:
Given that neither of these calculations have crisp, clear algorithms for finding the optimal solution, I'd be hesitant about baking a full algorithm into the spec. But I do agree that there should probably be some clarifications. |
We definitely should be able to get to the point where implementations agree on the available geometry for line boxes. What they do within those line boxes isn't well-specified enough to guarantee identical line breaks, though (we don't guarantee identical line breaks within simple rectangles!). And as @AmeliaBR points out part of the algorithm for determining where line boxes go depends on the content width, so if there are different line breaks then it's possible implementations will differ in line box placement next to floats. But I'm all for adding more details on how implementations should process float areas and line boxes so we can get as close as we can. |
Oh yeah, actual line-breaking within the boxes is an unrelated thing we don't have to worry about.
If we bake an algo into the spec, and later find a more optimal version that gives slightly different results, we can either decide the compat isn't bad and update the spec, or decide the compat is too bad and stick with our old algo. If we don't bake an algo into the spec, implementations will still choose some algorithm for now. If they later find a more optimal version, they'll also either decide they can or can't update, based on compat pain. So the two situations are identical here, and there's no existing platform compat or similar UA-varying constraints making it more attractive to leave it up to quality-of-implementation, so there's no reason to not specify an algorithm. |
There is precedent in https://drafts.csswg.org/css-backgrounds/#shadow-blur
|
That one was because there is legit visible differences between blur implementations, but also significant cost differences, but aside from looking slightly prettier/uglier the different algos didn't affect the rest of the page, so it was okay to just give reasonable bounds and let UAs do whatever. That's not the case here, as the algo you use affect the geometry of the element, and can have significant effects in how things are laid out - whether a line is allowed to go between two parts of a disjoint shape from an image (especially when the gap approaches the size of the linebox), for example, is a pretty big and significant difference that authors will care about. |
On @AmeliaBR's first point, I think there's enough in the spec to go by. It defines the result, not the algorithm to achieve it, but the result is well-defined and testable.
All implementations appear to be interoperable with the "circle around the sharp point" definition in this test: https://codepen.io/astearns/pen/abbmLPv I do need to add how you need to determine the shape (including shape-margin) first, then deal with box intersections. So I'm leaving this issue open until I've gotten that done. |
Added the bit about doing the float area before wrapping in 462fdd1 |
If we want interop on css-shapes the specification needs to define given an exclusion with shape-outside defined, how far can a line-box intrude into that float. E.g. something like:
The text was updated successfully, but these errors were encountered: