Bug 1471814 - Add a preference for Web Animations timelines; r?hiro, r?bz draft
authorBrian Birtles <birtles@gmail.com>
Sat, 14 Jul 2018 09:23:03 +0900
changeset 819082 0406bb33a0f7efd82a6f931ee75d1087e45dc71e
parent 819019 f6df6a982ee9510ca32dd3afa52dfe9f8c3586a3
child 819083 f71b4a1eea91f53a69712d904d1bb641fa297366
push id116436
push userbmo:bbirtles@mozilla.com
push dateTue, 17 Jul 2018 05:43:02 +0000
reviewershiro, bz
bugs1471814
milestone63.0a1
Bug 1471814 - Add a preference for Web Animations timelines; r?hiro, r?bz We don't intend to ship this in the near future until the integration with AnimationWorklet is clear (although we might ship a read-only version). That said, we use this feature extensively internally (e.g. in DevTools etc.) so we enable this feature for system callers. MozReview-Commit-ID: AhB7ZmU1Xzw
browser/components/extensions/test/browser/browser-common.ini
browser/components/resistfingerprinting/test/mochitest/test_animation_api.html
devtools/client/inspector/animation-old/test/head.js
devtools/client/inspector/animation/test/head.js
dom/animation/test/chrome/test_animation_observers_sync.html
dom/animation/test/crashtests/crashtests.list
dom/animation/test/mochitest.ini
dom/animation/test/mozilla/file_disable_animations_api_timelines.html
dom/animation/test/mozilla/test_deferred_start.html
dom/animation/test/mozilla/test_disable_animations_api_timelines.html
dom/animation/test/testcommon.js
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/webidl/Animation.webidl
dom/webidl/AnimationTimeline.webidl
dom/webidl/Document.webidl
dom/webidl/DocumentTimeline.webidl
dom/xslt/tests/mochitest/test_bug1135764.html
layout/style/test/mochitest.ini
modules/libpref/init/StaticPrefList.h
testing/web-platform/meta/css/css-animations/__dir__.ini
testing/web-platform/meta/css/css-transitions/__dir__.ini
testing/web-platform/meta/web-animations/__dir__.ini
testing/web-platform/tests/css/css-animations/support/testcommon.js
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 prefs =
     dom.animations-api.core.enabled=true
+    dom.animations-api.timelines.enabled=true
 support-files =
   head.js
   head_pageAction.js
   head_sessions.js
   head_webNavigation.js
   context.html
   context_frame.html
   ctxmenu-image.png
--- a/browser/components/resistfingerprinting/test/mochitest/test_animation_api.html
+++ b/browser/components/resistfingerprinting/test/mochitest/test_animation_api.html
@@ -33,17 +33,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     expectedPrecision = ep;
     resistFingerprinting = rfp;
     reduceTimerPrecision = rtp;
     prefName = "";
     prefName += resistFingerprinting ? "privacy.resistFingerprinting " : "";
     prefName += reduceTimerPrecision ? "privacy.reduceTimerPrecision " : "";
     SpecialPowers.pushPrefEnv({"set":
       [
-        ["dom.animations-api.core.enabled", true],
+        ["dom.animations-api.timelines.enabled", true],
         ["privacy.resistFingerprinting", resistFingerprinting],
         ["privacy.reduceTimerPrecision", reduceTimerPrecision],
         ["privacy.resistFingerprinting.reduceTimerPrecision.microseconds", expectedPrecision]
       ]
     }, runTest);
 
   }
 
