Bug 202505

Summary: Element jumps to wrong position after perspective change on ancestor
Product: WebKit Reporter: Simon Fraser (smfr) <simon.fraser>
Component: CompositingAssignee: Simon Fraser (smfr) <simon.fraser>
Status: RESOLVED FIXED    
Severity: Normal CC: commit-queue, esprehn+autocc, ews-watchlist, fred.wang, glenn, koivisto, kondapallykalyan, pdr, simon.fraser, webkit-bug-importer, zalan
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=204602
Attachments:
Description Flags
Patch
none
Patch
koivisto: review+
Patch none

Description Simon Fraser (smfr) 2019-10-02 17:11:24 PDT
https://codepen.io/smfr/pen/pozMXLo shows a bug where a layer jumps to the wrong place.
Comment 1 Radar WebKit Bug Importer 2019-10-02 17:14:35 PDT
<rdar://problem/55930710>
Comment 2 Simon Fraser (smfr) 2019-10-19 11:01:19 PDT
This only happens if the element with the perspective has no other property that triggers a RenderLayer, so its layer is disappearing.
Comment 3 Simon Fraser (smfr) 2019-10-19 11:19:02 PDT
This seems to be about the location() of the RenderLayer being wrong.
Comment 4 Simon Fraser (smfr) 2019-10-19 11:22:52 PDT
We never hit RenderLayer::updateLayerPositions() after this type of style change.
Comment 5 Simon Fraser (smfr) 2019-10-19 11:33:28 PDT
We detect that the RenderStyle "hasAutoZIndex" changes, so end up with diff=StyleDifference::RepaintLayer but that isn't enough to trigger layer position updates.

There's code in RenderStyle::diff() that makes assumptions about what style changes will trigger RenderLayer creation/destruction, but that's duplicating code in the various requiresLayer() functions. I think we need to detect RenderLayer tree mutations during style change more explicitly.
Comment 6 Simon Fraser (smfr) 2019-10-19 11:49:42 PDT
Antti, how would you feel about allowing renderer styleWill/DidChange to get at the current RenderTreeUpdater (via Document?) so they can set a "layer tree changed" bit for a given render tree update?
Comment 7 Antti Koivisto 2019-10-21 11:01:58 PDT
(In reply to Simon Fraser (smfr) from comment #6)
> Antti, how would you feel about allowing renderer styleWill/DidChange to get
> at the current RenderTreeUpdater (via Document?) so they can set a "layer
> tree changed" bit for a given render tree update?

Sounds terrible. I'd like to see some sort of patch to understand the problem better.
Comment 8 Simon Fraser (smfr) 2019-11-28 09:13:47 PST
Created attachment 384460 [details]
Patch
Comment 9 Antti Koivisto 2019-11-28 09:23:52 PST
Comment on attachment 384460 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384460&action=review

> Source/WebCore/rendering/RenderView.cpp:896
> +void RenderView::layerChildrenChangedDuringStyleChange(RenderLayer& layer)
> +{
> +    if (!m_styleChangeLayerMutationRoot) {
> +        m_styleChangeLayerMutationRoot = makeWeakPtr(layer);
> +        return;
> +    }
> +
> +    RenderLayer* commonAncestor = m_styleChangeLayerMutationRoot->commonAncestorWithLayer(layer);
> +    m_styleChangeLayerMutationRoot = makeWeakPtr(commonAncestor);
> +}
> +
> +RenderLayer* RenderView::takeStyleChangeLayerTreeMutationRoot()
> +{
> +    auto* result = m_styleChangeLayerMutationRoot.get();
> +    m_styleChangeLayerMutationRoot.clear();
> +    return result;
> +}

Should this go to the layer tree? It is bit weird to have this exclusively layer related code in RenderView. Don't we have any suitable root object?
Comment 10 Simon Fraser (smfr) 2019-11-28 10:48:26 PST
(In reply to Antti Koivisto from comment #9)
> Should this go to the layer tree? It is bit weird to have this exclusively
> layer related code in RenderView. Don't we have any suitable root object?

We don't.

Maybe RenderLayerCompositor should have a base class that's the layer tree root object? Not in this patch though.
Comment 11 Simon Fraser (smfr) 2019-11-28 10:50:54 PST
Created attachment 384467 [details]
Patch
Comment 12 Antti Koivisto 2019-11-28 10:58:46 PST
Comment on attachment 384467 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384467&action=review

> Source/WebCore/page/FrameView.cpp:812
> +void FrameView::styleDidChange()
> +{
> +    ScrollView::styleDidChange();
> +    RenderView* renderView = this->renderView();
> +    if (!renderView)
> +        return;
> +
> +    RenderLayer* layerTreeMutationRoot = renderView->takeStyleChangeLayerTreeMutationRoot();
> +    if (layerTreeMutationRoot && !needsLayout())
> +        layerTreeMutationRoot->updateLayerPositionsAfterStyleChange();
> +}

Can this code go to RenderView::styleDidChange where this function is invoked? You'll need to expose fewer functions (no takeStyleChangeLayerTreeMutationRoot).

> Source/WebCore/platform/ScrollView.h:143
> +    virtual void styleDidChange();

...and you avoid making this virtual.

> Source/WebCore/rendering/RenderView.cpp:880
> +void RenderView::layerChildrenChangedDuringStyleChange(RenderLayer& layer)

It feels like there is a need for a new root type where this sort of stuff can live.

> Source/WebCore/rendering/RenderView.cpp:891
> +RenderLayer* RenderView::takeStyleChangeLayerTreeMutationRoot()

Non-ownership transferring take() is bit surprising.
Comment 13 Antti Koivisto 2019-11-28 11:03:06 PST
I suppose not all styleDidChange calls go via RenderView though they could.
Comment 14 Antti Koivisto 2019-11-28 13:26:16 PST
Comment on attachment 384467 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384467&action=review

> Source/WebCore/rendering/RenderLayerModelObject.cpp:-174
> -                layer()->updateLayerPositionsAfterStyleChange();

Can you remove updateLayerPositionsAfterStyleChange() after this too?
Comment 15 Simon Fraser (smfr) 2019-11-28 20:03:07 PST
(In reply to Antti Koivisto from comment #14)
> Comment on attachment 384467 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=384467&action=review
> 
> > Source/WebCore/rendering/RenderLayerModelObject.cpp:-174
> > -                layer()->updateLayerPositionsAfterStyleChange();
> 
> Can you remove updateLayerPositionsAfterStyleChange() after this too?

No, it's still the right entry point for post-style-change-with-no-pending-layout.

Ideally this function would move to some kind of tree owner too.
Comment 16 Simon Fraser (smfr) 2019-11-28 20:03:18 PST
Created attachment 384477 [details]
Patch
Comment 17 WebKit Commit Bot 2019-11-28 22:27:57 PST
Comment on attachment 384477 [details]
Patch

Clearing flags on attachment: 384477

Committed r252935: <https://trac.webkit.org/changeset/252935>