Closed Bug 1719913 Opened 3 years ago Closed 3 years ago

Tweetdeck scrollbar jumps down when clicked on near the top of the column

Categories

(Core :: Panning and Zooming, defect, P2)

Firefox 89
defect

Tracking

()

RESOLVED FIXED
92 Branch
Tracking Status
firefox92 --- fixed

People

(Reporter: iii_iii, Assigned: botond)

References

Details

Attachments

(7 files)

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0

Steps to reproduce:

Sign into twitter. Visit tweetdeck.twitter.com. When the scroll bar grip is at or near the top of a column click on it and try to drag it upward.

Actual results:

The grip jumps downward. The grip seems to be out of sync with the location of the mouse pointer.

Expected results:

Normally dragging upward from the top would reveal a new tweet if there were one, otherwise do nothing.

This applies to all columns. I don't think it is connected with 1712040.

The Bugbug bot thinks this bug should belong to the 'Core::Panning and Zooming' component, and is moving the bug to that component. Please revert this change in case you think the bot is wrong.

Component: General → Panning and Zooming

Thanks for the report, I can reproduce. The issue seems to be specific to WebRender.

The bug is reproducible as far back as WebRender is usable, so I'm not able to find a useful regression window.

Finally, the issue does not reproduce with apz.drag.enabled=false, confirming that it's a bug in the APZ scrollbar dragging codepath.

Assignee: nobody → botond
Severity: -- → S2
Priority: -- → P2
See Also: → 1576770
See Also: → 1712040

I've noticed a work around of sorts. If you middle click (or click the mouse wheel) somewhere away from the scroll grip and hold it down, the scroll grip jumps under the mouse pointer, and then you can move the scroll grip normally without the bug as long as you hold down the middle mouse button.

(In reply to iii_iii from comment #6)

I've noticed a work around of sorts. If you middle click (or click the mouse wheel) somewhere away from the scroll grip and hold it down, the scroll grip jumps under the mouse pointer, and then you can move the scroll grip normally without the bug as long as you hold down the middle mouse button.

I expect using middle-click here forces us to take the main-thread scrollbar dragging codepath, which doesn't have this problem.

If you're looking for a workaround, a simpler one is to change the pref apz.drag.enabled to false in about:config (which forces us to always use the main-thread scrollbar dragging codepath).

It looks like the scrollable element in question has an incorrect composition bounds origin. The composition bounds origin is one of the quantities APZ relies on to correctly convert the vertical screen coordinate of a mouse event during a scrollbar drag to the corresponding scroll position of the scrollable element.

(In reply to Botond Ballo [:botond] from comment #8)

It looks like the scrollable element in question has an incorrect composition bounds origin.

I take that back. The composition bounds origin is (0,0) both with and without WR. That's not what I expected it to be, but it's also not what's causing the problem here.

The difference between WR and non-WR seems to be the local (ParentLayer) coordinates of the mouse event. I think this suggests there's a scroll node with a transform that's present in the non-WR case but absent in the WR case.

The page also trips up this assertion:

[Parent 4962, WRSceneBuilder#1] ###!!! ASSERTION: Two layers that scroll together have different ancestor transforms: 'false', file /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/APZCTreeManager.cpp:1419

I believe that's related to the problem. To see how, let's look at a hit-testing tree:

APZCTreeManager (7fe01be58800)
  HitTestingTreeNode (7fe01be06850) APZC (7fdffc9d2000) g=({ l=0x100000001, p=1, v=3 }) r=({ }) t=([ I ]) c=([0,0,1280,972])
    HitTestingTreeNode (7fe01be08d20) APZC (0) g=(l=0x100000001) r=({ }) t=([ 1 0; 0 1; 0 113; ]) c=(none)
      HitTestingTreeNode (7fe01be079c0) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=(none)
        HitTestingTreeNode (7fe01be07bb0) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=(none)
          HitTestingTreeNode (7fe01be096d0) APZC (7fe005846000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none)
          HitTestingTreeNode (7fe01be08b30) APZC (7fe005846000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none) scrollbar scrollthumb
          HitTestingTreeNode (7fe01be06660) APZC (7fe005846000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none)
            HitTestingTreeNode (7fe01be08f10) APZC (7fdfe92aa000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ I ]) c=([60,0,1280,843])
          HitTestingTreeNode (7fe01be09e90) APZC (7fe005846000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none) scrollbar scrollthumb
            HitTestingTreeNode (7fe01be06a40) APZC (7fdfe92aa000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ I ]) c=([60,0,1280,843]) scrollbar scrollthumb
          HitTestingTreeNode (7fe01be07f90) APZC (7fe005846000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ 1 0; 0 1; 382 50; ]) c=(none)
            HitTestingTreeNode (7fe01be08750) APZC (7fdfe92aa000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ I ]) c=([60,0,1280,843])
              HitTestingTreeNode (7fe01be094e0) APZC (7fdfe16fe000) g=({ l=0x100000002, p=2, v=7 }) r=({ }) t=([ I ]) c=([0,0,298,793])
          HitTestingTreeNode (7fe01be077d0) APZC (7fe005846000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none)
            HitTestingTreeNode (7fe01be09100) APZC (7fdfe92aa000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ I ]) c=([60,0,1280,843])
          HitTestingTreeNode (7fe01be098c0) APZC (7fe005846000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none)
  • The APZC whose scrollbar is being dragged is the one with v=7.
  • One of the ancestor nodes of this APZC has a translation transform of (382, 50).
  • However, this ancestor node is associated with the v=2 APZC.
  • The v=2 APZC in turn has several nodes associated with it, and not all of them have this transform.
  • This violates an APZ assumption, and APZ warns about this. In such cases, it uses the transform on the first node encountered for v=2 (which is the identity) for all nodes associated with v=2, i.e. the (382, 50) translation is effectively discarded.

I described APZ's requirement on the scroll nodes here incorrectly in the previous comment. The requirement is that, for a given APZC, all scroll nodes associated with that APZC must have the same ancestor transform. That's the transform from each node to their common ancestor, but not including the node's own transform.

So, in the above hit-testing tree, the v=2 APZC is not the one that violates this requirement -- the ancestor transforms for all of its nodes is the identity.

Rather, it's the v=4 APZC which violates this requirement -- it, too has several associated nodes, and one of them has the (382, 50) in its ancestor transform while the others don't.

Now, let's compare to a non-WR hit-testing tree:

APZCTreeManager (7fd597c7b000)
  HitTestingTreeNode (7fd597108560) APZC (7fd57e6a0000) g=({ l=0x100000001, p=1, v=3 }) r=({ }) t=([ I ]) c=([0,0,1280,972])
    HitTestingTreeNode (7fd597107bb0) APZC (0) g=(l=0x100000001) r=({ Hit=[0,0,1280,972] DispatchToContent=[0,28,1280,72] }) t=([ I ]) c=(none)
    HitTestingTreeNode (7fd573c804e0) APZC (0) g=(l=0x100000001) r=({ }) t=([ 1 0; 0 1; 0 113; ]) c=([0,113,1280,972])
      HitTestingTreeNode (7fd573c7fd20) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=(none)
        HitTestingTreeNode (7fd5971096d0) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=([])
        HitTestingTreeNode (7fd597108b30) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,1280,859] }) t=([ I ]) c=(none)
        HitTestingTreeNode (7fd573c808c0) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=([0,0,1280,859])
          HitTestingTreeNode (7fd597107f90) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ Hit=[0,0,1280,859] DispatchToContent=[60,843,1280,855] }) t=([ I ]) c=([0,0,1280,859])
          HitTestingTreeNode (7fd597106090) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([60,843,1280,855]) scrollbar scrollthumb
            HitTestingTreeNode (7fd597108180) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,1161,12] DispatchToContent=[0,0,1161,12] }) t=([ 1 0; 0 1; 60 843; ]) c=(none)
          HitTestingTreeNode (7fd59710a270) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fd597109e90) APZC (7fd56e84b000) g=({ l=0x100000002, p=2, v=4 }) r=({ Hit=[0,0,1270,843] DispatchToContent=[0,0,1264,843] }) t=([ 1 0; 0 1; 60 0; ]) c=([60,0,1280,843])
          HitTestingTreeNode (7fd59710a840) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fd59710a460) APZC (7fd56e84b000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ 1 0; 0 1; 66 50; ]) c=([66,0,376,843])
              HitTestingTreeNode (7fd59710ae10) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,310,793] DispatchToContent=[0,0,310,793] }) t=([ I ]) c=(none)
          HitTestingTreeNode (7fd573c802f0) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fd573c7d470) APZC (7fd56e84b000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ 1 0; 0 1; 382 50; ]) c=([382,0,692,843])
              HitTestingTreeNode (7fd59710a650) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,310,793] DispatchToContent=[0,0,310,793] }) t=([ I ]) c=(none)
              HitTestingTreeNode (7fd59710ac20) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=([298,0,310,793]) scrollbar scrollthumb
                HitTestingTreeNode (7fd59710aa30) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,12,103] DispatchToContent=[0,0,12,103] }) t=([ 1 0; 0 1; 298 0; ]) c=(none)
              HitTestingTreeNode (7fd573c7fb30) APZC (7fd569be6000) g=({ l=0x100000002, p=2, v=7 }) r=({ Hit=[0,0,298,5735] DispatchToContent=[0,0,298,5735] }) t=([ I ]) c=([0,0,298,793])
          HitTestingTreeNode (7fd573c7e3f0) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fd573c7dc30) APZC (7fd56e84b000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ 1 0; 0 1; 698 50; ]) c=([698,0,1008,843])
              HitTestingTreeNode (7fd573c7d280) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,310,793] DispatchToContent=[0,0,310,793] }) t=([ I ]) c=(none)
          HitTestingTreeNode (7fd573c80ca0) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fd59710a080) APZC (7fd56e84b000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ 1 0; 0 1; 1014 82; ]) c=([1014,0,1280,843])
              HitTestingTreeNode (7fd573c7e5e0) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,310,761] DispatchToContent=[0,0,310,761] }) t=([ I ]) c=(none)
          HitTestingTreeNode (7fd573c7ff10) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fd597108d20) APZC (7fd56a3a5000) g=({ l=0x100000002, p=2, v=3 }) r=({ Hit=[0,0,60,548] }) t=([ 1 0; 0 1; 0 112; ]) c=([0,112,60,660])
          HitTestingTreeNode (7fd597107010) APZC (7fd56de4a000) g=({ l=0x100000002, p=2, v=2 }) r=({ Hit=[0,632,60,751] }) t=([ I ]) c=([0,0,1280,859])

Note a very important difference: the (382, 50) transform is now on a v=4 node, not a v=2 node. So, it's no longer a part of the ancestor transform of the v=4 nodes, and thus the v=4 nodes no longer violate the APZ requirement.

This is the point where continuing to debug the full website starts to get unwieldy (as I need to look at display list dumps which get very long), so my next step here is to try and prepare a reduced testcase.

Attached file Reduced testcase
Status: UNCONFIRMED → NEW
Ever confirmed: true

Posting some new hit-testing trees for the reduced testcase.

WebRender:

APZCTreeManager (7f330f555800)
  HitTestingTreeNode (7f330f506470) APZC (7f32f04f1000) g=({ l=0x100000001, p=1, v=3 }) r=({ }) t=([ I ]) c=([0,0,1280,972])
    HitTestingTreeNode (7f330f508940) APZC (0) g=(l=0x100000001) r=({ }) t=([ 1 0; 0 1; 0 113; ]) c=(none)
      HitTestingTreeNode (7f330f5077d0) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=(none)
        HitTestingTreeNode (7f330f508750) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=(none)
          HitTestingTreeNode (7f330f506660) APZC (7f32efe68000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none)
          HitTestingTreeNode (7f330f507da0) APZC (7f32efe68000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none) scrollbar scrollthumb
          HitTestingTreeNode (7f330f5094e0) APZC (7f32efe68000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none)
            HitTestingTreeNode (7f330f507f90) APZC (7f330aca5000) g=({ l=0x100000002, p=2, v=3 }) r=({ }) t=([ I ]) c=([0,0,1268,859])
          HitTestingTreeNode (7f330f508560) APZC (7f32efe68000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none) scrollbar scrollthumb
            HitTestingTreeNode (7f330f5096d0) APZC (7f330aca5000) g=({ l=0x100000002, p=2, v=3 }) r=({ }) t=([ I ]) c=([0,0,1268,859]) scrollbar scrollthumb
          HitTestingTreeNode (7f330f5075e0) APZC (7f32efe68000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ 1 0; 0 1; 0 50; ]) c=(none)
            HitTestingTreeNode (7f330f508b30) APZC (7f330aca5000) g=({ l=0x100000002, p=2, v=3 }) r=({ }) t=([ I ]) c=([0,0,1268,859])
              HitTestingTreeNode (7f330f506e20) APZC (7f32defe8000) g=({ l=0x100000002, p=2, v=4 }) r=({ }) t=([ I ]) c=([0,0,622,859])
          HitTestingTreeNode (7f330f506c30) APZC (7f32efe68000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=(none)
            HitTestingTreeNode (7f330f509ab0) APZC (7f330aca5000) g=({ l=0x100000002, p=2, v=3 }) r=({ }) t=([ I ]) c=([0,0,1268,859])
  • scrollframe whose thumb is being dragged is v=4
  • enclosing transform (here the amount is (0, 50)) is on a v=2 node, making it part of the ancestor transform for v=3 nodes
  • APZ assumption is violated for v=3

non-WebRender:

APZCTreeManager (7fb3a5279000)
  HitTestingTreeNode (7fb3a4708b30) APZC (7fb38de8e000) g=({ l=0x100000001, p=1, v=3 }) r=({ }) t=([ I ]) c=([0,0,1280,972])
    HitTestingTreeNode (7fb3a47098c0) APZC (0) g=(l=0x100000001) r=({ Hit=[0,0,1280,972] DispatchToContent=[0,28,1280,72] }) t=([ I ]) c=(none)
    HitTestingTreeNode (7fb3a4708f10) APZC (0) g=(l=0x100000001) r=({ }) t=([ 1 0; 0 1; 0 113; ]) c=([0,113,1280,972])
      HitTestingTreeNode (7fb3a4708d20) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=(none)
        HitTestingTreeNode (7fb3a4707bb0) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=([])
        HitTestingTreeNode (7fb3a47077d0) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,1280,859] }) t=([ I ]) c=(none)
        HitTestingTreeNode (7fb3a4706e20) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=([0,0,1280,859])
          HitTestingTreeNode (7fb3a4706c30) APZC (7fb383bb0000) g=({ l=0x100000002, p=2, v=2 }) r=({ Hit=[0,0,1280,859] DispatchToContent=[1268,0,1280,859] }) t=([ I ]) c=([0,0,1280,859])
          HitTestingTreeNode (7fb3a4708940) APZC (7fb383bb0000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([1268,0,1280,859]) scrollbar scrollthumb
            HitTestingTreeNode (7fb3a4709100) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,12,415] DispatchToContent=[0,0,12,415] }) t=([ 1 0; 0 1; 1268 0; ]) c=(none)
          HitTestingTreeNode (7fb3a4708560) APZC (7fb383bb0000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fb3a47096d0) APZC (7fb383bb1000) g=({ l=0x100000002, p=2, v=3 }) r=({ Hit=[0,0,1268,1718] }) t=([ I ]) c=([0,0,1268,859])
          HitTestingTreeNode (7fb3a4706090) APZC (7fb383bb0000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fb3a4709ca0) APZC (7fb383bb1000) g=({ l=0x100000002, p=2, v=3 }) r=({ }) t=([ 1 0; 0 1; 0 50; ]) c=([0,0,1268,859])
              HitTestingTreeNode (7fb3a4708180) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,634,859] DispatchToContent=[622,0,634,859] }) t=([ I ]) c=(none)
              HitTestingTreeNode (7fb3a4708750) APZC (0) g=(l=0x100000002) r=({ }) t=([ I ]) c=([622,0,634,859]) scrollbar scrollthumb
                HitTestingTreeNode (7fb3a4708370) APZC (0) g=(l=0x100000002) r=({ Hit=[0,0,12,139] DispatchToContent=[0,0,12,139] }) t=([ 1 0; 0 1; 622 0; ]) c=(none)
              HitTestingTreeNode (7fb3a4706660) APZC (7fb3846c1000) g=({ l=0x100000002, p=2, v=4 }) r=({ Hit=[0,0,622,5000] }) t=([ I ]) c=([0,0,622,859])
          HitTestingTreeNode (7fb3a4707da0) APZC (7fb383bb0000) g=({ l=0x100000002, p=2, v=2 }) r=({ }) t=([ I ]) c=([0,0,1280,859])
            HitTestingTreeNode (7fb3a47094e0) APZC (7fb383bb1000) g=({ l=0x100000002, p=2, v=3 }) r=({ Hit=[0,859,634,1718] }) t=([ I ]) c=([0,0,1268,859])
  • scrollframe whose thumb is being dragged is v=4
  • enclosing (0, 50) transform is on a v=3 node, no assumption violations

