Re: Selector for parent/predecessor?

Giuseppe Bilotta wrote:
> IANAI (I Am Not An Implementor), but I don't really see how this is
> any different from having to know the entire content of the element
> before rendering it.

The main difference is how much needs to be recomputed and how often.

> And by judging from what I see in Opera or Mozilla, dynamic/progressive restyling is not really a problem

This is only true in Mozilla (which is the implementation I'm familiar with) 
because it's buggy.  We haven't even figured our a reasonably efficient way to 
implement dynamic changes to :empty yet, for example.  As a result, such dynamic 
changes are broken.

> and *after* all
> the juggling is done I add a <style>...</style> element to my document
> with all the CSS I'm interested in ... and *poof* the page gets
> rendered correctly.

Again, I can only speak for Mozilla.  What Gecko does in this case is to simply 
reresolve style for everything in the tree, starting with the root element and 
going down.  This is very expensive, but in this case we make the (correct, imo) 
assumption that tossing an entire stylesheet into the document is a very rare 
operation, so doing it slowly is acceptable.  For a document of any appreciable 
size (say for example the unzipped version of 
http://downloads.mysql.com/docs/refman-5.1-en.html.zip) this stle recomputation 
takes on the order of tens of seconds.

> Even without considering these extreme cases, a lot of complex pages
> with no JS code require some rendering box shuffling and restyling
> *while loading*, and both Opera and SeaMonkey seem to handle them
> pretty well.

The only restyling that Gecko handles correctly at the moment is:

1)  Styles the only depend on the element's attributes/state
2)  The '>' combinator

There are, as I said, known bugs with :empty; the behavior of '+' and '~' is ok 
for changes to state, but NOT for insertions into the document or removals from 
it.  Luckily, during the load of a page there are no such insertions or removals 
(because the '+' and '~' combinators only affect style of things after the node 
being inserted or removed, and during pageload nodes are always added at the 
end).  So in Gecko those combinators sort of work during pageload, but not 
during JS manipulation of the page.

Going into a little more detail, the way that Gecko implements dynamic changes 
at the moment is the following: when a node's state changes, we determine the 
set of nodes whose style may have changed as a result, and recompute their 
style.  For the '~' combinator, for example, this is the the set of following 
siblings of the node (and all their descendants, but that's implied anyway due 
to CSS inheritance).  This particular condition is very easy to express: "If the 
state of a node has changed such that it ceases or starts matching the sequence 
of simple selectors on the left of a '~' combinator, style needs to be 
recomputed on all following siblings of the node."  Checking whether this 
condition applies is very fast -- simply match the node against the left sides 
of all '~' combinators.  Recomputing the style itself might be a little slow, 
however, but we've accepted that as a tradeoff, especially because during 
pageload (which is the #1 most common dynamic restyling case) there are no 
following siblings around.

With regard to insertions of DOM nodes, the condition for '~' is: "If a node is 
inserted and either it, or any of its previous siblings matches the sequence of 
simple selectors on the left of a '~' combinator, style needs to be recomputed 
on all following siblings of the node."  Note that checking whether this 
condition applies is much slower due to the need to examine all previous 
siblings, unless one simply assumes that style on following siblings should be 
recomputed all the time.  Either approach makes incremental layout at best 
O(N^2) in the number of increments, leading to serious performance degradation 
of pageload.  This is why this case is not handled correctly by Gecko -- we 
haven't found a way to do it right without regressing pageload performance yet.

Now consider parent/predecessor selectors in all their forms (:matches, parent 
combinators, etc).  Let's take the parent combinator as a simple to analyze 
example.  The condition for correctness on insertion in this case is: "If a node 
is inserted, and any node anywhere in the document matches the sequence of 
simple selectors on the left of a parent combinator, style needs to be 
recomputed on all nodes in the document."  No comment on pageload performance.

> So please help me get something right: Opera and SeaMonkey already
> handle similar situations

My point is that Gecko doesn't handle them.  I can't speak for Opera.

> Plus,  as Allan Sandfeld Jensen mentions:

I'd love to see Allan's implementation; it may give me some ideas on how to do 
this in Gecko.  I'd also like to do some performance testing on it as compared 
to Gecko, of course.  ;)

> Even worse, I don't understand /who/ is objecting

Last I checked, people involved in Gecko (myself, say) and Webkit [Safari] 
(David Hyatt, say) were having concerns about being able to implement this in a 
performant way.

-Boris

Received on Monday, 21 August 2006 15:51:44 UTC