Bug 1272429 - When hit-testing layers nested inside scrollable content inside fixed-pos items, make sure to hit the scrollable layers. r?botond
MozReview-Commit-ID: 2lpK6Jp17s5
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1771,31 +1771,26 @@ APZCTreeManager::GetAPZCAtPoint(HitTesti
if (aOutHitScrollbar) {
for (HitTestingTreeNode* n = resultNode; n; n = n->GetParent()) {
if (n->IsScrollbarNode()) {
*aOutHitScrollbar = true;
}
}
}
- AsyncPanZoomController* result = nullptr;
-
- FrameMetrics::ViewID fpTarget =
- resultNode->GetNearestAncestorFixedPosTargetWithSameLayersId();
- if (fpTarget != FrameMetrics::NULL_SCROLL_ID) {
+ FrameMetrics::ViewID fpTarget = FrameMetrics::NULL_SCROLL_ID;
+ AsyncPanZoomController* result = resultNode->GetNearestContainingApzcOrFixedPosTargetWithSameLayersId(&fpTarget);
+ APZCTM_LOG("Found target %p using ancestor lookup\n", result);
+ if (!result && fpTarget != FrameMetrics::NULL_SCROLL_ID) {
ScrollableLayerGuid guid(resultNode->GetLayersId(), 0, fpTarget);
RefPtr<HitTestingTreeNode> hitNode = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
result = hitNode ? hitNode->GetApzc() : nullptr;
APZCTM_LOG("Found target %p using fixed-pos lookup on %" PRIu64 "\n", result, fpTarget);
}
if (!result) {
- result = resultNode->GetNearestContainingApzcWithSameLayersId();
- APZCTM_LOG("Found target %p using ancestor lookup\n", result);
- }
- if (!result) {
result = FindRootApzcForLayersId(resultNode->GetLayersId());
MOZ_ASSERT(result);
APZCTM_LOG("Found target %p using root lookup\n", result);
}
APZCTM_LOG("Successfully matched APZC %p via node %p (hit result %d)\n",
result, resultNode, *aOutHitResult);
return result;
}
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -128,29 +128,16 @@ HitTestingTreeNode::IsScrollbarNode() co
}
void
HitTestingTreeNode::SetFixedPosData(FrameMetrics::ViewID aFixedPosTarget)
{
mFixedPosTarget = aFixedPosTarget;
}
-FrameMetrics::ViewID
-HitTestingTreeNode::GetNearestAncestorFixedPosTargetWithSameLayersId() const
-{
- for (const HitTestingTreeNode* n = this;
- n && n->mLayersId == mLayersId;
- n = n->GetParent()) {
- if (n->mFixedPosTarget != FrameMetrics::NULL_SCROLL_ID) {
- return n->mFixedPosTarget;
- }
- }
- return FrameMetrics::NULL_SCROLL_ID;
-}
-
void
HitTestingTreeNode::SetPrevSibling(HitTestingTreeNode* aSibling)
{
mPrevSibling = aSibling;
if (aSibling) {
aSibling->mParent = mParent;
if (aSibling->GetApzc()) {
@@ -211,24 +198,29 @@ HitTestingTreeNode::GetNearestContaining
if (n->GetApzc()) {
return n->GetApzc();
}
}
return nullptr;
}
AsyncPanZoomController*
-HitTestingTreeNode::GetNearestContainingApzcWithSameLayersId() const
+HitTestingTreeNode::GetNearestContainingApzcOrFixedPosTargetWithSameLayersId(
+ FrameMetrics::ViewID* aOutFixedPosTarget) const
{
for (const HitTestingTreeNode* n = this;
n && n->mLayersId == mLayersId;
n = n->GetParent()) {
if (n->GetApzc()) {
return n->GetApzc();
}
+ if (aOutFixedPosTarget && n->mFixedPosTarget != FrameMetrics::NULL_SCROLL_ID) {
+ *aOutFixedPosTarget = n->mFixedPosTarget;
+ return nullptr;
+ }
}
return nullptr;
}
bool
HitTestingTreeNode::IsPrimaryHolder() const
{
return mIsPrimaryApzcHolder;
--- a/gfx/layers/apz/src/HitTestingTreeNode.h
+++ b/gfx/layers/apz/src/HitTestingTreeNode.h
@@ -73,17 +73,18 @@ public:
HitTestingTreeNode* GetLastChild() const;
HitTestingTreeNode* GetPrevSibling() const;
HitTestingTreeNode* GetParent() const;
/* APZC related methods */
AsyncPanZoomController* GetApzc() const;
AsyncPanZoomController* GetNearestContainingApzc() const;
- AsyncPanZoomController* GetNearestContainingApzcWithSameLayersId() const;
+ AsyncPanZoomController* GetNearestContainingApzcOrFixedPosTargetWithSameLayersId(
+ FrameMetrics::ViewID* aOutFixedPosTarget) const;
bool IsPrimaryHolder() const;
uint64_t GetLayersId() const;
/* Hit test related methods */
void SetHitTestData(const EventRegions& aRegions,
const CSSTransformMatrix& aTransform,
const Maybe<ParentLayerIntRegion>& aClipRegion,
@@ -98,17 +99,16 @@ public:
bool aIsScrollContainer);
bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const;
int32_t GetScrollSize() const;
bool IsScrollbarNode() const;
/* Fixed pos info */
void SetFixedPosData(FrameMetrics::ViewID aFixedPosTarget);
- FrameMetrics::ViewID GetNearestAncestorFixedPosTargetWithSameLayersId() const;
/* Convert aPoint into the LayerPixel space for the layer corresponding to
* this node. */
Maybe<LayerPoint> Untransform(const ParentLayerPoint& aPoint) const;
/* Assuming aPoint is inside the clip region for this node, check which of the
* event region spaces it falls inside. */
HitTestResult HitTest(const ParentLayerPoint& aPoint) const;
/* Returns the mOverride flag. */
--- a/gfx/layers/apz/test/mochitest/helper_scroll_on_position_fixed.html
+++ b/gfx/layers/apz/test/mochitest/helper_scroll_on_position_fixed.html
@@ -32,16 +32,28 @@ function* runTest() {
yield scrollWheelOver(iframeWin.document.body, 50, 150);
ok(iframeWin.scrollY > scrollPos, "iframe scrolled after wheeling over the position:sticky element");
// same, but using the iframe's position:fixed element
scrollPos = iframeWin.scrollY;
yield scrollWheelOver(iframeWin.document.body, 250, 150);
ok(iframeWin.scrollY > scrollPos, "iframe scrolled after wheeling over the position:fixed element");
+ // same, but scrolling the scrollable frame *inside* the position:fixed item
+ var fpos = document.getElementById('fpos_scrollable');
+ scrollPos = fpos.scrollTop;
+ yield scrollWheelOver(fpos, 50, 150);
+ ok(fpos.scrollTop > scrollPos, "scrollable item inside fixed-pos element scrolled");
+ // wait for it to layerize fully and then try again
+ yield waitForAllPaints(driveTest);
+ yield flushApzRepaints(driveTest);
+ scrollPos = fpos.scrollTop;
+ yield scrollWheelOver(fpos, 50, 150);
+ ok(fpos.scrollTop > scrollPos, "scrollable item inside fixed-pos element scrolled after layerization");
+
// same, but using the top-level window's position:sticky element
scrollPos = window.scrollY;
yield scrollWheelOver(document.body, 50, 150);
ok(window.scrollY > scrollPos, "top-level document scrolled after wheeling over the position:sticky element");
// same, but using the top-level window's position:fixed element
scrollPos = window.scrollY;
yield scrollWheelOver(document.body, 250, 150);
@@ -51,26 +63,28 @@ function* runTest() {
var gTestContinuation = null;
function driveTest() {
if (!gTestContinuation) {
gTestContinuation = runTest();
}
var ret = gTestContinuation.next();
if (ret.done) {
window.opener.testDone();
- } else {
- is(ret.value, true, "Test continuation chunk was successful");
}
}
window.onload = function() {
waitForAllPaints(function() {
flushApzRepaints(driveTest);
});
}
</script>
</head>
<body style="height:5000px; margin:0">
<div style="position:sticky; width: 100px; height: 300px; top: 0; background-color:red">sticky</div>
<div style="position:fixed; width: 100px; height: 300px; top: 0; left: 200px; background-color: green">fixed</div>
<iframe id='iframe' width="300" height="400" src="data:text/html,<body style='height:5000px; margin:0'><div style='position:sticky; width:100px; height:300px; top: 0; background-color:red'>sticky</div><div style='position:fixed; right:0; top: 0; width:100px; height:300px; background-color:green'>fixed</div>"></iframe>
+
+ <div id="fpos_scrollable" style="position:fixed; width: 100px; height: 300px; top: 0; left: 400px; background-color: red; overflow:scroll">
+ <div style="background-color: blue; height: 1000px; margin: 3px">scrollable content inside a fixed-pos item</div>
+ </div>
</body>
</head>