- From: Shelby Moore <shelby@coolpage.com>
- Date: Thu, 21 Oct 2010 11:51:57 -0400
- To: shelby@coolpage.com
- Cc: "Boris Zbarsky" <bzbarsky@mit.edu>, "www-style list" <www-style@w3.org>
Thinking about a fully generalized model for layout. I am approaching the problem posited by this thread, from the perspective that the way to successfully model such an egregarious divergence from current CSS2.1, is to remap the existing CSS2.1 into a more general metaphor. Then hypothetically, CSS2.1 becomes sub-classes (macros) of the general metaphor. If we were to instead build more special cases to try to understand the interactions, afaics we would be rapidly devolving towards gridlock in CSS, especially with respect to the limitations of the implementations of layout engines. As an initial simplifying thought experiment, I restrict the following to only one level of hierarchy with only relative element positioning (and relative element sizing), and positioning relative to the parent document element as the fixed point(s) of reference. I think perhaps this fully generalizes CSS layout once it is extended to multi-level hierarchy. Note I will not consider relative size here, simply to keep the examples less verbose, but it seems to be straight forward to incorporate. First the constraint solver walks all the relative relationships find to find at least one relative reference to parent position. Otherwise, return a hard fail. Relative positioning is a 4D vector, [referenced elem, target elem, direction, distance], where distance may be 'auto' and direction is at least a 2D vector [ref elem edge, target elem edge], and where edge is at least a 5 state enumeration [left|top|right|bottom|inline-valign], where inline-valign (aka vertical-align) is at least a 8 state enumeration [baseline|sub|super|top|text-top|middle|bottom|text-bottom]: http://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align So CSS2.1 { display:inline; vertical-align:baseline; letter-spacing:0; text-align:left } is equivalent to following, except there is no line, thus no wrap in relative positioning: http://lists.w3.org/Archives/Public/www-style/2010Oct/0408.html { position:element; element:prev-sibling; rhpos:left-right; rhmargin:0; rvpos:baseline; rvmargin:0; rsize:auto } *Note 'rvpos:baseline' is shorthand for 'rvpos:baseline-baseline'. **Note 'r?margin' is an enumeration [auto|<length>|flex], where default 'flex' is to justify except that relative sizing can consume these flex margins. ================================= We can add wrapping (thus lines) to relative positioning, it applies to all children, and if defines the position amongst all possible groupings of the children where wrapping is allow [none|each|letter|word]: { wrap:word } Wrapping complicates the relative direction and distance constraints, so I will not detail how to solve them for now. ***Note thus given prior inline emulation example, then {wrap:word} for parent with {rhmargin:flex} for children, is equivalent to {text-align:justify}. ================================= The constraint algorithm places each 4D relationship vector into a hash table, hashed on element for each of the elements in the pair of the relationship. It also places each derivative relationship into these hash tables. The size of the hash table is the combination n! / (2 * (n-2)!) = n * (n - 1) / 2. Here is an example: .rpos { position:element } .fixed { element:parent; rhpos:left-left; rvpos:top-top } .adjacent { element:prev-sibling; rhpos:left-right; rvpos:baseline } .first { element:id; elem-id:first; rhpos:right-left; rvpos:baseline} <parent style='wrap: <elem class='rpos fixed' id='first'></elem> <elem class='rpos adjacent'></elem> <elem class='rpos first'></elem> Note the above is unsolvable, because the 3rd elem wants to be left of the 1st elem, but the 1st elem wants to be fixed in the left, top corner of the (docElem) parent's box. The 6 (n = 4) entries for the hash tables are: [parent, 1st elem, [[left, top], [left, top]], [0, 0]]] [parent, 2nd elem, [[left, baseline], [left, baseline], [1st elem width, 0]]] [parent, 3rd elem, [[left, baseline], [right, baseline], [0, 0]]] [1st elem, 2nd elem, [[right, baseline], [left, baseline], [0, 0]]] [1st elem, 3rd elem, [[left, baseline], [right, baseline], [0, 0]]] [2nd elem, 3rd elem, [[left, baseline], [right, baseline], [1st elem width, 0]]] =============================== For each element, if any entries in the hash table are incongruent, then the constraints have no solution, and hard fail is returned. For example, the entries for the 3rd elem: [parent, 3rd elem, [[left, baseline], [right, baseline], [auto, auto]]] [1st elem, 3rd elem, [[left, baseline], [right, baseline], [auto, auto]]] [2nd elem, 3rd elem, [[left, baseline], [right, baseline], [1st elem width, auto]]] where 'auto' can be any constant value (e.g. 0). We see it wants to be 'rhpos:right-left' relative to the parent, which is illegal, since the parent's box must contain the union of its child boxes. Similarly, when compiling the entries, we would detect incongruencies where circular derivative relationships want to be in opposite directions or the same direction but with conflicting (i.e. not auto) distance. ============================= In a possible future post, I may attempt to contemplate how we generally solve the constraint vectors for wrapping, 2D viewports, 2D paged media, and 2D overflow containers. Once we generally solve this, we will have I think fully generalized CSS layout, since the CSS layout primitives can be expressed in this generalized models. I need to think more about whether that is true. Also what happens when we introduce multi-levels of hierarchy. Also there will need to be a metaphor for flowing content into a container and propagating to other containers, in order to support dynamic columns. This is as far as I can take it for now, because I have some other work to do. I just wanted to brain dump, in case it can help the brainstorming process. >> On 10/20/10 1:38 PM, Shelby Moore wrote: >>> The pagination algorithm tests the containing block for intersection >>> with >>> the page boundary, then it flags the constraint and re-runs the layout >>> (which calls the various constraint algorithms). This repeats until >>> there >>> are no more intersections. >> >> Uh... in general, you never got to "no more interesections". So I'm not >> sure what you're talking about here. > > I will uncompact what I meant for the generalized algorithm (this is just > off top of my head, I've never looked at browser layout code). > > 1) Run layout with the page rectangle as global constraint available to > all methods. The methods make local decisions about their position and > extent, e.g. the inline flow algorithm wraps (depending on wrapping style > etc) to the Min( viewport, container ) where container might be 'auto'. > The local decisions may cause their parents to clip. > > 2) Enumerate top-down hierarchy (i.e. box model) for paginate each > container box (margins excluded), and flag any parents which need to be > constrained. > > 3) If any were flagged, go back to step #1. > > In subsequent calls to step #1, the container will not longer be auto, but > rather constrained so that it does not intersect the clip boundary. > > I am skipping the complication of prioritizing no clip in the horizontal > direction, and using that constraint to push content to next page for > paged media. > > The point being that none of the above depends on how the container boxes > were positioned and sized. > >> >>> You optimize this for incremental updates, by making special case rules >>> about how certain constructs can change layout when changed, e.g. >>> identifying propogation boundaries, but you still need the generalized >>> algorithm above for those cases that your special case optimizer can't >>> handle. >>> >>> Am I far off base? >> >> Dunno. The one pagination setup in a browser that I'm very familiar >> with works nothing like this; the second one I've sort of looked at >> doesn't seem to either. > > I guess there are many ways to skin a cat. > > Sounds like an area I will enjoy experimenting and become more expert in.
Received on Thursday, 21 October 2010 15:52:34 UTC