Changeset 180063 in webkit


Ignore:
Timestamp:
Feb 13, 2015, 11:04:12 AM (10 years ago)
Author:
Simon Fraser
Message:

Crashes under RenderLayer::hitTestLayer under determinePrimarySnapshottedPlugIn()
https://bugs.webkit.org/show_bug.cgi?id=141551

Reviewed by Zalan Bujtas.

It's possible for a layout to dirty the parent frame's state, via the calls to
ownerElement()->scheduleSetNeedsStyleRecalc() that RenderLayerCompositor does when
iframes toggle their compositing mode.

That could cause FrameView::updateLayoutAndStyleIfNeededRecursive() to fail to
leave all the frames in a clean state. Later on, we could enter hit testing,
which calls document().updateLayout() on each frame's document. Document::updateLayout()
does layout on all ancestor documents, so in the middle of hit testing, we could
layout a subframe (dirtying an ancestor frame), then layout another frame, which
would forcing that ancestor to be laid out while we're hit testing it, thus
corrupting the RenderLayer tree while it's being iterated over.

Fix by having FrameView::updateLayoutAndStyleIfNeededRecursive() do a second
layout after laying out subframes, which most of the time will be a no-op.

Also add a stronger assertion, that this frame and all subframes are clean
at the end of FrameView::updateLayoutAndStyleIfNeededRecursive() for the
main frame.

Various existing frames tests hit the new assertion if the code change is removed,
so this is covered by existing tests.

  • page/FrameView.cpp:

(WebCore::FrameView::needsStyleRecalcOrLayout):
(WebCore::FrameView::updateLayoutAndStyleIfNeededRecursive):

  • page/FrameView.h:
  • rendering/RenderWidget.cpp:

(WebCore::RenderWidget::willBeDestroyed):

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified trunk/Source/WebCore/ChangeLog

    r180062 r180063  
     12015-02-13  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Crashes under RenderLayer::hitTestLayer under determinePrimarySnapshottedPlugIn()
     4        https://bugs.webkit.org/show_bug.cgi?id=141551
     5
     6        Reviewed by Zalan Bujtas.
     7       
     8        It's possible for a layout to dirty the parent frame's state, via the calls to
     9        ownerElement()->scheduleSetNeedsStyleRecalc() that RenderLayerCompositor does when
     10        iframes toggle their compositing mode.
     11       
     12        That could cause FrameView::updateLayoutAndStyleIfNeededRecursive() to fail to
     13        leave all the frames in a clean state. Later on, we could enter hit testing,
     14        which calls document().updateLayout() on each frame's document. Document::updateLayout()
     15        does layout on all ancestor documents, so in the middle of hit testing, we could
     16        layout a subframe (dirtying an ancestor frame), then layout another frame, which
     17        would forcing that ancestor to be laid out while we're hit testing it, thus
     18        corrupting the RenderLayer tree while it's being iterated over.
     19       
     20        Fix by having FrameView::updateLayoutAndStyleIfNeededRecursive() do a second
     21        layout after laying out subframes, which most of the time will be a no-op.
     22       
     23        Also add a stronger assertion, that this frame and all subframes are clean
     24        at the end of FrameView::updateLayoutAndStyleIfNeededRecursive() for the
     25        main frame.
     26
     27        Various existing frames tests hit the new assertion if the code change is removed,
     28        so this is covered by existing tests.
     29
     30        * page/FrameView.cpp:
     31        (WebCore::FrameView::needsStyleRecalcOrLayout):
     32        (WebCore::FrameView::updateLayoutAndStyleIfNeededRecursive):
     33        * page/FrameView.h:
     34        * rendering/RenderWidget.cpp:
     35        (WebCore::RenderWidget::willBeDestroyed):
     36
    1372015-02-12  Simon Fraser  <simon.fraser@apple.com>
    238
  • TabularUnified trunk/Source/WebCore/page/FrameView.cpp

    r180062 r180063  
    25622562}
    25632563
     2564bool FrameView::needsStyleRecalcOrLayout(bool includeSubframes) const
     2565{
     2566    if (frame().document() && frame().document()->childNeedsStyleRecalc())
     2567        return true;
     2568   
     2569    if (needsLayout())
     2570        return true;
     2571
     2572    if (!includeSubframes)
     2573        return false;
     2574
     2575    // Find child frames via the Widget tree, as updateLayoutAndStyleIfNeededRecursive() does.
     2576    Vector<Ref<FrameView>, 16> childViews;
     2577    childViews.reserveInitialCapacity(children().size());
     2578    for (auto& widget : children()) {
     2579        if (is<FrameView>(*widget))
     2580            childViews.uncheckedAppend(downcast<FrameView>(*widget));
     2581    }
     2582
     2583    for (unsigned i = 0; i < childViews.size(); ++i) {
     2584        if (childViews[i]->needsStyleRecalcOrLayout())
     2585            return true;
     2586    }
     2587
     2588    return false;
     2589}
     2590
    25642591bool FrameView::needsLayout() const
    25652592{
     
    39814008        childViews[i]->updateLayoutAndStyleIfNeededRecursive();
    39824009
    3983     // When frame flattening is on, child frame can mark parent frame dirty. In such case, child frame
    3984     // needs to call layout on parent frame recursively.
    3985     // This assert ensures that parent frames are clean, when child frames finished updating layout and style.
    3986     ASSERT(!needsLayout());
     4010    // A child frame may have dirtied us during its layout.
     4011    frame().document()->updateStyleIfNeeded();
     4012    if (needsLayout())
     4013        layout();
     4014
     4015    ASSERT(!frame().isMainFrame() || !needsStyleRecalcOrLayout());
    39874016}
    39884017
  • TabularUnified trunk/Source/WebCore/page/FrameView.h

    r179886 r180063  
    123123    void setViewportConstrainedObjectsNeedLayout();
    124124
     125    bool needsStyleRecalcOrLayout(bool includeSubframes = true) const;
     126
    125127    bool needsFullRepaint() const { return m_needsFullRepaint; }
    126128
  • TabularUnified trunk/Source/WebCore/rendering/RenderWidget.cpp

    r177412 r180063  
    100100    }
    101101
    102     setWidget(0);
     102    setWidget(nullptr);
    103103
    104104    RenderReplaced::willBeDestroyed();
Note: See TracChangeset for help on using the changeset viewer.