author | Daisuke Akatsuka <daisuke@mozilla-japan.org> |
Fri, 18 Mar 2016 16:28:22 +0900 | |
changeset 289744 | a0c0ea60eaefc2f2907527e77fd71fe8b84bb7eb |
parent 289743 | b798c62e43652ecc167d39c020f430f302716a2e |
child 289745 | b60ea1ba5f7ffb512b4b8f78da6e2cc27d8aedca |
push id | 30108 |
push user | cbook@mozilla.com |
push date | Tue, 22 Mar 2016 11:14:31 +0000 |
treeherder | mozilla-central@ea6298e1b4f7 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | birtles |
bugs | 1253470 |
milestone | 48.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/animation/AnimationUtils.cpp +++ b/dom/animation/AnimationUtils.cpp @@ -1,25 +1,22 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AnimationUtils.h" -#include "nsCSSParser.h" // For nsCSSParser #include "nsDebug.h" #include "nsIAtom.h" #include "nsIContent.h" #include "nsIDocument.h" #include "nsGlobalWindow.h" #include "nsString.h" -#include "mozilla/Attributes.h" -#include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction #include "xpcpublic.h" // For xpc::NativeGlobal namespace mozilla { /* static */ void AnimationUtils::LogAsyncAnimationFailure(nsCString& aMessage, const nsIContent* aContent) { @@ -34,74 +31,16 @@ AnimationUtils::LogAsyncAnimationFailure aMessage.Append('\''); } aMessage.Append(']'); } aMessage.Append('\n'); printf_stderr("%s", aMessage.get()); } -/* static */ Maybe<ComputedTimingFunction> -AnimationUtils::ParseEasing(const nsAString& aEasing, - nsIDocument* aDocument) -{ - MOZ_ASSERT(aDocument); - - nsCSSValue value; - nsCSSParser parser; - parser.ParseLonghandProperty(eCSSProperty_animation_timing_function, - aEasing, - aDocument->GetDocumentURI(), - aDocument->GetDocumentURI(), - aDocument->NodePrincipal(), - value); - - switch (value.GetUnit()) { - case eCSSUnit_List: { - const nsCSSValueList* list = value.GetListValue(); - if (list->mNext) { - // don't support a list of timing functions - break; - } - switch (list->mValue.GetUnit()) { - case eCSSUnit_Enumerated: - // Return Nothing() if "linear" is passed in. - if (list->mValue.GetIntValue() == - NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR) { - return Nothing(); - } - MOZ_FALLTHROUGH; - case eCSSUnit_Cubic_Bezier: - case eCSSUnit_Steps: { - nsTimingFunction timingFunction; - nsRuleNode::ComputeTimingFunction(list->mValue, timingFunction); - ComputedTimingFunction computedTimingFunction; - computedTimingFunction.Init(timingFunction); - return Some(computedTimingFunction); - } - default: - MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function list " - "item unit"); - break; - } - break; - } - case eCSSUnit_Null: - case eCSSUnit_Inherit: - case eCSSUnit_Initial: - case eCSSUnit_Unset: - case eCSSUnit_TokenStream: - break; - default: - MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function unit"); - break; - } - return Nothing(); -} - /* static */ nsIDocument* AnimationUtils::GetCurrentRealmDocument(JSContext* aCx) { nsGlobalWindow* win = xpc::CurrentWindowOrNull(aCx); if (!win) { return nullptr; } return win->GetDoc();
--- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -1287,20 +1287,23 @@ GenerateValueEntries(Element* aTarget, nsTArray<KeyframeValueEntry>& aResult, ErrorResult& aRv) { nsCSSPropertySet properties; // All properties encountered. nsCSSPropertySet propertiesWithFromValue; // Those with a defined 0% value. nsCSSPropertySet propertiesWithToValue; // Those with a defined 100% value. for (OffsetIndexedKeyframe& keyframe : aKeyframes) { + Maybe<ComputedTimingFunction> easing = + TimingParams::ParseEasing(keyframe.mKeyframeDict.mEasing, + aTarget->OwnerDoc(), aRv); + if (aRv.Failed()) { + return; + } float offset = float(keyframe.mKeyframeDict.mOffset.Value()); - Maybe<ComputedTimingFunction> easing = - AnimationUtils::ParseEasing(keyframe.mKeyframeDict.mEasing, - aTarget->OwnerDoc()); // We ignore keyframe.mKeyframeDict.mComposite since we don't support // composite modes on keyframes yet. // keyframe.mPropertyValuePairs is currently sorted by CSS property IDL // name, since that was the order we read the properties from the JS // object. Re-sort the list so that longhand properties appear before // shorthands, and with shorthands all appearing in increasing order of // number of components. For two longhand properties, or two shorthands @@ -1555,17 +1558,17 @@ BuildAnimationPropertyListFromPropertyIn binding_detail::FastPropertyIndexedKeyframes keyframes; if (!keyframes.Init(aCx, aValue, "PropertyIndexedKeyframes argument", false)) { aRv.Throw(NS_ERROR_FAILURE); return; } Maybe<ComputedTimingFunction> easing = - AnimationUtils::ParseEasing(keyframes.mEasing, aTarget->OwnerDoc()); + TimingParams::ParseEasing(keyframes.mEasing, aTarget->OwnerDoc(), aRv); // We ignore easing.mComposite since we don't support composite modes on // keyframes yet. // Get all the property--value-list pairs off the object. JS::Rooted<JSObject*> object(aCx, &aValue.toObject()); nsTArray<PropertyValuesPair> propertyValuesPairs; if (!GetPropertyValuesPairs(aCx, object, ListAllowance::eAllow,
--- a/dom/animation/TimingParams.cpp +++ b/dom/animation/TimingParams.cpp @@ -1,16 +1,17 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/TimingParams.h" +#include "nsCSSParser.h" // For nsCSSParser #include "nsIDocument.h" namespace mozilla { template <class OptionsType> static const dom::AnimationEffectTimingProperties& GetTimingProperties(const OptionsType& aOptions); @@ -59,25 +60,30 @@ TimingParamsFromOptionsUnion(const Optio TimingParams::ValidateIterationStart(timing.mIterationStart, aRv); if (aRv.Failed()) { return result; } TimingParams::ValidateIterations(timing.mIterations, aRv); if (aRv.Failed()) { return result; } + Maybe<ComputedTimingFunction> easing = + TimingParams::ParseEasing(timing.mEasing, aDocument, aRv); + if (aRv.Failed()) { + return result; + } result.mDuration = duration; result.mDelay = TimeDuration::FromMilliseconds(timing.mDelay); result.mEndDelay = TimeDuration::FromMilliseconds(timing.mEndDelay); result.mIterations = timing.mIterations; result.mIterationStart = timing.mIterationStart; result.mDirection = timing.mDirection; result.mFill = timing.mFill; - result.mFunction = AnimationUtils::ParseEasing(timing.mEasing, aDocument); + result.mFunction = easing; } return result; } /* static */ TimingParams TimingParams::FromOptionsUnion( const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions, nsIDocument* aDocument, @@ -90,16 +96,76 @@ TimingParams::FromOptionsUnion( TimingParams::FromOptionsUnion( const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions, nsIDocument* aDocument, ErrorResult& aRv) { return TimingParamsFromOptionsUnion(aOptions, aDocument, aRv); } +/* static */ Maybe<ComputedTimingFunction> +TimingParams::ParseEasing(const nsAString& aEasing, + nsIDocument* aDocument, + ErrorResult& aRv) +{ + MOZ_ASSERT(aDocument); + + nsCSSValue value; + nsCSSParser parser; + parser.ParseLonghandProperty(eCSSProperty_animation_timing_function, + aEasing, + aDocument->GetDocumentURI(), + aDocument->GetDocumentURI(), + aDocument->NodePrincipal(), + value); + + switch (value.GetUnit()) { + case eCSSUnit_List: { + const nsCSSValueList* list = value.GetListValue(); + if (list->mNext) { + // don't support a list of timing functions + break; + } + switch (list->mValue.GetUnit()) { + case eCSSUnit_Enumerated: + // Return Nothing() if "linear" is passed in. + if (list->mValue.GetIntValue() == + NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR) { + return Nothing(); + } + MOZ_FALLTHROUGH; + case eCSSUnit_Cubic_Bezier: + case eCSSUnit_Steps: { + nsTimingFunction timingFunction; + nsRuleNode::ComputeTimingFunction(list->mValue, timingFunction); + ComputedTimingFunction computedTimingFunction; + computedTimingFunction.Init(timingFunction); + return Some(computedTimingFunction); + } + default: + MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function list " + "item unit"); + break; + } + break; + } + case eCSSUnit_Inherit: + case eCSSUnit_Initial: + case eCSSUnit_Unset: + case eCSSUnit_TokenStream: + case eCSSUnit_Null: + break; + default: + MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function unit"); + break; + } + aRv.ThrowTypeError<dom::MSG_INVALID_EASING_ERROR>(); + return Nothing(); +} + bool TimingParams::operator==(const TimingParams& aOther) const { return mDuration == aOther.mDuration && mDelay == aOther.mDelay && mIterations == aOther.mIterations && mIterationStart == aOther.mIterationStart && mDirection == aOther.mDirection &&
--- a/dom/animation/TimingParams.h +++ b/dom/animation/TimingParams.h @@ -2,16 +2,17 @@ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_TimingParams_h #define mozilla_TimingParams_h +#include "nsStringFwd.h" #include "mozilla/dom/Nullable.h" #include "mozilla/dom/UnionTypes.h" // For OwningUnrestrictedDoubleOrString #include "mozilla/ComputedTimingFunction.h" #include "mozilla/Maybe.h" #include "mozilla/TimeStamp.h" // for TimeDuration // X11 has a #define for None #ifdef None @@ -75,16 +76,20 @@ struct TimingParams static void ValidateIterations(double aIterations, ErrorResult& aRv) { if (IsNaN(aIterations) || aIterations < 0) { aRv.ThrowTypeError<dom::MSG_ENFORCE_RANGE_OUT_OF_RANGE>( NS_LITERAL_STRING("iterations")); } } + static Maybe<ComputedTimingFunction> ParseEasing(const nsAString& aEasing, + nsIDocument* aDocument, + ErrorResult& aRv); + // mDuration.isNothing() represents the "auto" value Maybe<StickyTimeDuration> mDuration; TimeDuration mDelay; // Initializes to zero TimeDuration mEndDelay; double mIterations = 1.0; // Can be NaN, negative, +/-Infinity double mIterationStart = 0.0; dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal; dom::FillMode mFill = dom::FillMode::Auto;
--- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -87,9 +87,10 @@ MSG_DEF(MSG_PROMISE_CAPABILITY_HAS_SOMET MSG_DEF(MSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.") MSG_DEF(MSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.") MSG_DEF(MSG_PROMISE_ARG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable") MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise") MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.") MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.") MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer") MSG_DEF(MSG_CACHE_ADD_FAILED_RESPONSE, 3, JSEXN_TYPEERR, "Cache got {0} response with bad status {1} while trying to add request {2}") -MSG_DEF(MSG_INVALID_DURATION_ERROR, 0, JSEXN_TYPEERR, "Invalid duration.") \ No newline at end of file +MSG_DEF(MSG_INVALID_DURATION_ERROR, 0, JSEXN_TYPEERR, "Invalid duration.") +MSG_DEF(MSG_INVALID_EASING_ERROR, 0, JSEXN_TYPEERR, "Invalid easing.") \ No newline at end of file
--- a/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html +++ b/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html @@ -57,23 +57,18 @@ test(function(t) { gEmptyKeyframeListTests.forEach(function(frames) { assert_equals(new KeyframeEffectReadOnly(target, frames).getFrames().length, 0, "number of frames for " + JSON.stringify(frames)); }); }, "a KeyframeEffectReadOnly can be constructed with no frames"); // [specified easing value, expected easing value] var gEasingValueTests = [ - ["unrecognised", "linear"], ["linear", "linear"], ["ease-in-out", "ease-in-out"], - ["initial", "linear"], - ["inherit", "linear"], - ["var(--x)", "linear"], - ["ease-in-out, ease-out", "linear"], ["Ease\\2d in-out", "ease-in-out"], ["ease /**/", "ease"], ]; test(function(t) { gEasingValueTests.forEach(function(subtest) { var easing = subtest[0]; var expected = subtest[1]; @@ -444,16 +439,39 @@ gKeyframeSequenceTests.forEach(function( test(function(t) { var effect = new KeyframeEffectReadOnly(target, subtest.input); var secondEffect = new KeyframeEffectReadOnly(target, effect.getFrames()); assert_frame_lists_equal(secondEffect.getFrames(), effect.getFrames()); }, "a KeyframeEffectReadOnly constructed with " + subtest.desc + " roundtrips"); }); +var gInvalidEasingInKeyframeSequenceTests = [ + { desc: "a blank easing", + input: [{ easing: "" }] }, + { desc: "an unrecognized easing", + input: [{ easing: "unrecognized" }] }, + { desc: "an 'initial' easing", + input: [{ easing: "initial" }] }, + { desc: "an 'inherit' easing", + input: [{ easing: "inherit" }] }, + { desc: "a variable easing", + input: [{ easing: "var(--x)" }] }, + { desc: "a multi-value easing", + input: [{ easing: "ease-in-out, ease-out" }] } +]; + +gInvalidEasingInKeyframeSequenceTests.forEach(function(subtest) { + test(function(t) { + assert_throws(new TypeError, function() { + new KeyframeEffectReadOnly(target, subtest.input); + }); + }, "Invalid easing [" + subtest.desc + "] in KeyframeSequence " + + "should be thrown"); +}); test(function(t) { var effect = new KeyframeEffectReadOnly(target, {left: ["10px", "20px"]}); var timing = effect.timing; assert_equals(timing.delay, 0, "default delay"); assert_equals(timing.endDelay, 0, "default endDelay"); @@ -562,24 +580,42 @@ var gInvalidKeyframeEffectOptionTests = { desc: "a negative Infinity iterations", input: { iterations: -Infinity}, expected: { name: "TypeError" } }, { desc: "a NaN iterations", input: { iterations: NaN }, expected: { name: "TypeError" } }, { desc: "a negative iterations", input: { iterations: -1 }, + expected: { name: "TypeError" } }, + { desc: "a blank easing", + input: { easing: "" }, + expected: { name: "TypeError" } }, + { desc: "an unrecognized easing", + input: { easing: "unrecognised" }, + expected: { name: "TypeError" } }, + { desc: "an 'initial' easing", + input: { easing: "initial" }, + expected: { name: "TypeError" } }, + { desc: "an 'inherit' easing", + input: { easing: "inherit" }, + expected: { name: "TypeError" } }, + { desc: "a variable easing", + input: { easing: "var(--x)" }, + expected: { name: "TypeError" } }, + { desc: "a multi-value easing", + input: { easing: "ease-in-out, ease-out" }, expected: { name: "TypeError" } } ]; gInvalidKeyframeEffectOptionTests.forEach(function(stest) { test(function(t) { assert_throws(stest.expected, function() { new KeyframeEffectReadOnly(target, - {left: ["10px", "20px"]}, + { left: ["10px", "20px"] }, stest.input); }); }, "Invalid KeyframeEffectReadOnly option by " + stest.desc); }); test(function(t) { var effect = new KeyframeEffect(target, { left: ["10px", "20px"] });