Next, some content-side dumps.

For WebRender, a WebRenderLayerScrollData tree:

WebRenderLayerScrollData(0x7f564c310008), descendantCount=8, visible=[]
    WebRenderLayerScrollData(0x7f564c310188), descendantCount=7, visible=[]
        WebRenderLayerScrollData(0x7f564c310c08), descendantCount=0, metadata0={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [overscroll=auto] [0 scrollupdates] }, visible=[]
        WebRenderLayerScrollData(0x7f564c310a88), descendantCount=0, metadata0={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [overscroll=auto] [0 scrollupdates] }, visible=[1268,0,1280,415], scrollbarType=1, scrollbarAnimationId=0x509000000002
        WebRenderLayerScrollData(0x7f564c310908), descendantCount=0, metadata0={ [metrics={ [cb=(x=0, y=0, w=1268, h=859)] [sr=(x=0, y=0, w=1268, h=1718)] [s=(0,0)] [dp=(x=0, y=0, w=1268, h=1718)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1268, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 2)] scrollId=3 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=2] [overscroll=auto] [0 scrollupdates] }, metadata1={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [overscroll=auto] [0 scrollupdates] }, visible=[]
        WebRenderLayerScrollData(0x7f564c310788), descendantCount=0, metadata0={ [metrics={ [cb=(x=0, y=0, w=1268, h=859)] [sr=(x=0, y=0, w=1268, h=1718)] [s=(0,0)] [dp=(x=0, y=0, w=1268, h=1718)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1268, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 2)] scrollId=3 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=2] [overscroll=auto] [0 scrollupdates] }, metadata1={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [overscroll=auto] [0 scrollupdates] }, visible=[622,0,634,139], scrollbarType=1, scrollbarAnimationId=0x509000000003
        WebRenderLayerScrollData(0x7f564c310488), descendantCount=1, metadata0={ [metrics={ [cb=(x=0, y=0, w=1268, h=859)] [sr=(x=0, y=0, w=1268, h=1718)] [s=(0,0)] [dp=(x=0, y=0, w=1268, h=1718)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1268, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 2)] scrollId=3 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=2] [overscroll=auto] [0 scrollupdates] }, metadata1={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [overscroll=auto] [0 scrollupdates] }, ancestorTransform=[ 1 0; 0 1; 0 50; ], visible=[]
            WebRenderLayerScrollData(0x7f564c310608), descendantCount=0, metadata0={ [metrics={ [cb=(x=0, y=0, w=622, h=859)] [sr=(x=0, y=0, w=622, h=5000)] [s=(0,0)] [dp=(x=0, y=0, w=622, h=2304)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=622, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 3)] scrollId=4 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=3] [overscroll=auto] [1 scrollupdates] }, visible=[]
        WebRenderLayerScrollData(0x7f564c310308), descendantCount=0, metadata0={ [metrics={ [cb=(x=0, y=0, w=1268, h=859)] [sr=(x=0, y=0, w=1268, h=1718)] [s=(0,0)] [dp=(x=0, y=0, w=1268, h=1718)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1268, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 2)] scrollId=3 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=2] [overscroll=auto] [0 scrollupdates] }, metadata1={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [overscroll=auto] [0 scrollupdates] }, visible=[]

