Bug 1464568 - Set the shadow base transform value for the case where opacity animations' calculation was skipped. r?kats
And make DOMWindowUtils.getOMTCTransform work for opacity animations' layer.
MozReview-Commit-ID: 7P99WjYqPr0
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3764,19 +3764,23 @@ nsDOMWindowUtils::GetOMTCTransform(Eleme
}
nsIFrame* frame = frameOrError.unwrap();
aResult.Truncate();
if (!frame) {
return NS_OK;
}
- Layer* layer =
- FrameLayerBuilder::GetDedicatedLayer(frame,
- DisplayItemType::TYPE_TRANSFORM);
+ DisplayItemType itemType = DisplayItemType::TYPE_TRANSFORM;
+ if (nsLayoutUtils::HasEffectiveAnimation(frame, eCSSProperty_opacity) &&
+ !frame->IsTransformed()) {
+ itemType = DisplayItemType::TYPE_OPACITY;
+ }
+
+ Layer* layer = FrameLayerBuilder::GetDedicatedLayer(frame, itemType);
if (!layer) {
return NS_OK;
}
ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
if (!forwarder || !forwarder->HasShadowManager()) {
return NS_OK;
}
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1696,17 +1696,18 @@ interface nsIDOMWindowUtils : nsISupport
*/
AString getOMTAStyle(in Element aElement, in AString aProperty,
[optional] in AString aPseudoElement);
/*
* Returns the value of the transform value on the compositor thread.
* Unlike the above getOMTAStyle, the transform value returned by this
* includes both of animating and APZ values.
- * Note: This function doesn't work on WebRender at all.
+ * Note: This function doesn't work on WebRender at all. Also this function
+ * does work only for transform layer and opacity layer with animations.
*/
AString getOMTCTransform(in Element aElement,
[optional] in AString aPseudoElement);
/**
* If aHandlingInput is true, this informs the event state manager that
* we're handling user input. Otherwise, this is a no-op (as by default
* we're not handling user input).
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/helper_bug1464568_opacity.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that opacity animation is correctly placed during asynchronous scrolling</title>
+ <script src="apz_test_utils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <meta name="viewport" content="width=device-width"/>
+ <style>
+ #anim {
+ background: green;
+ width: 100px;
+ height: 100px;
+ animation: anim 100s step-start;
+ }
+ @keyframes anim {
+ from { opacity: 0; }
+ to { opacity: 1; }
+ }
+ </style>
+</head>
+<body>
+ <!--
+ This height should be smaller than window height, otherwise the animation
+ followed by this element will be out of view, thus the animation doesn't run
+ on the compositor.
+ -->
+ <div style="height: 500px"></div>
+ <div id="anim"></div>
+</body>
+<script>
+'use strict';
+
+const utils = SpecialPowers.getDOMWindowUtils(window);
+
+async function test_opacity() {
+ utils.setDisplayPortForElement(0, 0, 300, 1000, document.documentElement, 1);
+ await promiseAllPaintsDone();
+
+ let transform = utils.getOMTCTransform(anim);
+ is(transform, "matrix(1, 0, 0, 1, 0, 0)",
+ "The element shouldn't be moved before scrolling");
+
+ utils.setAsyncScrollOffset(document.documentElement, 0, 300);
+
+ await new Promise(resolve => waitForApzFlushedRepaints(resolve));
+
+ transform = utils.getOMTCTransform(anim);
+ is(transform, "matrix(1, 0, 0, 1, 0, -300)",
+ "Element should have been moved by the offset");
+}
+
+if (utils.layerManagerType == 'WebRender') {
+ ok(true, "This test doesn't need to run on WebRender");
+ subtestDone();
+} else {
+ waitUntilApzStable().then(test_opacity).then(subtestDone);
+}
+
+</script>
+</html>
--- a/gfx/layers/apz/test/mochitest/mochitest.ini
+++ b/gfx/layers/apz/test/mochitest/mochitest.ini
@@ -10,16 +10,17 @@
helper_bug1162771.html
helper_bug1271432.html
helper_bug1280013.html
helper_bug1285070.html
helper_bug1299195.html
helper_bug1346632.html
helper_bug1414336.html
helper_bug1464568_transform.html
+ helper_bug1464568_opacity.html
helper_click.html
helper_div_pan.html
helper_drag_click.html
helper_drag_scroll.html
helper_iframe_pan.html
helper_iframe1.html
helper_iframe2.html
helper_hittest_backface_hidden.html
--- a/gfx/layers/apz/test/mochitest/test_bug1464568.html
+++ b/gfx/layers/apz/test/mochitest/test_bug1464568.html
@@ -7,16 +7,18 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
if (isApzEnabled()) {
SimpleTest.waitForExplicitFinish();
const subtests = [
{ file: 'helper_bug1464568_transform.html',
prefs: [["apz.test.logging_enabled", true]] },
+ { file: 'helper_bug1464568_opacity.html',
+ prefs: [["apz.test.logging_enabled", true]] },
];
// Run the actual test in its own window, because it requires that the
// root APZC be scrollable. Mochitest pages themselves often run
// inside an iframe which means we have no control over the root APZC.
window.onload = () => {
runSubtestsSeriallyInFreshWindows(subtests)
.then(SimpleTest.finish, SimpleTest.finish);
};
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -705,27 +705,35 @@ SampleAnimations(Layer* aLayer,
aStorage,
animation.property(),
animation.data(),
animationValue);
break;
}
case AnimationHelper::SampleResult::Skipped:
switch (animations[0].property()) {
- case eCSSProperty_opacity:
+ case eCSSProperty_opacity: {
MOZ_ASSERT(
layer->AsHostLayer()->GetShadowOpacitySetByAnimation());
#ifdef DEBUG
// Disable this assertion until the root cause is fixed in bug
// 1459775.
// MOZ_ASSERT(FuzzyEqualsMultiplicative(
// Servo_AnimationValue_GetOpacity(animationValue),
// *(aStorage->GetAnimationOpacity(layer->GetCompositorAnimationsId()))));
#endif
+ // Even if opacity animation value has unchanged, we have to set
+ // the shadow base transform value here since the value might
+ // have been changed by APZC.
+ HostLayer* layerCompositor = layer->AsHostLayer();
+ layerCompositor->SetShadowBaseTransform(
+ layer->GetBaseTransform());
+ layerCompositor->SetShadowTransformSetByAnimation(false);
break;
+ }
case eCSSProperty_transform: {
MOZ_ASSERT(
layer->AsHostLayer()->GetShadowTransformSetByAnimation());
MOZ_ASSERT(previousValue);
#ifdef DEBUG
const TransformData& transformData =
animations[0].data().get_TransformData();
Matrix4x4 frameTransform =