From 98491d06875a295d8f402bbf1a3082cd7e5f262b Mon Sep 17 00:00:00 2001 From: roytam1 Date: Thu, 9 Nov 2023 09:50:40 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 382721 - Part 1: Fix spacing of simple 2px dotted border without radius. r=jrmuizel (8e83589f45) - Bug 382721 - Part 2: Split constants for border rendering to BorderConsts.h. r=jrmuizel (88ae5aee7f) - Bug 1237805 part 1 - [css-grid] Remove all empty 'auto-fit' tracks, not just those at the end. r=dholbert (1c0530b87b) - Bug 1237805 part 2 - [css-grid] 'auto-fit' reftest removing empty start/middle tracks. (3bfc688e2b) - Bug 1239036 - [css-grid] Deal with implicit tracks when computing grid-template-{columns,rows}. r=dholbert (cf36d9193a) - Bug 1239036 - [css-grid] Tests. (4aaec0499f) - Bug 1238294 part 1 - [css-grid] Make GridLineEdge() a method on the Tracks class rather than a static function (idempotent change). r=dholbert (ab81994ec6) - Bug 1238294 part 2 - [css-grid] Treat any gaps at the grid edges as "line thickness" so they behave the same as gaps between tracks for positioning areas. r=dholbert (fafdc1ceef) - Bug 1230695 - [css-grid] More abs.pos. grid alignment reftests. (330770cf1a) - Bug 1238294 part 3 - [css-grid] Add/tweak reftests for new behavior of gaps at the grid edges. (58ff8670a1) - Bug 1240795 - [css-grid] Refactor GetComputedTemplateColumns/Rows to return a self-contained value. r=dholbert (9c5e68418f) - Bug 1229739 - Use the color of shadow if available for drawing emphasis marks in shadow. r=jfkthame (c19c3deb1c) - Bug 1191597 part 3 - Convert fullscreen-api-keys to a browser chrome test. r=smaug (ad740d4c4c) - Bug 1174575 - Part 1: Define CSSPseudoElement interface. r=birtles, r=smaug (1a304d59c4) - Bug 1214536 - Part 1: Use unrestricted double for iterations. r=birtles (0dbb02e423) - Bug 1214536 - Part 2: Replace mIterationCount in layers::Animation. r=birtles (8a573046f5) - Bug 1214536 - Part 3: Store the original value of fill. r=birtles (df548c244a) - Bug 1214536 - Part 4: Use OwingUnrestrictedDoubleOrString for duration. r=birtles (567cfd1555) - Bug 1214536 - Part 5: Add AnimationEffectTimingReadOnly interface. r=birtles, r=smaug (47138ec7f0) - Bug 1214536 - Part 6: Revise AnimationTiming::operator==. r=birtles (616fc2c711) - Bug 1214536 - Part 7: Rename AnimationTiming as TimingParams. r=birtles, r=smaug (d7de0ec72b) - Bug 1214536 - Part 8: Add an operator=() for TimingParams. r=birtles (bfe22c6501) - Bug 1215406 - Part 6: Test. r=birtles (3f16796304) - Bug 1214536 - Part 9: Test. r=birtles (526419cc1d) - Bug 1147673 - Unadjust clip before intersecting it with the scroll clip. r=botond (85cd06d2d5) - Bug 1147673 - Determine more accurately whether an async transform affects a layer's clip rect. r=kats (8ce7d1e887) - Bug 1096773 part 1 - Make the frames argument to the KeyframeEffectReadOnly constructor NOT optional; r=bz (6e63b08671) - Bug 1096773 part 2 - Add a KeyframeEffectReadOnly constructor that takes a TimingParams argument; r=boris (24971306e6) - Bug 1096773 part 3 - Implement Animatable.animate(); r=bz (9d95ea800e) - Bug 1096773 part 4 - Add tests for Animatable.animate(); r=bz (03b866b2d8) - Bug 1179627 - Part 1: Implement Animation.id. r=smaug, r=birtles (51bbed6e9d) - Bug 1096774 - Part 1: Implement Animation Constructor. r=birtles, r=smaug (e09d7fbd7c) - Bug 1179627 - Part 2: Add animation.id for CSS animations test files. r=bbirtles, r=hiikezoe (329ea31f33) - Bug 1096774 - Part 2: Fix crash if animation has no timeline. r=birtles (d989b44866) - Bug 1096774 - Part 3: Tests for Animation Contructor. r=birtles (23786774bc) - Bug 1240265 - Annotate intentional switch fallthroughs in dom/. r=mrbkap (ffd9da3d5f) - Bug 1227458. Make setAttributeNode be an alias for setAttributeNodeNS and setNamedItem on the attribute map be an alias for setNamedItemNS. r=smaug (f804d28b93) - Bug 1226091 - Use MayHaveAnimations in Element::UnbindFromTree; r=smaug (1ec85f75b3) --- dom/animation/Animation.cpp | 37 +++- dom/animation/Animation.h | 10 +- dom/animation/AnimationEffectReadonly.h | 7 +- .../AnimationEffectTimingReadOnly.cpp | 88 ++++++++ dom/animation/AnimationEffectTimingReadOnly.h | 103 +++++++++ dom/animation/CSSPseudoElement.cpp | 44 ++++ dom/animation/CSSPseudoElement.h | 56 +++++ dom/animation/ComputedTimingFunction.h | 2 +- dom/animation/KeyframeEffect.cpp | 188 ++++++---------- dom/animation/KeyframeEffect.h | 100 +++++---- dom/animation/PendingAnimationTracker.cpp | 1 + dom/animation/moz.build | 4 + dom/animation/test/chrome.ini | 3 + .../test/chrome/file_animate_xrays.html | 19 ++ .../test/chrome/test_animate_xrays.html | 31 +++ .../test/chrome/test_animation_observers.html | 21 ++ .../css-animations/file_animation-id.html | 27 +++ .../css-animations/test_animation-id.html | 15 ++ dom/animation/test/mochitest.ini | 5 + dom/base/Element.cpp | 65 +++++- dom/base/Element.h | 7 + dom/base/nsDOMAttributeMap.cpp | 34 ++- dom/base/nsDOMAttributeMap.h | 17 +- dom/base/nsDocument.cpp | 3 + dom/base/nsGlobalWindow.cpp | 1 + dom/base/nsXMLContentSerializer.cpp | 2 +- dom/base/test/test_bug1075702.html | 2 +- dom/cache/AutoUtils.cpp | 1 + dom/html/HTMLInputElement.cpp | 3 +- dom/html/test/browser.ini | 2 + dom/html/test/browser_fullscreen-api-keys.js | 164 ++++++++++++++ dom/html/test/file_fullscreen-plugins.html | 8 + dom/html/test/mochitest.ini | 1 - dom/html/test/test_fullscreen-api.html | 1 - dom/storage/DOMStorageDBThread.cpp | 2 +- .../mochitest/general/test_interfaces.html | 4 + dom/webidl/Animatable.webidl | 8 + dom/webidl/Animation.webidl | 5 +- dom/webidl/AnimationEffectReadonly.webidl | 5 +- .../AnimationEffectTimingReadOnly.webidl | 23 ++ dom/webidl/CSSPseudoElement.webidl | 25 +++ dom/webidl/KeyframeEffect.webidl | 16 +- dom/webidl/NamedNodeMap.webidl | 2 +- dom/webidl/moz.build | 2 + dom/workers/ScriptLoader.cpp | 2 +- .../composite/AsyncCompositionManager.cpp | 76 ++++--- .../composite/AsyncCompositionManager.h | 7 +- gfx/layers/ipc/LayersMessages.ipdlh | 2 +- layout/base/BorderConsts.h | 25 +++ layout/base/nsCSSRendering.cpp | 1 + layout/base/nsCSSRenderingBorders.cpp | 3 +- layout/base/nsCSSRenderingBorders.h | 16 -- layout/base/nsDisplayList.cpp | 8 +- layout/generic/nsGridContainerFrame.cpp | 155 +++++++------ layout/generic/nsGridContainerFrame.h | 82 +++---- layout/generic/nsTextFrame.cpp | 8 +- layout/generic/nsTextFrame.h | 1 + .../css-grid/grid-abspos-items-013-ref.html | 133 ++++++++++++ .../css-grid/grid-abspos-items-013.html | 120 +++++++++++ ...rid-placement-abspos-implicit-001-ref.html | 6 +- .../grid-placement-abspos-implicit-001.html | 3 +- .../grid-repeat-auto-fill-fit-005-ref.html | 7 +- .../grid-repeat-auto-fill-fit-007-ref.html | 177 +++++++++++++++ .../grid-repeat-auto-fill-fit-007.html | 195 +++++++++++++++++ .../grid-repeat-auto-fill-fit-008-ref.html | 194 +++++++++++++++++ .../grid-repeat-auto-fill-fit-008.html | 204 ++++++++++++++++++ layout/reftests/css-grid/reftest.list | 3 + layout/style/nsAnimationManager.cpp | 23 +- layout/style/nsAnimationManager.h | 4 +- layout/style/nsComputedDOMStyle.cpp | 143 +++++++----- layout/style/nsComputedDOMStyle.h | 3 +- layout/style/nsTransitionManager.cpp | 15 +- layout/style/nsTransitionManager.h | 4 +- .../style/test/test_grid_computed_values.html | 23 ++ modules/libpref/init/all.js | 3 + testing/web-platform/meta/MANIFEST.json | 12 ++ .../animatable/animate.html.ini | 8 + .../animation/constructor.html.ini | 13 ++ .../web-animations/animatable/animate.html | 126 +++++++++++ .../web-animations/animation/constructor.html | 60 ++++++ .../keyframe-effect/constructor.html | 180 ++++++++++++++++ .../keyframe-effect/getComputedTiming.html | 195 +++++++++++++++++ .../tests/web-animations/testcommon.js | 2 +- 83 files changed, 2917 insertions(+), 489 deletions(-) create mode 100644 dom/animation/AnimationEffectTimingReadOnly.cpp create mode 100644 dom/animation/AnimationEffectTimingReadOnly.h create mode 100644 dom/animation/CSSPseudoElement.cpp create mode 100644 dom/animation/CSSPseudoElement.h create mode 100644 dom/animation/test/chrome/file_animate_xrays.html create mode 100644 dom/animation/test/chrome/test_animate_xrays.html create mode 100644 dom/animation/test/css-animations/file_animation-id.html create mode 100644 dom/animation/test/css-animations/test_animation-id.html create mode 100644 dom/html/test/browser_fullscreen-api-keys.js create mode 100644 dom/webidl/AnimationEffectTimingReadOnly.webidl create mode 100644 dom/webidl/CSSPseudoElement.webidl create mode 100644 layout/base/BorderConsts.h create mode 100644 layout/reftests/css-grid/grid-abspos-items-013-ref.html create mode 100644 layout/reftests/css-grid/grid-abspos-items-013.html create mode 100644 layout/reftests/css-grid/grid-repeat-auto-fill-fit-007-ref.html create mode 100644 layout/reftests/css-grid/grid-repeat-auto-fill-fit-007.html create mode 100644 layout/reftests/css-grid/grid-repeat-auto-fill-fit-008-ref.html create mode 100644 layout/reftests/css-grid/grid-repeat-auto-fill-fit-008.html create mode 100644 testing/web-platform/meta/web-animations/animatable/animate.html.ini create mode 100644 testing/web-platform/meta/web-animations/animation/constructor.html.ini create mode 100644 testing/web-platform/tests/web-animations/animatable/animate.html create mode 100644 testing/web-platform/tests/web-animations/animation/constructor.html create mode 100644 testing/web-platform/tests/web-animations/keyframe-effect/getComputedTiming.html diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index d13ff1c3b3..a693117ccf 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -81,6 +81,41 @@ namespace { // Animation interface: // // --------------------------------------------------------------------------- +/* static */ already_AddRefed +Animation::Constructor(const GlobalObject& aGlobal, + KeyframeEffectReadOnly* aEffect, + AnimationTimeline* aTimeline, + ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + RefPtr animation = new Animation(global); + + if (!aTimeline) { + // Bug 1096776: We do not support null timeline yet. + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + if (!aEffect) { + // Bug 1049975: We do not support null effect yet. + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + animation->SetTimeline(aTimeline); + animation->SetEffect(aEffect); + + return animation.forget(); +} + +void +Animation::SetId(const nsAString& aId) +{ + if (mId == aId) { + return; + } + mId = aId; + nsNodeUtils::AnimationChanged(this); +} void Animation::SetEffect(KeyframeEffectReadOnly* aEffect) @@ -1132,7 +1167,7 @@ Animation::EffectEnd() const return StickyTimeDuration(0); } - return mEffect->Timing().mDelay + return mEffect->SpecifiedTiming().mDelay + mEffect->GetComputedTiming().mActiveDuration; } diff --git a/dom/animation/Animation.h b/dom/animation/Animation.h index e1f4995d41..1852bc8c4e 100644 --- a/dom/animation/Animation.h +++ b/dom/animation/Animation.h @@ -90,7 +90,13 @@ public: }; // Animation interface methods - + static already_AddRefed + Constructor(const GlobalObject& aGlobal, + KeyframeEffectReadOnly* aEffect, + AnimationTimeline* aTimeline, + ErrorResult& aRv); + void GetId(nsAString& aResult) const { aResult = mId; } + void SetId(const nsAString& aId); KeyframeEffectReadOnly* GetEffect() const { return mEffect; } void SetEffect(KeyframeEffectReadOnly* aEffect); AnimationTimeline* GetTimeline() const { return mTimeline; } @@ -422,6 +428,8 @@ protected: // in that case mFinished is immediately reset to represent a new current // finished promise. bool mFinishedIsResolved; + + nsString mId; }; } // namespace dom diff --git a/dom/animation/AnimationEffectReadonly.h b/dom/animation/AnimationEffectReadonly.h index 7c38ca8bc3..016e4d979e 100644 --- a/dom/animation/AnimationEffectReadonly.h +++ b/dom/animation/AnimationEffectReadonly.h @@ -14,6 +14,7 @@ namespace mozilla { namespace dom { +class AnimationEffectTimingReadOnly; struct ComputedTimingProperties; class AnimationEffectReadOnly : public nsISupports, @@ -30,9 +31,9 @@ public: nsISupports* GetParentObject() const { return mParent; } - virtual void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const - { - } + virtual already_AddRefed Timing() const = 0; + + virtual void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const = 0; protected: virtual ~AnimationEffectReadOnly() = default; diff --git a/dom/animation/AnimationEffectTimingReadOnly.cpp b/dom/animation/AnimationEffectTimingReadOnly.cpp new file mode 100644 index 0000000000..ff574b3bdd --- /dev/null +++ b/dom/animation/AnimationEffectTimingReadOnly.cpp @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/dom/AnimationEffectTimingReadOnly.h" + +#include "mozilla/dom/AnimatableBinding.h" +#include "mozilla/dom/AnimationEffectTimingReadOnlyBinding.h" +#include "mozilla/dom/KeyframeEffectBinding.h" + +namespace mozilla { + +TimingParams::TimingParams(const dom::AnimationEffectTimingProperties& aRhs) + : mDuration(aRhs.mDuration) + , mDelay(TimeDuration::FromMilliseconds(aRhs.mDelay)) + , mIterations(aRhs.mIterations) + , mDirection(aRhs.mDirection) + , mFill(aRhs.mFill) +{ +} + +TimingParams::TimingParams(double aDuration) +{ + mDuration.SetAsUnrestrictedDouble() = aDuration; +} + +/* static */ TimingParams +TimingParams::FromOptionsUnion( + const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions) +{ + if (aOptions.IsUnrestrictedDouble()) { + return TimingParams(aOptions.GetAsUnrestrictedDouble()); + } else { + MOZ_ASSERT(aOptions.IsKeyframeEffectOptions()); + return TimingParams(aOptions.GetAsKeyframeEffectOptions()); + } +} + +/* static */ TimingParams +TimingParams::FromOptionsUnion( + const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions) +{ + if (aOptions.IsUnrestrictedDouble()) { + return TimingParams(aOptions.GetAsUnrestrictedDouble()); + } else { + MOZ_ASSERT(aOptions.IsKeyframeAnimationOptions()); + return TimingParams(aOptions.GetAsKeyframeAnimationOptions()); + } +} + +bool +TimingParams::operator==(const TimingParams& aOther) const +{ + bool durationEqual; + if (mDuration.IsUnrestrictedDouble()) { + durationEqual = aOther.mDuration.IsUnrestrictedDouble() && + (mDuration.GetAsUnrestrictedDouble() == + aOther.mDuration.GetAsUnrestrictedDouble()); + } else { + // We consider all string values and uninitialized values as meaning "auto". + // Since mDuration is either a string or uninitialized, we consider it equal + // if aOther.mDuration is also either a string or uninitialized. + durationEqual = !aOther.mDuration.IsUnrestrictedDouble(); + } + return durationEqual && + mDelay == aOther.mDelay && + mIterations == aOther.mIterations && + mDirection == aOther.mDirection && + mFill == aOther.mFill; +} + +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffectTimingReadOnly, mParent) + +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnimationEffectTimingReadOnly, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationEffectTimingReadOnly, Release) + +JSObject* +AnimationEffectTimingReadOnly::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return AnimationEffectTimingReadOnlyBinding::Wrap(aCx, this, aGivenProto); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/animation/AnimationEffectTimingReadOnly.h b/dom/animation/AnimationEffectTimingReadOnly.h new file mode 100644 index 0000000000..03873d5300 --- /dev/null +++ b/dom/animation/AnimationEffectTimingReadOnly.h @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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_dom_AnimationEffectTimingReadOnly_h +#define mozilla_dom_AnimationEffectTimingReadOnly_h + +#include "js/TypeDecls.h" +#include "mozilla/Attributes.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/UnionTypes.h" +#include "nsCycleCollectionParticipant.h" +#include "nsWrapperCache.h" + +// X11 has a #define for None +#ifdef None +#undef None +#endif +#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for FillMode + // and PlaybackDirection + +namespace mozilla { + +namespace dom { +struct AnimationEffectTimingProperties; +class UnrestrictedDoubleOrKeyframeEffectOptions; +class UnrestrictedDoubleOrKeyframeAnimationOptions; +} + +struct TimingParams +{ + TimingParams() = default; + explicit TimingParams( + const dom::AnimationEffectTimingProperties& aTimingProperties); + explicit TimingParams(double aDuration); + + static TimingParams FromOptionsUnion( + const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions); + static TimingParams FromOptionsUnion( + const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions); + + // The unitialized state of mDuration represents "auto". + // Bug 1237173: We will replace this with Maybe. + dom::OwningUnrestrictedDoubleOrString mDuration; + TimeDuration mDelay; // Initializes to zero + double mIterations = 1.0; // Can be NaN, negative, +/-Infinity + dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal; + dom::FillMode mFill = dom::FillMode::Auto; + + bool operator==(const TimingParams& aOther) const; + bool operator!=(const TimingParams& aOther) const + { + return !(*this == aOther); + } +}; + + +namespace dom { + +class AnimationEffectTimingReadOnly : public nsWrapperCache +{ +public: + AnimationEffectTimingReadOnly() = default; + explicit AnimationEffectTimingReadOnly(const TimingParams& aTiming) + : mTiming(aTiming) { } + + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationEffectTimingReadOnly) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AnimationEffectTimingReadOnly) + +protected: + virtual ~AnimationEffectTimingReadOnly() = default; + +public: + nsISupports* GetParentObject() const { return mParent; } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + double Delay() const { return mTiming.mDelay.ToMilliseconds(); } + double EndDelay() const { return 0.0; } + FillMode Fill() const { return mTiming.mFill; } + double IterationStart() const { return 0.0; } + double Iterations() const { return mTiming.mIterations; } + void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const + { + aRetVal = mTiming.mDuration; + } + PlaybackDirection Direction() const { return mTiming.mDirection; } + void GetEasing(nsString& aRetVal) const { aRetVal.AssignLiteral("linear"); } + + const TimingParams& AsTimingParams() const { return mTiming; } + void SetTimingParams(const TimingParams& aTiming) { mTiming = aTiming; } + +protected: + nsCOMPtr mParent; + TimingParams mTiming; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_AnimationEffectTimingReadOnly_h diff --git a/dom/animation/CSSPseudoElement.cpp b/dom/animation/CSSPseudoElement.cpp new file mode 100644 index 0000000000..5d67987497 --- /dev/null +++ b/dom/animation/CSSPseudoElement.cpp @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/dom/CSSPseudoElement.h" +#include "mozilla/dom/CSSPseudoElementBinding.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(CSSPseudoElement) + +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CSSPseudoElement, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CSSPseudoElement, Release) + +JSObject* +CSSPseudoElement::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return CSSPseudoElementBinding::Wrap(aCx, this, aGivenProto); +} + +void +CSSPseudoElement::GetAnimations(nsTArray>& aRetVal) +{ + // Bug 1234403: Implement this API. + NS_NOTREACHED("CSSPseudoElement::GetAnimations() is not implemented yet."); +} + +already_AddRefed +CSSPseudoElement::Animate( + JSContext* aContext, + JS::Handle aFrames, + const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions, + ErrorResult& aError) +{ + // Bug 1241784: Implement this API. + NS_NOTREACHED("CSSPseudoElement::Animate() is not implemented yet."); + return nullptr; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/animation/CSSPseudoElement.h b/dom/animation/CSSPseudoElement.h new file mode 100644 index 0000000000..992c4a8b24 --- /dev/null +++ b/dom/animation/CSSPseudoElement.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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_dom_CSSPseudoElement_h +#define mozilla_dom_CSSPseudoElement_h + +#include "js/TypeDecls.h" +#include "mozilla/Attributes.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { + +class Animation; +class Element; +class UnrestrictedDoubleOrKeyframeAnimationOptions; + +class CSSPseudoElement final : public nsWrapperCache +{ +public: + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CSSPseudoElement) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CSSPseudoElement) + +protected: + virtual ~CSSPseudoElement() = default; + +public: + ParentObject GetParentObject() const + { + // This will be implemented in later patch. + return ParentObject(nullptr, nullptr); + } + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + void GetType(nsString& aRetVal) const { } + already_AddRefed ParentElement() const { return nullptr; } + + void GetAnimations(nsTArray>& aRetVal); + already_AddRefed + Animate(JSContext* aContext, + JS::Handle aFrames, + const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions, + ErrorResult& aError); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_CSSPseudoElement_h diff --git a/dom/animation/ComputedTimingFunction.h b/dom/animation/ComputedTimingFunction.h index fa1b335b3a..6831d65b59 100644 --- a/dom/animation/ComputedTimingFunction.h +++ b/dom/animation/ComputedTimingFunction.h @@ -50,4 +50,4 @@ private: } // namespace mozilla -#endif // mozilla_dom_AnimationEffectReadOnly_h +#endif // mozilla_ComputedTimingFunction_h diff --git a/dom/animation/KeyframeEffect.cpp b/dom/animation/KeyframeEffect.cpp index 843f1ae53f..f6de95ce43 100644 --- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -6,7 +6,6 @@ #include "mozilla/dom/KeyframeEffect.h" -#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" #include "mozilla/dom/KeyframeEffectBinding.h" #include "mozilla/dom/PropertyIndexedKeyframesBinding.h" #include "mozilla/AnimationUtils.h" @@ -24,32 +23,19 @@ namespace mozilla { -bool -AnimationTiming::FillsForwards() const -{ - return mFillMode == dom::FillMode::Both || - mFillMode == dom::FillMode::Forwards; -} - -bool -AnimationTiming::FillsBackwards() const -{ - return mFillMode == dom::FillMode::Both || - mFillMode == dom::FillMode::Backwards; -} - // Helper functions for generating a ComputedTimingProperties dictionary static void GetComputedTimingDictionary(const ComputedTiming& aComputedTiming, const Nullable& aLocalTime, - const AnimationTiming& aTiming, + const TimingParams& aTiming, dom::ComputedTimingProperties& aRetVal) { // AnimationEffectTimingProperties aRetVal.mDelay = aTiming.mDelay.ToMilliseconds(); - aRetVal.mFill = aTiming.mFillMode; - aRetVal.mIterations = aTiming.mIterationCount; - aRetVal.mDuration.SetAsUnrestrictedDouble() = aTiming.mIterationDuration.ToMilliseconds(); + aRetVal.mFill = aComputedTiming.mFill; + aRetVal.mIterations = aComputedTiming.mIterations; + aRetVal.mDuration.SetAsUnrestrictedDouble() = + aComputedTiming.mDuration.ToMilliseconds(); aRetVal.mDirection = aTiming.mDirection; // ComputedTimingProperties @@ -89,14 +75,15 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly( nsIDocument* aDocument, Element* aTarget, nsCSSPseudoElements::Type aPseudoType, - const AnimationTiming& aTiming) + const TimingParams& aTiming) : AnimationEffectReadOnly(aDocument) , mTarget(aTarget) - , mTiming(aTiming) , mPseudoType(aPseudoType) , mInEffectOnLastAnimationTimingUpdate(false) { MOZ_ASSERT(aTarget, "null animation target is not yet supported"); + + mTiming = new AnimationEffectTimingReadOnly(aTiming); } JSObject* @@ -118,13 +105,20 @@ KeyframeEffectReadOnly::Composite() const return CompositeOperation::Replace; } -void -KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming) +already_AddRefed +KeyframeEffectReadOnly::Timing() const { - if (mTiming == aTiming) { + RefPtr temp(mTiming); + return temp.forget(); +} + +void +KeyframeEffectReadOnly::SetSpecifiedTiming(const TimingParams& aTiming) +{ + if (mTiming->AsTimingParams() == aTiming) { return; } - mTiming = aTiming; + mTiming->SetTimingParams(aTiming); if (mAnimation) { mAnimation->NotifyEffectTimingUpdated(); } @@ -205,31 +199,36 @@ void KeyframeEffectReadOnly::GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const { const Nullable currentTime = GetLocalTime(); - GetComputedTimingDictionary(GetComputedTimingAt(currentTime, mTiming), + GetComputedTimingDictionary(GetComputedTimingAt(currentTime, + SpecifiedTiming()), currentTime, - mTiming, + SpecifiedTiming(), aRetVal); } ComputedTiming KeyframeEffectReadOnly::GetComputedTimingAt( const Nullable& aLocalTime, - const AnimationTiming& aTiming) + const TimingParams& aTiming) { - const TimeDuration zeroDuration; - - // Currently we expect negative durations to be picked up during CSS - // parsing but when we start receiving timing parameters from other sources - // we will need to clamp negative durations here. - // For now, if we're hitting this it probably means we're overflowing - // integer arithmetic in mozilla::TimeStamp. - MOZ_ASSERT(aTiming.mIterationDuration >= zeroDuration, - "Expecting iteration duration >= 0"); + const StickyTimeDuration zeroDuration; // Always return the same object to benefit from return-value optimization. ComputedTiming result; - result.mActiveDuration = ActiveDuration(aTiming); + if (aTiming.mDuration.IsUnrestrictedDouble()) { + double durationMs = aTiming.mDuration.GetAsUnrestrictedDouble(); + if (!IsNaN(durationMs) && durationMs >= 0.0f) { + result.mDuration = StickyTimeDuration::FromMilliseconds(durationMs); + } + } + result.mIterations = IsNaN(aTiming.mIterations) || aTiming.mIterations < 0.0f ? + 1.0f : + aTiming.mIterations; + result.mActiveDuration = ActiveDuration(result.mDuration, result.mIterations); + result.mFill = aTiming.mFill == dom::FillMode::Auto ? + dom::FillMode::None : + aTiming.mFill; // The default constructor for ComputedTiming sets all other members to // values consistent with an animation that has not been sampled. @@ -247,7 +246,7 @@ KeyframeEffectReadOnly::GetComputedTimingAt( StickyTimeDuration activeTime; if (localTime >= aTiming.mDelay + result.mActiveDuration) { result.mPhase = ComputedTiming::AnimationPhase::After; - if (!aTiming.FillsForwards()) { + if (!result.FillsForwards()) { // The animation isn't active or filling at this time. result.mProgress.SetNull(); return result; @@ -255,12 +254,11 @@ KeyframeEffectReadOnly::GetComputedTimingAt( activeTime = result.mActiveDuration; // Note that infinity == floor(infinity) so this will also be true when we // have finished an infinitely repeating animation of zero duration. - isEndOfFinalIteration = - aTiming.mIterationCount != 0.0 && - aTiming.mIterationCount == floor(aTiming.mIterationCount); + isEndOfFinalIteration = result.mIterations != 0.0 && + result.mIterations == floor(result.mIterations); } else if (localTime < aTiming.mDelay) { result.mPhase = ComputedTiming::AnimationPhase::Before; - if (!aTiming.FillsBackwards()) { + if (!result.FillsBackwards()) { // The animation isn't active or filling at this time. result.mProgress.SetNull(); return result; @@ -275,19 +273,19 @@ KeyframeEffectReadOnly::GetComputedTimingAt( // Get the position within the current iteration. StickyTimeDuration iterationTime; - if (aTiming.mIterationDuration != zeroDuration) { + if (result.mDuration != zeroDuration) { iterationTime = isEndOfFinalIteration - ? StickyTimeDuration(aTiming.mIterationDuration) - : activeTime % aTiming.mIterationDuration; + ? result.mDuration + : activeTime % result.mDuration; } /* else, iterationTime is zero */ // Determine the 0-based index of the current iteration. if (isEndOfFinalIteration) { result.mCurrentIteration = - aTiming.mIterationCount == NS_IEEEPositiveInfinity() + IsInfinite(result.mIterations) // Positive Infinity? ? UINT64_MAX // In GetComputedTimingDictionary(), we will convert this // into Infinity. - : static_cast(aTiming.mIterationCount) - 1; + : static_cast(result.mIterations) - 1; } else if (activeTime == zeroDuration) { // If the active time is zero we're either in the first iteration // (including filling backwards) or we have finished an animation with an @@ -295,11 +293,11 @@ KeyframeEffectReadOnly::GetComputedTimingAt( // the exact end of an iteration since we deal with that above). result.mCurrentIteration = result.mPhase == ComputedTiming::AnimationPhase::After - ? static_cast(aTiming.mIterationCount) // floor + ? static_cast(result.mIterations) // floor : 0; } else { result.mCurrentIteration = - static_cast(activeTime / aTiming.mIterationDuration); // floor + static_cast(activeTime / result.mDuration); // floor } // Normalize the iteration time into a fraction of the iteration duration. @@ -308,15 +306,15 @@ KeyframeEffectReadOnly::GetComputedTimingAt( } else if (result.mPhase == ComputedTiming::AnimationPhase::After) { double progress = isEndOfFinalIteration ? 1.0 - : fmod(aTiming.mIterationCount, 1.0f); + : fmod(result.mIterations, 1.0); result.mProgress.SetValue(progress); } else { // We are in the active phase so the iteration duration can't be zero. - MOZ_ASSERT(aTiming.mIterationDuration != zeroDuration, + MOZ_ASSERT(result.mDuration != zeroDuration, "In the active phase of a zero-duration animation?"); - double progress = aTiming.mIterationDuration == TimeDuration::Forever() + double progress = result.mDuration == StickyTimeDuration::Forever() ? 0.0 - : iterationTime / aTiming.mIterationDuration; + : iterationTime / result.mDuration; result.mProgress.SetValue(progress); } @@ -345,19 +343,19 @@ KeyframeEffectReadOnly::GetComputedTimingAt( } StickyTimeDuration -KeyframeEffectReadOnly::ActiveDuration(const AnimationTiming& aTiming) +KeyframeEffectReadOnly::ActiveDuration(const StickyTimeDuration& aIterationDuration, + double aIterationCount) { - if (aTiming.mIterationCount == mozilla::PositiveInfinity()) { + if (IsInfinite(aIterationCount)) { // An animation that repeats forever has an infinite active duration // unless its iteration duration is zero, in which case it has a zero // active duration. const StickyTimeDuration zeroDuration; - return aTiming.mIterationDuration == zeroDuration - ? zeroDuration - : StickyTimeDuration::Forever(); + return aIterationDuration == zeroDuration ? + zeroDuration : + StickyTimeDuration::Forever(); } - return StickyTimeDuration( - aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount)); + return aIterationDuration.MultDouble(aIterationCount); } // https://w3c.github.io/web-animations/#in-play @@ -641,55 +639,6 @@ DumpAnimationProperties(nsTArray& aAnimationProperties) } #endif -// Extract an iteration duration from an UnrestrictedDoubleOrXXX object. -template -static TimeDuration -GetIterationDuration(const T& aDuration) { - // Always return the same object to benefit from return-value optimization. - TimeDuration result; - if (aDuration.IsUnrestrictedDouble()) { - double durationMs = aDuration.GetAsUnrestrictedDouble(); - if (!IsNaN(durationMs) && durationMs >= 0.0f) { - result = TimeDuration::FromMilliseconds(durationMs); - } - } - // else, aDuration should be zero - return result; -} - -/* static */ AnimationTiming -KeyframeEffectReadOnly::ConvertKeyframeEffectOptions( - const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions) -{ - AnimationTiming animationTiming; - - if (aOptions.IsKeyframeEffectOptions()) { - const KeyframeEffectOptions& opt = aOptions.GetAsKeyframeEffectOptions(); - - animationTiming.mIterationDuration = GetIterationDuration(opt.mDuration); - animationTiming.mDelay = TimeDuration::FromMilliseconds(opt.mDelay); - // FIXME: Covert mIterationCount to a valid value. - // Bug 1214536 should revise this and keep the original value, so - // AnimationTimingEffectReadOnly can get the original iterations. - animationTiming.mIterationCount = (IsNaN(opt.mIterations) || - opt.mIterations < 0.0f) ? - 1.0f : - opt.mIterations; - animationTiming.mDirection = opt.mDirection; - // FIXME: We should store original value. - animationTiming.mFillMode = (opt.mFill == FillMode::Auto) ? - FillMode::None : - opt.mFill; - } else { - animationTiming.mIterationDuration = GetIterationDuration(aOptions); - animationTiming.mDelay = TimeDuration(0); - animationTiming.mIterationCount = 1.0f; - animationTiming.mDirection = PlaybackDirection::Normal; - animationTiming.mFillMode = FillMode::None; - } - return animationTiming; -} - /** * A property and StyleAnimationValue pair. */ @@ -1666,7 +1615,7 @@ BuildAnimationPropertyListFromPropertyIndexedKeyframes( KeyframeEffectReadOnly::BuildAnimationPropertyList( JSContext* aCx, Element* aTarget, - const Optional>& aFrames, + JS::Handle aFrames, InfallibleTArray& aResult, ErrorResult& aRv) { @@ -1682,17 +1631,16 @@ KeyframeEffectReadOnly::BuildAnimationPropertyList( // we can look at the open-ended set of properties on a // PropertyIndexedKeyframes or Keyframe. - if (!aFrames.WasPassed() || !aFrames.Value().get()) { - // The argument was omitted, or was explicitly null. In both cases, - // the default dictionary value for PropertyIndexedKeyframes would - // result in no keyframes. + if (!aFrames) { + // The argument was explicitly null. In this case, the default dictionary + // value for PropertyIndexedKeyframes would result in no keyframes. return; } // At this point we know we have an object. We try to convert it to a // sequence first, and if that fails due to not being iterable, // we try to convert it to PropertyIndexedKeyframes. - JS::Rooted objectValue(aCx, JS::ObjectValue(*aFrames.Value())); + JS::Rooted objectValue(aCx, JS::ObjectValue(*aFrames)); JS::ForOfIterator iter(aCx); if (!iter.init(objectValue, JS::ForOfIterator::AllowNonIterable)) { aRv.Throw(NS_ERROR_FAILURE); @@ -1713,8 +1661,8 @@ KeyframeEffectReadOnly::BuildAnimationPropertyList( KeyframeEffectReadOnly::Constructor( const GlobalObject& aGlobal, Element* aTarget, - const Optional>& aFrames, - const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions, + JS::Handle aFrames, + const TimingParams& aTiming, ErrorResult& aRv) { if (!aTarget) { @@ -1723,8 +1671,6 @@ KeyframeEffectReadOnly::Constructor( return nullptr; } - AnimationTiming timing = ConvertKeyframeEffectOptions(aOptions); - InfallibleTArray animationProperties; BuildAnimationPropertyList(aGlobal.Context(), aTarget, aFrames, animationProperties, aRv); @@ -1736,7 +1682,7 @@ KeyframeEffectReadOnly::Constructor( RefPtr effect = new KeyframeEffectReadOnly(aTarget->OwnerDoc(), aTarget, nsCSSPseudoElements::ePseudo_NotPseudoElement, - timing); + aTiming); effect->mProperties = Move(animationProperties); return effect.forget(); } diff --git a/dom/animation/KeyframeEffect.h b/dom/animation/KeyframeEffect.h index c2978ee5f9..5e27301ac2 100644 --- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -15,14 +15,17 @@ #include "mozilla/Attributes.h" #include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction #include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords +#include "mozilla/OwningNonNull.h" // OwningNonNull<...> #include "mozilla/StickyTimeDuration.h" #include "mozilla/StyleAnimationValue.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/AnimationEffectReadOnly.h" +#include "mozilla/dom/AnimationEffectTimingReadOnly.h" // TimingParams #include "mozilla/dom/Element.h" #include "mozilla/dom/KeyframeBinding.h" #include "mozilla/dom/Nullable.h" + struct JSContext; class nsCSSPropertySet; class nsIContent; @@ -36,41 +39,11 @@ struct AnimationCollection; class AnimValuesStyleRule; namespace dom { -struct ComputedTimingProperties; class UnrestrictedDoubleOrKeyframeEffectOptions; enum class IterationCompositeOperation : uint32_t; enum class CompositeOperation : uint32_t; } -/** - * Input timing parameters. - * - * Eventually this will represent all the input timing parameters specified - * by content but for now it encapsulates just the subset of those - * parameters passed to GetPositionInIteration. - */ -struct AnimationTiming -{ - TimeDuration mIterationDuration; - TimeDuration mDelay; - float mIterationCount; // mozilla::PositiveInfinity() means infinite - dom::PlaybackDirection mDirection; - dom::FillMode mFillMode; - - bool FillsForwards() const; - bool FillsBackwards() const; - bool operator==(const AnimationTiming& aOther) const { - return mIterationDuration == aOther.mIterationDuration && - mDelay == aOther.mDelay && - mIterationCount == aOther.mIterationCount && - mDirection == aOther.mDirection && - mFillMode == aOther.mFillMode; - } - bool operator!=(const AnimationTiming& aOther) const { - return !(*this == aOther); - } -}; - /** * Stores the results of calculating the timing properties of an animation * at a given sample time. @@ -88,6 +61,25 @@ struct ComputedTiming Nullable mProgress; // Zero-based iteration index (meaningless if mProgress is null). uint64_t mCurrentIteration = 0; + // Unlike TimingParams::mIterations, this value is + // guaranteed to be in the range [0, Infinity]. + double mIterations = 1.0; + StickyTimeDuration mDuration; + + // This is the computed fill mode so it is never auto + dom::FillMode mFill = dom::FillMode::None; + bool FillsForwards() const { + MOZ_ASSERT(mFill != dom::FillMode::Auto, + "mFill should not be Auto in ComputedTiming."); + return mFill == dom::FillMode::Both || + mFill == dom::FillMode::Forwards; + } + bool FillsBackwards() const { + MOZ_ASSERT(mFill != dom::FillMode::Auto, + "mFill should not be Auto in ComputedTiming."); + return mFill == dom::FillMode::Both || + mFill == dom::FillMode::Backwards; + } enum class AnimationPhase { Null, // Not sampled (null sample time) @@ -178,7 +170,7 @@ public: KeyframeEffectReadOnly(nsIDocument* aDocument, Element* aTarget, nsCSSPseudoElements::Type aPseudoType, - const AnimationTiming& aTiming); + const TimingParams& aTiming); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadOnly, @@ -197,9 +189,23 @@ public: static already_AddRefed Constructor(const GlobalObject& aGlobal, Element* aTarget, - const Optional>& aFrames, + JS::Handle aFrames, const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions, + ErrorResult& aRv) + { + return Constructor(aGlobal, aTarget, aFrames, + TimingParams::FromOptionsUnion(aOptions), aRv); + } + + // More generalized version for Animatable.animate. + // Not exposed to content. + static already_AddRefed + Constructor(const GlobalObject& aGlobal, + Element* aTarget, + JS::Handle aFrames, + const TimingParams& aTiming, ErrorResult& aRv); + Element* GetTarget() const { // Currently we never return animations from the API whose effect // targets a pseudo-element so this should never be called when @@ -227,9 +233,13 @@ public: aRetVal.AssignLiteral("distribute"); } - const AnimationTiming& Timing() const { return mTiming; } - AnimationTiming& Timing() { return mTiming; } - void SetTiming(const AnimationTiming& aTiming); + already_AddRefed Timing() const override; + + const TimingParams& SpecifiedTiming() const + { + return mTiming->AsTimingParams(); + } + void SetSpecifiedTiming(const TimingParams& aTiming); void NotifyAnimationTimingUpdated(); Nullable GetLocalTime() const; @@ -246,22 +256,25 @@ public: // (because it is not currently active and is not filling at this time). static ComputedTiming GetComputedTimingAt(const Nullable& aLocalTime, - const AnimationTiming& aTiming); + const TimingParams& aTiming); // Shortcut for that gets the computed timing using the current local time as // calculated from the timeline time. ComputedTiming - GetComputedTiming(const AnimationTiming* aTiming = nullptr) const + GetComputedTiming(const TimingParams* aTiming = nullptr) const { - return GetComputedTimingAt(GetLocalTime(), aTiming ? *aTiming : mTiming); + return GetComputedTimingAt(GetLocalTime(), + aTiming ? *aTiming : SpecifiedTiming()); } void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const override; - // Return the duration of the active interval for the given timing parameters. + // Return the duration of the active interval for the given duration and + // iteration count. static StickyTimeDuration - ActiveDuration(const AnimationTiming& aTiming); + ActiveDuration(const StickyTimeDuration& aIterationDuration, + double aIterationCount); bool IsInPlay() const; bool IsCurrent() const; @@ -334,20 +347,17 @@ protected: // owning Animation's timing. void UpdateTargetRegistration(); - static AnimationTiming ConvertKeyframeEffectOptions( - const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions); - static void BuildAnimationPropertyList( JSContext* aCx, Element* aTarget, - const Optional>& aFrames, + JS::Handle aFrames, InfallibleTArray& aResult, ErrorResult& aRv); nsCOMPtr mTarget; RefPtr mAnimation; - AnimationTiming mTiming; + OwningNonNull mTiming; nsCSSPseudoElements::Type mPseudoType; InfallibleTArray mProperties; diff --git a/dom/animation/PendingAnimationTracker.cpp b/dom/animation/PendingAnimationTracker.cpp index 75033ec552..a97814a7c0 100644 --- a/dom/animation/PendingAnimationTracker.cpp +++ b/dom/animation/PendingAnimationTracker.cpp @@ -63,6 +63,7 @@ PendingAnimationTracker::TriggerPendingAnimationsOnNextTick(const TimeStamp& // itself on the next tick where it has a timeline. if (!timeline) { iter.Remove(); + continue; } // When the timeline's refresh driver is under test control, its values diff --git a/dom/animation/moz.build b/dom/animation/moz.build index e42a975d5b..f5ae4a93b9 100644 --- a/dom/animation/moz.build +++ b/dom/animation/moz.build @@ -10,7 +10,9 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini'] EXPORTS.mozilla.dom += [ 'Animation.h', 'AnimationEffectReadOnly.h', + 'AnimationEffectTimingReadOnly.h', 'AnimationTimeline.h', + 'CSSPseudoElement.h', 'DocumentTimeline.h', 'KeyframeEffect.h', ] @@ -29,10 +31,12 @@ EXPORTS.mozilla += [ UNIFIED_SOURCES += [ 'Animation.cpp', 'AnimationEffectReadOnly.cpp', + 'AnimationEffectTimingReadOnly.cpp', 'AnimationTimeline.cpp', 'AnimationUtils.cpp', 'AnimValuesStyleRule.cpp', 'ComputedTimingFunction.cpp', + 'CSSPseudoElement.cpp', 'DocumentTimeline.cpp', 'EffectCompositor.cpp', 'EffectSet.cpp', diff --git a/dom/animation/test/chrome.ini b/dom/animation/test/chrome.ini index 1ae7c74d7a..7bff7243a2 100644 --- a/dom/animation/test/chrome.ini +++ b/dom/animation/test/chrome.ini @@ -3,6 +3,9 @@ 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_restyles.html] [chrome/test_running_on_compositor.html] diff --git a/dom/animation/test/chrome/file_animate_xrays.html b/dom/animation/test/chrome/file_animate_xrays.html new file mode 100644 index 0000000000..8a68fc548f --- /dev/null +++ b/dom/animation/test/chrome/file_animate_xrays.html @@ -0,0 +1,19 @@ + + + + + + +
+ + diff --git a/dom/animation/test/chrome/test_animate_xrays.html b/dom/animation/test/chrome/test_animate_xrays.html new file mode 100644 index 0000000000..e636af4b68 --- /dev/null +++ b/dom/animation/test/chrome/test_animate_xrays.html @@ -0,0 +1,31 @@ + + + + + + + + +Mozilla Bug 1045994 +
+ + + diff --git a/dom/animation/test/chrome/test_animation_observers.html b/dom/animation/test/chrome/test_animation_observers.html index 28a8115fdf..5090609c58 100644 --- a/dom/animation/test/chrome/test_animation_observers.html +++ b/dom/animation/test/chrome/test_animation_observers.html @@ -763,6 +763,27 @@ function assert_records(expected, desc) { }); }); + addAsyncAnimTest("change_id", aOptions, function*() { + e.style.animation = "anim 100s"; + + var animation = div.getAnimations()[0]; + yield await_frame(); + assert_records([{ added: [animation], changed: [], removed: []}], + "records after creation"); + animation.id = "new id"; + yield await_frame(); + assert_records([{ added: [], changed: [animation], removed: []}], + "records after id is changed"); + + animation.id = "new id"; + yield await_frame(); + assert_records([], + "records after assigning same value with id"); + + e.style.animation = ""; + yield await_frame(); + }); + // Test that making a redundant change to currentTime while an Animation // is pause-pending still generates a change MutationRecord since setting // the currentTime to any value in this state aborts the pending pause. diff --git a/dom/animation/test/css-animations/file_animation-id.html b/dom/animation/test/css-animations/file_animation-id.html new file mode 100644 index 0000000000..9f2b117b70 --- /dev/null +++ b/dom/animation/test/css-animations/file_animation-id.html @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/dom/animation/test/css-animations/test_animation-id.html b/dom/animation/test/css-animations/test_animation-id.html new file mode 100644 index 0000000000..c23501b8d6 --- /dev/null +++ b/dom/animation/test/css-animations/test_animation-id.html @@ -0,0 +1,15 @@ + + + + +
+ + diff --git a/dom/animation/test/mochitest.ini b/dom/animation/test/mochitest.ini index dd64f9321c..7abf0b088d 100644 --- a/dom/animation/test/mochitest.ini +++ b/dom/animation/test/mochitest.ini @@ -1,6 +1,9 @@ [DEFAULT] +# Support files for chrome tests that we want to load over HTTP need +# to go in here, not chrome.ini. support-files = testcommon.js + chrome/file_animate_xrays.html [css-animations/test_animations-dynamic-changes.html] support-files = css-animations/file_animations-dynamic-changes.html @@ -14,6 +17,8 @@ support-files = css-animations/file_animation-currenttime.html support-files = css-animations/file_animation-finish.html [css-animations/test_animation-finished.html] support-files = css-animations/file_animation-finished.html +[css-animations/test_animation-id.html] +support-files = css-animations/file_animation-id.html [css-animations/test_animation-oncancel.html] support-files = css-animations/file_animation-oncancel.html [css-animations/test_animation-onfinish.html] diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 8cca2d5294..390c8bc476 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -21,6 +21,7 @@ #include "nsIContentInlines.h" #include "mozilla/dom/NodeInfo.h" #include "nsIDocumentInlines.h" +#include "mozilla/dom/DocumentTimeline.h" #include "nsIDOMNodeList.h" #include "nsIDOMDocument.h" #include "nsIContentIterator.h" @@ -51,6 +52,7 @@ #include "nsDOMString.h" #include "nsIScriptSecurityManager.h" #include "nsIDOMMutationEvent.h" +#include "mozilla/dom/AnimatableBinding.h" #include "mozilla/AnimationComparator.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/ContentEvents.h" @@ -1267,9 +1269,11 @@ Element::GetAttributeNode(const nsAString& aName) already_AddRefed Element::SetAttributeNode(Attr& aNewAttr, ErrorResult& aError) { + // XXXbz can we just remove this warning and the one in setAttributeNodeNS and + // alias setAttributeNode to setAttributeNodeNS? OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNode); - return Attributes()->SetNamedItem(aNewAttr, aError); + return Attributes()->SetNamedItemNS(aNewAttr, aError); } already_AddRefed @@ -1812,8 +1816,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) // We need to delete the properties while we're still in document // (if we were in document). // FIXME (Bug 522599): Need a test for this. - //XXXsmaug this looks slow. - if (HasFlag(NODE_HAS_PROPERTIES)) { + if (MayHaveAnimations()) { DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty); DeleteProperty(nsGkAtoms::transitionsOfAfterProperty); DeleteProperty(nsGkAtoms::transitionsProperty); @@ -2966,7 +2969,7 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor) // Set the status bar similarly for mouseover and focus case eMouseOver: aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; - // FALL THROUGH + MOZ_FALLTHROUGH; case eFocus: { InternalFocusEvent* focusEvent = aVisitor.mEvent->AsFocusEvent(); if (!focusEvent || !focusEvent->isRefocus) { @@ -2981,7 +2984,7 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor) } case eMouseOut: aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; - // FALL THROUGH + MOZ_FALLTHROUGH; case eBlur: rv = LeaveLink(aVisitor.mPresContext); if (NS_SUCCEEDED(rv)) { @@ -3370,6 +3373,58 @@ Element::MozRequestPointerLock() OwnerDoc()->RequestPointerLock(this); } +already_AddRefed +Element::Animate(JSContext* aContext, + JS::Handle aFrames, + const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions, + ErrorResult& aError) +{ + nsCOMPtr ownerGlobal = GetOwnerGlobal(); + if (!ownerGlobal) { + aError.Throw(NS_ERROR_FAILURE); + return nullptr; + } + GlobalObject global(aContext, ownerGlobal->GetGlobalJSObject()); + MOZ_ASSERT(!global.Failed()); + + // Wrap the aFrames object for the cross-compartment case. + JS::Rooted frames(aContext); + frames = aFrames; + Maybe ac; + if (js::GetContextCompartment(aContext) != + js::GetObjectCompartment(ownerGlobal->GetGlobalJSObject())) { + ac.emplace(aContext, ownerGlobal->GetGlobalJSObject()); + if (!JS_WrapObject(aContext, &frames)) { + return nullptr; + } + } + + // Bug 1211783: Use KeyframeEffect here (instead of KeyframeEffectReadOnly) + RefPtr effect = + KeyframeEffectReadOnly::Constructor(global, this, frames, + TimingParams::FromOptionsUnion(aOptions), aError); + if (aError.Failed()) { + return nullptr; + } + + RefPtr animation = + Animation::Constructor(global, effect, OwnerDoc()->Timeline(), aError); + if (aError.Failed()) { + return nullptr; + } + + if (aOptions.IsKeyframeAnimationOptions()) { + animation->SetId(aOptions.GetAsKeyframeAnimationOptions().mId); + } + + animation->Play(aError, Animation::LimitBehavior::AutoRewind); + if (aError.Failed()) { + return nullptr; + } + + return animation.forget(); +} + void Element::GetAnimations(nsTArray>& aAnimations) { diff --git a/dom/base/Element.h b/dom/base/Element.h index ca056b8da9..536c953a4f 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -58,6 +58,7 @@ namespace mozilla { namespace dom { struct ScrollIntoViewOptions; struct ScrollToOptions; + class UnrestrictedDoubleOrKeyframeAnimationOptions; } // namespace dom } // namespace mozilla @@ -852,6 +853,12 @@ public: { } + already_AddRefed Animate( + JSContext* aContext, + JS::Handle aFrames, + const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions, + ErrorResult& aError); + // Note: GetAnimations will flush style while GetAnimationsUnsorted won't. void GetAnimations(nsTArray>& aAnimations); void GetAnimationsUnsorted(nsTArray>& aAnimations); diff --git a/dom/base/nsDOMAttributeMap.cpp b/dom/base/nsDOMAttributeMap.cpp index 346707ffe4..b953496824 100644 --- a/dom/base/nsDOMAttributeMap.cpp +++ b/dom/base/nsDOMAttributeMap.cpp @@ -221,7 +221,7 @@ nsDOMAttributeMap::SetNamedItem(nsIDOMAttr* aAttr, nsIDOMAttr** aReturn) NS_ENSURE_ARG(attribute); ErrorResult rv; - *aReturn = SetNamedItem(*attribute, rv).take(); + *aReturn = SetNamedItemNS(*attribute, rv).take(); return rv.StealNSResult(); } @@ -237,9 +237,7 @@ nsDOMAttributeMap::SetNamedItemNS(nsIDOMAttr* aAttr, nsIDOMAttr** aReturn) } already_AddRefed -nsDOMAttributeMap::SetNamedItemInternal(Attr& aAttr, - bool aWithNS, - ErrorResult& aError) +nsDOMAttributeMap::SetNamedItemNS(Attr& aAttr, ErrorResult& aError) { NS_ENSURE_TRUE(mContent, nullptr); @@ -274,24 +272,18 @@ nsDOMAttributeMap::SetNamedItemInternal(Attr& aAttr, // Get nodeinfo and preexisting attribute (if it exists) RefPtr oldNi; - if (!aWithNS) { - nsAutoString name; - aAttr.GetName(name); - oldNi = mContent->GetExistingAttrNameFromQName(name); - } else { - uint32_t i, count = mContent->GetAttrCount(); - for (i = 0; i < count; ++i) { - const nsAttrName* name = mContent->GetAttrNameAt(i); - int32_t attrNS = name->NamespaceID(); - nsIAtom* nameAtom = name->LocalName(); + uint32_t i, count = mContent->GetAttrCount(); + for (i = 0; i < count; ++i) { + const nsAttrName* name = mContent->GetAttrNameAt(i); + int32_t attrNS = name->NamespaceID(); + nsIAtom* nameAtom = name->LocalName(); - // we're purposefully ignoring the prefix. - if (aAttr.NodeInfo()->Equals(nameAtom, attrNS)) { - oldNi = mContent->NodeInfo()->NodeInfoManager()-> - GetNodeInfo(nameAtom, name->GetPrefix(), aAttr.NodeInfo()->NamespaceID(), - nsIDOMNode::ATTRIBUTE_NODE); - break; - } + // we're purposefully ignoring the prefix. + if (aAttr.NodeInfo()->Equals(nameAtom, attrNS)) { + oldNi = mContent->NodeInfo()->NodeInfoManager()-> + GetNodeInfo(nameAtom, name->GetPrefix(), aAttr.NodeInfo()->NamespaceID(), + nsIDOMNode::ATTRIBUTE_NODE); + break; } } diff --git a/dom/base/nsDOMAttributeMap.h b/dom/base/nsDOMAttributeMap.h index 7ebe61aa13..3abacf8aee 100644 --- a/dom/base/nsDOMAttributeMap.h +++ b/dom/base/nsDOMAttributeMap.h @@ -141,11 +141,6 @@ public: Attr* NamedGetter(const nsAString& aAttrName, bool& aFound); bool NameIsEnumerable(const nsAString& aName); already_AddRefed - SetNamedItem(Attr& aAttr, ErrorResult& aError) - { - return SetNamedItemInternal(aAttr, false, aError); - } - already_AddRefed RemoveNamedItem(mozilla::dom::NodeInfo* aNodeInfo, ErrorResult& aError); already_AddRefed RemoveNamedItem(const nsAString& aName, ErrorResult& aError); @@ -158,10 +153,7 @@ public: GetNamedItemNS(const nsAString& aNamespaceURI, const nsAString& aLocalName); already_AddRefed - SetNamedItemNS(Attr& aNode, ErrorResult& aError) - { - return SetNamedItemInternal(aNode, true, aError); - } + SetNamedItemNS(Attr& aNode, ErrorResult& aError); already_AddRefed RemoveNamedItemNS(const nsAString& aNamespaceURI, const nsAString& aLocalName, ErrorResult& aError); @@ -184,13 +176,6 @@ private: */ AttrCache mAttributeCache; - /** - * SetNamedItem() (aWithNS = false) and SetNamedItemNS() (aWithNS = - * true) implementation. - */ - already_AddRefed - SetNamedItemInternal(Attr& aNode, bool aWithNS, ErrorResult& aError); - already_AddRefed GetAttrNodeInfo(const nsAString& aNamespaceURI, const nsAString& aLocalName); diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 6b5f746ed6..708f8bf03b 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -6671,6 +6671,7 @@ nsIDocument::ImportNode(nsINode& aNode, bool aDeep, ErrorResult& rv) const if (ShadowRoot::FromNode(imported)) { break; } + MOZ_FALLTHROUGH; } case nsIDOMNode::ATTRIBUTE_NODE: case nsIDOMNode::ELEMENT_NODE: @@ -7705,6 +7706,7 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv) rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); return nullptr; } + MOZ_FALLTHROUGH; } case nsIDOMNode::ELEMENT_NODE: case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: @@ -7992,6 +7994,7 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize) mValidMaxScale = !maxScaleStr.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode); mViewportType = Specified; + MOZ_FALLTHROUGH; } case Specified: default: diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 2bffa2018b..2b58a5f0ed 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8031,6 +8031,7 @@ nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl) case openOverridden: if (PopupWhitelisted()) abuse = PopupControlState(abuse - 1); + break; case openAllowed: break; default: NS_WARNING("Strange PopupControlState!"); diff --git a/dom/base/nsXMLContentSerializer.cpp b/dom/base/nsXMLContentSerializer.cpp index 887a9b78d0..f1f8d76f3e 100644 --- a/dom/base/nsXMLContentSerializer.cpp +++ b/dom/base/nsXMLContentSerializer.cpp @@ -1388,7 +1388,7 @@ nsXMLContentSerializer::AppendFormatedWrapped_WhitespaceSequence( case ' ': case '\t': sawBlankOrTab = true; - // no break + MOZ_FALLTHROUGH; case '\n': ++aPos; // do not increase mColPos, diff --git a/dom/base/test/test_bug1075702.html b/dom/base/test/test_bug1075702.html index 0798e42170..ccee454df5 100644 --- a/dom/base/test/test_bug1075702.html +++ b/dom/base/test/test_bug1075702.html @@ -29,7 +29,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1075702 document.documentElement.setAttributeNode(a1); document.documentElement.setAttributeNode(a2); - is(document.documentElement.getAttributeNS("", "aa"), null, "Should be NULL!"); + is(document.documentElement.getAttributeNS("", "aa"), "lowercase", "Should be lowercase!"); is(document.documentElement.getAttributeNS("", "AA"), "UPPERCASE", "Should be UPPERCASE!"); var a3 = document.createAttribute("AA"); diff --git a/dom/cache/AutoUtils.cpp b/dom/cache/AutoUtils.cpp index 0b7c76b487..1f9c8a52c7 100644 --- a/dom/cache/AutoUtils.cpp +++ b/dom/cache/AutoUtils.cpp @@ -483,6 +483,7 @@ AutoParentOpResult::~AutoParentOpResult() break; } Unused << PCacheParent::Send__delete__(result.actorParent()); + break; } default: // other types do not need clean up diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 00702c0894..bdf4148d62 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -3805,6 +3805,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) break; // If we are submitting, do not send click event } // else fall through and treat Space like click... + MOZ_FALLTHROUGH; } case NS_FORM_INPUT_BUTTON: case NS_FORM_INPUT_RESET: @@ -3826,7 +3827,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) case NS_VK_UP: case NS_VK_LEFT: isMovingBack = true; - // FALLTHROUGH + MOZ_FALLTHROUGH; case NS_VK_DOWN: case NS_VK_RIGHT: // Arrow key pressed, focus+select prev/next radio button diff --git a/dom/html/test/browser.ini b/dom/html/test/browser.ini index 3e2cbf83b2..803b18936e 100644 --- a/dom/html/test/browser.ini +++ b/dom/html/test/browser.ini @@ -4,6 +4,7 @@ support-files = dummy_page.html file_bug649778.html file_bug649778.html^headers^ + file_fullscreen-api-keys.html head.js [browser_bug592641.js] @@ -16,4 +17,5 @@ support-files = file_bug1108547-2.html file_bug1108547-3.html [browser_DOMDocElementInserted.js] +[browser_fullscreen-api-keys.js] [browser_fullscreen-contextmenu-esc.js] diff --git a/dom/html/test/browser_fullscreen-api-keys.js b/dom/html/test/browser_fullscreen-api-keys.js new file mode 100644 index 0000000000..ef55ced6cc --- /dev/null +++ b/dom/html/test/browser_fullscreen-api-keys.js @@ -0,0 +1,164 @@ +"use strict"; + +/** Test for Bug 545812 **/ + +// List of key codes which should exit full-screen mode. +const kKeyList = [ + { code: "VK_ESCAPE", suppressed: true}, + { code: "VK_F11", suppressed: false}, +]; + +function frameScript() { + let doc = content.document; + addMessageListener("Test:RequestFullscreen", () => { + doc.body.mozRequestFullScreen(); + }); + addMessageListener("Test:DispatchUntrustedKeyEvents", msg => { + var evt = new content.CustomEvent("Test:DispatchKeyEvents", { + detail: { code: msg.data } + }); + content.dispatchEvent(evt); + }); + + doc.addEventListener("mozfullscreenchange", () => { + sendAsyncMessage("Test:FullscreenChanged", !!doc.mozFullScreenElement); + }); + + function keyHandler(evt) { + sendAsyncMessage("Test:KeyReceived", { + type: evt.type, + keyCode: evt.keyCode + }); + } + doc.addEventListener("keydown", keyHandler, true); + doc.addEventListener("keyup", keyHandler, true); + doc.addEventListener("keypress", keyHandler, true); + + function waitUntilActive() { + if (doc.docShell.isActive && doc.hasFocus()) { + sendAsyncMessage("Test:Activated"); + } else { + setTimeout(waitUntilActive, 10); + } + } + waitUntilActive(); +} + +var gMessageManager; + +function listenOneMessage(aMsg, aListener) { + function listener({ data }) { + gMessageManager.removeMessageListener(aMsg, listener); + aListener(data); + } + gMessageManager.addMessageListener(aMsg, listener); +} + +function promiseOneMessage(aMsg) { + return new Promise(resolve => listenOneMessage(aMsg, resolve)); +} + +function captureUnexpectedFullscreenChange() { + ok(false, "Caught an unexpected fullscreen change"); +} + +function* temporaryRemoveUnexpectedFullscreenChangeCapture(callback) { + gMessageManager.removeMessageListener( + "Test:FullscreenChanged", captureUnexpectedFullscreenChange); + yield* callback(); + gMessageManager.addMessageListener( + "Test:FullscreenChanged", captureUnexpectedFullscreenChange); +} + +function captureUnexpectedKeyEvent(type) { + ok(false, `Caught an unexpected ${type} event`); +} + +function* temporaryRemoveUnexpectedKeyEventCapture(callback) { + gMessageManager.removeMessageListener( + "Test:KeyReceived", captureUnexpectedKeyEvent); + yield* callback(); + gMessageManager.addMessageListener( + "Test:KeyReceived", captureUnexpectedKeyEvent); +} + +function* receiveExpectedKeyEvents(keyCode) { + info("Waiting for key events"); + let events = ["keydown", "keypress", "keyup"]; + while (events.length > 0) { + let evt = yield promiseOneMessage("Test:KeyReceived"); + let expected = events.shift(); + is(evt.type, expected, `Should receive a ${expected} event`); + is(evt.keyCode, keyCode, + `Should receive the event with key code ${keyCode}`); + } +} + +const kPage = "http://example.org/browser/" + + "dom/html/test/file_fullscreen-api-keys.html"; + +add_task(function* () { + yield pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"]); + + let tab = gBrowser.addTab(kPage); + let browser = tab.linkedBrowser; + gBrowser.selectedTab = tab; + registerCleanupFunction(() => gBrowser.removeTab(tab)); + yield waitForDocLoadComplete(); + + gMessageManager = browser.messageManager; + gMessageManager.loadFrameScript( + "data:,(" + frameScript.toString() + ")();", false); + + // Wait for the document being actived, so that + // fullscreen request won't be denied. + yield promiseOneMessage("Test:Activated"); + + // Register listener to capture unexpected events + gMessageManager.addMessageListener( + "Test:FullscreenChanged", captureUnexpectedFullscreenChange); + gMessageManager.addMessageListener( + "Test:KeyReceived", captureUnexpectedKeyEvent); + registerCleanupFunction(() => { + gMessageManager.removeMessageListener( + "Test:FullscreenChanged", captureUnexpectedFullscreenChange); + gMessageManager.removeMessageListener( + "Test:KeyReceived", captureUnexpectedKeyEvent); + }); + + for (let {code, suppressed} of kKeyList) { + var keyCode = KeyEvent["DOM_" + code]; + info(`Test keycode ${code} (${keyCode})`); + + info("Enter fullscreen"); + yield* temporaryRemoveUnexpectedFullscreenChangeCapture(function* () { + gMessageManager.sendAsyncMessage("Test:RequestFullscreen"); + let state = yield promiseOneMessage("Test:FullscreenChanged"); + ok(state, "The content should have entered fullscreen"); + ok(document.mozFullScreenElement, + "The chrome should also be in fullscreen"); + }); + + info("Dispatch untrusted key events from content"); + yield* temporaryRemoveUnexpectedKeyEventCapture(function* () { + gMessageManager.sendAsyncMessage("Test:DispatchUntrustedKeyEvents", code); + yield* receiveExpectedKeyEvents(keyCode); + }); + + info("Send trusted key events"); + yield* temporaryRemoveUnexpectedFullscreenChangeCapture(function* () { + yield* temporaryRemoveUnexpectedKeyEventCapture(function* () { + EventUtils.synthesizeKey(code, {}); + if (!suppressed) { + yield* receiveExpectedKeyEvents(keyCode); + } + let state = yield promiseOneMessage("Test:FullscreenChanged"); + ok(!state, "The content should have exited fullscreen"); + ok(!document.mozFullScreenElement, + "The chrome should also have exited fullscreen"); + }); + }); + } +}); diff --git a/dom/html/test/file_fullscreen-plugins.html b/dom/html/test/file_fullscreen-plugins.html index b1a99df2be..4ba485cd06 100644 --- a/dom/html/test/file_fullscreen-plugins.html +++ b/dom/html/test/file_fullscreen-plugins.html @@ -58,6 +58,10 @@ function e(id) { return document.getElementById(id); } +function removeElement(e) { + e.parentNode.removeChild(e); +} + const isMacOs = navigator.appVersion.indexOf("Macintosh") != -1; var windowedPlugin = null; @@ -108,6 +112,10 @@ function nonMacTest2() { function nonMacTest3() { ok(!document.mozFullScreen, "Full-screen should have been revoked when windowed-plugin was focused."); + // Remove windowed plugins before closing the window + // to work around bug 1237853. + removeElement(e("windowed-plugin")); + removeElement(e("subdoc-plugin").contentDocument.getElementById("windowed-plugin")); opener.nextTest(); } diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index e4a79ed736..936d3a6924 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -46,7 +46,6 @@ support-files = file_bug893537.html file_formSubmission_img.jpg file_formSubmission_text.txt - file_fullscreen-api-keys.html file_fullscreen-api.html file_fullscreen-backdrop.html file_fullscreen-denied-inner.html diff --git a/dom/html/test/test_fullscreen-api.html b/dom/html/test/test_fullscreen-api.html index 3e5480ae91..bc47604e96 100644 --- a/dom/html/test/test_fullscreen-api.html +++ b/dom/html/test/test_fullscreen-api.html @@ -33,7 +33,6 @@ var gTestWindows = [ "file_fullscreen-esc-exit.html", "file_fullscreen-denied.html", "file_fullscreen-api.html", - "file_fullscreen-api-keys.html", "file_fullscreen-plugins.html", "file_fullscreen-hidden.html", "file_fullscreen-svg-element.html", diff --git a/dom/storage/DOMStorageDBThread.cpp b/dom/storage/DOMStorageDBThread.cpp index 310ff9e9a4..9d7eda6c48 100644 --- a/dom/storage/DOMStorageDBThread.cpp +++ b/dom/storage/DOMStorageDBThread.cpp @@ -220,7 +220,7 @@ DOMStorageDBThread::InsertDBOp(DOMStorageDBThread::DBOperation* aOperation) aOperation->Finalize(NS_OK); return NS_OK; } - // NO BREAK + MOZ_FALLTHROUGH; case DBOperation::opGetUsage: if (aOperation->Type() == DBOperation::opPreloadUrgent) { diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 0e7ebb9f7e..ee0714dcea 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -126,6 +126,8 @@ var interfaceNamesInGlobalScope = {name: "Animation", release: false}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "AnimationEffectReadOnly", release: false}, +// IMPORTANT: Do not change this list without review from a DOM peer! + {name: "AnimationEffectTimingReadOnly", release: false}, // IMPORTANT: Do not change this list without review from a DOM peer! "AnimationEvent", // IMPORTANT: Do not change this list without review from a DOM peer! @@ -349,6 +351,8 @@ var interfaceNamesInGlobalScope = "CSSPageRule", // IMPORTANT: Do not change this list without review from a DOM peer! "CSSPrimitiveValue", +// IMPORTANT: Do not change this list without review from a DOM peer! + {name: "CSSPseudoElement", release: false}, // IMPORTANT: Do not change this list without review from a DOM peer! "CSSRule", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/Animatable.webidl b/dom/webidl/Animatable.webidl index 03985f797b..f1e0a5564f 100644 --- a/dom/webidl/Animatable.webidl +++ b/dom/webidl/Animatable.webidl @@ -10,8 +10,16 @@ * liability, trademark and document use rules apply. */ +dictionary KeyframeAnimationOptions : KeyframeEffectOptions { + DOMString id = ""; +}; + [NoInterfaceObject] interface Animatable { + [Func="nsDocument::IsWebAnimationsEnabled", Throws] + Animation animate(object? frames, + optional (unrestricted double or KeyframeAnimationOptions) + options); [Func="nsDocument::IsWebAnimationsEnabled"] sequence getAnimations(); }; diff --git a/dom/webidl/Animation.webidl b/dom/webidl/Animation.webidl index 6ca9d42535..7264db1549 100644 --- a/dom/webidl/Animation.webidl +++ b/dom/webidl/Animation.webidl @@ -12,8 +12,11 @@ enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" }; -[Func="nsDocument::IsWebAnimationsEnabled"] +[Func="nsDocument::IsWebAnimationsEnabled", + Constructor (optional KeyframeEffectReadOnly? effect = null, + optional AnimationTimeline? timeline = null)] interface Animation : EventTarget { + attribute DOMString id; // Bug 1049975: Make 'effect' writeable [Pure] readonly attribute AnimationEffectReadOnly? effect; diff --git a/dom/webidl/AnimationEffectReadonly.webidl b/dom/webidl/AnimationEffectReadonly.webidl index a71bb6c354..8922f1afd2 100644 --- a/dom/webidl/AnimationEffectReadonly.webidl +++ b/dom/webidl/AnimationEffectReadonly.webidl @@ -46,9 +46,8 @@ dictionary ComputedTimingProperties : AnimationEffectTimingProperties { [Func="nsDocument::IsWebAnimationsEnabled"] interface AnimationEffectReadOnly { - // Not yet implemented: - // readonly attribute AnimationEffectTimingReadOnly timing; - + [Cached, Constant] + readonly attribute AnimationEffectTimingReadOnly timing; [BinaryName="getComputedTimingAsDict"] ComputedTimingProperties getComputedTiming(); }; diff --git a/dom/webidl/AnimationEffectTimingReadOnly.webidl b/dom/webidl/AnimationEffectTimingReadOnly.webidl new file mode 100644 index 0000000000..4aff51e011 --- /dev/null +++ b/dom/webidl/AnimationEffectTimingReadOnly.webidl @@ -0,0 +1,23 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * https://w3c.github.io/web-animations/#animationeffecttimingreadonly + * + * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +[Func="nsDocument::IsWebAnimationsEnabled"] +interface AnimationEffectTimingReadOnly { + readonly attribute double delay; + readonly attribute double endDelay; + readonly attribute FillMode fill; + readonly attribute double iterationStart; + readonly attribute unrestricted double iterations; + readonly attribute (unrestricted double or DOMString) duration; + readonly attribute PlaybackDirection direction; + readonly attribute DOMString easing; +}; diff --git a/dom/webidl/CSSPseudoElement.webidl b/dom/webidl/CSSPseudoElement.webidl new file mode 100644 index 0000000000..96d191e3af --- /dev/null +++ b/dom/webidl/CSSPseudoElement.webidl @@ -0,0 +1,25 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * https://drafts.csswg.org/css-pseudo/#CSSPseudoElement-interface + * https://drafts.csswg.org/cssom/#pseudoelement + * + * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +// Both CSSOM and CSS Pseudo-Elements 4 provide contradictory definitions for +// this interface. +// What we implement here is a minimal subset of the two definitions which we +// ship behind a pref until the specification issues have been resolved. +[Func="nsDocument::IsWebAnimationsEnabled"] +interface CSSPseudoElement { + readonly attribute DOMString type; + readonly attribute Element parentElement; +}; + +// https://w3c.github.io/web-animations/#extensions-to-the-pseudoelement-interface +CSSPseudoElement implements Animatable; diff --git a/dom/webidl/KeyframeEffect.webidl b/dom/webidl/KeyframeEffect.webidl index 9782e00814..9d4317ec05 100644 --- a/dom/webidl/KeyframeEffect.webidl +++ b/dom/webidl/KeyframeEffect.webidl @@ -21,22 +21,12 @@ dictionary KeyframeEffectOptions : AnimationEffectTimingProperties { DOMString spacing = "distribute"; }; -// For the constructor: -// -// 1. We use Element? for the first argument since we don't support Animatable -// for pseudo-elements yet. -// -// 2. We use object? instead of -// -// (PropertyIndexedKeyframes or sequence or SharedKeyframeList) -// -// for the second argument so that we can get the property-value pairs from -// the PropertyIndexedKeyframes or Keyframe objects. We also don't support -// SharedKeyframeList yet. +// For the constructor we use Element? for the first argument since we +// don't support Animatable for pseudo-elements yet. [HeaderFile="mozilla/dom/KeyframeEffect.h", Func="nsDocument::IsWebAnimationsEnabled", Constructor(Element? target, - optional object? frames, + object? frames, optional (unrestricted double or KeyframeEffectOptions) options)] interface KeyframeEffectReadOnly : AnimationEffectReadOnly { readonly attribute Element? target; diff --git a/dom/webidl/NamedNodeMap.webidl b/dom/webidl/NamedNodeMap.webidl index 71d61181ce..82a8730195 100644 --- a/dom/webidl/NamedNodeMap.webidl +++ b/dom/webidl/NamedNodeMap.webidl @@ -5,7 +5,7 @@ interface NamedNodeMap { getter Attr? getNamedItem(DOMString name); - [Throws] + [Throws, BinaryName="setNamedItemNS"] Attr? setNamedItem(Attr arg); [Throws] Attr removeNamedItem(DOMString name); diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index e2f8155a5b..5387a8671d 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -25,6 +25,7 @@ WEBIDL_FILES = [ 'Animatable.webidl', 'Animation.webidl', 'AnimationEffectReadOnly.webidl', + 'AnimationEffectTimingReadOnly.webidl', 'AnimationEvent.webidl', 'AnimationTimeline.webidl', 'AnonymousContent.webidl', @@ -98,6 +99,7 @@ WEBIDL_FILES = [ 'CSSAnimation.webidl', 'CSSLexer.webidl', 'CSSPrimitiveValue.webidl', + 'CSSPseudoElement.webidl', 'CSSRuleList.webidl', 'CSSStyleDeclaration.webidl', 'CSSStyleSheet.webidl', diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 5f0b1bdde8..43f564cd87 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -1970,7 +1970,7 @@ void ReportLoadError(JSContext* aCx, nsresult aLoadResult) case NS_ERROR_MALFORMED_URI: aLoadResult = NS_ERROR_DOM_SYNTAX_ERR; - // fall through + MOZ_FALLTHROUGH; case NS_ERROR_DOM_SECURITY_ERR: case NS_ERROR_DOM_SYNTAX_ERR: Throw(aCx, aLoadResult); diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 49d9a1cf4a..476c68db18 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -385,7 +385,8 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer, FrameMetrics::ViewID aTransformScrollId, const Matrix4x4& aPreviousTransformForRoot, const Matrix4x4& aCurrentTransformForRoot, - const ScreenMargin& aFixedLayerMargins) + const ScreenMargin& aFixedLayerMargins, + bool aTransformAffectsLayerClip) { FrameMetrics::ViewID fixedTo; // the scroll id of the scroll frame we are fixed/sticky to bool isRootOfFixedSubtree = aLayer->GetIsFixedPosition() && @@ -411,7 +412,8 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer, for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { AlignFixedAndStickyLayers(child, aTransformedSubtreeRoot, aTransformScrollId, aPreviousTransformForRoot, - aCurrentTransformForRoot, aFixedLayerMargins); + aCurrentTransformForRoot, aFixedLayerMargins, + true /* descendants' clip rects are always affected */); } return; } @@ -489,18 +491,15 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer, IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost()); } - // Finally, apply the translation to the layer transform. Note that in - // general we need to apply the same translation to the layer's clip rect, so + // Finally, apply the translation to the layer transform. Note that in cases + // where the async transform on |aTransformedSubtreeRoot| affects this layer's + // clip rect, we need to apply the same translation to said clip rect, so // that the effective transform on the clip rect takes it back to where it was - // originally, had there been no async scroll. In the case where the - // fixed/sticky layer is the same as aTransformedSubtreeRoot, then the clip - // rect is not affected by the scroll-induced async scroll transform anyway - // (since the clip is applied post-transform) so we don't need to make the - // adjustment. Also, some layers want async scrolling to move their clip rect + // originally, had there been no async scroll. + // Also, some layers want async scrolling to move their clip rect // (IsClipFixed() = false), so we don't make a compensating adjustment for // those. - bool adjustClipRect = aLayer != aTransformedSubtreeRoot && - aLayer->IsClipFixed(); + bool adjustClipRect = aTransformAffectsLayerClip && aLayer->IsClipFixed(); TranslateShadowLayer(aLayer, ThebesPoint(translation.ToUnknownPoint()), adjustClipRect); } @@ -580,18 +579,20 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint) continue; } - AnimationTiming timing; - timing.mIterationDuration = animation.duration(); + TimingParams timing; + timing.mDuration.SetAsUnrestrictedDouble() = + animation.duration().ToMilliseconds(); // Currently animations run on the compositor have their delay factored // into their start time, hence the delay is effectively zero. timing.mDelay = TimeDuration(0); - timing.mIterationCount = animation.iterationCount(); - timing.mDirection = static_cast(animation.direction()); + timing.mIterations = animation.iterations(); + timing.mDirection = + static_cast(animation.direction()); // Animations typically only run on the compositor during their active // interval but if we end up sampling them outside that range (for // example, while they are waiting to be removed) we currently just // assume that we should fill. - timing.mFillMode = dom::FillMode::Both; + timing.mFill = dom::FillMode::Both; ComputedTiming computedTiming = dom::KeyframeEffectReadOnly::GetComputedTimingAt( @@ -900,6 +901,29 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, asyncClip = Some(TransformBy( ViewAs(asyncTransform), *asyncClip)); } + aLayer->AsLayerComposite()->SetShadowClipRect(asyncClip); + + combinedAsyncTransform *= asyncTransform; + + // For the purpose of aligning fixed and sticky layers, we disregard + // the overscroll transform as well as any OMTA transform when computing the + // 'aCurrentTransformForRoot' parameter. This ensures that the overscroll + // and OMTA transforms are not unapplied, and therefore that the visual + // effects apply to fixed and sticky layers. We do this by using + // GetTransform() as the base transform rather than GetLocalTransform(), + // which would include those factors. + Matrix4x4 transformWithoutOverscrollOrOmta = aLayer->GetTransform() * + AdjustForClip(asyncTransformWithoutOverscroll, aLayer); + + // Since fixed/sticky layers are relative to their nearest scrolling ancestor, + // we use the ViewID from the bottommost scrollable metrics here. + AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform, + transformWithoutOverscrollOrOmta, fixedLayerMargins, + asyncClip.isSome()); + + // AlignFixedAndStickyLayers may have changed the clip rect, so we have to + // read it from the layer again. + asyncClip = aLayer->AsLayerComposite()->GetShadowClipRect(); // Combine the local clip with the ancestor scrollframe clip. This is not // included in the async transform above, since the ancestor clip should not @@ -932,23 +956,6 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, Layer* ancestorMaskLayer = aLayer->GetAncestorMaskLayerAt(maskLayerIndex); ancestorMaskLayers.AppendElement(ancestorMaskLayer); } - - combinedAsyncTransform *= asyncTransform; - - // For the purpose of aligning fixed and sticky layers, we disregard - // the overscroll transform as well as any OMTA transform when computing the - // 'aCurrentTransformForRoot' parameter. This ensures that the overscroll - // and OMTA transforms are not unapplied, and therefore that the visual - // effects apply to fixed and sticky layers. We do this by using - // GetTransform() as the base transform rather than GetLocalTransform(), - // which would include those factors. - Matrix4x4 transformWithoutOverscrollOrOmta = aLayer->GetTransform() * - AdjustForClip(asyncTransformWithoutOverscroll, aLayer); - - // Since fixed/sticky layers are relative to their nearest scrolling ancestor, - // we use the ViewID from the bottommost scrollable metrics here. - AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform, - transformWithoutOverscrollOrOmta, fixedLayerMargins); } if (hasAsyncTransform || clipDeferredFromChildren) { @@ -1331,7 +1338,8 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) // Make sure fixed position layers don't move away from their anchor points // when we're asynchronously panning or zooming AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform, - aLayer->GetLocalTransform(), fixedLayerMargins); + aLayer->GetLocalTransform(), fixedLayerMargins, + false); ExpandRootClipRect(aLayer, fixedLayerMargins); } diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index 24af80c0bf..e21e4da62f 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -177,12 +177,17 @@ private: * This function will also adjust layers so that the given content document * fixed position margins will be respected during asynchronous panning and * zooming. + * aTransformAffectsLayerClip indicates whether the transform on + * aTransformedSubtreeRoot affects aLayer's clip rects, so we know + * whether we need to perform a corresponding unadjustment to keep + * the clip rect fixed. */ void AlignFixedAndStickyLayers(Layer* aLayer, Layer* aTransformedSubtreeRoot, FrameMetrics::ViewID aTransformScrollId, const gfx::Matrix4x4& aPreviousTransformForRoot, const gfx::Matrix4x4& aCurrentTransformForRoot, - const ScreenMargin& aFixedLayerMargins); + const ScreenMargin& aFixedLayerMargins, + bool aTransformAffectsLayerClip); /** * DRAWING PHASE ONLY diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 28c8f24b12..2dc49a37a6 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -193,7 +193,7 @@ struct Animation { // Number of times to repeat the animation, including positive infinity. // Values <= 0 mean the animation will not play (although events are still // dispatched on the main thread). - float iterationCount; + float iterations; // This uses the NS_STYLE_ANIMATION_DIRECTION_* constants. int32_t direction; nsCSSProperty property; diff --git a/layout/base/BorderConsts.h b/layout/base/BorderConsts.h new file mode 100644 index 0000000000..ce47dad206 --- /dev/null +++ b/layout/base/BorderConsts.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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_BorderConsts_h_ +#define mozilla_BorderConsts_h_ + +// thickness of dashed line relative to dotted line +#define DOT_LENGTH 1 // square +#define DASH_LENGTH 3 // 3 times longer than dot + +// some shorthand for side bits +#define SIDE_BIT_TOP (1 << NS_SIDE_TOP) +#define SIDE_BIT_RIGHT (1 << NS_SIDE_RIGHT) +#define SIDE_BIT_BOTTOM (1 << NS_SIDE_BOTTOM) +#define SIDE_BIT_LEFT (1 << NS_SIDE_LEFT) +#define SIDE_BITS_ALL (SIDE_BIT_TOP|SIDE_BIT_RIGHT|SIDE_BIT_BOTTOM|SIDE_BIT_LEFT) + +#define C_TL NS_CORNER_TOP_LEFT +#define C_TR NS_CORNER_TOP_RIGHT +#define C_BR NS_CORNER_BOTTOM_RIGHT +#define C_BL NS_CORNER_BOTTOM_LEFT + +#endif /* mozilla_BorderConsts_h_ */ diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 2eff22d7fb..49a99eaac9 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -17,6 +17,7 @@ #include "mozilla/HashFunctions.h" #include "mozilla/MathAlgorithms.h" +#include "BorderConsts.h" #include "nsStyleConsts.h" #include "nsPresContext.h" #include "nsIFrame.h" diff --git a/layout/base/nsCSSRenderingBorders.cpp b/layout/base/nsCSSRenderingBorders.cpp index a99d33a823..5ab3532a71 100644 --- a/layout/base/nsCSSRenderingBorders.cpp +++ b/layout/base/nsCSSRenderingBorders.cpp @@ -11,6 +11,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Helpers.h" #include "mozilla/gfx/PathHelpers.h" +#include "BorderConsts.h" #include "nsLayoutUtils.h" #include "nsStyleConsts.h" #include "nsCSSColorUtils.h" @@ -1616,7 +1617,7 @@ nsCSSBorderRenderer::DrawBorders() Float dash = mBorderWidths[0]; strokeOptions.mDashPattern = ‐ strokeOptions.mDashLength = 1; - strokeOptions.mDashOffset = 0.5f; + strokeOptions.mDashOffset = 0.5f * dash; DrawOptions drawOptions; drawOptions.mAntialiasMode = AntialiasMode::NONE; mDrawTarget->StrokeRect(rect, color, strokeOptions, drawOptions); diff --git a/layout/base/nsCSSRenderingBorders.h b/layout/base/nsCSSRenderingBorders.h index 581577847c..951f680da0 100644 --- a/layout/base/nsCSSRenderingBorders.h +++ b/layout/base/nsCSSRenderingBorders.h @@ -28,22 +28,6 @@ class GradientStops; // define this to enable a bunch of debug dump info #undef DEBUG_NEW_BORDERS -//thickness of dashed line relative to dotted line -#define DOT_LENGTH 1 //square -#define DASH_LENGTH 3 //3 times longer than dot - -//some shorthand for side bits -#define SIDE_BIT_TOP (1 << NS_SIDE_TOP) -#define SIDE_BIT_RIGHT (1 << NS_SIDE_RIGHT) -#define SIDE_BIT_BOTTOM (1 << NS_SIDE_BOTTOM) -#define SIDE_BIT_LEFT (1 << NS_SIDE_LEFT) -#define SIDE_BITS_ALL (SIDE_BIT_TOP|SIDE_BIT_RIGHT|SIDE_BIT_BOTTOM|SIDE_BIT_LEFT) - -#define C_TL NS_CORNER_TOP_LEFT -#define C_TR NS_CORNER_TOP_RIGHT -#define C_BR NS_CORNER_BOTTOM_RIGHT -#define C_BL NS_CORNER_BOTTOM_LEFT - /* * Helper class that handles border rendering. * diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index b9cff393f8..0cd7d0417b 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -383,7 +383,9 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty, aLayer->AddAnimationForNextTransaction() : aLayer->AddAnimation(); - const AnimationTiming& timing = aAnimation->GetEffect()->Timing(); + const TimingParams& timing = aAnimation->GetEffect()->SpecifiedTiming(); + const ComputedTiming computedTiming = + aAnimation->GetEffect()->GetComputedTiming(); Nullable startTime = aAnimation->GetCurrentOrPendingStartTime(); animation->startTime() = startTime.IsNull() ? TimeStamp() @@ -391,8 +393,8 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty, StickyTimeDuration(timing.mDelay)); animation->initialCurrentTime() = aAnimation->GetCurrentTime().Value() - timing.mDelay; - animation->duration() = timing.mIterationDuration; - animation->iterationCount() = timing.mIterationCount; + animation->duration() = computedTiming.mDuration; + animation->iterations() = computedTiming.mIterations; animation->direction() = static_cast(timing.mDirection); animation->property() = aProperty.mProperty; animation->playbackRate() = aAnimation->PlaybackRate(); diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index 89cd0fbe4a..a1116bc333 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -35,6 +35,12 @@ const uint32_t nsGridContainerFrame::kAutoLine = kTranslatedMaxLine + 3457U; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TrackSize::StateBits) +enum class GridLineSide +{ + eBeforeGridGap, + eAfterGridGap, +}; + class nsGridContainerFrame::GridItemCSSOrderIterator { public: @@ -914,6 +920,27 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::Tracks void AlignJustifyContent(const nsHTMLReflowState& aReflowState, const LogicalSize& aContainerSize); + nscoord GridLineEdge(uint32_t aLine, GridLineSide aSide) const + { + if (MOZ_UNLIKELY(mSizes.IsEmpty())) { + // https://drafts.csswg.org/css-grid/#grid-definition + // "... the explicit grid still contains one grid line in each axis." + MOZ_ASSERT(aLine == 0, "We should only resolve line 1 in an empty grid"); + return nscoord(0); + } + MOZ_ASSERT(aLine <= mSizes.Length(), "mSizes is too small"); + if (aSide == GridLineSide::eBeforeGridGap) { + if (aLine == 0) { + return nscoord(0); + } + const TrackSize& sz = mSizes[aLine - 1]; + return sz.mPosition + sz.mBase; + } + if (aLine == mSizes.Length()) { + return mContentBoxSize; + } + return mSizes[aLine].mPosition; + } nscoord SumOfGridGaps() const { auto len = mSizes.Length(); @@ -932,6 +959,7 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::Tracks #endif nsAutoTArray mSizes; + nscoord mContentBoxSize; nscoord mGridGap; LogicalAxis mAxis; }; @@ -1041,36 +1069,6 @@ IsNameWithStartSuffix(const nsString& aString, uint32_t* aIndex) return IsNameWithSuffix(aString, NS_LITERAL_STRING("-start"), aIndex); } -enum class GridLineSide { - eBeforeGridGap, - eAfterGridGap, -}; - -static nscoord -GridLineEdge(uint32_t aLine, const nsTArray& aTrackSizes, - GridLineSide aSide) -{ - if (MOZ_UNLIKELY(aTrackSizes.IsEmpty())) { - // https://drafts.csswg.org/css-grid/#grid-definition - // "... the explicit grid still contains one grid line in each axis." - MOZ_ASSERT(aLine == 0, "We should only resolve line 1 in an empty grid"); - return nscoord(0); - } - MOZ_ASSERT(aLine <= aTrackSizes.Length(), "aTrackSizes is too small"); - if (aSide == GridLineSide::eBeforeGridGap) { - if (aLine == 0) { - return aTrackSizes[0].mPosition; - } - const TrackSize& sz = aTrackSizes[aLine - 1]; - return sz.mPosition + sz.mBase; - } - if (aLine == aTrackSizes.Length()) { - const TrackSize& sz = aTrackSizes[aLine - 1]; - return sz.mPosition + sz.mBase; - } - return aTrackSizes[aLine].mPosition; -} - /** * (XXX share this utility function with nsFlexContainerFrame at some point) * @@ -2139,45 +2137,73 @@ nsGridContainerFrame::PlaceGridItems(GridReflowState& aState, } } - // Count empty 'auto-fit' tracks at the end of the repeat() range. + // Count empty 'auto-fit' tracks in the repeat() range. + // |colAdjust| will have a count for each line in the grid of how many + // tracks were empty between the start of the grid and that line. + Maybe> colAdjust; uint32_t numEmptyCols = 0; if (aState.mColFunctions.mHasRepeatAuto && !gridStyle->mGridTemplateColumns.mIsAutoFill && aState.mColFunctions.NumRepeatTracks() > 0) { - for (int32_t start = aState.mColFunctions.mRepeatAutoStart, - col = aState.mColFunctions.mRepeatAutoEnd - 1; - col >= start && mCellMap.IsEmptyCol(col); - --col) { - ++numEmptyCols; + for (uint32_t col = aState.mColFunctions.mRepeatAutoStart, + endRepeat = aState.mColFunctions.mRepeatAutoEnd, + numColLines = mGridColEnd + 1; + col < numColLines; ++col) { + if (numEmptyCols) { + (*colAdjust)[col] = numEmptyCols; + } + if (col < endRepeat && mCellMap.IsEmptyCol(col)) { + ++numEmptyCols; + if (colAdjust.isNothing()) { + colAdjust.emplace(numColLines); + colAdjust->SetLength(numColLines); + PodZero(colAdjust->Elements(), colAdjust->Length()); + } + } } } + Maybe> rowAdjust; uint32_t numEmptyRows = 0; if (aState.mRowFunctions.mHasRepeatAuto && !gridStyle->mGridTemplateRows.mIsAutoFill && aState.mRowFunctions.NumRepeatTracks() > 0) { - for (int32_t start = aState.mRowFunctions.mRepeatAutoStart, - row = aState.mRowFunctions.mRepeatAutoEnd - 1; - row >= start && mCellMap.IsEmptyRow(row); - --row) { - ++numEmptyRows; + for (uint32_t row = aState.mRowFunctions.mRepeatAutoStart, + endRepeat = aState.mRowFunctions.mRepeatAutoEnd, + numRowLines = mGridRowEnd + 1; + row < numRowLines; ++row) { + if (numEmptyRows) { + (*rowAdjust)[row] = numEmptyRows; + } + if (row < endRepeat && mCellMap.IsEmptyRow(row)) { + ++numEmptyRows; + if (rowAdjust.isNothing()) { + rowAdjust.emplace(numRowLines); + rowAdjust->SetLength(numRowLines); + PodZero(rowAdjust->Elements(), rowAdjust->Length()); + } + } } } // Remove the empty 'auto-fit' tracks we found above, if any. if (numEmptyCols || numEmptyRows) { // Adjust the line numbers in the grid areas. - const uint32_t firstRemovedCol = - aState.mColFunctions.mRepeatAutoEnd - numEmptyCols; - const uint32_t firstRemovedRow = - aState.mRowFunctions.mRepeatAutoEnd - numEmptyRows; for (auto& item : mGridItems) { GridArea& area = item.mArea; - area.mCols.AdjustForRemovedTracks(firstRemovedCol, numEmptyCols); - area.mRows.AdjustForRemovedTracks(firstRemovedRow, numEmptyRows); + if (numEmptyCols) { + area.mCols.AdjustForRemovedTracks(*colAdjust); + } + if (numEmptyRows) { + area.mRows.AdjustForRemovedTracks(*rowAdjust); + } } for (auto& item : mAbsPosItems) { GridArea& area = item.mArea; - area.mCols.AdjustAbsPosForRemovedTracks(firstRemovedCol, numEmptyCols); - area.mRows.AdjustAbsPosForRemovedTracks(firstRemovedRow, numEmptyRows); + if (numEmptyCols) { + area.mCols.AdjustAbsPosForRemovedTracks(*colAdjust); + } + if (numEmptyRows) { + area.mRows.AdjustAbsPosForRemovedTracks(*rowAdjust); + } } // Adjust the grid size. mGridColEnd -= numEmptyCols; @@ -2257,6 +2283,7 @@ nsGridContainerFrame::Tracks::Initialize( aFunctions.MaxSizingFor(i)); } mGridGap = aGridGap; + mContentBoxSize = aContentBoxSize; MOZ_ASSERT(mGridGap >= nscoord(0), "negative grid gap"); } @@ -3062,7 +3089,7 @@ nsGridContainerFrame::LineRange::ToLength( void nsGridContainerFrame::LineRange::ToPositionAndLengthForAbsPos( - const nsTArray& aTrackSizes, nscoord aGridOrigin, + const Tracks& aTracks, nscoord aGridOrigin, nscoord* aPos, nscoord* aLength) const { // kAutoLine for abspos children contributes the corresponding edge @@ -3073,18 +3100,17 @@ nsGridContainerFrame::LineRange::ToPositionAndLengthForAbsPos( } else { const nscoord endPos = *aPos + *aLength; nscoord startPos = - ::GridLineEdge(mStart, aTrackSizes, GridLineSide::eAfterGridGap); + aTracks.GridLineEdge(mStart, GridLineSide::eAfterGridGap); *aPos = aGridOrigin + startPos; *aLength = std::max(endPos - *aPos, 0); } } else { if (mStart == kAutoLine) { - nscoord endPos = - ::GridLineEdge(mEnd, aTrackSizes, GridLineSide::eBeforeGridGap); + nscoord endPos = aTracks.GridLineEdge(mEnd, GridLineSide::eBeforeGridGap); *aLength = std::max(aGridOrigin + endPos, 0); } else { nscoord pos; - ToPositionAndLength(aTrackSizes, &pos, aLength); + ToPositionAndLength(aTracks.mSizes, &pos, aLength); *aPos = aGridOrigin + pos; } } @@ -3113,11 +3139,9 @@ nsGridContainerFrame::ContainingBlockForAbsPos(const GridReflowState& aState, nscoord b = aGridCB.BStart(wm); nscoord iSize = aGridCB.ISize(wm); nscoord bSize = aGridCB.BSize(wm); - aArea.mCols.ToPositionAndLengthForAbsPos(aState.mCols.mSizes, - aGridOrigin.I(wm), + aArea.mCols.ToPositionAndLengthForAbsPos(aState.mCols, aGridOrigin.I(wm), &i, &iSize); - aArea.mRows.ToPositionAndLengthForAbsPos(aState.mRows.mSizes, - aGridOrigin.B(wm), + aArea.mRows.ToPositionAndLengthForAbsPos(aState.mRows, aGridOrigin.B(wm), &b, &bSize); return LogicalRect(wm, i, b, iSize, bSize); } @@ -3313,14 +3337,21 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, for (const TrackSize& sz : gridReflowState.mCols.mSizes) { colTrackSizes.AppendElement(sz.mBase); } - Properties().Set(GridColTrackSizes(), - new nsTArray(mozilla::Move(colTrackSizes))); + ComputedGridTrackInfo* colInfo = new ComputedGridTrackInfo( + gridReflowState.mColFunctions.mExplicitGridOffset, + gridReflowState.mColFunctions.NumExplicitTracks(), + Move(colTrackSizes)); + Properties().Set(GridColTrackInfo(), colInfo); + nsTArray rowTrackSizes(gridReflowState.mRows.mSizes.Length()); for (const TrackSize& sz : gridReflowState.mRows.mSizes) { rowTrackSizes.AppendElement(sz.mBase); } - Properties().Set(GridRowTrackSizes(), - new nsTArray(mozilla::Move(rowTrackSizes))); + ComputedGridTrackInfo* rowInfo = new ComputedGridTrackInfo( + gridReflowState.mRowFunctions.mExplicitGridOffset, + gridReflowState.mRowFunctions.NumExplicitTracks(), + Move(rowTrackSizes)); + Properties().Set(GridRowTrackInfo(), rowInfo); nscoord bSize = 0; if (computedBSize == NS_AUTOHEIGHT) { diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h index c41fc5a502..cd43dc7e53 100644 --- a/layout/generic/nsGridContainerFrame.h +++ b/layout/generic/nsGridContainerFrame.h @@ -21,6 +21,25 @@ nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); +namespace mozilla { +/** + * The number of implicit / explicit tracks and their sizes. + */ +struct ComputedGridTrackInfo +{ + ComputedGridTrackInfo(uint32_t aNumLeadingImplicitTracks, + uint32_t aNumExplicitTracks, + nsTArray&& aSizes) + : mNumLeadingImplicitTracks(aNumLeadingImplicitTracks) + , mNumExplicitTracks(aNumExplicitTracks) + , mSizes(aSizes) + {} + uint32_t mNumLeadingImplicitTracks; + uint32_t mNumExplicitTracks; + nsTArray mSizes; +}; +} // namespace mozilla + class nsGridContainerFrame final : public nsContainerFrame { public: @@ -88,18 +107,16 @@ public: NS_DECLARE_FRAME_PROPERTY(GridItemContainingBlockRect, DeleteValue) - NS_DECLARE_FRAME_PROPERTY(GridColTrackSizes, DeleteValue>) - - const nsTArray* GetComputedTemplateColumns() + NS_DECLARE_FRAME_PROPERTY(GridColTrackInfo, DeleteValue) + const ComputedGridTrackInfo* GetComputedTemplateColumns() { - return static_cast*>(Properties().Get(GridColTrackSizes())); + return static_cast(Properties().Get(GridColTrackInfo())); } - NS_DECLARE_FRAME_PROPERTY(GridRowTrackSizes, DeleteValue>) - - const nsTArray* GetComputedTemplateRows() + NS_DECLARE_FRAME_PROPERTY(GridRowTrackInfo, DeleteValue) + const ComputedGridTrackInfo* GetComputedTemplateRows() { - return static_cast*>(Properties().Get(GridRowTrackSizes())); + return static_cast(Properties().Get(GridRowTrackInfo())); } protected: @@ -192,47 +209,34 @@ protected: /** * Translate the lines to account for (empty) removed tracks. This method * is only for grid items and should only be called after placement. + * aNumRemovedTracks contains a count for each line in the grid how many + * tracks were removed between the start of the grid and that line. */ - void AdjustForRemovedTracks(uint32_t aFirstRemovedTrack, - uint32_t aNumRemovedTracks) + void AdjustForRemovedTracks(const nsTArray& aNumRemovedTracks) { MOZ_ASSERT(mStart != kAutoLine, "invalid resolved line for a grid item"); MOZ_ASSERT(mEnd != kAutoLine, "invalid resolved line for a grid item"); - if (mStart >= aFirstRemovedTrack) { - MOZ_ASSERT(mStart >= aFirstRemovedTrack + aNumRemovedTracks, - "can't start in a removed range of tracks - those tracks " - "are supposed to be empty"); - mStart -= aNumRemovedTracks; - mEnd -= aNumRemovedTracks; - } else { - MOZ_ASSERT(mEnd <= aFirstRemovedTrack, "can't span into a removed " - "range of tracks - those tracks are supposed to be empty"); - } + uint32_t numRemovedTracks = aNumRemovedTracks[mStart]; + MOZ_ASSERT(numRemovedTracks == aNumRemovedTracks[mEnd], + "tracks that a grid item spans can't be removed"); + mStart -= numRemovedTracks; + mEnd -= numRemovedTracks; } /** * Translate the lines to account for (empty) removed tracks. This method * is only for abs.pos. children and should only be called after placement. * Same as for in-flow items, but we don't touch 'auto' lines here and we - * also need to adjust areas that span into the removed range. + * also need to adjust areas that span into the removed tracks. */ - void AdjustAbsPosForRemovedTracks(uint32_t aFirstRemovedTrack, - uint32_t aNumRemovedTracks) + void AdjustAbsPosForRemovedTracks(const nsTArray& aNumRemovedTracks) { - if (mStart != nsGridContainerFrame::kAutoLine && - mStart > aFirstRemovedTrack) { - if (mStart < aFirstRemovedTrack + aNumRemovedTracks) { - mStart = aFirstRemovedTrack; - } else { - mStart -= aNumRemovedTracks; - } + if (mStart != nsGridContainerFrame::kAutoLine) { + mStart -= aNumRemovedTracks[mStart]; } - if (mEnd != nsGridContainerFrame::kAutoLine && - mEnd > aFirstRemovedTrack) { - if (mEnd < aFirstRemovedTrack + aNumRemovedTracks) { - mEnd = aFirstRemovedTrack; - } else { - mEnd -= aNumRemovedTracks; - } + if (mEnd != nsGridContainerFrame::kAutoLine) { + MOZ_ASSERT(mStart == nsGridContainerFrame::kAutoLine || + mEnd > mStart, "invalid line range"); + mEnd -= aNumRemovedTracks[mEnd]; } if (mStart == mEnd) { mEnd = nsGridContainerFrame::kAutoLine; @@ -255,12 +259,12 @@ protected: */ nscoord ToLength(const nsTArray& aTrackSizes) const; /** - * Given an array of track sizes and a grid origin coordinate, adjust the + * Given a set of tracks and a grid origin coordinate, adjust the * abs.pos. containing block along an axis given by aPos and aLength. * aPos and aLength should already be initialized to the grid container * containing block for this axis before calling this method. */ - void ToPositionAndLengthForAbsPos(const nsTArray& aTrackSizes, + void ToPositionAndLengthForAbsPos(const Tracks& aTracks, nscoord aGridOrigin, nscoord* aPos, nscoord* aLength) const; diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 7bf3d72810..62649e7123 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -6268,6 +6268,7 @@ void nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM, const gfxPoint& aTextBaselinePt, uint32_t aOffset, uint32_t aLength, + const nscolor* aDecorationOverrideColor, PropertyProvider& aProvider) { auto info = static_cast( @@ -6276,8 +6277,8 @@ nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM, return; } - nscolor color = nsLayoutUtils:: - GetColor(this, eCSSProperty_text_emphasis_color); + nscolor color = aDecorationOverrideColor ? *aDecorationOverrideColor : + nsLayoutUtils::GetColor(this, eCSSProperty_text_emphasis_color); aContext->SetColor(Color::FromABGR(color)); gfxPoint pt(aTextBaselinePt); if (!aWM.IsVertical()) { @@ -6799,7 +6800,8 @@ nsTextFrame::DrawTextRunAndDecorations( aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks); // Emphasis marks - DrawEmphasisMarks(aCtx, wm, aTextBaselinePt, aOffset, aLength, aProvider); + DrawEmphasisMarks(aCtx, wm, aTextBaselinePt, aOffset, aLength, + aDecorationOverrideColor, aProvider); // Line-throughs for (uint32_t i = aDecorations.mStrikes.Length(); i-- > 0; ) { diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index f83d82ff12..904da87b0d 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -460,6 +460,7 @@ public: mozilla::WritingMode aWM, const gfxPoint& aTextBaselinePt, uint32_t aOffset, uint32_t aLength, + const nscolor* aDecorationOverrideColor, PropertyProvider& aProvider); virtual nscolor GetCaretColorAt(int32_t aOffset) override; diff --git a/layout/reftests/css-grid/grid-abspos-items-013-ref.html b/layout/reftests/css-grid/grid-abspos-items-013-ref.html new file mode 100644 index 0000000000..9104efb42a --- /dev/null +++ b/layout/reftests/css-grid/grid-abspos-items-013-ref.html @@ -0,0 +1,133 @@ + + + + + Reference: grid abs.pos. child in grid with gutters + + + + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + diff --git a/layout/reftests/css-grid/grid-abspos-items-013.html b/layout/reftests/css-grid/grid-abspos-items-013.html new file mode 100644 index 0000000000..0793a0c2c9 --- /dev/null +++ b/layout/reftests/css-grid/grid-abspos-items-013.html @@ -0,0 +1,120 @@ + + + + + CSS Grid Test: grid abs.pos. child in grid with gutters + + + + + + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + diff --git a/layout/reftests/css-grid/grid-placement-abspos-implicit-001-ref.html b/layout/reftests/css-grid/grid-placement-abspos-implicit-001-ref.html index c01334985b..3c9999f850 100644 --- a/layout/reftests/css-grid/grid-placement-abspos-implicit-001-ref.html +++ b/layout/reftests/css-grid/grid-placement-abspos-implicit-001-ref.html @@ -45,8 +45,8 @@ body,html { color:black; background:white; font-size:16px; padding:0; margin:0; width: 51px; height: 2px; } .d { - left: 1px; top: 11px; - width: 212px; height: 1px; + left: 1px; top: 5px; + width: 212px; height: 7px; } .e { right: 5px; bottom: 1px; @@ -98,7 +98,7 @@ span {
-d +
diff --git a/layout/reftests/css-grid/grid-placement-abspos-implicit-001.html b/layout/reftests/css-grid/grid-placement-abspos-implicit-001.html index dd44d083fb..98e026bace 100644 --- a/layout/reftests/css-grid/grid-placement-abspos-implicit-001.html +++ b/layout/reftests/css-grid/grid-placement-abspos-implicit-001.html @@ -52,6 +52,7 @@ span.negative { .d { grid-column: auto / A -3; grid-row: 2 / 1; + top: -3px; } .e { grid-column: A -3 / auto; @@ -111,7 +112,7 @@ span {
-d +
diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-005-ref.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-005-ref.html index 7c29879df3..0a4103f04b 100644 --- a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-005-ref.html +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-005-ref.html @@ -28,7 +28,8 @@ html,body { .r0 { grid-template-rows: [a] repeat(1, [b] 0 [c]) [d]; } .r10,.r1 { grid-template-rows: [a] repeat(1, [b] 20px [c]) [d]; } -.r01 { grid-template-rows: [a] repeat(1, [b] 0 [c]) [d]; } +.r01 { grid-template-rows: [a] repeat(1, [b] 0 [c]) 20px [d]; grid-gap:0;} +.r01 a {grid-row-end:auto; } .r2 { grid-template-rows: [a] repeat(1, [b] 20px [c]) [d] 30px [e]; } .r20 { width:22px; grid-template-rows: [a] repeat(1, [b] 20px [c]) [d] 30px [e]; } .r02 { grid-template-rows: [a] repeat(1, [b] 0 [c]) [d] 30px [e]; } @@ -274,11 +275,11 @@ fill,fit {
-
+
-
+

diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-007-ref.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-007-ref.html new file mode 100644 index 0000000000..81ba8aff8f --- /dev/null +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-007-ref.html @@ -0,0 +1,177 @@ + + + + + Reference: repeat(auto-fit) with grid-aligned abs.pos. with removed start/middle tracks + + + + + + +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + +
+
+
+ +
+
+
+
+ + + diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-007.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-007.html new file mode 100644 index 0000000000..d8fae6faa8 --- /dev/null +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-007.html @@ -0,0 +1,195 @@ + + + + + CSS Grid Test: repeat(auto-fit) with grid-aligned abs.pos. with removed start/middle tracks + + + + + + + + +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + +
+
+
+ +
+
+
+
+ + + + + diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-008-ref.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-008-ref.html new file mode 100644 index 0000000000..96f606682a --- /dev/null +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-008-ref.html @@ -0,0 +1,194 @@ + + + + + CSS Grid Test: repeat(auto-fit) with grid-aligned abs.pos. with removed start/middle tracks and implicit tracks on either/both sides + + + + + + +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + +
+
+
+ +
+
+
+
+ + + diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-008.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-008.html new file mode 100644 index 0000000000..3f8faafebd --- /dev/null +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-008.html @@ -0,0 +1,204 @@ + + + + + CSS Grid Test: repeat(auto-fit) with grid-aligned abs.pos. with removed start/middle tracks and implicit tracks on either/both sides + + + + + + + + +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + +
+
+
+ +
+
+
+
+ + + + + diff --git a/layout/reftests/css-grid/reftest.list b/layout/reftests/css-grid/reftest.list index 3cad9b04d8..7381660017 100644 --- a/layout/reftests/css-grid/reftest.list +++ b/layout/reftests/css-grid/reftest.list @@ -24,6 +24,7 @@ fails == grid-whitespace-handling-1b.xhtml grid-whitespace-handling-1-ref.xhtml == grid-abspos-items-010.html grid-abspos-items-010-ref.html == grid-abspos-items-011.html grid-abspos-items-011-ref.html == grid-abspos-items-012.html grid-abspos-items-012-ref.html +== grid-abspos-items-013.html grid-abspos-items-013-ref.html == grid-order-abspos-items-001.html grid-order-abspos-items-001-ref.html == grid-order-placement-auto-001.html grid-order-placement-auto-001-ref.html == grid-order-placement-definite-001.html grid-order-placement-definite-001-ref.html @@ -96,3 +97,5 @@ fuzzy-if(winWidget,1,36) == grid-auto-min-sizing-definite-001.html grid-auto-min == grid-repeat-auto-fill-fit-004.html grid-repeat-auto-fill-fit-004-ref.html == grid-repeat-auto-fill-fit-005.html grid-repeat-auto-fill-fit-005-ref.html == grid-repeat-auto-fill-fit-006.html grid-repeat-auto-fill-fit-006-ref.html +== grid-repeat-auto-fill-fit-007.html grid-repeat-auto-fill-fit-007-ref.html +== grid-repeat-auto-fill-fit-008.html grid-repeat-auto-fill-fit-008-ref.html diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index 0e239cf48b..d6c023ef20 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -262,10 +262,9 @@ CSSAnimation::QueueEvents() StickyTimeDuration elapsedTime; if (message == eAnimationStart || message == eAnimationIteration) { - TimeDuration iterationStart = mEffect->Timing().mIterationDuration * - computedTiming.mCurrentIteration; - elapsedTime = StickyTimeDuration(std::max(iterationStart, - InitialAdvance())); + StickyTimeDuration iterationStart = computedTiming.mDuration * + computedTiming.mCurrentIteration; + elapsedTime = std::max(iterationStart, StickyTimeDuration(InitialAdvance())); } else { MOZ_ASSERT(message == eAnimationEnd); elapsedTime = computedTiming.mActiveDuration; @@ -309,7 +308,8 @@ CSSAnimation::ElapsedTimeToTimeStamp(const StickyTimeDuration& return result; } - result = AnimationTimeToTimeStamp(aElapsedTime + mEffect->Timing().mDelay); + result = AnimationTimeToTimeStamp(aElapsedTime + + mEffect->SpecifiedTiming().mDelay); return result; } @@ -442,9 +442,9 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, KeyframeEffectReadOnly* oldEffect = oldAnim->GetEffect(); KeyframeEffectReadOnly* newEffect = newAnim->GetEffect(); animationChanged = - oldEffect->Timing() != newEffect->Timing() || + oldEffect->SpecifiedTiming() != newEffect->SpecifiedTiming() || oldEffect->Properties() != newEffect->Properties(); - oldEffect->SetTiming(newEffect->Timing()); + oldEffect->SetSpecifiedTiming(newEffect->SpecifiedTiming()); oldEffect->CopyPropertiesFrom(*newEffect); } @@ -644,13 +644,12 @@ nsAnimationManager::BuildAnimations(nsStyleContext* aStyleContext, dest->SetAnimationIndex(static_cast(animIdx)); aAnimations.AppendElement(dest); - AnimationTiming timing; - timing.mIterationDuration = - TimeDuration::FromMilliseconds(src.GetDuration()); + TimingParams timing; + timing.mDuration.SetAsUnrestrictedDouble() = src.GetDuration(); timing.mDelay = TimeDuration::FromMilliseconds(src.GetDelay()); - timing.mIterationCount = src.GetIterationCount(); + timing.mIterations = src.GetIterationCount(); timing.mDirection = src.GetDirection(); - timing.mFillMode = src.GetFillMode(); + timing.mFill = src.GetFillMode(); RefPtr destEffect = new KeyframeEffectReadOnly(mPresContext->Document(), aTarget, diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h index 558001567d..6aa1cd2731 100644 --- a/layout/style/nsAnimationManager.h +++ b/layout/style/nsAnimationManager.h @@ -169,11 +169,11 @@ protected: // Returns the duration from the start of the animation's source effect's // active interval to the point where the animation actually begins playback. // This is zero unless the animation's source effect has a negative delay in - // which // case it is the absolute value of that delay. + // which case it is the absolute value of that delay. // This is used for setting the elapsedTime member of CSS AnimationEvents. TimeDuration InitialAdvance() const { return mEffect ? - std::max(TimeDuration(), mEffect->Timing().mDelay * -1) : + std::max(TimeDuration(), mEffect->SpecifiedTiming().mDelay * -1) : TimeDuration(); } // Converts an AnimationEvent's elapsedTime value to an equivalent TimeStamp diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 72341c1a0c..696b5f2b33 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -2454,8 +2454,9 @@ nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue, } already_AddRefed -nsComputedDOMStyle::GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrackList, - const nsTArray* aTrackSizes) +nsComputedDOMStyle::GetGridTemplateColumnsRows( + const nsStyleGridTemplate& aTrackList, + const ComputedGridTrackInfo* aTrackInfo) { if (aTrackList.mIsSubgrid) { // XXX TODO: add support for repeat(auto-fill) for 'subgrid' (bug 1234311) @@ -2491,76 +2492,102 @@ nsComputedDOMStyle::GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrack uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length(); MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes, "Different number of min and max track sizing functions"); - if (aTrackSizes) { - numSizes = aTrackSizes->Length(); - MOZ_ASSERT(numSizes > 0 || - (aTrackList.HasRepeatAuto() && !aTrackList.mIsAutoFill), - "only 'auto-fit' can result in zero tracks"); + if (aTrackInfo) { + DebugOnly isAutoFill = + aTrackList.HasRepeatAuto() && aTrackList.mIsAutoFill; + DebugOnly isAutoFit = + aTrackList.HasRepeatAuto() && !aTrackList.mIsAutoFill; + DebugOnly numExplicitTracks = aTrackInfo->mNumExplicitTracks; + MOZ_ASSERT(numExplicitTracks == numSizes || + (isAutoFill && numExplicitTracks >= numSizes) || + (isAutoFit && numExplicitTracks + 1 >= numSizes), + "expected all explicit tracks (or possibly one less, if there's " + "an 'auto-fit' track, since that can collapse away)"); + numSizes = aTrackInfo->mSizes.Length(); } + // An empty is represented as "none" in syntax. if (numSizes == 0) { RefPtr val = new nsROCSSPrimitiveValue; val->SetIdent(eCSSKeyword_none); return val.forget(); } - // Delimiting N (specified) tracks requires N+1 lines: - // one before each track, plus one at the very end. - MOZ_ASSERT(aTrackList.mLineNameLists.Length() == - aTrackList.mMinTrackSizingFunctions.Length() + 1, - "Unexpected number of line name lists"); RefPtr valueList = GetROCSSValueList(false); - if (aTrackSizes) { + if (aTrackInfo) { // We've done layout on the grid and have resolved the sizes of its tracks, // so we'll return those sizes here. The grid spec says we MAY use // repeat(, Npx) here for consecutive tracks with the same // size, but that doesn't seem worth doing since even for repeat(auto-*) // the resolved size might differ for the repeated tracks. - int32_t endOfRepeat = 0; // first index after any repeat() tracks - int32_t offsetToLastRepeat = 0; - if (aTrackList.HasRepeatAuto()) { - // offsetToLastRepeat is -1 if all repeat(auto-fit) tracks are empty - offsetToLastRepeat = numSizes + 1 - aTrackList.mLineNameLists.Length(); - endOfRepeat = aTrackList.mRepeatAutoIndex + offsetToLastRepeat + 1; + const nsTArray& trackSizes = aTrackInfo->mSizes; + const uint32_t numExplicitTracks = aTrackInfo->mNumExplicitTracks; + const uint32_t numLeadingImplicitTracks = aTrackInfo->mNumLeadingImplicitTracks; + MOZ_ASSERT(numSizes > 0 && + numSizes >= numLeadingImplicitTracks + numExplicitTracks); + + // Add any leading implicit tracks. + for (uint32_t i = 0; i < numLeadingImplicitTracks; ++i) { + RefPtr val = new nsROCSSPrimitiveValue; + val->SetAppUnits(trackSizes[i]); + valueList->AppendCSSValue(val.forget()); } - MOZ_ASSERT(numSizes > 0); - for (int32_t i = 0;; i++) { + + // Then add any explicit tracks. + if (numExplicitTracks) { + int32_t endOfRepeat = 0; // first index after any repeat() tracks + int32_t offsetToLastRepeat = 0; if (aTrackList.HasRepeatAuto()) { - if (i == aTrackList.mRepeatAutoIndex) { - const nsTArray& lineNames = aTrackList.mLineNameLists[i]; - if (i == endOfRepeat) { - // all auto-fit tracks are empty, so "[a] repeat(...) [b]" - // becomes "[a b]" - AppendGridLineNames(valueList, lineNames, - aTrackList.mLineNameLists[i + 1]); - } else { - AppendGridLineNames(valueList, lineNames, + // offsetToLastRepeat is -1 if all repeat(auto-fit) tracks are empty + offsetToLastRepeat = numExplicitTracks + 1 - aTrackList.mLineNameLists.Length(); + endOfRepeat = aTrackList.mRepeatAutoIndex + offsetToLastRepeat + 1; + } + for (int32_t i = 0;; i++) { + if (aTrackList.HasRepeatAuto()) { + if (i == aTrackList.mRepeatAutoIndex) { + const nsTArray& lineNames = aTrackList.mLineNameLists[i]; + if (i == endOfRepeat) { + // all auto-fit tracks are empty, so "[a] repeat(...) [b]" + // becomes "[a b]" + AppendGridLineNames(valueList, lineNames, + aTrackList.mLineNameLists[i + 1]); + } else { + AppendGridLineNames(valueList, lineNames, + aTrackList.mRepeatAutoLineNameListBefore); + } + } else if (i == endOfRepeat) { + const nsTArray& lineNames = + aTrackList.mLineNameLists[aTrackList.mRepeatAutoIndex + 1]; + AppendGridLineNames(valueList, + aTrackList.mRepeatAutoLineNameListAfter, + lineNames); + } else if (i > aTrackList.mRepeatAutoIndex && i < endOfRepeat) { + AppendGridLineNames(valueList, + aTrackList.mRepeatAutoLineNameListAfter, aTrackList.mRepeatAutoLineNameListBefore); + } else { + uint32_t j = i > endOfRepeat ? i - offsetToLastRepeat : i; + const nsTArray& lineNames = aTrackList.mLineNameLists[j]; + AppendGridLineNames(valueList, lineNames); } - } else if (i == endOfRepeat) { - const nsTArray& lineNames = - aTrackList.mLineNameLists[aTrackList.mRepeatAutoIndex + 1]; - AppendGridLineNames(valueList, - aTrackList.mRepeatAutoLineNameListAfter, - lineNames); - } else if (i > aTrackList.mRepeatAutoIndex && i < endOfRepeat) { - AppendGridLineNames(valueList, - aTrackList.mRepeatAutoLineNameListAfter, - aTrackList.mRepeatAutoLineNameListBefore); } else { - uint32_t j = i > endOfRepeat ? i - offsetToLastRepeat : i; - const nsTArray& lineNames = aTrackList.mLineNameLists[j]; + const nsTArray& lineNames = aTrackList.mLineNameLists[i]; AppendGridLineNames(valueList, lineNames); } - } else { - const nsTArray& lineNames = aTrackList.mLineNameLists[i]; - AppendGridLineNames(valueList, lineNames); - } - if (uint32_t(i) == numSizes) { - break; + if (uint32_t(i) == numExplicitTracks) { + break; + } + RefPtr val = new nsROCSSPrimitiveValue; + val->SetAppUnits(trackSizes[i + numLeadingImplicitTracks]); + valueList->AppendCSSValue(val.forget()); } + } + + // Add any trailing implicit tracks. + for (uint32_t i = numLeadingImplicitTracks + numExplicitTracks; + i < numSizes; ++i) { RefPtr val = new nsROCSSPrimitiveValue; - val->SetAppUnits((*aTrackSizes)[i]); + val->SetAppUnits(trackSizes[i]); valueList->AppendCSSValue(val.forget()); } } else { @@ -2634,31 +2661,31 @@ nsComputedDOMStyle::DoGetGridAutoRows() already_AddRefed nsComputedDOMStyle::DoGetGridTemplateColumns() { - const nsTArray* trackSizes = nullptr; + const ComputedGridTrackInfo* info = nullptr; if (mInnerFrame) { nsIFrame* gridContainerCandidate = mInnerFrame->GetContentInsertionFrame(); if (gridContainerCandidate && gridContainerCandidate->GetType() == nsGkAtoms::gridContainerFrame) { - auto gridContainer = static_cast(gridContainerCandidate); - trackSizes = gridContainer->GetComputedTemplateColumns(); + info = static_cast(gridContainerCandidate)-> + GetComputedTemplateColumns(); } } - return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns, trackSizes); + return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns, info); } already_AddRefed nsComputedDOMStyle::DoGetGridTemplateRows() { - const nsTArray* trackSizes = nullptr; + const ComputedGridTrackInfo* info = nullptr; if (mInnerFrame) { nsIFrame* gridContainerCandidate = mInnerFrame->GetContentInsertionFrame(); if (gridContainerCandidate && gridContainerCandidate->GetType() == nsGkAtoms::gridContainerFrame) { - auto gridContainer = static_cast(gridContainerCandidate); - trackSizes = gridContainer->GetComputedTemplateRows(); - } + info = static_cast(gridContainerCandidate)-> + GetComputedTemplateRows(); + } } - return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows, trackSizes); + return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows, info); } already_AddRefed diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index df04293ce6..ea0b97999a 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -27,6 +27,7 @@ namespace mozilla { namespace dom { class Element; } // namespace dom +struct ComputedGridTrackInfo; } // namespace mozilla struct nsComputedStyleMap; @@ -190,7 +191,7 @@ private: const nsStyleCoord& aMaxSize); already_AddRefed GetGridTemplateColumnsRows( const nsStyleGridTemplate& aTrackList, - const nsTArray* aTrackSizes); + const mozilla::ComputedGridTrackInfo* aTrackInfo); already_AddRefed GetGridLine(const nsStyleGridLine& aGridLine); bool GetLineHeightCoord(nscoord& aCoord); diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index aa7a3becac..ad8e6d1e1e 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -55,8 +55,8 @@ ElementPropertyTransition::CurrentValuePortion() const // causing us to get called *after* the animation interval. So, just in // case, we override the fill mode to 'both' to ensure the progress // is never null. - AnimationTiming timingToUse = mTiming; - timingToUse.mFillMode = dom::FillMode::Both; + TimingParams timingToUse = SpecifiedTiming(); + timingToUse.mFill = dom::FillMode::Both; ComputedTiming computedTiming = GetComputedTiming(&timingToUse); MOZ_ASSERT(!computedTiming.mProgress.IsNull(), @@ -150,7 +150,8 @@ CSSTransition::QueueEvents() nsTransitionManager* manager = presContext->TransitionManager(); manager->QueueEvent(TransitionEventInfo(owningElement, owningPseudoType, property, - mEffect->Timing().mIterationDuration, + mEffect->GetComputedTiming() + .mDuration, AnimationTimeToTimeStamp(EffectEnd()), this)); } @@ -665,12 +666,12 @@ nsTransitionManager::ConsiderStartingTransition( reversePortion = valuePortion; } - AnimationTiming timing; - timing.mIterationDuration = TimeDuration::FromMilliseconds(duration); + TimingParams timing; + timing.mDuration.SetAsUnrestrictedDouble() = duration; timing.mDelay = TimeDuration::FromMilliseconds(delay); - timing.mIterationCount = 1; + timing.mIterations = 1.0; timing.mDirection = dom::PlaybackDirection::Normal; - timing.mFillMode = dom::FillMode::Backwards; + timing.mFill = dom::FillMode::Backwards; RefPtr pt = new ElementPropertyTransition(aElement->OwnerDoc(), aElement, diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index 6b873bbc0c..134a018983 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -38,7 +38,7 @@ struct ElementPropertyTransition : public dom::KeyframeEffectReadOnly ElementPropertyTransition(nsIDocument* aDocument, dom::Element* aTarget, nsCSSPseudoElements::Type aPseudoType, - const AnimationTiming &aTiming) + const TimingParams &aTiming) : dom::KeyframeEffectReadOnly(aDocument, aTarget, aPseudoType, aTiming) { } @@ -214,7 +214,7 @@ struct TransitionEventInfo { TransitionEventInfo(dom::Element* aElement, nsCSSPseudoElements::Type aPseudoType, nsCSSProperty aProperty, - TimeDuration aDuration, + StickyTimeDuration aDuration, const TimeStamp& aTimeStamp, dom::Animation* aAnimation) : mElement(aElement) diff --git a/layout/style/test/test_grid_computed_values.html b/layout/style/test/test_grid_computed_values.html index 0ee0689a08..de77fec340 100644 --- a/layout/style/test/test_grid_computed_values.html +++ b/layout/style/test/test_grid_computed_values.html @@ -26,6 +26,13 @@ grid-auto-columns: 3fr; grid-auto-rows: 2fr; } + #grid2 { + display: grid; + width: 500px; + height: 400px; + grid-auto-columns: 10px; + grid-auto-rows: 2fr; + } @@ -36,6 +43,10 @@
+
+
+
+
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 8fa85b554c..6e81a06536 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2815,6 +2815,9 @@ pref("layout.float-fragments-inside-column.enabled", true); #endif // Is support for the Web Animations API enabled? +// Before enabling this by default, make sure also CSSPseudoElement interface +// has been spec'ed properly, or we should add a separate pref for +// CSSPseudoElement interface. See Bug 1174575 for further details. #ifdef RELEASE_BUILD pref("dom.animations-api.core.enabled", false); #else diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 27f9441a0b..ad3755d646 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -18789,6 +18789,10 @@ "path": "vibration/silent-ignore.html", "url": "/vibration/silent-ignore.html" }, + { + "path": "web-animations/animatable/animate.html", + "url": "/web-animations/animatable/animate.html" + }, { "path": "web-animations/animation-node/animation-node-after.html", "url": "/web-animations/animation-node/animation-node-after.html" @@ -21469,6 +21473,14 @@ "path": "web-animations/keyframe-effect/constructor.html", "url": "/web-animations/keyframe-effect/constructor.html" }, + { + "path": "web-animations/keyframe-effect/getComputedTiming.html", + "url": "/web-animations/keyframe-effect/getComputedTiming.html" + }, + { + "path": "web-animations/animation/constructor.html", + "url": "/web-animations/animation/constructor.html" + }, { "path": "webdriver/user_input/clear_test.py" } diff --git a/testing/web-platform/meta/web-animations/animatable/animate.html.ini b/testing/web-platform/meta/web-animations/animatable/animate.html.ini new file mode 100644 index 0000000000..cc950d3cf4 --- /dev/null +++ b/testing/web-platform/meta/web-animations/animatable/animate.html.ini @@ -0,0 +1,8 @@ +[animate.html] + type: testharness + [Element.animate() creates an Animation object with a KeyframeEffect] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1211783 + [Element.animate() accepts a single-valued keyframe specification] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1216844 diff --git a/testing/web-platform/meta/web-animations/animation/constructor.html.ini b/testing/web-platform/meta/web-animations/animation/constructor.html.ini new file mode 100644 index 0000000000..7ad2742a8e --- /dev/null +++ b/testing/web-platform/meta/web-animations/animation/constructor.html.ini @@ -0,0 +1,13 @@ +[constructor.html] + type: testharness + [Animation can be constructed with null effect and null timeline] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1049975 + + [Animation can be constructed with null effect and non-null timeline] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1049975 + + [Animation can be constructed with non-null effect and null timeline] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1096776 diff --git a/testing/web-platform/tests/web-animations/animatable/animate.html b/testing/web-platform/tests/web-animations/animatable/animate.html new file mode 100644 index 0000000000..d649aef28a --- /dev/null +++ b/testing/web-platform/tests/web-animations/animatable/animate.html @@ -0,0 +1,126 @@ + + +Animatable.animate tests + + + + + + + +
+ + + diff --git a/testing/web-platform/tests/web-animations/animation/constructor.html b/testing/web-platform/tests/web-animations/animation/constructor.html new file mode 100644 index 0000000000..dcb09a2136 --- /dev/null +++ b/testing/web-platform/tests/web-animations/animation/constructor.html @@ -0,0 +1,60 @@ + + +Animation constructor tests + + + + + + + +
+
+ + diff --git a/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html b/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html index 2e549fef37..edc5f4552b 100644 --- a/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html +++ b/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html @@ -449,6 +449,186 @@ gKeyframeSequenceTests.forEach(function(subtest) { " roundtrips"); }); + +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"); + assert_equals(timing.fill, "auto", "default fill"); + assert_equals(timing.iterations, 1.0, "default iterations"); + assert_equals(timing.iterationStart, 0.0, "default iterationStart"); + assert_equals(timing.duration, "auto", "default duration"); + assert_equals(timing.direction, "normal", "default direction"); + assert_equals(timing.easing, "linear", "default easing"); + + assert_equals(effect.composite, "replace", "default composite"); + assert_equals(effect.iterationComposite, "replace", + "default iterationComposite"); + assert_equals(effect.spacing, "distribute", + "default spacing"); +}, "a KeyframeEffectReadOnly constructed without any " + + "KeyframeEffectOptions object"); + +var gKeyframeEffectOptionTests = [ + { desc: "an empty KeyframeEffectOption", + input: {}, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: "auto", + direction: "normal"} }, + { desc: "a normal KeyframeEffectOption", + input: {delay: 1000, + fill: "auto", + iterations: 5.5, + duration: "auto", + direction: "alternate"}, + expected: {delay: 1000, + fill: "auto", + iterations: 5.5, + duration: "auto", + direction: "alternate"} }, + { desc: "a double value", + input: 3000, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: 3000, + direction: "normal"} }, + { desc: "+Infinity", + input: Infinity, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: Infinity, + direction: "normal"} }, + { desc: "-Infinity", + input: -Infinity, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: -Infinity, + direction: "normal"} }, + { desc: "NaN", + input: NaN, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: NaN, + direction: "normal"} }, + { desc: "a negative value", + input: -1, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: -1, + direction: "normal"} }, + { desc: "an Infinity duration", + input: {duration: Infinity}, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: Infinity, + direction: "normal"} }, + { desc: "a negative Infinity duration", + input: {duration: -Infinity}, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: -Infinity, + direction: "normal"} }, + { desc: "a NaN duration", + input: {duration: NaN}, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: NaN, + direction: "normal"} }, + { desc: "a negative duration", + input: {duration: -1}, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: -1, + direction: "normal"} }, + { desc: "a string duration", + input: {duration: "merrychristmas"}, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: "merrychristmas", + direction: "normal"} }, + { desc: "an auto duration", + input: {duration: "auto"}, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: "auto", + direction: "normal"} }, + { desc: "an Infinity iterations", + input: {iterations: Infinity}, + expected: {delay: 0, + fill: "auto", + iterations: Infinity, + duration: "auto", + direction: "normal"} }, + { desc: "a negative Infinity iterations", + input: {iterations: -Infinity}, + expected: {delay: 0, + fill: "auto", + iterations: -Infinity, + duration: "auto", + direction: "normal"} }, + { desc: "a NaN iterations", + input: {iterations: NaN}, + expected: {delay: 0, + fill: "auto", + iterations: NaN, + duration: "auto", + direction: "normal"} }, + { desc: "a negative iterations", + input: {iterations: -1}, + expected: {delay: 0, + fill: "auto", + iterations: -1, + duration: "auto", + direction: "normal"} }, + { desc: "an auto fill", + input: {fill: "auto"}, + expected: {delay: 0, + fill: "auto", + iterations: 1, + duration: "auto", + direction: "normal"} }, + { desc: "a forwards fill", + input: {fill: "forwards"}, + expected: {delay: 0, + fill: "forwards", + iterations: 1, + duration: "auto", + direction: "normal"} } +]; + +gKeyframeEffectOptionTests.forEach(function(stest) { + test(function(t) { + var effect = new KeyframeEffectReadOnly(target, + {left: ["10px", "20px"]}, + stest.input); + + var timing = effect.timing; + assert_equals(timing.delay, stest.expected.delay, "timing delay"); + assert_equals(timing.fill, stest.expected.fill, "timing fill"); + assert_equals(timing.iterations, stest.expected.iterations, + "timing iterations"); + assert_equals(timing.duration, stest.expected.duration, "timing duration"); + assert_equals(timing.direction, stest.expected.direction, + "timing direction"); + }, "a KeyframeEffectReadOnly constructed by " + stest.desc); +}); + done(); diff --git a/testing/web-platform/tests/web-animations/keyframe-effect/getComputedTiming.html b/testing/web-platform/tests/web-animations/keyframe-effect/getComputedTiming.html new file mode 100644 index 0000000000..320cd78141 --- /dev/null +++ b/testing/web-platform/tests/web-animations/keyframe-effect/getComputedTiming.html @@ -0,0 +1,195 @@ + + +KeyframeEffectReadOnly getComputedTiming() tests + + + + + + + +
+
+ + diff --git a/testing/web-platform/tests/web-animations/testcommon.js b/testing/web-platform/tests/web-animations/testcommon.js index 5a704bb4dc..d9876c30f5 100644 --- a/testing/web-platform/tests/web-animations/testcommon.js +++ b/testing/web-platform/tests/web-animations/testcommon.js @@ -34,7 +34,7 @@ function newAnimation(animationTarget) { } // creates div element, appends it to the document body and -// add removing of the created element to test cleanup +// removes the created element during test cleanup function createDiv(test, doc) { if (!doc) { doc = document;