And for non-WebRender, a layer tree:

ClientLayerManager (0x7fca4066e800) --- in content order
  ClientContainerLayer (0x7fca3d73a800) [visible=[0,0,1280,859]] [opaqueContent] [presShellResolution=1]
    ClientPaintedLayer (0x7fca3d73b800) [clip=(x=0, y=0, w=0, h=0)] [not visible]
    ClientColorLayer (0x7fca3d740800) [visible=[0,0,1280,859]] { Hit=[0,0,1280,859] } [opaqueContent] [color=dev_rgba(255, 255, 255, 1.000000)] [bounds=(x=0, y=0, w=1280, h=859)]
    ClientContainerLayer (0x7fca3d73b000) [clip=(x=0, y=0, w=1280, h=859)] [visible=[0,0,1280,859]] [asyncZoomContainer scrollId=2] [presShellResolution=1]
      ClientPaintedLayer (0x7fca3d73c800) [visible=[0,0,1280,859]] { Hit=[0,0,1280,859] DispatchToContent=[1268,0,1280,859] } [opaqueContent] [metrics0={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [clip=(x=0, y=0, w=1280, h=859)] [overscroll=auto] [0 scrollupdates] }] [valid=[0,0,1280,859]]
      ClientContainerLayer (0x7fca3d73c000) [clip=(x=1268, y=0, w=12, h=859)] [visible=[1268,0,1280,415]] [vscrollbar=3] [metrics0={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [clip=(x=0, y=0, w=1280, h=859)] [overscroll=auto] [0 scrollupdates] }] [presShellResolution=1]
        ClientPaintedLayer (0x7fca3d73d800) [transform=[ 1 0; 0 1; 1268 0; ]] [effective-transform=[ 1 0; 0 1; 1268 0; ]] [visible=[0,0,12,415]] { Hit=[0,0,12,415] DispatchToContent=[0,0,12,415] } [valid=[0,0,12,415]]
      ClientPaintedLayer (0x7fca3d743800) [not visible] { Hit=[0,0,1268,1718] } [opaqueContent] [metrics0={ [metrics={ [cb=(x=0, y=0, w=1268, h=859)] [sr=(x=0, y=0, w=1268, h=1718)] [s=(0,0)] [dp=(x=0, y=0, w=1268, h=1718)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1268, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 2)] scrollId=3 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=2] [clip=(x=0, y=0, w=1268, h=859)] [overscroll=auto] [0 scrollupdates] }] [metrics1={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [clip=(x=0, y=0, w=1280, h=859)] [overscroll=auto] [0 scrollupdates] }]
      ClientContainerLayer (0x7fca3d73d000) [clip=(x=0, y=0, w=1268, h=1718)] [transform=[ 1 0; 0 1; 0 50; ]] [effective-transform=[ 1 0; 0 1; 0 50; ]] [visible=[0,0,634,859]] [metrics0={ [metrics={ [cb=(x=0, y=0, w=1268, h=859)] [sr=(x=0, y=0, w=1268, h=1718)] [s=(0,0)] [dp=(x=0, y=0, w=1268, h=1718)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1268, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 2)] scrollId=3 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=2] [clip=(x=0, y=0, w=1268, h=859)] [overscroll=auto] [0 scrollupdates] }] [metrics1={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [clip=(x=0, y=0, w=1280, h=859)] [overscroll=auto] [0 scrollupdates] }] [presShellResolution=1]
        ClientPaintedLayer (0x7fca3d73f800) [effective-transform=[ 1 0; 0 1; 0 50; ]] [visible=[622,0,634,859]] { Hit=[0,0,634,859] DispatchToContent=[622,0,634,859] } [opaqueContent] [valid=[622,0,634,859]]
        ClientContainerLayer (0x7fca440cd800) [clip=(x=622, y=0, w=12, h=859)] [effective-transform=[ 1 0; 0 1; 0 50; ]] [visible=[622,0,634,139]] [vscrollbar=4] [presShellResolution=1]
          ClientPaintedLayer (0x7fca440d0000) [transform=[ 1 0; 0 1; 622 0; ]] [effective-transform=[ 1 0; 0 1; 622 50; ]] [visible=[0,0,12,139]] { Hit=[0,0,12,139] DispatchToContent=[0,0,12,139] } [valid=[0,0,12,139]]
        ClientPaintedLayer (0x7fca440ce800) [effective-transform=[ 1 0; 0 1; 0 50; ]] [visible=[0,0,622,3200]] { Hit=[0,0,622,5000] } [opaqueContent] [metrics0={ [metrics={ [cb=(x=0, y=0, w=622, h=859)] [sr=(x=0, y=0, w=622, h=5000)] [s=(0,0)] [dp=(x=0, y=0, w=622, h=3200)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=622, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 3)] scrollId=4 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=3] [clip=(x=0, y=0, w=622, h=859)] [overscroll=auto] [1 scrollupdates] }] [valid=[0,0,622,3200]]
      ClientPaintedLayer (0x7fca3d743000) [not visible] { Hit=[0,859,634,1718] } [opaqueContent] [metrics0={ [metrics={ [cb=(x=0, y=0, w=1268, h=859)] [sr=(x=0, y=0, w=1268, h=1718)] [s=(0,0)] [dp=(x=0, y=0, w=1268, h=1718)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1268, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 2)] scrollId=3 }] [color=dev_rgba(0, 0, 0, 0.000000)] [scrollParent=2] [clip=(x=0, y=0, w=1268, h=859)] [overscroll=auto] [0 scrollupdates] }] [metrics1={ [metrics={ [cb=(x=0, y=0, w=1280, h=859)] [sr=(x=0, y=0, w=1280, h=859)] [s=(0,0)] [dp=(x=0, y=0, w=1280, h=859)] [cdp=(x=0, y=0, w=0, h=0)] [rcs=(1280 x 859)] [v=(x=0, y=0, w=1280, h=859)] [z=(ld=1.000 r=1.000 cr=1 z=1 er=1 )] [u=(0 1)] scrollId=2 [rcd] }] [color=dev_rgba(255, 255, 255, 1.000000)] [clip=(x=0, y=0, w=1280, h=859)] [overscroll=auto] [0 scrollupdates] }]