--- a/devtools/client/inspector/animation-old/test/head.js
+++ b/devtools/client/inspector/animation-old/test/head.js
@@ -38,16 +38,17 @@ registerCleanupFunction(() => {
 // Some animation features are not enabled by default in release/beta channels
 // yet including:
 // * parts of the Web Animations API (Bug 1264101), and
 // * the frames() timing function (Bug 1379582).
 function enableAnimationFeatures() {
   return new Promise(resolve => {
     SpecialPowers.pushPrefEnv({"set": [
       ["dom.animations-api.core.enabled", true],
+      ["dom.animations-api.timelines.enabled", true],
       ["layout.css.frames-timing.enabled", true],
     ]}, resolve);
   });
 }
 
 /**
  * Add a new test tab in the browser and load the given url.
  * @param {String} url The url to be loaded in the new tab
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -56,16 +56,17 @@ const closeAnimationInspector = async fu
  * yet including:
  *   * parts of the Web Animations API (Bug 1264101), and
  *   * the frames() timing function (Bug 1379582).
  */
 const enableAnimationFeatures = function() {
   return new Promise(resolve => {
     SpecialPowers.pushPrefEnv({"set": [
       ["dom.animations-api.core.enabled", true],
+      ["dom.animations-api.timelines.enabled", true],
       ["layout.css.frames-timing.enabled", true],
     ]}, resolve);
   });
 };
 
 /**
  * Add a new test tab in the browser and load the given url.
  *
--- a/dom/animation/test/chrome/test_animation_observers_sync.html
+++ b/dom/animation/test/chrome/test_animation_observers_sync.html
@@ -1579,16 +1579,21 @@ function runTest() {
     assert_equals_records(observer.takeRecords(),
       [{ added: [], changed: [], removed: [anim] }],
       "records after animation is finished");
   }, "exclude_animations_targeting_pseudo_elements");
 }
 
 setup({explicit_done: true});
 SpecialPowers.pushPrefEnv(
-  { set: [["dom.animations-api.core.enabled", true]] },
+  {
+    set: [
+      ["dom.animations-api.core.enabled", true],
+      ["dom.animations-api.timelines.enabled", true],
+    ],
+  },
   function() {
     runTest();
     done();
   }
 );
 
 </script>
--- a/dom/animation/test/crashtests/crashtests.list
+++ b/dom/animation/test/crashtests/crashtests.list
@@ -1,44 +1,44 @@
 pref(dom.animations-api.core.enabled,true) load 1239889-1.html
 load 1244595-1.html
-pref(dom.animations-api.core.enabled,true) load 1216842-1.html
-pref(dom.animations-api.core.enabled,true) load 1216842-2.html
-pref(dom.animations-api.core.enabled,true) load 1216842-3.html
-pref(dom.animations-api.core.enabled,true) load 1216842-4.html
-pref(dom.animations-api.core.enabled,true) load 1216842-5.html
-pref(dom.animations-api.core.enabled,true) load 1216842-6.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1216842-1.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1216842-2.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1216842-3.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1216842-4.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1216842-5.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1216842-6.html
 load 1272475-1.html
 load 1272475-2.html
 load 1278485-1.html
-pref(dom.animations-api.core.enabled,true) load 1277272-1.html
+pref(dom.animations-api.timelines.enabled,true) load 1277272-1.html
 load 1282691-1.html
 pref(dom.animations-api.core.enabled,true) load 1291413-1.html
 pref(dom.animations-api.core.enabled,true) load 1291413-2.html
 pref(dom.animations-api.core.enabled,true) load 1304886-1.html
 pref(dom.animations-api.core.enabled,true) load 1309198-1.html
 pref(dom.animations-api.core.enabled,true) load 1322382-1.html
 pref(dom.animations-api.core.enabled,true) load 1322291-1.html
 pref(dom.animations-api.core.enabled,true) load 1322291-2.html
 pref(dom.animations-api.core.enabled,true) load 1323114-1.html
 pref(dom.animations-api.core.enabled,true) load 1323114-2.html
 pref(dom.animations-api.core.enabled,true) load 1323119-1.html
 pref(dom.animations-api.core.enabled,true) load 1324554-1.html
 pref(dom.animations-api.core.enabled,true) load 1325193-1.html
 pref(dom.animations-api.core.enabled,true) load 1330190-1.html
 pref(dom.animations-api.core.enabled,true) load 1330190-2.html
 pref(dom.animations-api.core.enabled,true) load 1330513-1.html
-pref(dom.animations-api.core.enabled,true) load 1333539-1.html
-pref(dom.animations-api.core.enabled,true) load 1333539-2.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1333539-1.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1333539-2.html
 load 1334582-1.html
 load 1334582-2.html
 load 1334583-1.html
 pref(dom.animations-api.core.enabled,true) load 1335998-1.html
 pref(dom.animations-api.core.enabled,true) load 1343589-1.html
 pref(dom.animations-api.core.enabled,true) load 1359658-1.html
 pref(dom.animations-api.core.enabled,true) load 1373712-1.html
 pref(dom.animations-api.core.enabled,true) load 1379606-1.html
 load 1393605-1.html
 load 1400022-1.html
 pref(dom.animations-api.core.enabled,true) load 1401809.html
-pref(dom.animations-api.core.enabled,true) load 1411318-1.html
+pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) load 1411318-1.html
 load 1468294-1.html
 load 1467277-1.html
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -1,18 +1,20 @@
 [DEFAULT]
 prefs =
   dom.animations-api.core.enabled=true
+  dom.animations-api.timelines.enabled=true
 # Support files for chrome tests that we want to load over HTTP need
 # to go in here, not chrome.ini.
 support-files =
   chrome/file_animate_xrays.html
   mozilla/xhr_doc.html
   mozilla/file_deferred_start.html
   mozilla/file_disable_animations_api_core.html
+  mozilla/file_disable_animations_api_timelines.html
   mozilla/file_discrete_animations.html
   mozilla/file_restyles.html
   mozilla/file_transition_finish_on_compositor.html
   ../../../layout/style/test/property_database.js
   testcommon.js
   !/dom/events/test/event_leak_utils.js
 
 [css-transitions/test_animation-cancel.html]
@@ -33,16 +35,17 @@ support-files =
 [document-timeline/test_document-timeline.html]
 skip-if = (verify && !debug && (os == 'mac'))
 [document-timeline/test_request_animation_frame.html]
 [mozilla/test_cascade.html]
 [mozilla/test_cubic_bezier_limits.html]
 [mozilla/test_deferred_start.html]
 skip-if = (toolkit == 'android' && debug) || (os == 'win' && bits == 64) # Bug 1363957
 [mozilla/test_disable_animations_api_core.html]
+[mozilla/test_disable_animations_api_timelines.html]
 [mozilla/test_disabled_properties.html]
 [mozilla/test_discrete_animations.html]
 [mozilla/test_distance_of_basic_shape.html]
 [mozilla/test_distance_of_filter.html]
 [mozilla/test_distance_of_transform.html]
 [mozilla/test_document_timeline_origin_time_range.html]
 [mozilla/test_hide_and_show.html]
 [mozilla/test_moz_prefixed_properties.html]
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/mozilla/file_disable_animations_api_timelines.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="../testcommon.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+  assert_false(
+    window.hasOwnProperty('DocumentTimeline'),
+    'DocumentTimeline should not be exposed on the global'
+  );
+  assert_false(
+    window.hasOwnProperty('AnimationTimeline'),
+    'AnimationTimeline should not be exposed on the global'
+  );
+  assert_false(
+    'timeline' in document,
+    'document should not have a timeline property'
+  );
+
+  const anim = addDiv(t).animate(null);
+  assert_false(
+    'timeline' in anim,
+    'Animation should not have a timeline property'
+  );
+}, 'Timeline-related interfaces and members are disabled');
+
+done();
+</script>
--- a/dom/animation/test/mozilla/test_deferred_start.html
+++ b/dom/animation/test/mozilla/test_deferred_start.html
@@ -2,13 +2,19 @@
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <div id="log"></div>
 <script>
 'use strict';
 setup({explicit_done: true});
 SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
+  {
+    set: [
+      ["dom.animations-api.core.enabled", true],
+      ["dom.animations-api.timelines.enabled", true],
+    ],
+  },
   function() {
     window.open("file_deferred_start.html");
-  });
+  }
+);
 </script>
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/mozilla/test_disable_animations_api_timelines.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+setup({ explicit_done: true });
+SpecialPowers.pushPrefEnv(
+  { set: [['dom.animations-api.timelines.enabled', false]] },
+  function() {
+    window.open('file_disable_animations_api_timelines.html');
+  }
+);
+</script>
--- a/dom/animation/test/testcommon.js
+++ b/dom/animation/test/testcommon.js
@@ -215,17 +215,18 @@ function propertyToIDL(property) {
 function waitForFrame() {
   return new Promise(function(resolve, reject) {
     window.requestAnimationFrame(resolve);
   });
 }
 
 /**
  * Waits for a requestAnimationFrame callback in the next refresh driver tick.
- * Note that 'dom.animations-api.core.enabled' pref should be true to use this
+ * Note that the 'dom.animations-api.core.enabled' and
+ * 'dom.animations-api.timelines.enabled' prefs should be true to use this
  * function.
  */
 function waitForNextFrame() {
   const timeAtStart = document.timeline.currentTime;
   return new Promise(resolve => {
     window.requestAnimationFrame(() => {
       if (timeAtStart === document.timeline.currentTime) {
         window.requestAnimationFrame(resolve);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3302,16 +3302,27 @@ bool
 nsDocument::IsWebAnimationsEnabled(CallerType aCallerType)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   return aCallerType == dom::CallerType::System ||
          nsContentUtils::AnimationsAPICoreEnabled();
 }
 
+bool
+nsDocument::AreWebAnimationsTimelinesEnabled(JSContext* aCx,
+                                             JSObject* /*unused*/
+)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return nsContentUtils::IsSystemCaller(aCx) ||
+         StaticPrefs::dom_animations_api_timelines_enabled();
+}
+
 DocumentTimeline*
 nsIDocument::Timeline()
 {
   if (!mDocumentTimeline) {
     mDocumentTimeline = new DocumentTimeline(this, TimeDuration(0));
   }
 
   return mDocumentTimeline;
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -155,16 +155,18 @@ public:
                                      nsIStreamListener **aDocListener,
                                      bool aReset = true,
                                      nsIContentSink* aContentSink = nullptr) override = 0;
 
   virtual void StopDocumentLoad() override;
 
   static bool IsWebAnimationsEnabled(JSContext* aCx, JSObject* aObject);
   static bool IsWebAnimationsEnabled(mozilla::dom::CallerType aCallerType);
+  static bool AreWebAnimationsTimelinesEnabled(JSContext* aCx,
+                                               JSObject* aObject);
 
   virtual void EndUpdate() override;
   virtual void BeginLoad() override;
   virtual void EndLoad() override;
 
   // nsIRadioGroupContainer
   NS_IMETHOD WalkRadioGroup(const nsAString& aName,
                             nsIRadioVisitor* aVisitor,
--- a/dom/webidl/Animation.webidl
+++ b/dom/webidl/Animation.webidl
@@ -13,17 +13,17 @@
 enum AnimationPlayState { "idle", "running", "paused", "finished" };
 
 [Constructor (optional AnimationEffect? effect = null,
               optional AnimationTimeline? timeline)]
 interface Animation : EventTarget {
   attribute DOMString id;
   [Func="nsDocument::IsWebAnimationsEnabled", Pure]
   attribute AnimationEffect? effect;
-  [Func="nsDocument::IsWebAnimationsEnabled"]
+  [Func="nsDocument::AreWebAnimationsTimelinesEnabled"]
   attribute AnimationTimeline? timeline;
   [BinaryName="startTimeAsDouble"]
   attribute double? startTime;
   [SetterThrows, BinaryName="currentTimeAsDouble"]
   attribute double? currentTime;
 
            attribute double             playbackRate;
   [BinaryName="playStateFromJS"]
--- a/dom/webidl/AnimationTimeline.webidl
+++ b/dom/webidl/AnimationTimeline.webidl
@@ -5,13 +5,13 @@
  *
  * The origin of this IDL file is
  * https://drafts.csswg.org/web-animations/#animationtimeline
  *
  * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-[Func="nsDocument::IsWebAnimationsEnabled"]
+[Func="nsDocument::AreWebAnimationsTimelinesEnabled"]
 interface AnimationTimeline {
   [BinaryName="currentTimeAsDouble"]
   readonly attribute double? currentTime;
 };
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -318,17 +318,17 @@ partial interface Document {
   NodeList  querySelectorAll(DOMString selectors);
 
   //(Not implemented)Element?  find(DOMString selectors, optional (Element or sequence<Node>)? refNodes);
   //(Not implemented)NodeList  findAll(DOMString selectors, optional (Element or sequence<Node>)? refNodes);
 };
 
 // https://drafts.csswg.org/web-animations/#extensions-to-the-document-interface
 partial interface Document {
-  [Func="nsDocument::IsWebAnimationsEnabled"]
+  [Func="nsDocument::AreWebAnimationsTimelinesEnabled"]
   readonly attribute DocumentTimeline timeline;
   [Func="nsDocument::IsWebAnimationsEnabled"]
   sequence<Animation> getAnimations();
 };
 
 // https://svgwg.org/svg2-draft/struct.html#InterfaceDocumentExtensions
 partial interface Document {
   [BinaryName="SVGRootElement"]
--- a/dom/webidl/DocumentTimeline.webidl
+++ b/dom/webidl/DocumentTimeline.webidl
@@ -9,12 +9,12 @@
  * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 dictionary DocumentTimelineOptions {
   DOMHighResTimeStamp originTime = 0;
 };
 
-[Func="nsDocument::IsWebAnimationsEnabled",
+[Func="nsDocument::AreWebAnimationsTimelinesEnabled",
  Constructor (optional DocumentTimelineOptions options)]
 interface DocumentTimeline : AnimationTimeline {
 };
--- a/dom/xslt/tests/mochitest/test_bug1135764.html
+++ b/dom/xslt/tests/mochitest/test_bug1135764.html
@@ -22,26 +22,31 @@ https://bugzilla.mozilla.org/show_bug.cg
       return;
     }
     ok(frames[0].document.timeline.currentTime !== startTimelineValue,
        "The timeline in an XSLT-transformed document should still advance");
     SimpleTest.finish();
   }
   addLoadEvent(function() {
     SpecialPowers.pushPrefEnv(
-      { "set": [[ "dom.animations-api.core.enabled", true]] },
+      {
+        set: [
+          ["dom.animations-api.timelines.enabled", true],
+        ],
+      },
       function() {
         var ifr = document.querySelector("iframe");
         ifr.onload = function() {
           startTimelineValue = frames[0].document.timeline.currentTime;
           frames[0].requestAnimationFrame(waitATick);
-        }
+        };
         ifr.src = "file_bug1135764.xml";
-     })
-  })
+      }
+    );
+  });
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1135764">Mozilla Bug 1135764</a>
 <p id="display">
   <iframe></iframe>
 </p>
 <div id="content" style="display: none">
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 prefs =
   dom.animations-api.core.enabled=true
+  dom.animations-api.timelines.enabled=true
 support-files =
   animation_utils.js
   ccd-quirks.html
   ccd.sjs
   ccd-standards.html
   chrome/bug418986-2.js
   chrome/match.png
   chrome/mismatch.png
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -86,16 +86,29 @@ VARCACHE_PREF(
    accessibility_monoaudio_enable,
   RelaxedAtomicBool, false
 )
 
 //---------------------------------------------------------------------------
 // DOM prefs
 //---------------------------------------------------------------------------
 
+// Is support for timelines from the Web Animations API enabled?
+#ifdef RELEASE_OR_BETA
+# define PREF_VALUE false
+#else
+# define PREF_VALUE true
+#endif
+VARCACHE_PREF(
+  "dom.animations-api.timelines.enabled",
+   dom_animations_api_timelines_enabled,
+  bool, PREF_VALUE
+)
+#undef PREF_VALUE
+
 VARCACHE_PREF(
   "dom.webcomponents.shadowdom.report_usage",
    dom_webcomponents_shadowdom_report_usage,
   bool, false
 )
 
 // Whether we disable triggering mutation events for changes to style
 // attribute via CSSOM.
--- a/testing/web-platform/meta/css/css-animations/__dir__.ini
+++ b/testing/web-platform/meta/css/css-animations/__dir__.ini
@@ -1,1 +1,2 @@
-prefs: [dom.animations-api.core.enabled:true]
+prefs: [dom.animations-api.core.enabled:true,
+        dom.animations-api.timelines.enabled:true]
--- a/testing/web-platform/meta/css/css-transitions/__dir__.ini
+++ b/testing/web-platform/meta/css/css-transitions/__dir__.ini
@@ -1,1 +1,2 @@
-prefs: [dom.animations-api.core.enabled:true]
+prefs: [dom.animations-api.core.enabled:true,
+        dom.animations-api.timelines.enabled:true]
--- a/testing/web-platform/meta/web-animations/__dir__.ini
+++ b/testing/web-platform/meta/web-animations/__dir__.ini
@@ -1,2 +1,3 @@
 prefs: [dom.animations-api.core.enabled:true,
+        dom.animations-api.timelines.enabled:true,
         layout.css.frames-timing.enabled:true]
--- a/testing/web-platform/tests/css/css-animations/support/testcommon.js
+++ b/testing/web-platform/tests/css/css-animations/support/testcommon.js
@@ -98,18 +98,16 @@ function addStyle(t, rules) {
 function waitForFrame() {
   return new Promise(function(resolve, reject) {
     window.requestAnimationFrame(resolve);
   });
 }
 
 /**
  * Waits for a requestAnimationFrame callback in the next refresh driver tick.
- * Note that 'dom.animations-api.core.enabled' pref should be true to use this
- * function.
  */
 function waitForNextFrame() {
   const timeAtStart = document.timeline.currentTime;
   return new Promise(resolve => {
     window.requestAnimationFrame(() => {
       if (timeAtStart === document.timeline.currentTime) {
         window.requestAnimationFrame(resolve);
       } else {