Bug 1471814 - Add a preference for implicit keyframes; r=bz,hiro

This preference controls whether authors are allowed to specify animations
without a 0% or 100% keyframe.

We intend to ship this soon but this preference acts as a safeguard in case we
discover we need to disable it.

This feature is very convenient and commonly used so this patch ensures it is
always enabled for system content.

MozReview-Commit-ID: BHTsuS2xO61

--HG--
rename : dom/animation/test/mozilla/file_disable_animations_api_core.html => dom/animation/test/mozilla/file_disable_animations_api_implicit_keyframes.html
rename : dom/animation/test/mozilla/test_disable_animations_api_core.html => dom/animation/test/mozilla/test_disable_animations_api_implicit_keyframes.html
extra : rebase_source : 04fd93dd26a4765c14b0b22febdb0311b650ea59
This commit is contained in:
Brian Birtles 2018-07-14 09:23:03 +09:00
parent 5d13151cb9
commit fc657410ff
20 changed files with 164 additions and 86 deletions

View File

@ -43,6 +43,7 @@ function enableAnimationFeatures() {
return new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
["dom.animations-api.core.enabled", true],
["dom.animations-api.implicit-keyframes.enabled", true],
["dom.animations-api.timelines.enabled", true],
["layout.css.frames-timing.enabled", true],
]}, resolve);

View File

@ -61,6 +61,7 @@ const enableAnimationFeatures = function() {
return new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
["dom.animations-api.core.enabled", true],
["dom.animations-api.implicit-keyframes.enabled", true],
["dom.animations-api.timelines.enabled", true],
["layout.css.frames-timing.enabled", true],
]}, resolve);

View File

