[Webkit-unassigned] [Bug 125306] New: Invalidating two disjoint elements' relayouts triggers full relayout

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Thu Dec 5 08:22:09 PST 2013


https://bugs.webkit.org/show_bug.cgi?id=125306

           Summary: Invalidating two disjoint elements' relayouts triggers
                    full relayout
           Product: WebKit
           Version: 528+ (Nightly build)
          Platform: All
               URL: http://www.russellmcc.com/private/abslayoutwebkit/test
                    .html
        OS/Version: Unspecified
            Status: NEW
          Severity: Normal
          Priority: P2
         Component: New Bugs
        AssignedTo: webkit-unassigned at lists.webkit.org
        ReportedBy: russell.mcclellan at gmail.com


We ran into this while developing a web app with a complicated layout.  Performing a full layout can take 10s or 100s of ms due to the complexity of the layout.  This bug totally cripples the mobile user experience during drags that affect multiple elements without using one of the workarounds described below.

If you invalidate the layouts two elements where neither are ancestors of the other, without triggering a layout in between, Webkit will decide that the whole document's layout is invalid.  In many cases, this is a very bad performance decision.  For example, see the linked page: clicking the "click here" button will change the text on the two absolutely-positioned divs.  As a web developer, I might expect this to cause a relayout of each of those divs and nothing else.  Instead, the entire document has a relayout event (as can been seen from the web inspector's timeline view), even though almost all of the document is *not* invalid.

As a web developer, I came up with two different workarounds (perhaps there are more): you can force a synchronous layout by querying something like the layoutHeight after invalidating the layout of a simple element (this is what the "or here" button in the test page does to prevent a full-document reflow).  Another option would be to institute a policy of always deferring functions that might affect the layout to their own stack by using setTimeout with zero timeout (webkit seems to always do a layout when the javascript stack clears, but I didn't look at the source to confirm this).  Neither of these workarounds is really a natural coding style.

I couldn't resist poking around in the source to find where this logic occurs: it seems to me that the culprit is in WebCore:page/FrameView.cpp's  FrameView::scheduleRelayoutOfSubtree function, which updates a "m_layoutRoot" variable which represents the RenderElement to start the layout from the next time a layout is triggered.  If there's already a layout scheduled, and it can't find an ancestor relationship between the new invalid element and the existing m_layoutRoot, it decides to do a full relayout.

I had two ideas of approaches that might be better than the status quo.  Please take these suggestions with a grain of salt as I'm not too familiar with the WebKit codebase - I'm just thinking out loud.  If someone familiar with this stuff thinks these are good ideas and would be willing to hold my hand a little bit I'd be happy to try to contribute either.

A somewhat complex approach that may be much more performant would be to replace "m_layoutRoot" with an "m_layoutRoots" an array of requested layout reflows, and then scheduleRelayoutOfSubtree would just add the subtree into m_layoutRoots.  Then, in layout, go through each of the m_layoutRoots in order, making sure to remove from the array any element  that happens to be layed out before it's turn (e.g.,  if it was a descendent of a previous member of m_layoutRoots).

Another approach that perhaps would be better than the current situation and would perhaps be easier to code would be, instead of triggering a full layout, synchronously layout the pending m_layoutRoot right there in the scheduleRelayoutOfSubtree function.

-- 
Configure bugmail: https://bugs.webkit.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.



More information about the webkit-unassigned mailing list