Bug 1316101 - Avoid excessive clamping in StickyScrollContainer::GetScrollRanges(). r=mstange

Excessive clamping can cause incorrect behaviour in the presence of negative
margins.

MozReview-Commit-ID: AkQEqcQpAxx

--HG--
extra : rebase_source : 33cde31c15608792299a1dbef475e0fe0936270d
This commit is contained in:
Botond Ballo 2016-11-14 19:01:37 -05:00
parent ed42034845
commit cdbef9ee0c
4 changed files with 65 additions and 10 deletions

View File

@ -283,16 +283,7 @@ StickyScrollContainer::GetScrollRanges(nsIFrame* aFrame, nsRect* aOuter,
aOuter->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
aInner->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
// Due to margin collapsing, |firstCont->GetNormalPosition()| can sometimes
// fall outside of |contain|. (This is because GetNormalPosition() returns
// the actual position after margin collapsing, while|contain| is
// calculated based on the frame's GetUsedMargin() which is pre-collapsing.)
// This can cause |aInner|, as computed below, to not be contained inside
// |aOuter|, which confuses the code that consumes these values.
// This is hard to fix properly (TODO), but clamping |normalPosition| to
// |contain| works around it.
const nsPoint normalPosition =
contain.ClampPoint(firstCont->GetNormalPosition());
const nsPoint normalPosition = firstCont->GetNormalPosition();
// Bottom and top
if (stick.YMost() != nscoord_MAX/2) {
@ -315,6 +306,17 @@ StickyScrollContainer::GetScrollRanges(nsIFrame* aFrame, nsRect* aOuter,
aInner->SetRightEdge(normalPosition.x - stick.x);
aOuter->SetRightEdge(contain.XMost() - stick.x);
}
// Make sure |inner| does not extend outside of |outer|. (The consumers of
// the Layers API, to which this information is propagated, expect this
// invariant to hold.) The calculated value of |inner| can sometimes extend
// outside of |outer|, for example due to margin collapsing, since
// GetNormalPosition() returns the actual position after margin collapsing,
// while |contain| is calculated based on the frame's GetUsedMargin() which
// is pre-collapsing.
// Note that this doesn't necessarily solve all problems stemming from
// comparing pre- and post-collapsing margins (TODO: find a proper solution).
*aInner = aInner->Intersect(*aOuter);
}
void

View File

@ -26,6 +26,7 @@ skip-if(!asyncPan) == split-layers-multi-scrolling-1.html split-layers-multi-scr
fuzzy-if(skiaContent,2,240000) fuzzy-if(browserIsRemote&&!skiaContent&&(cocoaWidget||winWidget),1,240000) skip-if(!asyncPan) == split-opacity-layers-1.html split-opacity-layers-1-ref.html
skip-if(!asyncPan) == sticky-pos-scrollable-1.html sticky-pos-scrollable-1-ref.html
skip-if(!asyncPan) == sticky-pos-scrollable-2.html sticky-pos-scrollable-2-ref.html
skip-if(!asyncPan) == sticky-pos-scrollable-3.html sticky-pos-scrollable-3-ref.html
skip-if(!asyncPan) == fixed-pos-scrollable-1.html fixed-pos-scrollable-1-ref.html
skip-if(!asyncPan) == culling-1.html culling-1-ref.html
skip-if(!asyncPan) == position-fixed-iframe-1.html position-fixed-iframe-1-ref.html

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<style>
#header {
position: fixed;
top: 0;
}
#header > div {
border: solid blue 2px;
height: 100px;
width: 100px;
}
</style>
<div id="section">
<div id="header">
<div></div>
</div>
</div>
</html>

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html reftest-async-scroll
reftest-displayport-x="0" reftest-displayport-y="0"
reftest-displayport-w="800" reftest-displayport-h="2000"
reftest-async-scroll-x="0" reftest-async-scroll-y="100">
<style>
html {
overflow: hidden;
}
#section {
padding-top: 1px;
}
#header {
position: sticky;
top: 0;
}
#header > div {
margin-top: -50px;
border: solid blue 2px;
height: 100px;
width: 100px;
}
#spacer {
height: 1500px;
}
</style>
<div id="section">
<div id="header">
<div></div>
</div>
<div id="spacer"></div>
</div>
</html>