Changeset 188298 in webkit


Ignore:
Timestamp:
Aug 11, 2015 2:50:32 PM (9 years ago)
Author:
Alan Bujtas
Message:

Invalid FrameView::m_viewportRenderer after layout is finished.
https://bugs.webkit.org/show_bug.cgi?id=147848
rdar://problem/22205197

Reviewed by Simon Fraser.

We cache the current viewport renderer (FrameView::m_viewportRenderer) right before layout.
It gets dereferenced later when layout is finished to update the overflow status.
If the viewport renderer gets destroyed during layout, we end up with a dangling pointer.
This patch replaces the pointer caching with type caching (none, body, document).

Unable to construct a test case.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r188291 r188298  
     12015-08-11  Zalan Bujtas  <zalan@apple.com>
     2
     3        Invalid FrameView::m_viewportRenderer after layout is finished.
     4        https://bugs.webkit.org/show_bug.cgi?id=147848
     5        rdar://problem/22205197
     6
     7        Reviewed by Simon Fraser.
     8
     9        We cache the current viewport renderer (FrameView::m_viewportRenderer) right before layout.
     10        It gets dereferenced later when layout is finished to update the overflow status.
     11        If the viewport renderer gets destroyed during layout, we end up with a dangling pointer.
     12        This patch replaces the pointer caching with type caching (none, body, document).
     13
     14        Unable to construct a test case.
     15
    1162015-08-11  Brent Fulgham  <bfulgham@apple.com>
    217
  • trunk/Source/WebCore/page/FrameView.cpp

    r188164 r188298  
    173173    , m_mediaType("screen")
    174174    , m_overflowStatusDirty(true)
    175     , m_viewportRenderer(nullptr)
    176175    , m_wasScrolledByUser(false)
    177176    , m_inProgrammaticScroll(false)
     
    622621{
    623622    RenderView* renderView = this->renderView();
    624     if (!renderView || !m_viewportRenderer || !is<RenderBox>(m_viewportRenderer) || !frame().isMainFrame())
     623    auto* viewportRenderer = this->viewportRenderer();
     624    if (!renderView || !is<RenderBox>(viewportRenderer) || !frame().isMainFrame())
    625625        return contentsSize();
    626626
     
    628628
    629629    FloatRect contentRect = renderView->unscaledDocumentRect();
    630     RenderBox& viewportRendererBox = downcast<RenderBox>(*m_viewportRenderer);
    631 
    632     if (m_viewportRenderer->style().overflowX() == OHIDDEN)
     630    RenderBox& viewportRendererBox = downcast<RenderBox>(*viewportRenderer);
     631
     632    if (viewportRendererBox.style().overflowX() == OHIDDEN)
    633633        contentRect.setWidth(std::min<float>(contentRect.width(), viewportRendererBox.frameRect().width()));
    634634
    635     if (m_viewportRenderer->style().overflowY() == OHIDDEN)
     635    if (viewportRendererBox.style().overflowY() == OHIDDEN)
    636636        contentRect.setHeight(std::min<float>(contentRect.height(), viewportRendererBox.frameRect().height()));
    637637
     
    642642}
    643643
    644 void FrameView::applyOverflowToViewport(RenderElement* renderer, ScrollbarMode& hMode, ScrollbarMode& vMode)
     644void FrameView::applyOverflowToViewport(const RenderElement& renderer, ScrollbarMode& hMode, ScrollbarMode& vMode)
    645645{
    646646    // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
     
    655655    bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
    656656
    657     EOverflow overflowX = renderer->style().overflowX();
    658     EOverflow overflowY = renderer->style().overflowY();
    659 
    660     if (is<RenderSVGRoot>(*renderer)) {
     657    EOverflow overflowX = renderer.style().overflowX();
     658    EOverflow overflowY = renderer.style().overflowY();
     659
     660    if (is<RenderSVGRoot>(renderer)) {
    661661        // FIXME: evaluate if we can allow overflow for these cases too.
    662662        // Overflow is always hidden when stand-alone SVG documents are embedded.
    663         if (downcast<RenderSVGRoot>(*renderer).isEmbeddedThroughFrameContainingSVGDocument()) {
     663        if (downcast<RenderSVGRoot>(renderer).isEmbeddedThroughFrameContainingSVGDocument()) {
    664664            overflowX = OHIDDEN;
    665665            overflowY = OHIDDEN;
     
    702702            ;
    703703    }
    704 
    705     m_viewportRenderer = renderer;
    706704}
    707705
     
    734732void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
    735733{
    736     m_viewportRenderer = nullptr;
     734    m_viewportRendererType = ViewportRendererType::None;
    737735
    738736    const HTMLFrameOwnerElement* owner = frame().ownerElement();
     
    751749    }
    752750   
    753     if (!m_layoutRoot) {
    754         Document* document = frame().document();
    755         auto documentElement = document->documentElement();
    756         RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr;
    757         auto* body = document->bodyOrFrameset();
    758         if (body && body->renderer()) {
    759             if (is<HTMLFrameSetElement>(*body) && !frameFlatteningEnabled()) {
    760                 vMode = ScrollbarAlwaysOff;
    761                 hMode = ScrollbarAlwaysOff;
    762             } else if (is<HTMLBodyElement>(*body)) {
    763                 // It's sufficient to just check the X overflow,
    764                 // since it's illegal to have visible in only one direction.
    765                 RenderElement* o = rootRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(*document->documentElement()) ? body->renderer() : rootRenderer;
    766                 applyOverflowToViewport(o, hMode, vMode);
     751    if (m_layoutRoot)
     752        return;
     753   
     754    auto* document = frame().document();
     755    if (!document)
     756        return;
     757
     758    auto documentElement = document->documentElement();
     759    if (!documentElement)
     760        return;
     761
     762    auto* bodyOrFrameset = document->bodyOrFrameset();
     763    auto* rootRenderer = documentElement->renderer();
     764    if (!bodyOrFrameset || !bodyOrFrameset->renderer()) {
     765        if (rootRenderer) {
     766            applyOverflowToViewport(*rootRenderer, hMode, vMode);
     767            m_viewportRendererType = ViewportRendererType::Document;
     768        }
     769        return;
     770    }
     771   
     772    if (is<HTMLFrameSetElement>(*bodyOrFrameset) && !frameFlatteningEnabled()) {
     773        vMode = ScrollbarAlwaysOff;
     774        hMode = ScrollbarAlwaysOff;
     775        return;
     776    }
     777
     778    if (is<HTMLBodyElement>(*bodyOrFrameset) && rootRenderer) {
     779        // It's sufficient to just check the X overflow,
     780        // since it's illegal to have visible in only one direction.
     781        if (rootRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(documentElement)) {
     782            auto* bodyRenderer = bodyOrFrameset->renderer();
     783            if (bodyRenderer) {
     784                applyOverflowToViewport(*bodyRenderer, hMode, vMode);
     785                m_viewportRendererType = ViewportRendererType::Body;
    767786            }
    768         } else if (rootRenderer)
    769             applyOverflowToViewport(rootRenderer, hMode, vMode);
    770     }   
     787        } else {
     788            applyOverflowToViewport(*rootRenderer, hMode, vMode);
     789            m_viewportRendererType = ViewportRendererType::Document;
     790        }
     791    }
    771792}
    772793
     
    32643285}
    32653286
     3287RenderElement* FrameView::viewportRenderer() const
     3288{
     3289    if (m_viewportRendererType == ViewportRendererType::None)
     3290        return nullptr;
     3291
     3292    auto* document = frame().document();
     3293    if (!document)
     3294        return nullptr;
     3295
     3296    if (m_viewportRendererType == ViewportRendererType::Document) {
     3297        auto* documentElement = document->documentElement();
     3298        if (!documentElement)
     3299            return nullptr;
     3300        return documentElement->renderer();
     3301    }
     3302
     3303    if (m_viewportRendererType == ViewportRendererType::Body) {
     3304        auto* body = document->body();
     3305        if (!body)
     3306            return nullptr;
     3307        return body->renderer();
     3308    }
     3309
     3310    ASSERT_NOT_REACHED();
     3311    return nullptr;
     3312}
     3313
    32663314void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
    32673315{
    3268     if (!m_viewportRenderer)
     3316    auto* viewportRenderer = this->viewportRenderer();
     3317    if (!viewportRenderer)
    32693318        return;
    32703319   
     
    32853334        RefPtr<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
    32863335            verticalOverflowChanged, verticalOverflow);
    3287         overflowEvent->setTarget(m_viewportRenderer->element());
     3336        overflowEvent->setTarget(viewportRenderer->element());
    32883337
    32893338        frame().document()->enqueueOverflowEvent(overflowEvent.release());
  • trunk/Source/WebCore/page/FrameView.h

    r188163 r188298  
    595595    virtual void scrollPositionChangedViaPlatformWidgetImpl(const IntPoint& oldPosition, const IntPoint& newPosition) override;
    596596
    597     void applyOverflowToViewport(RenderElement*, ScrollbarMode& hMode, ScrollbarMode& vMode);
     597    void applyOverflowToViewport(const RenderElement&, ScrollbarMode& hMode, ScrollbarMode& vMode);
    598598    void applyPaginationToViewport();
    599599
     
    676676    void notifyWidgets(WidgetNotification);
    677677
     678    RenderElement* viewportRenderer() const;
     679
    678680    HashSet<Widget*> m_widgetsInRenderTree;
    679681
     
    719721    bool m_overflowStatusDirty;
    720722    bool m_horizontalOverflow;
    721     bool m_verticalOverflow;   
    722     RenderElement* m_viewportRenderer;
     723    bool m_verticalOverflow;
     724    enum class ViewportRendererType { None, Document, Body };
     725    ViewportRendererType m_viewportRendererType { ViewportRendererType::None };
    723726
    724727    Pagination m_pagination;
Note: See TracChangeset for help on using the changeset viewer.