@ -14,6 +14,7 @@
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/ServoCSSParser.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/TimingParams.h"
#include "mozilla/dom/BaseKeyframeTypesBinding.h" // For FastBaseKeyframe etc.
#include "mozilla/dom/Element.h"
@ -22,12 +23,11 @@
#include "mozilla/dom/Nullable.h"
#include "jsapi.h" // For ForOfIterator etc.
#include "nsClassHashtable.h"
#include "nsContentUtils.h" // For GetContextForContent, and
// AnimationsAPICoreEnabled
#include "nsContentUtils.h" // For GetContextForContent
#include "nsCSSPropertyIDSet.h"
#include "nsCSSProps.h"
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
#include "nsDocument.h" // For nsDocument::IsWebAnimationsEnabled
#include "nsDocument.h" // For nsDocument::AreWebAnimationsImplicitKeyframesEnabled
#include "nsIScriptError.h"
#include "nsTArray.h"
#include <algorithm> // For std::stable_sort, std::min
@ -206,7 +206,7 @@ GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx,
ErrorResult& aRv);
static bool
RequiresAdditiveAnimation(const nsTArray<Keyframe>& aKeyframes,
HasImplicitKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
nsIDocument* aDocument);
static void
@ -256,8 +256,8 @@ KeyframeUtils::GetKeyframesFromObject(JSContext* aCx,
return keyframes;
}
if (!nsDocument::IsWebAnimationsEnabled(aCx, nullptr) &&
RequiresAdditiveAnimation(keyframes, aDocument)) {
if (!nsDocument::AreWebAnimationsImplicitKeyframesEnabled(aCx, nullptr) &&
HasImplicitKeyframeValues(keyframes, aDocument)) {
keyframes.Clear();
aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
}
@ -781,7 +781,7 @@ AppendFinalSegment(AnimationProperty* aAnimationProperty,
// Returns a newly created AnimationProperty if one was created to fill-in the
// missing keyframe, nullptr otherwise (if we decided not to fill the keyframe
// becase we don't support additive animation).
// becase we don't support implicit keyframes).
static AnimationProperty*
HandleMissingInitialKeyframe(nsTArray<AnimationProperty>& aResult,
const KeyframeValueEntry& aEntry)
@ -789,10 +789,9 @@ HandleMissingInitialKeyframe(nsTArray<AnimationProperty>& aResult,
MOZ_ASSERT(aEntry.mOffset != 0.0f,
"The offset of the entry should not be 0.0");
// If the preference of the core Web Animations API is not enabled, don't fill
// in the missing keyframe since the missing keyframe requires support for
// additive animation which is guarded by this pref.
if (!nsContentUtils::AnimationsAPICoreEnabled()) {
// If the preference for implicit keyframes is not enabled, don't fill in the
// missing keyframe.
if (!StaticPrefs::dom_animations_api_implicit_keyframes_enabled()) {
return nullptr;
}
@ -812,10 +811,9 @@ HandleMissingFinalKeyframe(nsTArray<AnimationProperty>& aResult,
MOZ_ASSERT(aEntry.mOffset != 1.0f,
"The offset of the entry should not be 1.0");
// If the preference of the core Web Animations API is not enabled, don't fill
// in the missing keyframe since the missing keyframe requires support for
// additive animation which is guarded by this pref.
if (!nsContentUtils::AnimationsAPICoreEnabled()) {
// If the preference for implicit keyframes is not enabled, don't fill
// in the missing keyframe.
if (!StaticPrefs::dom_animations_api_implicit_keyframes_enabled()) {
// If we have already appended a new entry for the property so we have to
// remove it.
if (aCurrentAnimationProperty) {
@ -1055,9 +1053,9 @@ GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx,
}
// If we only have one value, we should animate from the underlying value
// using additive animation--however, we don't support additive animation
// when the core animation API pref is switched off.
if (!nsContentUtils::AnimationsAPICoreEnabled() && count == 1) {
// but not if the pref for supporting implicit keyframes is disabled.
if (!StaticPrefs::dom_animations_api_implicit_keyframes_enabled() &&
count == 1) {
aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
return;
}
@ -1216,17 +1214,15 @@ GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx,
/**
* Returns true if the supplied set of keyframes has keyframe values for
* any property for which it does not also supply a value for the 0% and 100%
* offsets. In this case we are supposed to synthesize an additive zero value
* but since we don't support additive animation yet we can't support this
* case. We try to detect that here so we can throw an exception. The check is
* not entirely accurate but should detect most common cases.
* offsets. The check is not entirely accurate but should detect most common
* cases.
*
* @param aKeyframes The set of keyframes to analyze.
* @param aDocument The document to use when parsing keyframes so we can
* try to detect where we have an invalid value at 0%/100%.
*/
static bool
RequiresAdditiveAnimation(const nsTArray<Keyframe>& aKeyframes,
HasImplicitKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
nsIDocument* aDocument)
{
// We are looking to see if that every property referenced in |aKeyframes|
@ -1237,7 +1233,8 @@ RequiresAdditiveAnimation(const nsTArray<Keyframe>& aKeyframes,
// a document which we might not always have at the point where we want to
// perform this check.
//
// This is only a temporary measure until we implement additive animation.
// This is only a temporary measure until we ship implicit keyframes and
// remove the corresponding pref.
// So as long as this check catches most cases, and we don't do anything
// horrible in one of the cases we can't detect, it should be sufficient.

View File

@ -1587,6 +1587,7 @@ SpecialPowers.pushPrefEnv(
{
set: [
["dom.animations-api.core.enabled", true],
["dom.animations-api.implicit-keyframes.enabled", true],
["dom.animations-api.timelines.enabled", true],
],
},

View File

@ -807,14 +807,21 @@ var gTests = [
];
SpecialPowers.pushPrefEnv(
{ set: [["dom.animations-api.core.enabled", true]] },
{
set: [
["dom.animations-api.core.enabled", true],
["dom.animations-api.implicit-keyframes.enabled", true],
],
},
function() {
gTests.forEach(function(subtest) {
test(function(t) {
var div = addDiv(t);
var animation = div.animate(subtest.frames, 100 * MS_PER_SEC);
assert_properties_equal(animation.effect.getProperties(),
subtest.expected);
assert_properties_equal(
animation.effect.getProperties(),
subtest.expected
);
}, subtest.desc);
});

View File

@ -346,14 +346,21 @@ var gTests = [
setup({explicit_done: true});
SpecialPowers.pushPrefEnv(
{ set: [["dom.animations-api.core.enabled", false]] },
{
set: [
["dom.animations-api.core.enabled", false],
["dom.animations-api.implicit-keyframes.enabled", false],
],
},
function() {
gTests.forEach(function(subtest) {
test(function(t) {
var div = addDiv(t);
var animation = div.animate(subtest.frames, 100 * MS_PER_SEC);
assert_properties_equal(animation.effect.getProperties(),
subtest.expected);
assert_properties_equal(
animation.effect.getProperties(),
subtest.expected
);
}, subtest.desc);
});

View File

@ -15,17 +15,17 @@ 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.implicit-keyframes.enabled,true) load 1322382-1.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1322291-1.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1322291-2.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.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.implicit-keyframes.enabled,true) load 1323119-1.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1324554-1.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1325193-1.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1330190-1.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1330190-2.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1330513-1.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
@ -34,11 +34,11 @@ 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
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1373712-1.html
pref(dom.animations-api.implicit-keyframes.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) pref(dom.animations-api.timelines.enabled,true) load 1411318-1.html
load 1468294-1.html
load 1467277-1.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1401809.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1411318-1.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1468294-1.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1467277-1.html

View File

@ -1,6 +1,7 @@
[DEFAULT]
prefs =
dom.animations-api.core.enabled=true
dom.animations-api.implicit-keyframes.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.
@ -9,6 +10,7 @@ support-files =
mozilla/xhr_doc.html
mozilla/file_deferred_start.html
mozilla/file_disable_animations_api_core.html
mozilla/file_disable_animations_api_implicit_keyframes.html
mozilla/file_disable_animations_api_timelines.html
mozilla/file_discrete_animations.html
mozilla/file_restyles.html
@ -40,6 +42,7 @@ skip-if = (verify && !debug && (os == 'mac'))
[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_implicit_keyframes.html]
[mozilla/test_disable_animations_api_timelines.html]
[mozilla/test_disabled_properties.html]
[mozilla/test_discrete_animations.html]

View File

@ -25,38 +25,6 @@ test(function(t) {
}, 'iterationComposite should not affect at all if the Web Animations API ' +
'is not enabled');
// Tests for cases we don't handle and should throw an exception for in case
// the Web Animation API is disabled.
var gTests = [
{ desc: "single Keyframe with no offset",
keyframes: [{ left: "100px" }] },
{ desc: "multiple Keyframes with missing 0% Keyframe",
keyframes: [{ left: "100px", offset: 0.25 },
{ left: "200px", offset: 0.50 },
{ left: "300px", offset: 1.00 }] },
{ desc: "multiple Keyframes with missing 100% Keyframe",
keyframes: [{ left: "100px", offset: 0.00 },
{ left: "200px", offset: 0.50 },
{ left: "300px", offset: 0.75 }] },
{ desc: "multiple Keyframes with missing properties on first Keyframe",
keyframes: [{ left: "100px", offset: 0.0 },
{ left: "200px", top: "200px", offset: 0.5 },
{ left: "300px", top: "300px", offset: 1.0 }] },
{ desc: "multiple Keyframes with missing properties on last Keyframe",
keyframes: [{ left: "100px", top: "200px", offset: 0.0 },
{ left: "200px", top: "200px", offset: 0.5 },
{ left: "300px", offset: 1.0 }] },
];
gTests.forEach(function(subtest) {
test(function(t) {
var div = addDiv(t);
assert_throws("NotSupportedError", function() {
div.animate(subtest.keyframes, 100 * MS_PER_SEC);
});
}, "Element.animate() throws with " + subtest.desc);
});
done();
</script>
</body>

View File

@ -0,0 +1,48 @@
<!doctype html>
<meta charset=utf-8>
<script src="../testcommon.js"></script>
<body>
<script>
'use strict';
// Tests for cases we should throw an exception for if implicit keyframes are
// disabled.
var gTests = [
{ desc: "single Keyframe value",
keyframes: { left: "100px" } },
{ desc: "single Keyframe with no offset",
keyframes: [{ left: "100px" }] },
{ desc: "single Keyframe with 0% offset",
keyframes: [{ left: "100px", offset: 0 }] },
{ desc: "single Keyframe with 100% offset",
keyframes: [{ left: "100px", offset: 1 }] },
{ desc: "multiple Keyframes with missing 0% Keyframe",
keyframes: [{ left: "100px", offset: 0.25 },
{ left: "200px", offset: 0.50 },
{ left: "300px", offset: 1.00 }] },
{ desc: "multiple Keyframes with missing 100% Keyframe",
keyframes: [{ left: "100px", offset: 0.00 },
{ left: "200px", offset: 0.50 },
{ left: "300px", offset: 0.75 }] },
{ desc: "multiple Keyframes with missing properties on first Keyframe",
keyframes: [{ left: "100px", offset: 0.0 },
{ left: "200px", top: "200px", offset: 0.5 },
{ left: "300px", top: "300px", offset: 1.0 }] },
{ desc: "multiple Keyframes with missing properties on last Keyframe",
keyframes: [{ left: "100px", top: "200px", offset: 0.0 },
{ left: "200px", top: "200px", offset: 0.5 },
{ left: "300px", offset: 1.0 }] },
];
gTests.forEach(function(subtest) {
test(function(t) {
var div = addDiv(t);
assert_throws("NotSupportedError", function() {
div.animate(subtest.keyframes, 100 * MS_PER_SEC);
});
}, "Element.animate() throws with " + subtest.desc);
});
done();
</script>
</body>

View File

@ -0,0 +1,14 @@
<!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.implicit-keyframes.enabled", false]]},
function() {
window.open("file_disable_animations_api_implicit_keyframes.html");
});
</script>

View File

@ -3307,6 +3307,17 @@ nsDocument::IsWebAnimationsEnabled(CallerType aCallerType)
nsContentUtils::AnimationsAPICoreEnabled();
}
bool
nsDocument::AreWebAnimationsImplicitKeyframesEnabled(JSContext* aCx,
JSObject* /*unused*/
)
{
MOZ_ASSERT(NS_IsMainThread());
return nsContentUtils::IsSystemCaller(aCx) ||
StaticPrefs::dom_animations_api_implicit_keyframes_enabled();
}
bool
nsDocument::AreWebAnimationsTimelinesEnabled(JSContext* aCx,
JSObject* /*unused*/

View File

@ -160,6 +160,8 @@ public:
static bool IsWebAnimationsEnabled(JSContext* aCx, JSObject* aObject);
static bool IsWebAnimationsEnabled(mozilla::dom::CallerType aCallerType);
static bool AreWebAnimationsImplicitKeyframesEnabled(JSContext* aCx,
JSObject* aObject);
static bool AreWebAnimationsTimelinesEnabled(JSContext* aCx,
JSObject* aObject);

View File

@ -491,7 +491,7 @@ load 1308848-1.html
load 1308848-2.html
load 1338772-1.html
load 1340571.html
pref(dom.animations-api.core.enabled,true) load 1343139-1.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1343139-1.html
asserts(0-1) load 1343606.html # bug 1343948
load 1343937.html
load 1352380.html

View File

@ -176,7 +176,7 @@ load 1321357-1.html
load 1328535-1.html
load 1331272.html
HTTP load 1333001-1.html
pref(dom.animations-api.core.enabled,true) load 1340344.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1340344.html
load 1342316-1.html
load 1344210.html
load 1356601-1.html
@ -195,11 +195,11 @@ load 1381420-1.html
load 1381682.html
load 1382672.html
load 1382710.html
pref(dom.animations-api.core.enabled,true) load 1383493-1.html
pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.implicit-keyframes.enabled,true) load 1383493-1.html
load 1383001.html
load 1383001-2.html
load 1383319.html
pref(dom.animations-api.core.enabled,true) load 1383589-1.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1383589-1.html
load 1383975.html
load border-image-visited-link.html
load content-only-on-link-before.html
@ -219,14 +219,14 @@ load 1387499.html
load 1388234.html
load 1391577.html
load 1393189.html
load 1393580.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1393580.html
load 1389645.html
load 1390726.html
load 1393791.html
load 1384232.html
load 1395725.html
load 1396041.html
load 1397363-1.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1397363-1.html
load 1397439-1.html
load 1395719.html
load 1397091.html
@ -239,7 +239,7 @@ load 1400325.html
load 1400926.html
load 1400936-1.html
load 1400936-2.html
load 1401256.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1401256.html
load 1401692.html
load 1401706.html
load 1401801.html
@ -275,7 +275,7 @@ load 1413361.html
load 1413670.html
pref(dom.webcomponents.shadowdom.enabled,true) load 1415353.html
load 1418059.html
test-pref(dom.animations-api.core.enabled,true) load 1418867.html
test-pref(dom.animations-api.core.enabled,true) test-pref(dom.animations-api.implicit-keyframes.enabled,true) load 1418867.html
pref(dom.webcomponents.shadowdom.enabled,true) load 1419554.html
load 1426312.html
load 1439793.html

View File

@ -1,6 +1,7 @@
[DEFAULT]
prefs =
dom.animations-api.core.enabled=true
dom.animations-api.implicit-keyframes.enabled=true
dom.animations-api.timelines.enabled=true
support-files =
animation_utils.js

View File

@ -91,6 +91,20 @@ VARCACHE_PREF(
// DOM prefs
//---------------------------------------------------------------------------
// Is support for animations from the Web Animations API without 0%/100%
// keyframes enabled?
#ifdef RELEASE_OR_BETA
# define PREF_VALUE false
#else
# define PREF_VALUE true
#endif
VARCACHE_PREF(
"dom.animations-api.implicit-keyframes.enabled",
dom_animations_api_implicit_keyframes_enabled,
bool, PREF_VALUE
)
#undef PREF_VALUE
// Is support for timelines from the Web Animations API enabled?
#ifdef RELEASE_OR_BETA
# define PREF_VALUE false

View File

@ -1,2 +1,3 @@
prefs: [dom.animations-api.core.enabled:true,
dom.animations-api.implicit-keyframes.enabled:true,
dom.animations-api.timelines.enabled:true]

View File

@ -1,2 +1,3 @@
prefs: [dom.animations-api.core.enabled:true,
dom.animations-api.implicit-keyframes.enabled:true,
dom.animations-api.timelines.enabled:true]

View File

@ -1,3 +1,4 @@
prefs: [dom.animations-api.core.enabled:true,
dom.animations-api.implicit-keyframes.enabled:true,
dom.animations-api.timelines.enabled:true,
layout.css.frames-timing.enabled:true]