Changeset 252935 in webkit


Ignore:
Timestamp:
Nov 28, 2019 10:27:49 PM (4 years ago)
Author:
Simon Fraser
Message:

Element jumps to wrong position after perspective change on ancestor
https://bugs.webkit.org/show_bug.cgi?id=202505
<rdar://problem/55930710>

Reviewed by Antti Koivisto.
Source/WebCore:

This modifies the fix in r252879 to be better-performing and to avoid a new call site for updateLayerPositions*.

Style can change in a way that creates or destroys RenderLayers, but does not result in a layout; this can happen
with changes of properties like opacity or perspective. When this happens, something needs to trigger a call to
RenderLayer::updateLayerPositions() on the root of the changed subtree. This is best done after the style update,
to avoid multiple updateLayerPositions traversals.

Implement this by storing on RenderView the rootmost changed layer, and having FrameView::styleDidChange()
call updateLayerPositionsAfterStyleChange() if we're after a style change with no pending layout.

Test: compositing/geometry/layer-position-after-removing-perspective.html

  • page/FrameView.cpp:

(WebCore::FrameView::styleDidChange):

  • page/FrameView.h:
  • platform/ScrollView.h:
  • rendering/RenderElement.cpp:

(WebCore::RenderElement::didAttachChild):

  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::insertOnlyThisLayer):
(WebCore::RenderLayer::removeOnlyThisLayer):
(WebCore::findCommonAncestor):
(WebCore::RenderLayer::commonAncestorWithLayer const):

  • rendering/RenderLayer.h:
  • rendering/RenderLayerModelObject.cpp:

(WebCore::RenderLayerModelObject::createLayer):
(WebCore::RenderLayerModelObject::styleDidChange):

  • rendering/RenderView.cpp:

(WebCore::RenderView::layerChildrenChangedDuringStyleChange):
(WebCore::RenderView::takeStyleChangeLayerTreeMutationRoot):

  • rendering/RenderView.h:

LayoutTests:

  • compositing/geometry/layer-position-after-removing-perspective-expected.html: Added.
  • compositing/geometry/layer-position-after-removing-perspective.html: Added.
  • css3/blending/repaint/blend-mode-isolate-stacking-context-expected.txt: Rebaselined.
Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r252934 r252935  
     12019-11-28  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Element jumps to wrong position after perspective change on ancestor
     4        https://bugs.webkit.org/show_bug.cgi?id=202505
     5        <rdar://problem/55930710>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        * compositing/geometry/layer-position-after-removing-perspective-expected.html: Added.
     10        * compositing/geometry/layer-position-after-removing-perspective.html: Added.
     11        * css3/blending/repaint/blend-mode-isolate-stacking-context-expected.txt: Rebaselined.
     12
    1132019-11-28  Jonathan Bedard  <jbedard@apple.com>
    214
  • trunk/LayoutTests/css3/blending/repaint/blend-mode-isolate-stacking-context-expected.txt

    r236632 r252935  
    1212
    1313(repaint rects
    14   (rect 48 54 60 60)
    1514  (rect 48 54 60 60)
    1615  (rect 48 54 60 60)
     
    3029  (rect 28 290 60 60)
    3130  (rect 48 644 60 60)
     31  (rect 48 54 60 60)
    3232  (rect 48 290 60 60)
    3333  (rect 28 526 60 60)
  • trunk/LayoutTests/platform/ios/css3/blending/repaint/blend-mode-isolate-stacking-context-expected.txt

    r236692 r252935  
    1212
    1313(repaint rects
    14   (rect 48 56 60 60)
    1514  (rect 48 56 60 60)
    1615  (rect 48 56 60 60)
     
    3029  (rect 28 296 60 60)
    3130  (rect 48 656 60 60)
     31  (rect 48 56 60 60)
    3232  (rect 48 296 60 60)
    3333  (rect 28 536 60 60)
  • trunk/Source/WebCore/ChangeLog

    r252932 r252935  
     12019-11-28  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Element jumps to wrong position after perspective change on ancestor
     4        https://bugs.webkit.org/show_bug.cgi?id=202505
     5        <rdar://problem/55930710>
     6
     7        Reviewed by Antti Koivisto.
     8       
     9        This modifies the fix in r252879 to be better-performing and to avoid a new call site for updateLayerPositions*.
     10
     11        Style can change in a way that creates or destroys RenderLayers, but does not result in a layout; this can happen
     12        with changes of properties like opacity or perspective. When this happens, something needs to trigger a call to
     13        RenderLayer::updateLayerPositions() on the root of the changed subtree. This is best done after the style update,
     14        to avoid multiple updateLayerPositions traversals.
     15
     16        Implement this by storing on RenderView the rootmost changed layer, and having FrameView::styleDidChange()
     17        call updateLayerPositionsAfterStyleChange() if we're after a style change with no pending layout.
     18
     19        Test: compositing/geometry/layer-position-after-removing-perspective.html
     20
     21        * page/FrameView.cpp:
     22        (WebCore::FrameView::styleDidChange):
     23        * page/FrameView.h:
     24        * platform/ScrollView.h:
     25        * rendering/RenderElement.cpp:
     26        (WebCore::RenderElement::didAttachChild):
     27        * rendering/RenderLayer.cpp:
     28        (WebCore::RenderLayer::insertOnlyThisLayer):
     29        (WebCore::RenderLayer::removeOnlyThisLayer):
     30        (WebCore::findCommonAncestor):
     31        (WebCore::RenderLayer::commonAncestorWithLayer const):
     32        * rendering/RenderLayer.h:
     33        * rendering/RenderLayerModelObject.cpp:
     34        (WebCore::RenderLayerModelObject::createLayer):
     35        (WebCore::RenderLayerModelObject::styleDidChange):
     36        * rendering/RenderView.cpp:
     37        (WebCore::RenderView::layerChildrenChangedDuringStyleChange):
     38        (WebCore::RenderView::takeStyleChangeLayerTreeMutationRoot):
     39        * rendering/RenderView.h:
     40
    1412019-11-28  Antti Koivisto  <antti@apple.com>
    242
  • trunk/Source/WebCore/page/FrameView.cpp

    r252761 r252935  
    800800}
    801801
     802void FrameView::styleDidChange()
     803{
     804    ScrollView::styleDidChange();
     805    RenderView* renderView = this->renderView();
     806    if (!renderView)
     807        return;
     808
     809    RenderLayer* layerTreeMutationRoot = renderView->takeStyleChangeLayerTreeMutationRoot();
     810    if (layerTreeMutationRoot && !needsLayout())
     811        layerTreeMutationRoot->updateLayerPositionsAfterStyleChange();
     812}
     813
    802814bool FrameView::updateCompositingLayersAfterStyleChange()
    803815{
  • trunk/Source/WebCore/page/FrameView.h

    r252761 r252935  
    139139
    140140    void willRecalcStyle();
     141    void styleDidChange() override;
    141142    bool updateCompositingLayersAfterStyleChange();
    142143    void updateCompositingLayersAfterLayout();
  • trunk/Source/WebCore/platform/ScrollView.h

    r246488 r252935  
    141141    virtual Ref<Scrollbar> createScrollbar(ScrollbarOrientation);
    142142
    143     void styleDidChange();
     143    virtual void styleDidChange();
    144144
    145145    // If the prohibits scrolling flag is set, then all scrolling in the view (even programmatic scrolling) is turned off.
  • trunk/Source/WebCore/rendering/RenderElement.cpp

    r252724 r252935  
    471471    // and stop creating layers at all for these cases - they're not used anyways.
    472472    if (child.hasLayer() && !layerCreationAllowedForSubtree())
    473         downcast<RenderLayerModelObject>(child).layer()->removeOnlyThisLayer();
     473        downcast<RenderLayerModelObject>(child).layer()->removeOnlyThisLayer(RenderLayer::LayerChangeTiming::RenderTreeConstruction);
    474474}
    475475
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r252724 r252935  
    497497}
    498498
    499 void RenderLayer::insertOnlyThisLayer()
     499void RenderLayer::insertOnlyThisLayer(LayerChangeTiming timing)
    500500{
    501501    if (!m_parent && renderer().parent()) {
     
    512512        child.moveLayers(m_parent, this);
    513513
     514    if (parent()) {
     515        if (timing == LayerChangeTiming::StyleChange)
     516            renderer().view().layerChildrenChangedDuringStyleChange(*parent());
     517    }
     518   
    514519    // Clear out all the clip rects.
    515520    clearClipRectsIncludingDescendants();
    516521}
    517522
    518 void RenderLayer::removeOnlyThisLayer()
     523void RenderLayer::removeOnlyThisLayer(LayerChangeTiming timing)
    519524{
    520525    if (!m_parent)
    521526        return;
     527
     528    if (timing == LayerChangeTiming::StyleChange)
     529        renderer().view().layerChildrenChangedDuringStyleChange(*parent());
    522530
    523531    // Mark that we are about to lose our layer. This makes render tree
     
    22492257    }
    22502258    return false;
     2259}
     2260
     2261static RenderLayer* findCommonAncestor(const RenderLayer& firstLayer, const RenderLayer& secondLayer)
     2262{
     2263    if (&firstLayer == &secondLayer)
     2264        return const_cast<RenderLayer*>(&firstLayer);
     2265
     2266    HashSet<const RenderLayer*> ancestorChain;
     2267    for (auto* currLayer = &firstLayer; currLayer; currLayer = currLayer->parent())
     2268        ancestorChain.add(currLayer);
     2269
     2270    for (auto* currLayer = &secondLayer; currLayer; currLayer = currLayer->parent()) {
     2271        if (ancestorChain.contains(currLayer))
     2272            return const_cast<RenderLayer*>(currLayer);
     2273    }
     2274    return nullptr;
     2275}
     2276
     2277RenderLayer* RenderLayer::commonAncestorWithLayer(const RenderLayer& layer) const
     2278{
     2279    return findCommonAncestor(*this, layer);
    22512280}
    22522281
  • trunk/Source/WebCore/rendering/RenderLayer.h

    r252724 r252935  
    164164    RenderLayer* lastChild() const { return m_last; }
    165165    bool isDescendantOf(const RenderLayer&) const;
     166    RenderLayer* commonAncestorWithLayer(const RenderLayer&) const;
    166167
    167168    // This does an ancestor tree walk. Avoid it!
     
    177178    void removeChild(RenderLayer&);
    178179
    179     void insertOnlyThisLayer();
    180     void removeOnlyThisLayer();
     180    enum class LayerChangeTiming {
     181        StyleChange,
     182        RenderTreeConstruction,
     183    };
     184    void insertOnlyThisLayer(LayerChangeTiming);
     185    void removeOnlyThisLayer(LayerChangeTiming);
    181186
    182187    bool isNormalFlowOnly() const { return m_isNormalFlowOnly; }
  • trunk/Source/WebCore/rendering/RenderLayerModelObject.cpp

    r252879 r252935  
    9898    m_layer = makeUnique<RenderLayer>(*this);
    9999    setHasLayer(true);
    100     m_layer->insertOnlyThisLayer();
     100    m_layer->insertOnlyThisLayer(RenderLayer::LayerChangeTiming::StyleChange);
    101101}
    102102
     
    170170                setChildNeedsLayout();
    171171            createLayer();
    172             if (parent() && !needsLayout() && containingBlock()) {
     172            if (parent() && !needsLayout() && containingBlock())
    173173                layer()->setRepaintStatus(NeedsFullRepaint);
    174                 layer()->updateLayerPositionsAfterStyleChange();
    175             }
    176174        }
    177175    } else if (layer() && layer()->parent()) {
     
    180178            layer()->willRemoveChildWithBlendMode();
    181179#endif
    182         setHasTransformRelatedProperty(false); // All transform-related propeties force layers, so we know we don't have one or the object doesn't support them.
     180        setHasTransformRelatedProperty(false); // All transform-related properties force layers, so we know we don't have one or the object doesn't support them.
    183181        setHasReflection(false);
    184182        // Repaint the about to be destroyed self-painting layer when style change also triggers repaint.
    185183        if (layer()->isSelfPaintingLayer() && layer()->repaintStatus() == NeedsFullRepaint && hasRepaintLayoutRects())
    186184            repaintUsingContainer(containerForRepaint(), repaintLayoutRects().m_repaintRect);
    187         // If the layer we're about to destroy had a position, then the positions of the current children will no longer be correct.
    188         auto* parentLayer = layer()->parent();
    189         bool layerHadLocation = !layer()->location().isZero();
    190         layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer
    191         if (layerHadLocation && parentLayer && !parentLayer->renderer().needsLayout())
    192             parentLayer->updateLayerPositionsAfterStyleChange();
     185
     186        layer()->removeOnlyThisLayer(RenderLayer::LayerChangeTiming::StyleChange); // calls destroyLayer() which clears m_layer
    193187        if (s_wasFloating && isFloating())
    194188            setChildNeedsLayout();
  • trunk/Source/WebCore/rendering/RenderView.cpp

    r249222 r252935  
    878878}
    879879
     880void RenderView::layerChildrenChangedDuringStyleChange(RenderLayer& layer)
     881{
     882    if (!m_styleChangeLayerMutationRoot) {
     883        m_styleChangeLayerMutationRoot = makeWeakPtr(layer);
     884        return;
     885    }
     886
     887    RenderLayer* commonAncestor = m_styleChangeLayerMutationRoot->commonAncestorWithLayer(layer);
     888    m_styleChangeLayerMutationRoot = makeWeakPtr(commonAncestor);
     889}
     890
     891RenderLayer* RenderView::takeStyleChangeLayerTreeMutationRoot()
     892{
     893    auto* result = m_styleChangeLayerMutationRoot.get();
     894    m_styleChangeLayerMutationRoot.clear();
     895    return result;
     896}
     897
    880898#if ENABLE(CSS_SCROLL_SNAP)
    881899void RenderView::registerBoxWithScrollSnapPositions(const RenderBox& box)
  • trunk/Source/WebCore/rendering/RenderView.h

    r249309 r252935  
    185185    void scheduleLazyRepaint(RenderBox&);
    186186    void unscheduleLazyRepaint(RenderBox&);
     187   
     188    void layerChildrenChangedDuringStyleChange(RenderLayer&);
     189    RenderLayer* takeStyleChangeLayerTreeMutationRoot();
    187190
    188191    void protectRenderWidgetUntilLayoutIsDone(RenderWidget& widget) { m_protectedRenderWidgets.append(&widget); }
     
    219222    mutable std::unique_ptr<Region> m_accumulatedRepaintRegion;
    220223    SelectionRangeData m_selection;
     224
     225    WeakPtr<RenderLayer> m_styleChangeLayerMutationRoot;
    221226
    222227    // FIXME: Only used by embedded WebViews inside AppKit NSViews.  Find a way to remove.
Note: See TracChangeset for help on using the changeset viewer.