Bug 1196114 - Part 2: Add AnimationPropertyStatus interface and KeyframeEffectReadOnly.runningStatus(). r?birtles,smaug
MozReview-Commit-ID: CPz3DtWxKll
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -1872,16 +1872,40 @@ KeyframeEffectReadOnly::GetFrames(JSCont
previousEntry = entry;
entry = &entries[i];
} while (entry->SameKeyframe(*previousEntry));
aResult.AppendElement(keyframe);
}
}
+
+void
+KeyframeEffectReadOnly::GetPropertyState(
+ nsTArray<AnimationPropertyState>& aStates) const
+{
+ for (const AnimationProperty& property : mProperties) {
+ // Bug 1252730: We should also expose this winsInCascade as well.
+ if (!property.mWinsInCascade) {
+ continue;
+ }
+
+ AnimationPropertyState state;
+ state.mProperty.Construct(
+ NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(property.mProperty)));
+ state.mRunningOnCompositor.Construct(property.mIsRunningOnCompositor);
+
+ if (property.mPerformanceWarning.isSome()) {
+ state.mWarning.Construct(property.mPerformanceWarning.value());
+ }
+
+ aStates.AppendElement(state);
+ }
+}
+
/* static */ const TimeDuration
KeyframeEffectReadOnly::OverflowRegionRefreshInterval()
{
// The amount of time we can wait between updating throttled animations
// on the main thread that influence the overflow region.
static const TimeDuration kOverflowRegionRefreshInterval =
TimeDuration::FromMilliseconds(200);
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -38,16 +38,17 @@ class AnimValuesStyleRule;
enum class CSSPseudoElementType : uint8_t;
namespace dom {
class ElementOrCSSPseudoElement;
class OwningElementOrCSSPseudoElement;
class UnrestrictedDoubleOrKeyframeEffectOptions;
enum class IterationCompositeOperation : uint32_t;
enum class CompositeOperation : uint32_t;
+struct AnimationPropertyState;
}
/**
* Stores the results of calculating the timing properties of an animation
* at a given sample time.
*/
struct ComputedTiming
{
@@ -302,16 +303,18 @@ public:
// contained in |aSetProperties|.
// Any updated properties are added to |aSetProperties|.
void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties);
// Returns true if at least one property is being animated on compositor.
bool IsRunningOnCompositor() const;
void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
+ void GetPropertyState(nsTArray<AnimationPropertyState>& aStates) const;
+
// Returns true if this effect, applied to |aFrame|, contains
// properties that mean we shouldn't run *any* compositor animations on this
// element.
//
// For example, if we have an animation of geometric properties like 'left'
// and 'top' on an element, we force all 'transform' and 'opacity' animations
// running at the same time on the same element to run on the main thread.
//
--- a/dom/animation/test/chrome.ini
+++ b/dom/animation/test/chrome.ini
@@ -2,11 +2,12 @@
support-files =
testcommon.js
../../imptests/testharness.js
../../imptests/testharnessreport.js
[chrome/test_animate_xrays.html]
# file_animate_xrays.html needs to go in mochitest.ini since it is served
# over HTTP
[chrome/test_animation_observers.html]
+[chrome/test_animation_property_state.html]
[chrome/test_restyles.html]
[chrome/test_running_on_compositor.html]
skip-if = buildapp == 'b2g'
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/chrome/test_animation_property_state.html
@@ -0,0 +1,127 @@
+<!doctype html>
+<head>
+<meta charset=utf-8>
+<title>Bug 1196114 - Animation property which indicates
+ running on the compositor or not</title>
+<script type="application/javascript" src="../testharness.js"></script>
+<script type="application/javascript" src="../testharnessreport.js"></script>
+<script type="application/javascript" src="../testcommon.js"></script>
+<style>
+div {
+ /* Element needs geometry to be eligible for layerization */
+ width: 100px;
+ height: 100px;
+ background-color: white;
+}
+</style>
+</head>
+<body>
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1196114"
+ target="_blank">Mozilla Bug 1196114</a>
+<div id="log"></div>
+<script>
+'use strict';
+
+function compare_property_state(a, b) {
+ if (a.property > b.property) {
+ return -1;
+ } else if (a.property < b.property) {
+ return 1;
+ }
+ if (a.runningOnCompositor != b.runningOnCompositor) {
+ return a.runningOnCompositor ? 1 : -1;
+ }
+ return a.warning > b.warning ? -1 : 1;
+}
+
+function assert_animation_property_state_equals(actual, expected) {
+ assert_equals(actual.length, expected.length);
+
+ var sortedActual = actual.sort(compare_property_state);
+ var sortedExpected = expected.sort(compare_property_state);
+
+ for (var i = 0; i < sortedActual.length; i++) {
+ assert_equals(sortedActual[i].property,
+ sortedExpected[i].property,
+ 'CSS property name should match');
+ assert_equals(sortedActual[i].runningOnCompositor,
+ sortedExpected[i].runningOnCompositor,
+ 'runningOnCompositor property should match');
+ }
+}
+
+var gAnimationsTests = [
+ {
+ desc: 'animations on compositor',
+ frames: {
+ opacity: [0, 1]
+ },
+ expected: [
+ {
+ property: 'opacity',
+ runningOnCompositor: true
+ }
+ ]
+ },
+ {
+ desc: 'animations on main thread',
+ frames: {
+ backgroundColor: ['white', 'red']
+ },
+ expected: [
+ {
+ property: 'background-color',
+ runningOnCompositor: false
+ }
+ ]
+ },
+ {
+ desc: 'animations on both threads',
+ frames: {
+ backgroundColor: ['white', 'red'],
+ transform: ['translate(0px)', 'translate(100px)']
+ },
+ expected: [
+ {
+ property: 'background-color',
+ runningOnCompositor: false
+ },
+ {
+ property: 'transform',
+ runningOnCompositor: true
+ }
+ ]
+ },
+ {
+ desc: 'two animation properties on compositor thread',
+ frames: {
+ opacity: [0, 1],
+ transform: ['translate(0px)', 'translate(100px)']
+ },
+ expected: [
+ {
+ property: 'opacity',
+ runningOnCompositor: true
+ },
+ {
+ property: 'transform',
+ runningOnCompositor: true
+ }
+ ]
+ }
+];
+
+gAnimationsTests.forEach(function(subtest) {
+ promise_test(function(t) {
+ var div = addDiv(t);
+ var animation = div.animate(subtest.frames, 100000);
+ return animation.ready.then(t.step_func(function() {
+ assert_animation_property_state_equals(
+ animation.effect.getPropertyState(),
+ subtest.expected);
+ }));
+ }, subtest.desc);
+});
+
+</script>
+</body>
--- a/dom/webidl/KeyframeEffect.webidl
+++ b/dom/webidl/KeyframeEffect.webidl
@@ -40,16 +40,26 @@ interface KeyframeEffectReadOnly : Anima
// Not yet implemented:
// KeyframeEffect clone();
// We use object instead of ComputedKeyframe so that we can put the
// property-value pairs on the object.
[Throws] sequence<object> getFrames();
};
+// Non-standard extensions
+dictionary AnimationPropertyState {
+ DOMString property;
+ boolean runningOnCompositor;
+ DOMString? warning;
+};
+
+partial interface KeyframeEffectReadOnly {
+ [ChromeOnly] sequence<AnimationPropertyState> getPropertyState();
+};
[Func="nsDocument::IsWebAnimationsEnabled",
Constructor ((Element or CSSPseudoElement)? target,
object? frames,
optional (unrestricted double or KeyframeEffectOptions) options)]
interface KeyframeEffect : KeyframeEffectReadOnly {
// Bug 1067769 - Allow setting KeyframeEffect.target
// inherit attribute Animatable? target;