In both cases, the parent (v=3) and grandparent (v=2) of the v=4 hit-testing tree node come from a single node in the above trees. That single node has two metrics (v=2 and v=3), and the (0,50) transform is present on that node (as a property of the node itself, not one of the metrics). However, when the hit-testing tree is created, with WebRender the transform ends up on the v=2 node whereas with non-WR the transform ends up on the v=3 node.

It looks like layers have only one transform associated with them, and it gets associated with the bottommost node (here, v=3).

WebRenderLayerScrollData, on the other hand, has both a "transform" and an "ancestor transform"; the former gets associated with the bottommost layer (v=3), while the latter with the topmost layer (v=2), and the (0,50) is in the ancestor transform.

I've been reading the WebRender code for creating WebRenderLayerScrollData nodes, and my understanding so far is that the "ancestor transform" is an optimization of sorts. Rather than having every nsDisplayTransform display item create its own WebRenderLayerScrollData node, we try to "defer" some transforms and combine them into other nodes (and possibly also combine them with each other); this is explained in more detail in this comment. When a WebRenderLayerScrollData node is finally emitted, the deferred transforms are stored in the "ancestor transform" field, which gets associated with the topmost metrics during hit-testing tree building.

If I disable this optimization (by commenting out the branches here and here), the bug goes away.

In this case, the transform display item has v=3 as its ASR.

That means we want the transform to end up on a hit-testing tree node with v=3, not on an ancestor of such a node. (Otherwise, the transform will become part of the ancestor transform [here using that term in the APZ sense] of the v=3 node, which may violate APZ's requirement if there are v=3 nodes elsewhere in the tree (which will not have that as part of their ancestor transform).)

Since WebRenderLayerScrollData::mAncestorTransform is associated with the topmost metrics, that in turn means that if the transform is deferred, it better end up on a WRLSD node whose topmost metrics is v=3.

The metrics that get put on a WRLSD are determined by the aStopAtAsr parameter of WebRenderLayerScrollData::Initialize(). If we want the topmost metrics to be v=3, we need aStopAtAsr = ancestor(3) = 2.

That's not what happens here. We have aStopAtAsr = nullptr, and the WRLSD ends up with both v=3 and v=2 metrics.

Basically, I think the APZ requirement induces a limitation on how aggressively we can collapse WRLSD nodes (i.e. use the "deferred transform" mechanism to stuff more things into a single WRLSD node), which the code to build the WRLSD tree is not respecting.

The codepath that creates the WRLSD item is this one.

  • item is a descendant item of the transform, with ASR v=4
  • the transform item is the current deferred transform item; its ASR is v=3 so we take the enclosing if-branch
  • earlier in the branch, we create a WRLSD for the descendant item
    • we pass the deferred item's ASR for aStopAtAsr, so this WRLSD just gets the v=4 metrics
  • then we create the WRLSD for the transform item, with the transform as ancestor transform
    • stopAtAsr is nullptr, so this WRLSD gets v=3 and v=2 metrics

I guess, in this case, we need to create a third WRLSD, such that the one for the transform item has the transform's ASR (v=3) as topmost?

A couple of open questions:

  • Do we need to handle a similar scenario in the else-branch? (I suspect yes.)
  • Should we somehow be handling this earlier instead, at the time we populate the deferred transform?

(In reply to Botond Ballo [:botond] from comment #20)

I guess, in this case, we need to create a third WRLSD, such that the one for the transform item has the transform's ASR (v=3) as topmost?

I realized that this approach is probably not going to work, as creating an additional WRLSD node with v=2 metrics requires as input a display item with v=2 as its ASR, and such a display item may not be available.

So, I'm now thinking of a revised approach:

  • Keep the same number of WRLSD nodes as before.
  • When setting an ancestor transform on a WRLSD node, annotate it with the transform's ASR (in this case, v=3).
  • When generating hit-testing tree nodes based on the WRLSD, instead of placing the transform on the topmost node, place it on the node with the matching scroll id.

I've got a fix based on the approach in comment 21 working locally.

Try push is showing some test failures I need to investigate.

This push is looking better.

Transforms stored in WebRenderLayerScrollData::mAncestorTransform would
always end up on the topmost hit-testing tree node generated by that
WebRenderLayerScrollData node. That topmost node may not correspond
to the ASR of the transform item(s) which are the source of the
mAncestorTransform. The transform being in the wrong place in the
hit-testing tree can in turn violate APZ's assumptions about different
nodes that scroll together having the same ancestor transform.

To resolve this, this patch stores the transform item's ASR in the
WebRenderLayerScrollData, and applies it to the matching hit-testing
tree node.

Depends on D120566

Maybe<T*> is a redundant representation if there is no semantic
difference between Nothing() and Some(nullptr), and just makes
for cumbersome access syntax.

This bug doesn't seem to be happening in 90.0.2. Did you fix it?

(In reply to iii_iii from comment #30)

This bug doesn't seem to be happening in 90.0.2. Did you fix it?

I can still reproduce the issue in 90.0.2, with WebRender enabled.

Perhaps you have WebRender disabled for some reason? You can check in about:support, under "Compositing".

(The fix hasn't merged yet and is likely headed for Firefox 92.)

Depends on D120568

This is very odd. The bug came back again earlier today. But now it has gone away again. I haven't changed any settings. Perhaps a website can change the settings?

about:support
Compositing WebRender (Software)

but further down the page:

WEBRENDER
available by default
disabled by env: Not qualified

When the bug comes back I will check this page again.

I see what to do. When in tweetdeck and the bug is present, click on the new tweet button in the panel on the left. This opens a new column and the others shift to the right. Then close the new column clicking the cross, the other columns move to the left again, and now the bug has gone away.

See Also: → 1576514
See Also: → 1722308
Blocks: 1576514
See Also: 1576514
Pushed by tnikkel@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/a822ab0de8d0 Fix the comment describing what FrameMetrics::mCompositionBounds is relative to. r=tnikkel https://hg.mozilla.org/integration/autoland/rev/8716a1f06b9a Fix an include-what-you-use error in WebRenderScrollDataWrapper.h. r=tnikkel https://hg.mozilla.org/integration/autoland/rev/1ae004db16d3 Factor out a ViewID typedef in WebRenderScrollData.h. r=tnikkel https://hg.mozilla.org/integration/autoland/rev/0b9d07ef46cb Make sure transforms end up on a hit testing tree node corresponding to their ASR. r=tnikkel https://hg.mozilla.org/integration/autoland/rev/67eef5d179da Simplify representation of StackingContextHelper::mDeferredTransformItem. r=tnikkel https://hg.mozilla.org/integration/autoland/rev/2bffa50c624a Add a mochitest. r=tnikkel
Regressions: 1723200
Blocks: 1726450
Regressions: 1805082
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: