WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
70103
[chromium] Implement position:fixed in compositor thread
https://bugs.webkit.org/show_bug.cgi?id=70103
Summary
[chromium] Implement position:fixed in compositor thread
Hin-Chung Lam
Reported
2011-10-14 05:40:24 PDT
One of the feature missing in compositor thread is position:fixed. This needs to get implemented.
Attachments
Work in progress demo
(31.14 KB, patch)
2011-10-14 05:46 PDT
,
Hin-Chung Lam
webkit.review.bot
: commit-queue-
Details
Formatted Diff
Diff
simple fixed element
(111 bytes, text/html)
2011-10-20 09:01 PDT
,
Hin-Chung Lam
no flags
Details
fixed element in iframe
(428 bytes, text/html)
2011-10-20 09:02 PDT
,
Hin-Chung Lam
no flags
Details
fixed element with parent transform
(184 bytes, text/html)
2011-10-20 09:02 PDT
,
Hin-Chung Lam
no flags
Details
fixed element with local transform
(160 bytes, text/html)
2011-10-20 09:02 PDT
,
Hin-Chung Lam
no flags
Details
Work in progress, attempt 2
(17.17 KB, patch)
2011-10-20 09:06 PDT
,
Hin-Chung Lam
no flags
Details
Formatted Diff
Diff
fixed in transformed iframe
(668 bytes, text/html)
2011-10-31 08:23 PDT
,
Hin-Chung Lam
no flags
Details
Patch 3
(13.66 KB, patch)
2011-10-31 08:24 PDT
,
Hin-Chung Lam
no flags
Details
Formatted Diff
Diff
Attempt 4
(14.33 KB, patch)
2011-11-01 11:57 PDT
,
Hin-Chung Lam
no flags
Details
Formatted Diff
Diff
WebCore common changes
(5.47 KB, patch)
2011-11-03 06:28 PDT
,
Hin-Chung Lam
no flags
Details
Formatted Diff
Diff
Patch
(14.50 KB, patch)
2011-11-03 06:58 PDT
,
Hin-Chung Lam
no flags
Details
Formatted Diff
Diff
Chromium port changes
(14.51 KB, patch)
2011-11-03 07:00 PDT
,
Hin-Chung Lam
no flags
Details
Formatted Diff
Diff
Patch
(31.10 KB, patch)
2012-04-24 11:34 PDT
,
Sami Kyostila
no flags
Details
Formatted Diff
Diff
Patch
(17.44 KB, patch)
2012-04-27 14:03 PDT
,
Sami Kyostila
no flags
Details
Formatted Diff
Diff
Patch
(16.32 KB, patch)
2012-05-17 11:55 PDT
,
Sami Kyostila
no flags
Details
Formatted Diff
Diff
Patch
(16.28 KB, patch)
2012-05-31 06:17 PDT
,
Sami Kyostila
no flags
Details
Formatted Diff
Diff
Patch
(16.62 KB, patch)
2012-06-01 12:08 PDT
,
Sami Kyostila
no flags
Details
Formatted Diff
Diff
Transformed element within a fixed element in a translucent container.
(820 bytes, text/html)
2012-06-01 12:10 PDT
,
Sami Kyostila
no flags
Details
Another example of fixed-position with a renderSurface in-between.
(590 bytes, text/html)
2012-06-05 15:56 PDT
,
Shawn Singh
no flags
Details
In good condition, but still needs more unit tests
(19.26 KB, patch)
2012-06-05 17:53 PDT
,
Shawn Singh
no flags
Details
Formatted Diff
Diff
Polished and buffed, and with unit tests
(37.87 KB, patch)
2012-06-07 00:18 PDT
,
Shawn Singh
no flags
Details
Formatted Diff
Diff
Patch for archival, still need to address comment 65
(36.03 KB, patch)
2012-06-07 13:12 PDT
,
Shawn Singh
no flags
Details
Formatted Diff
Diff
Rewrote from scratch, added more tests, feels solid
(50.71 KB, patch)
2012-06-07 23:51 PDT
,
Shawn Singh
no flags
Details
Formatted Diff
Diff
Again from scratch, tested and still feels solid
(52.25 KB, patch)
2012-06-08 16:07 PDT
,
Shawn Singh
no flags
Details
Formatted Diff
Diff
Addressed reviewers comments
(57.22 KB, patch)
2012-06-11 14:23 PDT
,
Shawn Singh
enne
: review+
Details
Formatted Diff
Diff
Show Obsolete
(18)
View All
Add attachment
proposed patch, testcase, etc.
Hin-Chung Lam
Comment 1
2011-10-14 05:46:02 PDT
Created
attachment 111002
[details]
Work in progress demo This is really a work in progress as I'm trying to get familiar with the code. This patch is based on Vangelis's change and added change to CCLayerTreeHostCommon.cpp that implements the idea I described. The algorithm is pretty simple, as we recursively compute the draw transform, keep a copy with scroll delta translation, then when we hit a layer that doesn't want scrolling then it switches to the unscrolled draw transform. This will keep all the children to have maintain proper transformation.
Vangelis Kokkevis
Comment 2
2011-10-14 10:00:46 PDT
Comment on
attachment 111002
[details]
Work in progress demo View in context:
https://bugs.webkit.org/attachment.cgi?id=111002&action=review
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:136 > +
I generally expect that fixed position layers will be the exception rather than the rule. In addition scroll deltas will only happen when running on the thread. I would prefer to pay the penalty of adjusting the transform only when really necessary. In other words, as we descend the layer hierarchy, if we find a fixed position layer then walk upwards until the enclosing scrolling parent and compute the transform delta.
WebKit Review Bot
Comment 3
2011-10-16 00:52:27 PDT
Attachment 111002
[details]
did not pass style-queue: Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebCore/page/Settings.cpp', u'Sourc..." exit_code: 1 Source/WebKit/chromium/src/WebCompositorImpl.cpp:36: Alphabetical sorting problem. [build/include_order] [4] Source/WebKit/chromium/src/WebCompositorImpl.cpp:122: Missing spaces around < [whitespace/operators] [3] Total errors found: 2 in 23 files If any of these errors are false positives, please file a bug against check-webkit-style.
WebKit Review Bot
Comment 4
2011-10-16 01:16:32 PDT
Comment on
attachment 111002
[details]
Work in progress demo
Attachment 111002
[details]
did not pass chromium-ews (chromium-xvfb): Output:
http://queues.webkit.org/results/10073578
Hin-Chung Lam
Comment 5
2011-10-20 09:01:46 PDT
Created
attachment 111784
[details]
simple fixed element
Hin-Chung Lam
Comment 6
2011-10-20 09:02:09 PDT
Created
attachment 111785
[details]
fixed element in iframe
Hin-Chung Lam
Comment 7
2011-10-20 09:02:36 PDT
Created
attachment 111786
[details]
fixed element with parent transform
Hin-Chung Lam
Comment 8
2011-10-20 09:02:57 PDT
Created
attachment 111787
[details]
fixed element with local transform
Hin-Chung Lam
Comment 9
2011-10-20 09:06:03 PDT
Created
attachment 111788
[details]
Work in progress, attempt 2 The is the second attempt for implementing position:fixed in compositor thread. This change assumes a position:fixed layer is a direct descendant from tree root. It walks up the tree to determine the scroll delta from parent and offset the scroll delta. I've tested this with various test cases I've updated in this bug.
Vangelis Kokkevis
Comment 10
2011-10-20 09:33:39 PDT
Comment on
attachment 111788
[details]
Work in progress, attempt 2 View in context:
https://bugs.webkit.org/attachment.cgi?id=111788&action=review
> WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:91 > + return getParentScrollDelta(layer->parent()) + layer->scrollDelta();
We should only be compensating for scrollDelta of the closest enclosing scrolling frame, not all of them.
> WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:184 > + position += getParentScrollDelta(layer->parent());
I'm afraid I may have mislead you with my previous comments. You'll need to first transform the frame's scroll delta to the layer's coordinate system before adjusting the position. What you have here won't work if, for example, one of the ancestors of the fixed position layer is rotated.
Hin-Chung Lam
Comment 11
2011-10-20 09:43:39 PDT
(In reply to
comment #10
)
> (From update of
attachment 111788
[details]
) > View in context:
https://bugs.webkit.org/attachment.cgi?id=111788&action=review
> > > WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:91 > > + return getParentScrollDelta(layer->parent()) + layer->scrollDelta(); > > We should only be compensating for scrollDelta of the closest enclosing scrolling frame, not all of them. > > > WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:184 > > + position += getParentScrollDelta(layer->parent()); > > I'm afraid I may have mislead you with my previous comments. You'll need to first transform the frame's scroll delta to the layer's coordinate system before adjusting the position. What you have here won't work if, for example, one of the ancestors of the fixed position layer is rotated.
I agree, that matches what I was expected too.. Actually I'm not so sure about separating the logic for transformation of position:fixed elements (i.e. walk up the tree and walk down again to recompute transformation with scroll). I worry that we'll have to duplicate the logic for transformation in two places.. note that calculateDrawTransformsAndVisibilityInternal has side effect and I don't think it's suitable for re-computation of transformation without scroll delta. On the other hand, if we maintain a nonscrolled transformation, most of the time it'll just be a copy of the scrolled, so we can probably shortcut the extra matrix multiplications.
Vangelis Kokkevis
Comment 12
2011-10-25 12:19:41 PDT
> I agree, that matches what I was expected too.. > > Actually I'm not so sure about separating the logic for transformation of position:fixed elements (i.e. walk up the tree and walk down again to recompute transformation with scroll). I worry that we'll have to duplicate the logic for transformation in two places.. note that calculateDrawTransformsAndVisibilityInternal has side effect and I don't think it's suitable for re-computation of transformation without scroll delta. > > On the other hand, if we maintain a nonscrolled transformation, most of the time it'll just be a copy of the scrolled, so we can probably shortcut the extra matrix multiplications.
The code in CCLayerTreeHostCommon computes a "screenspace" transform for every layer, which accounts for the entire chain of transforms from the root to the layer. To adjust the position of a fixed layer, we need to subtract the scroll offset of the scrolling container from the layer's current position. However, the layer's position is expressed in the layer's parent coordinate system so we cannot apply the scroll offset directly. We could however presumably use the screenspace transform of the parent and that of the scrolling container to compute the offset in the right space. So if the scroll offset expressed in the container's coordinate system is given by vector o(c) and we have the following screen space matrices: M(c) : screen space matrix for scrolling container M(p) : screen space matrix for the parent of the fixed layer Then: o(p) = M(p)^-1 * M(c) * o(c) should the the scroll offset expressed in the layer's parent coordinate system. We should be able to subtract o(p) from the current layer position to get it to stay fixed. This should avoid additional (and possibly unnecessary) matrix math going down the hierarchy.
Hin-Chung Lam
Comment 13
2011-10-28 07:49:04 PDT
(In reply to
comment #12
)
> > I agree, that matches what I was expected too.. > > > > Actually I'm not so sure about separating the logic for transformation of position:fixed elements (i.e. walk up the tree and walk down again to recompute transformation with scroll). I worry that we'll have to duplicate the logic for transformation in two places.. note that calculateDrawTransformsAndVisibilityInternal has side effect and I don't think it's suitable for re-computation of transformation without scroll delta. > > > > On the other hand, if we maintain a nonscrolled transformation, most of the time it'll just be a copy of the scrolled, so we can probably shortcut the extra matrix multiplications. > > The code in CCLayerTreeHostCommon computes a "screenspace" transform for every layer, which accounts for the entire chain of transforms from the root to the layer. > > To adjust the position of a fixed layer, we need to subtract the scroll offset of the scrolling container from the layer's current position. However, the layer's position is expressed in the layer's parent coordinate system so we cannot apply the scroll offset directly. We could however presumably use the screenspace transform of the parent and that of the scrolling container to compute the offset in the right space. > > So if the scroll offset expressed in the container's coordinate system is given by vector o(c) and we have the following screen space matrices: > > M(c) : screen space matrix for scrolling container > M(p) : screen space matrix for the parent of the fixed layer > > Then: o(p) = M(p)^-1 * M(c) * o(c) > > should the the scroll offset expressed in the layer's parent coordinate system. We should be able to subtract o(p) from the current layer position to get it to stay fixed. > > This should avoid additional (and possibly unnecessary) matrix math going down the hierarchy.
I'm actually thinking of a different formula to get the unscrolled screen space matrix: M(u) : unscrolled screen matrix for the parent of the fixed layer M(-o(c)) : local transformation matrix that reverse the scroll delta M(u) = M(c) * M(-o(c)) * M(c)^-1 * M(p)
Hin-Chung Lam
Comment 14
2011-10-31 08:23:51 PDT
Created
attachment 113051
[details]
fixed in transformed iframe
Hin-Chung Lam
Comment 15
2011-10-31 08:24:22 PDT
Created
attachment 113052
[details]
Patch 3
Hin-Chung Lam
Comment 16
2011-10-31 08:25:14 PDT
Hi Vangelis, I've updated the patch after the discussion we had. Please take a look to see if this is ready for review or I should make more changes.
Vangelis Kokkevis
Comment 17
2011-10-31 14:29:02 PDT
Comment on
attachment 113052
[details]
Patch 3 View in context:
https://bugs.webkit.org/attachment.cgi?id=113052&action=review
Patch looks good. My main concern is the naming for the GraphicsLayer addition. I was thinking of splitting this up to a WebKit common patch that just sets the properties on GraphicsLayer and an additional chromium-specific patch that handles scrolling.
> Source/WebCore/platform/graphics/GraphicsLayer.h:362 > + bool anchorLayer() const { return m_anchorLayer; }
The word "anchor" is already used by "anchorPoint" which makes it confusing to reuse for a different purpose. Let's see what we're able to check into webkit.
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:107 > +template<typename LayerType> static IntSize enclosingAncestorScrollDelta(LayerType* layer) {
The name of this function should reflect that it adds up deltas up to the enclosing ancestor. Maybe something like: cummulativeScrollDeltasFromEnclosingAncestor() ? Also, have you considered implementing it as a while() loop instead of a recursion? It will be faster.
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:209 > + // and the anchor layer.
It would be useful to add a short blurb here as to why there are no other transformations in between.
Vangelis Kokkevis
Comment 18
2011-10-31 23:53:09 PDT
One more observation: It looks like we're not marking the right layer as a container. The scroll delta gets applied to a layer that's higher in the hierarchy so we miss it.
Hin-Chung Lam
Comment 19
2011-11-01 11:57:15 PDT
Created
attachment 113199
[details]
Attempt 4
Hin-Chung Lam
Comment 20
2011-11-03 06:28:40 PDT
Created
attachment 113475
[details]
WebCore common changes
Hin-Chung Lam
Comment 21
2011-11-03 06:58:09 PDT
Created
attachment 113481
[details]
Patch
Hin-Chung Lam
Comment 22
2011-11-03 07:00:34 PDT
Created
attachment 113482
[details]
Chromium port changes
WebKit Review Bot
Comment 23
2011-11-03 08:26:03 PDT
Comment on
attachment 113482
[details]
Chromium port changes
Attachment 113482
[details]
did not pass chromium-ews (chromium-xvfb): Output:
http://queues.webkit.org/results/10175633
Hin-Chung Lam
Comment 24
2011-11-04 04:58:03 PDT
Taking reviews off since I'm still making some changes.
Sami Kyostila
Comment 25
2012-04-24 11:32:32 PDT
Taking over from Alpha.
Sami Kyostila
Comment 26
2012-04-24 11:34:36 PDT
Created
attachment 138609
[details]
Patch WIP patch. Still missing layout tests and support for intermediate render surfaces between a fixed layer and its container. Feel free to comment, e.g., the ScrollingCoordinator integration, though.
Sami Kyostila
Comment 27
2012-04-24 11:40:12 PDT
Removing [chromium] from title since the latest patch also touches other WebCore parts. Please let me know if you'd prefer me to split the patch instead.
WebKit Review Bot
Comment 28
2012-04-24 11:44:59 PDT
Attachment 138609
[details]
did not pass style-queue: Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebCore/ChangeLog', u'Source/WebCor..." exit_code: 1 Source/WebCore/ChangeLog:10: You should remove the 'No new tests' and either add and list tests, or explain why no new tests were possible. [changelog/nonewtests] [5] Total errors found: 1 in 17 files If any of these errors are false positives, please file a bug against check-webkit-style.
Gustavo Noronha (kov)
Comment 29
2012-04-24 11:56:21 PDT
Comment on
attachment 138609
[details]
Patch
Attachment 138609
[details]
did not pass gtk-ews (gtk): Output:
http://queues.webkit.org/results/12529274
James Robinson
Comment 30
2012-04-24 12:09:17 PDT
Comment on
attachment 138609
[details]
Patch Please at a minimum split the cross-platform bits (WebCore up to ScrollingCoordinator interface) from the chromium compositor implementation bits
Build Bot
Comment 31
2012-04-24 12:23:13 PDT
Comment on
attachment 138609
[details]
Patch
Attachment 138609
[details]
did not pass mac-ews (mac): Output:
http://queues.webkit.org/results/12523326
Early Warning System Bot
Comment 32
2012-04-24 13:04:54 PDT
Comment on
attachment 138609
[details]
Patch
Attachment 138609
[details]
did not pass qt-ews (qt): Output:
http://queues.webkit.org/results/12526346
Early Warning System Bot
Comment 33
2012-04-24 13:14:18 PDT
Comment on
attachment 138609
[details]
Patch
Attachment 138609
[details]
did not pass qt-wk2-ews (qt): Output:
http://queues.webkit.org/results/12528323
Iain Merrick
Comment 34
2012-04-26 07:32:34 PDT
Experimenting with this patch, I found a bug: if you scroll the page, go back to the previous page, then forward again, the old scroll position is restored, but it is not taken into account in the positioning of the composited fixed-position layers. If you scroll further, the fixed-position layers pop into the correct position. It seems like HistoryController::restoreScrollPositionAndViewState is not being propagated through to the compositor correctly. I'm looking for a fix. Not sure yet if it's specific to this patch; I'll file a separate bug if it's a existing latent problem.
Iain Merrick
Comment 35
2012-04-26 07:49:23 PDT
OK, I think the problem is that the scroll position is restored while we're inside FrameView::layout(), and updateFixedElementsAfterScrolling() looks like this: void FrameView::updateFixedElementsAfterScrolling() { #if USE(ACCELERATED_COMPOSITING) if (!m_nestedLayoutCount && hasFixedObjects()) { if (RenderView* root = rootRenderer(this)) { root->compositor()->updateCompositingLayers(CompositingUpdateOnScroll); } } #endif } m_nestedLayoutCount is 1, so we don't call updateCompositingLayers().
Iain Merrick
Comment 36
2012-04-26 08:14:45 PDT
This bug is independent of Sami's patch. Filed as
https://bugs.webkit.org/show_bug.cgi?id=84965
Sami Kyostila
Comment 37
2012-04-27 13:55:19 PDT
This patch now depends on the WebCore changes in
bug 78864
.
Sami Kyostila
Comment 38
2012-04-27 14:03:41 PDT
Created
attachment 139271
[details]
Patch
Sami Kyostila
Comment 39
2012-05-17 11:55:25 PDT
Created
attachment 142519
[details]
Patch
Sami Kyostila
Comment 40
2012-05-17 11:56:52 PDT
N.B. the unit test in this version doesn't build since 73350 was reverted.
James Robinson
Comment 41
2012-05-18 15:30:44 PDT
Comment on
attachment 142519
[details]
Patch I don't think this will even apply without 73350. I would strongly prefer that we get 73350 landed and stabilized first so we can make sure we're on a good foundation and can test this patch as soon as landing it. Having untested and untestable code in the tree is a tax on everyone who wants to modify it.
Sami Kyostila
Comment 42
2012-05-21 05:46:07 PDT
(In reply to
comment #41
)
> I don't think this will even apply without 73350. I would strongly prefer that we get 73350 landed and stabilized first so we can make sure we're on a good foundation and can test this patch as soon as landing it. Having untested and untestable code in the tree is a tax on everyone who wants to modify it.
Definitely agreed. I'll get 73350 relanded before continuing with this.
Sami Kyostila
Comment 43
2012-05-31 06:17:39 PDT
Created
attachment 145072
[details]
Patch Removed dependency on 73350 to avoid blocking this patch. Note that this still requires 78864 to be in place.
Sami Kyostila
Comment 44
2012-05-31 06:26:31 PDT
Since it's taking a while to get 73350 in shape (because I need to verify it on ChromeOS), so I opted to break the dependency between these patches. Since they are mostly orthogonal and the only linkage was in the unit tests, this didn't result in any changes in the implementation. This latest version together with 78864 gives us compositor thread positioned fixed position layers when --enable-fixed-position-compositing is used in Chromium. Note that since I didn't change the rules for layer promotion, you also need --fixed-position-creates-stacking-context or a transform on the fixed element for this to work.
Dana Jansens
Comment 45
2012-05-31 06:32:12 PDT
(In reply to
comment #44
)
> Since it's taking a while to get 73350 in shape (because I need to verify it on ChromeOS), so I opted to break the dependency between these patches. Since they are mostly orthogonal and the only linkage was in the unit tests, this didn't result in any changes in the implementation. > > This latest version together with 78864 gives us compositor thread positioned fixed position layers when --enable-fixed-position-compositing is used in Chromium. Note that since I didn't change the rules for layer promotion, you also need --fixed-position-creates-stacking-context or a transform on the fixed element for this to work.
Just curious, how do these layers behave when pageScaleFactor changes?
Sami Kyostila
Comment 46
2012-05-31 08:02:14 PDT
(In reply to
comment #45
)
> Just curious, how do these layers behave when pageScaleFactor changes?
When page scale factor changes on the main thread, both the fixed layer and its container are scaled appropriately and the layer remains fixed relative the visible part of the container. For example, if the page scale factor increases, all layers get bigger and a fixed element starts covering a larger fraction of its container. However, if the page scale changes as a response to a pinch gesture event on the compositor thread, it isn't applied to the fixed layers until the next commit from the main thread. Visually this means that the fixed layer drifts around while the user is pinch zooming. This isn't ideal, so I'll see if I can improve it.
Vangelis Kokkevis
Comment 47
2012-05-31 16:26:28 PDT
Comment on
attachment 145072
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=145072&action=review
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:427 > + // 2. A container layer's parent layer is a clip layer.
Do we care specifically that the parent of the container is a "clip" layer?
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:462 > + TransformationMatrix renderSurfaceMatrix = ancestor->transform().inverse();
I'm not convinced that this is correct. It's not taking into account the anchor points of the ancestor layer which need to be used when applying the layer transform. Should you be using the RS originTransform instead?
Sami Kyostila
Comment 48
2012-06-01 12:06:50 PDT
Comment on
attachment 145072
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=145072&action=review
>> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:427 >> + // 2. A container layer's parent layer is a clip layer. > > Do we care specifically that the parent of the container is a "clip" layer?
Not really. It is just the layer that defines the coordinate space for container layer's scroll delta. However, since scroll layers are generally contained in clip layers, I think it makes sense to call it that here. I've improved the comment to mention this.
>> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:462 >> + TransformationMatrix renderSurfaceMatrix = ancestor->transform().inverse(); > > I'm not convinced that this is correct. It's not taking into account the anchor points of the ancestor layer which need to be used when applying the layer transform. Should you be using the RS originTransform instead?
originTransform() is probably more appropriate, but it cannot be used as such because we end up applying the scroll offset to the fixed layer twice. I tried to come up with a scheme to make this work, but it needs some more thought. Essentially we need to undo the orientation of the RS relative to the screen, but how the RS's sublayer transform should be applied to the fixed position is a bit unclear. Perhaps it shouldn't apply at all, but that would break the (normal) case where the RS is the fixed position container. Meanwhile I'll attach a test page that shows the problem with originTransform(). Note that testing other types of RS/fixed interactions interactively is a bit tricky because WebCore needs to be changed to not consider transformed elements containers for fixed position.
Sami Kyostila
Comment 49
2012-06-01 12:08:49 PDT
Created
attachment 145350
[details]
Patch Checkpoint, don't apply.
Sami Kyostila
Comment 50
2012-06-01 12:10:26 PDT
Created
attachment 145351
[details]
Transformed element within a fixed element in a translucent container.
Vangelis Kokkevis
Comment 51
2012-06-01 12:37:27 PDT
Comment on
attachment 145350
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=145350&action=review
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:465 > + // FIXME: renderSurfaceMatrix also includes the scroll offset.
I'm not sure I understand. In what cases does the RSM include the scroll offset?
Shawn Singh
Comment 52
2012-06-04 21:35:36 PDT
I think the math is accidentally a little bit wrong, even for the non-renderSurface case. The problem is that we're using clipLayer->drawTransform. However, this does not create the intended composite matrix for what combinedTransform (the local layer's draw transform) should be. What we really wanted was clipLayer->parentMatrix() which is actually only a temporary matrix that is never stored. It will be extremely messy and error-prone to walk the tree and recompute that matrix - we should probably try to find a different solution first. Writing out the math explicitly (see the huge comment in CCLayerTreeHostCommon.cpp): A layer's draw transform is: M[draw] = M[parent] * Tr[parent2origin] * compositeLayerTransform * Tr[origin2center] A child layer's parentMatrix is: M[parent]_for_child = M[parent] * Tr[parent2origin] * compositeLayerTransform * compositeSubLayerTransform The fixed position layer, for the sake of discussion here, is the child layer. We're trying to decompose that so that we can insert an additional translation that cancels out the scroll. So according to the comments in this patch, we decompose M[parent]_for_child into: M[clip] * Tr[container] * M[descendant] However, M[clip] is unclear here, and that's where the mistake might be. It's not supposed to be the clip layer's draw transform. Instead, M[clip] should probably be the parentMatrix that is inherited by the scrolling layer. So what we really need is clipLayer->parentMatrix() which we do not actually store. Finally, its worth pointing out that I couldn't manually test any of this yet.... even though we removed 73350 as a dependency on this patch, actually it still is a dependency in my opinion because without that patch, scrollDelta is always 0,0. That is the only way to manually test and develop this patch further, and not having scrollDelta plumbed through just makes it impossible to reason through this math. Tomorrow I'll try to apply that patch, to iron out the math some more.
Vangelis Kokkevis
Comment 53
2012-06-04 21:57:19 PDT
(In reply to
comment #52
)
> Finally, its worth pointing out that I couldn't manually test any of this yet.... even though we removed 73350 as a dependency on this patch, actually it still is a dependency in my opinion because without that patch, scrollDelta is always 0,0.
You should be able to get a non-zero scrollDelta with the threaded compositor by scrolling the root layer. It may be easier though to hack in some scroll delta values directly in the code to see how the math works out.
Shawn Singh
Comment 54
2012-06-05 15:56:50 PDT
Created
attachment 145886
[details]
Another example of fixed-position with a renderSurface in-between. the red element should be fixed, and the blue element should scroll. the reflection behavior seems broken on stable chromium and safari, but seems correct with the new scrolling patches (probably because something gets composited/stacked differently, seems like a bug in webcore to address separately.)
Shawn Singh
Comment 55
2012-06-05 15:57:15 PDT
OK, I've gotten a decently complete picture of how this works now. Summary: I will submit a patch that refactors this to be more intuitive and clean. Sami's math was mostly already correct, and I've also figured out the RenderSurface case. Details: In theory its slightly wrong to use drawTransform instead of parentMatrix, but it turns out the differences are provably not going to affect the math, under current W3C specs. There's also a much more intuitive interpretation of the math, which helps illustrate all cases in general. Key observation: to undo the scroll, we have to apply the scroll in the space of the "clip" layer. So we do the following steps (note carefully, interpreting the transforms from left-to-right): 1. transform from fixed layer's target surface space to clip layer space. 2. apply the "undoScrollTranslation" 3. transform back to fixed layer's target surface space 4. continue with using the normal parentMatrix, which transforms from target surface space to local layer space. In math/code: scrollCompensation = clipLayerDrawTransform * undoScrollTranslation * clipLayerDrawTransform.inverse(); if layer is fixedPosition combinedTransform = scrollCompensation * parentMatrix; else combinedTransform = parentMatrix; For renderSurfaces, the same 4 steps above still apply. But steps (1) and (3) are just a little bit more involved, because fixed layer's target surface space is not the same as clip layer's target surface space. localTargetSpaceToClipLayerSpace = renderSurface.originTransform.inverse() * clipLayerDrawTransform; scrollCompensation = localTargetSpaceToClipLayerSpace * underScrollTranslation * localTargetSpaceToClipLayerSpace.inverse(); I believe this should work correctly in all cases. I attached my own version of the renderSurface case, too. Both Sami's and my attachments seem to work correctly with my new patch; I'll submit the new patch after adding some more unit tests.
Shawn Singh
Comment 56
2012-06-05 17:53:00 PDT
Created
attachment 145907
[details]
In good condition, but still needs more unit tests This patch passes all 7 tests attached on this bug when testing manually (using usleep() to make main thread really slow). Changelogs and unit tests still need updating. Compared to the previous patch, for now I only modified CCLayerTreeHostCommon.cpp.
James Robinson
Comment 57
2012-06-05 18:00:32 PDT
(In reply to
comment #56
)
> Created an attachment (id=145907) [details] > In good condition, but still needs more unit tests > > This patch passes all 7 tests attached on this bug when testing manually (using usleep() to make main thread really slow). Changelogs and unit tests still need updating. Compared to the previous patch, for now I only modified CCLayerTreeHostCommon.cpp.
FYI, there are some test cases here that might be helpful:
http://webstuff.nfshost.com/scrolling/
They are not exhaustive.
Shawn Singh
Comment 58
2012-06-05 18:17:58 PDT
(In reply to
comment #57
)
> (In reply to
comment #56
) > > Created an attachment (id=145907) [details] [details] > > In good condition, but still needs more unit tests > > > > This patch passes all 7 tests attached on this bug when testing manually (using usleep() to make main thread really slow). Changelogs and unit tests still need updating. Compared to the previous patch, for now I only modified CCLayerTreeHostCommon.cpp. > > FYI, there are some test cases here that might be helpful:
http://webstuff.nfshost.com/scrolling/
They are not exhaustive.
Thanks, those links seem to work, too.
Shawn Singh
Comment 59
2012-06-06 11:36:25 PDT
Received Sami's go-ahead to own this bug to completion. As I understand, he's actively working on testing/landing 78864 which this patch will depend on.
Shawn Singh
Comment 60
2012-06-07 00:18:38 PDT
Created
attachment 146216
[details]
Polished and buffed, and with unit tests This patch is now pretty clean and robust, including unit tests. Please note that I removed the ScrollingCoordinator code from this patch; if you want, this patch could even land before 78864 (the included unit tests will cover the code in this patch even without 78864).
Sami Kyostila
Comment 61
2012-06-07 09:41:17 PDT
Comment on
attachment 146216
[details]
Polished and buffed, and with unit tests View in context:
https://bugs.webkit.org/attachment.cgi?id=146216&action=review
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:352 > + // Since we're going backwards up the hierarchy, the surface's inverse originTransform should pre-multiply the accumulating transform.
I'm trying to figure out whether we should also undo scroll offsets from all ancestor layers that are *not* the container. That could happen if the fixed element is embedded in a scrollable child layer but the root layer is the fixed position container. I think one way to trigger this would be to use -webkit-overflow-scrolling: touch to cause a layer to be created for the scrollable child layer.
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:425 > + if ((scrollDelta.width() || scrollDelta.height())) {
Nit: could use !scrollDelta.isZero().
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:570 > WebTransformationMatrix combinedTransform = parentMatrix;
Nit: could leave combinedTransform uninitialized at this point since we always assign to it below.
Shawn Singh
Comment 62
2012-06-07 09:57:20 PDT
Thanks for the comments - I'll submit a new patch based on these. I'll also fix a few variable names that can be clearer and clean up the unit tests a bit more. One question below: (In reply to
comment #61
)
> (From update of
attachment 146216
[details]
) > View in context:
https://bugs.webkit.org/attachment.cgi?id=146216&action=review
> > > Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:352 > > + // Since we're going backwards up the hierarchy, the surface's inverse originTransform should pre-multiply the accumulating transform. > > I'm trying to figure out whether we should also undo scroll offsets from all ancestor layers that are *not* the container. That could happen if the fixed element is embedded in a scrollable child layer but the root layer is the fixed position container. > > I think one way to trigger this would be to use -webkit-overflow-scrolling: touch to cause a layer to be created for the scrollable child layer.
Are you referring to undoing the scroll offsets so that they affect the final transform of the surface? or the final transform of the fixed-position layer? I don't think we need to change any transforms on any other layers except the fixed-position one. And for that layer, the scroll offsets that are embedded in intermediate renderSurfaces do not affect the actual scroll compensation we need to apply since we apply transformToContainerSpace * scroll translation * transformToContainerSpace.inverse(). Or am I misunderstanding what you're saying?
Sami Kyostila
Comment 63
2012-06-07 10:49:35 PDT
(In reply to
comment #62
)
> Are you referring to undoing the scroll offsets so that they affect the final transform of the surface? or the final transform of the fixed-position layer? I don't think we need to change any transforms on any other layers except the fixed-position one. And for that layer, the scroll offsets that are embedded in intermediate renderSurfaces do not affect the actual scroll compensation we need to apply since we apply transformToContainerSpace * scroll translation * transformToContainerSpace.inverse(). Or am I misunderstanding what you're saying?
Ah, I meant the undoing the scroll deltas for the fixed position layer itself. Scroll deltas coming from any ancestor layer and not just render surfaces to be exact. For example: <div style="overflow: scroll; -webkit-overflow-scrolling: touch"> <div style="position: fixed"> </div> </div> I think in this case the fixed element should stay fixed to the view root.
Shawn Singh
Comment 64
2012-06-07 11:33:15 PDT
(In reply to
comment #63
)
> (In reply to
comment #62
) > > Are you referring to undoing the scroll offsets so that they affect the final transform of the surface? or the final transform of the fixed-position layer? I don't think we need to change any transforms on any other layers except the fixed-position one. And for that layer, the scroll offsets that are embedded in intermediate renderSurfaces do not affect the actual scroll compensation we need to apply since we apply transformToContainerSpace * scroll translation * transformToContainerSpace.inverse(). Or am I misunderstanding what you're saying? > > Ah, I meant the undoing the scroll deltas for the fixed position layer itself. Scroll deltas coming from any ancestor layer and not just render surfaces to be exact. For example: > > <div style="overflow: scroll; -webkit-overflow-scrolling: touch"> > <div style="position: fixed"> > </div> > </div> > > I think in this case the fixed element should stay fixed to the view root.
Is it possible to have non-zero scroll deltas on a non-container layer? If so, then yeah we have to completely rearrange the algorithm. If not, then its only a concern about the root layer, and I'll test and check, I think it should work. And I suppose we need a few more debug assertions if we're allowed to assume that non-containers will always have zero scroll.
Sami Kyostila
Comment 65
2012-06-07 11:40:54 PDT
(In reply to
comment #64
)
> Is it possible to have non-zero scroll deltas on a non-container layer? If so, then yeah we have to completely rearrange the algorithm. If not, then its only a concern about the root layer, and I'll test and check, I think it should work. And I suppose we need a few more debug assertions if we're allowed to assume that non-containers will always have zero scroll.
I think in my example the enclosing overflow div will not be marked as a container because it doesn't have a CSS transform, and since the layer is scrollable it may indeed have a non-zero scroll delta. Note that this doesn't happen with current master because there's ever only one scrollable layer, but with the patch from 73350 I think it's possible. Practically I guess this could be handled by undoing all scroll deltas from the fixed layer up to the first container.
Shawn Singh
Comment 66
2012-06-07 13:12:04 PDT
Created
attachment 146365
[details]
Patch for archival, still need to address
comment 65
It looks like we definitely should wait for other patches to land so we can better test more possible things that can happen on web pages. I'm just uploading this for backup and will revisit this in just a few days. Thanks!
Shawn Singh
Comment 67
2012-06-07 18:53:05 PDT
isContainerForFixedPositionLayers is a very sore misnomer. in the DOM, yes technically it is an ancestor that contains the fixedPositionLayer. But with the current approach we are taking, it is not the layer that the fixedPositionLayer is actually fixed onto. We should either revise our approach to set this flag on the layer just above it (needs a bit more careful thought), or we should re-name this flag.
Shawn Singh
Comment 68
2012-06-07 23:51:18 PDT
Created
attachment 146492
[details]
Rewrote from scratch, added more tests, feels solid
Shawn Singh
Comment 69
2012-06-07 23:54:11 PDT
Almost done! Summary: Vangelis and James, this is ready for review. I'm feeling good about this new algorithm and tests in this patch. In addition to unit tests, I manually tested a good bit, and everything seems to work as desired. Hopefully we can land the final version tomorrow (Friday)!! Details: (1) Because of
comment #65
, and thanks to fruitful offline discussion with Vangelis, it became clear that we had to rewrite this from scratch with a new approach, so that we can remove undesirable assumptions. This patch uses the strictly correct geometric space where scrollDelta needs to be undone. In addition to being more correct, this way we don't have to make assumptions about the relationships between layers to ensure we're in the correct space. It also makes the concept of the "clipLayer" unnecessary, and therefore it is not as fragile to walk the hierarchy. (2) Vangelis suggested we should go ahead and try to land it ASAP, and the new unit tests on this patch already cover the scrolling possibilities that we're worried about. It will be far easier and less risky to back-merge smaller fix after m21 if needed, rather than delaying this and needing to merge this large patch after it branches. (3) Added more unit tests, in particular to verify that the ordering of transforms is computed correctly when compensating for the scroll, and that multiple scrollDeltas can exist before finding the container for fixed position elements. (4) Re-named transformation matrix variables, so that the name represents the right-to-left interpretation of what the transform actually does. This is backwards from the previous patch, apologies if this causes drastic confusion.
Shawn Singh
Comment 70
2012-06-08 16:07:46 PDT
Created
attachment 146659
[details]
Again from scratch, tested and still feels solid Vangelis and I had another discusison about this and decided to try seeing what it would look like if we computed scrollCompensation in the recursion itself. It works just as well as the previous patch, just a different algorithm. It does seem like less scary code, but I think it depends on who you ask whether its actually more complicated or less complicated =) At any rate, both this patch and the previous one should work equally well, whichever one reviewers like better is fine with me. Thanks!
Vangelis Kokkevis
Comment 71
2012-06-10 23:27:58 PDT
Comment on
attachment 146659
[details]
Again from scratch, tested and still feels solid View in context:
https://bugs.webkit.org/attachment.cgi?id=146659&action=review
I like this approach better. Thanks for writing it up! One comment to avoid adding unnecessary operations in the common path.
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:540 > + // Special case: this layer is a composited fixed-position element; we need to
nit: I would say "fixed position _layer_" instead of "fixed position _element_" since the compositor doesn't know about HTML elements.
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:703 > + WebTransformationMatrix nextScrollCompensationMatrix = computeScrollCompensationMatrixForChildren(layer, parentMatrix, currentScrollCompensationMatrix);;
Since having a scroll delta or creating a RS are somewhat rare occurrences, it would be more efficient to eliminate the above function and move the code that computes the next matrix here. In the most common case we can pass "currentScrollCompensationMatrix" down the recursion (no matrix copy necessary) and overwrite it only when needed.
Adrienne Walker
Comment 72
2012-06-11 12:15:35 PDT
Comment on
attachment 146659
[details]
Again from scratch, tested and still feels solid View in context:
https://bugs.webkit.org/attachment.cgi?id=146659&action=review
I like this approach a lot. Can you add one more test where a fixed position layer is separated from its container by at least two intermediate render surfaces?
> Source/WebCore/ChangeLog:8 > + Unit tests added to CCLayerTreeHostCommonTest:
nit: put the testing block below the description, like layout tests are listed.
> Source/WebCore/ChangeLog:28 > + its own. This allows fixed-position elements to be composited,
Not sure what you mean by composited here. "This allows fixed position layers to be positioned correctly when scrolling in the compositor" maybe?
> Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h:239 > + const WebKit::WebTransformationMatrix& scrollDeltaSpaceToSurfaceTransform() { return m_scrollDeltaSpaceToSurfaceTransform; } > + void setScrollDeltaSpaceToSurfaceTransform(const WebKit::WebTransformationMatrix& matrix) { m_scrollDeltaSpaceToSurfaceTransform = matrix; }
Unused?
> Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h:337 > + // Set for the layer that has position fixed to the container layer's visible rect.
container => closest ancestor container?
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:365 > + // it is fixed to an ancsestor, and is a container for any fixed-position descendants.
ancsestor => ancestor
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:541 > + // explicitly compensate for all ancestors nonzero scrollDeltas to keep this layer
ancestors => ancestors'
> Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:707 > + // > + // Recursion happens here. > + //
nit: needless comment.
Shawn Singh
Comment 73
2012-06-11 13:54:18 PDT
Thanks for the comments. New patch is coming in a moment, with the following differences: - added an early exit that avoids stack allocation and matrix initialization/copy overheads in the computeScrollCompensationMatrixForChildren() helper function. This represents the compromise Vangelis and I reached discussing offline. - added a new unit test for multiple intermediate surfaces - addressed reviewers' nits
Shawn Singh
Comment 74
2012-06-11 14:23:29 PDT
Created
attachment 146909
[details]
Addressed reviewers comments tested manually on all examples attached as well as some real pages, and passes all unit tests.
Adrienne Walker
Comment 75
2012-06-11 14:33:04 PDT
Comment on
attachment 146909
[details]
Addressed reviewers comments R=me. Thanks for the extra test.
Shawn Singh
Comment 76
2012-06-11 14:38:06 PDT
Committed
r120008
: <
http://trac.webkit.org/changeset/120008
>
Shawn Singh
Comment 77
2012-06-11 14:39:21 PDT
(In reply to
comment #75
)
> (From update of
attachment 146909
[details]
) > R=me. Thanks for the extra test.
And thanks for the review =)
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug