Bug 1247854 - Apply the correct scroll clips to the nsDisplayTransform and nsDisplayPerspective of a scrolled perspective item. r=mattwoodrow a=ritu

I've decided to fix this in a very explicit way. The only "magic" part that's
left is how we decide that the AGR of the perspective item is outside the
scrolled frame (and I'm not sure myself how that works).

I didn't want to change what scroll clips we set on what items, because the
scroll clip really belongs on the perspective item, because that's the item
that needs to be clipped, and it should also be the item that should be
scrolled if it weren't for the fact that APZ wouldn't know that it should
apply the perspective transform before the APZ transform.

MozReview-Commit-ID: BBw8VPohQI4
This commit is contained in:
Markus Stange 2016-02-26 01:29:41 +01:00
parent d34ce692fb
commit f0caad65e4
9 changed files with 242 additions and 0 deletions

View File

@ -1060,6 +1060,7 @@ public:
mContainerLayer(aContainerLayer),
mContainerBounds(aContainerBounds),
mContainerScrollClip(aContainerScrollClip),
mScrollClipForPerspectiveChild(aParameters.mScrollClipForPerspectiveChild),
mParameters(aParameters),
mPaintedLayerDataTree(*this, aBackgroundColor),
mFlattenToSingleLayer(aFlattenToSingleLayer)
@ -1365,6 +1366,7 @@ protected:
ContainerLayer* mContainerLayer;
nsRect mContainerBounds;
const DisplayItemScrollClip* mContainerScrollClip;
const DisplayItemScrollClip* mScrollClipForPerspectiveChild;
DebugOnly<nsRect> mAccumulatedChildBounds;
ContainerLayerParameters mParameters;
/**
@ -3939,6 +3941,22 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
continue;
}
if (mScrollClipForPerspectiveChild) {
// We are the single transform child item of an nsDisplayPerspective.
// Our parent forwarded a scroll clip to us. Pick it up.
// We do this after any clipping has been applied, because this
// forwarded scroll clip is only used for scrolling (in the form of
// APZ frame metrics), not for clipping - the clip still belongs on
// the perspective item.
MOZ_ASSERT(itemType == nsDisplayItem::TYPE_TRANSFORM);
MOZ_ASSERT(!itemScrollClip);
MOZ_ASSERT(!agrScrollClip);
MOZ_ASSERT(DisplayItemScrollClip::IsAncestor(mContainerScrollClip,
mScrollClipForPerspectiveChild));
itemScrollClip = mScrollClipForPerspectiveChild;
agrScrollClip = mScrollClipForPerspectiveChild;
}
// 3D-transformed layers don't necessarily draw in the order in which
// they're added to their parent container layer.
bool mayDrawOutOfOrder = itemType == nsDisplayItem::TYPE_TRANSFORM &&
@ -3992,6 +4010,21 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
mParameters.mBackgroundColor = uniformColor;
mParameters.mScrollClip = agrScrollClip;
mParameters.mScrollClipForPerspectiveChild = nullptr;
if (itemType == nsDisplayItem::TYPE_PERSPECTIVE) {
// Perspective items have a single child item, an nsDisplayTransform.
// If the perspective item is scrolled, but the perspective-inducing
// frame is outside the scroll frame (indicated by this items AGR
// being outside that scroll frame), we have to take special care to
// make APZ scrolling work properly. APZ needs us to put the scroll
// frame's FrameMetrics on our child transform ContainerLayer instead.
// Our agrScrollClip is the scroll clip that's applicable to our
// perspective frame, so it won't be the scroll clip for the scrolled
// frame in the case that we care about, and we'll forward that scroll
// clip to our child.
mParameters.mScrollClipForPerspectiveChild = itemScrollClip;
}
// Just use its layer.
// Set layerContentsVisibleRect.width/height to -1 to indicate we

View File

@ -56,6 +56,7 @@ struct ContainerLayerParameters {
, mLayerContentsVisibleRect(nullptr)
, mBackgroundColor(NS_RGBA(0,0,0,0))
, mScrollClip(nullptr)
, mScrollClipForPerspectiveChild(nullptr)
, mInTransformedSubtree(false)
, mInActiveTransformedSubtree(false)
, mDisableSubpixelAntialiasingInDescendants(false)
@ -68,6 +69,7 @@ struct ContainerLayerParameters {
, mLayerContentsVisibleRect(nullptr)
, mBackgroundColor(NS_RGBA(0,0,0,0))
, mScrollClip(nullptr)
, mScrollClipForPerspectiveChild(nullptr)
, mInTransformedSubtree(false)
, mInActiveTransformedSubtree(false)
, mDisableSubpixelAntialiasingInDescendants(false)
@ -83,6 +85,7 @@ struct ContainerLayerParameters {
, mOffset(aOffset)
, mBackgroundColor(aParent.mBackgroundColor)
, mScrollClip(aParent.mScrollClip)
, mScrollClipForPerspectiveChild(aParent.mScrollClipForPerspectiveChild)
, mInTransformedSubtree(aParent.mInTransformedSubtree)
, mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree)
, mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants)
@ -113,6 +116,10 @@ struct ContainerLayerParameters {
nscolor mBackgroundColor;
const DisplayItemScrollClip* mScrollClip;
// usually nullptr, except when building children of an nsDisplayPerspective
const DisplayItemScrollClip* mScrollClipForPerspectiveChild;
bool mInTransformedSubtree;
bool mInActiveTransformedSubtree;
bool mDisableSubpixelAntialiasingInDescendants;

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>Perspective scrolling</title>
<style>
html {
height: 100%;
overflow: hidden;
}
body {
height: 100%;
perspective: 1px;
overflow: auto;
margin: 0;
}
div {
height: 4000px;
margin: 200px 100px;
border: 10px solid black;
}
</style>
<div></div>
<script>
document.body.scrollTop = 100;
</script>

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en" reftest-async-scroll>
<meta charset="utf-8">
<title>Perspective scrolling</title>
<style>
html {
height: 100%;
overflow: hidden;
}
body {
height: 100%;
perspective: 1px;
overflow: auto;
margin: 0;
}
div {
transform-style: preserve-3d;
height: 4000px;
margin: 200px 100px;
border: 10px solid black;
}
</style>
<body 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">
<div></div>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>Perspective in unscrolled state</title>
<style>
html {
height: 100%;
overflow: hidden;
}
body {
height: 100%;
perspective: 1px;
overflow: auto;
margin: 0;
}
div {
height: 4000px;
margin: 200px 100px 200px;
border: 10px solid black;
}
</style>
<div></div>

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en" reftest-async-scroll>
<meta charset="utf-8">
<title>Perspective in unscrolled state</title>
<style>
html {
height: 100%;
overflow: hidden;
}
body {
margin: 0;
height: 100%;
perspective: 1px;
perspective-origin: top left;
overflow: auto;
}
div {
transform: translateZ(-1px) scale(2);
transform-origin: -100px -200px;
margin: 200px 100px;
height: 4000px;
border: 10px solid black;
}
</style>
<body 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="0"> <!-- no async scrolling -->
<div></div>

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>Perspective in scrolled state</title>
<style>
html {
height: 100%;
overflow: hidden;
}
body {
height: 100%;
perspective: 1px;
overflow: auto;
margin: 0;
}
div {
height: 4000px;
margin: 300px 100px 100px;
border: 10px solid black;
}
</style>
<div></div>
<script>
document.body.scrollTop = 200;
</script>

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en" reftest-async-scroll>
<meta charset="utf-8">
<title>Perspective in scrolled state</title>
<style>
html {
height: 100%;
overflow: hidden;
}
body {
margin: 0;
height: 100%;
perspective: 1px;
perspective-origin: top left;
overflow: auto;
}
div {
transform: translateZ(-1px) scale(2);
transform-origin: -100px -200px;
margin: 200px 100px;
height: 4000px;
border: 10px solid black;
}
</style>
<body 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="200">
<div></div>

View File

@ -36,6 +36,9 @@ fuzzy-if(Android,6,4) == offscreen-clipped-blendmode-1.html offscreen-clipped-bl
fuzzy-if(Android,6,4) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html
fuzzy-if(Android,6,4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item
fuzzy-if(Android,6,4) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html
fuzzy-if(Android,7,4) == perspective-scrolling-1.html perspective-scrolling-1-ref.html
fuzzy-if(Android,7,4) == perspective-scrolling-2.html perspective-scrolling-2-ref.html
fuzzy-if(Android,7,4) == perspective-scrolling-3.html perspective-scrolling-3-ref.html
# for the following tests, we want to disable the low-precision buffer
# as it will expand the displayport beyond what the test specifies in