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)
This commit is contained in:
2023-11-09 09:50:40 +08:00
parent 3e34b8d21b
commit 98491d0687
83 changed files with 2917 additions and 489 deletions
+36 -1
View File
@@ -81,6 +81,41 @@ namespace {
// Animation interface:
//
// ---------------------------------------------------------------------------
/* static */ already_AddRefed<Animation>
Animation::Constructor(const GlobalObject& aGlobal,
KeyframeEffectReadOnly* aEffect,
AnimationTimeline* aTimeline,
ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<Animation> 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;
}
+9 -1
View File
@@ -90,7 +90,13 @@ public:
};
// Animation interface methods
static already_AddRefed<Animation>
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
+4 -3
View File
@@ -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<AnimationEffectTimingReadOnly> Timing() const = 0;
virtual void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const = 0;
protected:
virtual ~AnimationEffectReadOnly() = default;
@@ -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<JSObject*> aGivenProto)
{
return AnimationEffectTimingReadOnlyBinding::Wrap(aCx, this, aGivenProto);
}
} // namespace dom
} // namespace mozilla
@@ -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<TimeDuration>.
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<JSObject*> 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<nsISupports> mParent;
TimingParams mTiming;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_AnimationEffectTimingReadOnly_h
+44
View File
@@ -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<JSObject*> aGivenProto)
{
return CSSPseudoElementBinding::Wrap(aCx, this, aGivenProto);
}
void
CSSPseudoElement::GetAnimations(nsTArray<RefPtr<Animation>>& aRetVal)
{
// Bug 1234403: Implement this API.
NS_NOTREACHED("CSSPseudoElement::GetAnimations() is not implemented yet.");
}
already_AddRefed<Animation>
CSSPseudoElement::Animate(
JSContext* aContext,
JS::Handle<JSObject*> 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
+56
View File
@@ -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<JSObject*> aGivenProto) override;
void GetType(nsString& aRetVal) const { }
already_AddRefed<Element> ParentElement() const { return nullptr; }
void GetAnimations(nsTArray<RefPtr<Animation>>& aRetVal);
already_AddRefed<Animation>
Animate(JSContext* aContext,
JS::Handle<JSObject*> aFrames,
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
ErrorResult& aError);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_CSSPseudoElement_h
+1 -1
View File
@@ -50,4 +50,4 @@ private:
} // namespace mozilla
#endif // mozilla_dom_AnimationEffectReadOnly_h
#endif // mozilla_ComputedTimingFunction_h
+67 -121
View File
@@ -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<TimeDuration>& 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<AnimationEffectTimingReadOnly>
KeyframeEffectReadOnly::Timing() const
{
if (mTiming == aTiming) {
RefPtr<AnimationEffectTimingReadOnly> 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<TimeDuration> currentTime = GetLocalTime();
GetComputedTimingDictionary(GetComputedTimingAt(currentTime, mTiming),
GetComputedTimingDictionary(GetComputedTimingAt(currentTime,
SpecifiedTiming()),
currentTime,
mTiming,
SpecifiedTiming(),
aRetVal);
}
ComputedTiming
KeyframeEffectReadOnly::GetComputedTimingAt(
const Nullable<TimeDuration>& 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<uint64_t>(aTiming.mIterationCount) - 1;
: static_cast<uint64_t>(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<uint64_t>(aTiming.mIterationCount) // floor
? static_cast<uint64_t>(result.mIterations) // floor
: 0;
} else {
result.mCurrentIteration =
static_cast<uint64_t>(activeTime / aTiming.mIterationDuration); // floor
static_cast<uint64_t>(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<float>()) {
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<AnimationProperty>& aAnimationProperties)
}
#endif
// Extract an iteration duration from an UnrestrictedDoubleOrXXX object.
template <typename T>
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<JS::Handle<JSObject*>>& aFrames,
JS::Handle<JSObject*> aFrames,
InfallibleTArray<AnimationProperty>& 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<Keyframe> first, and if that fails due to not being iterable,
// we try to convert it to PropertyIndexedKeyframes.
JS::Rooted<JS::Value> objectValue(aCx, JS::ObjectValue(*aFrames.Value()));
JS::Rooted<JS::Value> 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<JS::Handle<JSObject*>>& aFrames,
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
JS::Handle<JSObject*> aFrames,
const TimingParams& aTiming,
ErrorResult& aRv)
{
if (!aTarget) {
@@ -1723,8 +1671,6 @@ KeyframeEffectReadOnly::Constructor(
return nullptr;
}
AnimationTiming timing = ConvertKeyframeEffectOptions(aOptions);
InfallibleTArray<AnimationProperty> animationProperties;
BuildAnimationPropertyList(aGlobal.Context(), aTarget, aFrames,
animationProperties, aRv);
@@ -1736,7 +1682,7 @@ KeyframeEffectReadOnly::Constructor(
RefPtr<KeyframeEffectReadOnly> effect =
new KeyframeEffectReadOnly(aTarget->OwnerDoc(), aTarget,
nsCSSPseudoElements::ePseudo_NotPseudoElement,
timing);
aTiming);
effect->mProperties = Move(animationProperties);
return effect.forget();
}
+55 -45
View File
@@ -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<float>() 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<double> 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<KeyframeEffectReadOnly>
Constructor(const GlobalObject& aGlobal,
Element* aTarget,
const Optional<JS::Handle<JSObject*>>& aFrames,
JS::Handle<JSObject*> 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<KeyframeEffectReadOnly>
Constructor(const GlobalObject& aGlobal,
Element* aTarget,
JS::Handle<JSObject*> 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<AnimationEffectTimingReadOnly> Timing() const override;
const TimingParams& SpecifiedTiming() const
{
return mTiming->AsTimingParams();
}
void SetSpecifiedTiming(const TimingParams& aTiming);
void NotifyAnimationTimingUpdated();
Nullable<TimeDuration> 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<TimeDuration>& 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<JS::Handle<JSObject*>>& aFrames,
JS::Handle<JSObject*> aFrames,
InfallibleTArray<AnimationProperty>& aResult,
ErrorResult& aRv);
nsCOMPtr<Element> mTarget;
RefPtr<Animation> mAnimation;
AnimationTiming mTiming;
OwningNonNull<AnimationEffectTimingReadOnly> mTiming;
nsCSSPseudoElements::Type mPseudoType;
InfallibleTArray<AnimationProperty> mProperties;
@@ -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
+4
View File
@@ -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',
+3
View File
@@ -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]
@@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<script>
Element.prototype.animate = function() {
throw 'Called animate() as defined in content document';
}
// Bug 1211783: Use KeyframeEffect (not KeyframeEffectReadOnly) here
for (var obj of [KeyframeEffectReadOnly, Animation]) {
obj = function() {
throw 'Called overridden ' + String(obj) + ' constructor';
};
}
</script>
<body>
<div id="target"></div>
</body>
</html>
@@ -0,0 +1,31 @@
<!doctype html>
<head>
<meta charset=utf-8>
<script type="application/javascript" src="../testharness.js"></script>
<script type="application/javascript" src="../testharnessreport.js"></script>
<script type="application/javascript" src="../testcommon.js"></script>
</head>
<body>
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1045994"
target="_blank">Mozilla Bug 1045994</a>
<div id="log"></div>
<iframe id="iframe"
src="http://example.org/tests/dom/animation/test/chrome/file_animate_xrays.html"></iframe>
<script>
'use strict';
var win = document.getElementById('iframe').contentWindow;
async_test(function(t) {
window.addEventListener('load', t.step_func(function() {
var target = win.document.getElementById('target');
var anim = target.animate({ opacity: [ 0, 1 ] }, 2000);
// In the x-ray case, the frames object will be given an opaque wrapper
// so it won't be possible to fetch any frames from it.
assert_equals(anim.effect.getFrames().length, 0);
t.done();
}));
}, 'Calling animate() across x-rays');
</script>
</body>
@@ -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.
@@ -0,0 +1,27 @@
<!doctype html>
<meta charset=utf-8>
<script src="../testcommon.js"></script>
<style>
@keyframes abc { }
</style>
<body>
<script>
'use strict';
test(function(t) {
var div = addDiv(t);
div.style.animation = 'abc 100s';
var animation = div.getAnimations()[0];
assert_equals(animation.id, '', 'id for CSS Animation is initially empty');
animation.id = 'anim'
assert_equals(animation.id, 'anim', 'animation.id reflects the value set');
}, 'Animation.id for CSS Animations');
done();
</script>
</body>
</html>
@@ -0,0 +1,15 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
'use strict';
setup({explicit_done: true});
SpecialPowers.pushPrefEnv(
{ "set": [["dom.animations-api.core.enabled", true]]},
function() {
window.open("file_animation-id.html");
});
</script>
</html>
+5
View File
@@ -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]
+60 -5
View File
@@ -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<Attr>
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<Attr>
@@ -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<Animation>
Element::Animate(JSContext* aContext,
JS::Handle<JSObject*> aFrames,
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
ErrorResult& aError)
{
nsCOMPtr<nsIGlobalObject> 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<JSObject*> frames(aContext);
frames = aFrames;
Maybe<JSAutoCompartment> 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<KeyframeEffectReadOnly> effect =
KeyframeEffectReadOnly::Constructor(global, this, frames,
TimingParams::FromOptionsUnion(aOptions), aError);
if (aError.Failed()) {
return nullptr;
}
RefPtr<Animation> 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<RefPtr<Animation>>& aAnimations)
{
+7
View File
@@ -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<Animation> Animate(
JSContext* aContext,
JS::Handle<JSObject*> aFrames,
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
ErrorResult& aError);
// Note: GetAnimations will flush style while GetAnimationsUnsorted won't.
void GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations);
void GetAnimationsUnsorted(nsTArray<RefPtr<Animation>>& aAnimations);
+13 -21
View File
@@ -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<Attr>
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<NodeInfo> 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;
}
}
+1 -16
View File
@@ -141,11 +141,6 @@ public:
Attr* NamedGetter(const nsAString& aAttrName, bool& aFound);
bool NameIsEnumerable(const nsAString& aName);
already_AddRefed<Attr>
SetNamedItem(Attr& aAttr, ErrorResult& aError)
{
return SetNamedItemInternal(aAttr, false, aError);
}
already_AddRefed<Attr>
RemoveNamedItem(mozilla::dom::NodeInfo* aNodeInfo, ErrorResult& aError);
already_AddRefed<Attr>
RemoveNamedItem(const nsAString& aName, ErrorResult& aError);
@@ -158,10 +153,7 @@ public:
GetNamedItemNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName);
already_AddRefed<Attr>
SetNamedItemNS(Attr& aNode, ErrorResult& aError)
{
return SetNamedItemInternal(aNode, true, aError);
}
SetNamedItemNS(Attr& aNode, ErrorResult& aError);
already_AddRefed<Attr>
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<Attr>
SetNamedItemInternal(Attr& aNode, bool aWithNS, ErrorResult& aError);
already_AddRefed<mozilla::dom::NodeInfo>
GetAttrNodeInfo(const nsAString& aNamespaceURI,
const nsAString& aLocalName);
+3
View File
@@ -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:
+1
View File
@@ -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!");
+1 -1
View File
@@ -1388,7 +1388,7 @@ nsXMLContentSerializer::AppendFormatedWrapped_WhitespaceSequence(
case ' ':
case '\t':
sawBlankOrTab = true;
// no break
MOZ_FALLTHROUGH;
case '\n':
++aPos;
// do not increase mColPos,
+1 -1
View File
@@ -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");
+1
View File
@@ -483,6 +483,7 @@ AutoParentOpResult::~AutoParentOpResult()
break;
}
Unused << PCacheParent::Send__delete__(result.actorParent());
break;
}
default:
// other types do not need clean up
+2 -1
View File
@@ -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
+2
View File
@@ -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]
@@ -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");
});
});
}
});
@@ -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();
}
-1
View File
@@ -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
-1
View File
@@ -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",
+1 -1
View File
@@ -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) {
@@ -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!
+8
View File
@@ -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<Animation> getAnimations();
};
+4 -1
View File
@@ -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;
+2 -3
View File
@@ -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();
};
@@ -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;
};
+25
View File
@@ -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;
+3 -13
View File
@@ -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<Keyframe> 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;
+1 -1
View File
@@ -5,7 +5,7 @@
interface NamedNodeMap {
getter Attr? getNamedItem(DOMString name);
[Throws]
[Throws, BinaryName="setNamedItemNS"]
Attr? setNamedItem(Attr arg);
[Throws]
Attr removeNamedItem(DOMString name);
+2
View File
@@ -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',
+1 -1
View File
@@ -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);
@@ -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<dom::PlaybackDirection>(animation.direction());
timing.mIterations = animation.iterations();
timing.mDirection =
static_cast<dom::PlaybackDirection>(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<ParentLayerToParentLayerMatrix4x4>(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);
}
@@ -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
+1 -1
View File
@@ -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;
+25
View File
@@ -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_ */
+1
View File
@@ -17,6 +17,7 @@
#include "mozilla/HashFunctions.h"
#include "mozilla/MathAlgorithms.h"
#include "BorderConsts.h"
#include "nsStyleConsts.h"
#include "nsPresContext.h"
#include "nsIFrame.h"
+2 -1
View File
@@ -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 = &dash;
strokeOptions.mDashLength = 1;
strokeOptions.mDashOffset = 0.5f;
strokeOptions.mDashOffset = 0.5f * dash;
DrawOptions drawOptions;
drawOptions.mAntialiasMode = AntialiasMode::NONE;
mDrawTarget->StrokeRect(rect, color, strokeOptions, drawOptions);
-16
View File
@@ -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.
*
+5 -3
View File
@@ -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<TimeDuration> 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<uint32_t>(timing.mDirection);
animation->property() = aProperty.mProperty;
animation->playbackRate() = aAnimation->PlaybackRate();
+93 -62
View File
@@ -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<TrackSize, 32> 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<TrackSize>& 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<nsTArray<uint32_t>> 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<nsTArray<uint32_t>> 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<TrackSize>& 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<nscoord>(mozilla::Move(colTrackSizes)));
ComputedGridTrackInfo* colInfo = new ComputedGridTrackInfo(
gridReflowState.mColFunctions.mExplicitGridOffset,
gridReflowState.mColFunctions.NumExplicitTracks(),
Move(colTrackSizes));
Properties().Set(GridColTrackInfo(), colInfo);
nsTArray<nscoord> rowTrackSizes(gridReflowState.mRows.mSizes.Length());
for (const TrackSize& sz : gridReflowState.mRows.mSizes) {
rowTrackSizes.AppendElement(sz.mBase);
}
Properties().Set(GridRowTrackSizes(),
new nsTArray<nscoord>(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) {
+43 -39
View File
@@ -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<nscoord>&& aSizes)
: mNumLeadingImplicitTracks(aNumLeadingImplicitTracks)
, mNumExplicitTracks(aNumExplicitTracks)
, mSizes(aSizes)
{}
uint32_t mNumLeadingImplicitTracks;
uint32_t mNumExplicitTracks;
nsTArray<nscoord> mSizes;
};
} // namespace mozilla
class nsGridContainerFrame final : public nsContainerFrame
{
public:
@@ -88,18 +107,16 @@ public:
NS_DECLARE_FRAME_PROPERTY(GridItemContainingBlockRect, DeleteValue<nsRect>)
NS_DECLARE_FRAME_PROPERTY(GridColTrackSizes, DeleteValue<nsTArray<nscoord>>)
const nsTArray<nscoord>* GetComputedTemplateColumns()
NS_DECLARE_FRAME_PROPERTY(GridColTrackInfo, DeleteValue<ComputedGridTrackInfo>)
const ComputedGridTrackInfo* GetComputedTemplateColumns()
{
return static_cast<nsTArray<nscoord>*>(Properties().Get(GridColTrackSizes()));
return static_cast<ComputedGridTrackInfo*>(Properties().Get(GridColTrackInfo()));
}
NS_DECLARE_FRAME_PROPERTY(GridRowTrackSizes, DeleteValue<nsTArray<nscoord>>)
const nsTArray<nscoord>* GetComputedTemplateRows()
NS_DECLARE_FRAME_PROPERTY(GridRowTrackInfo, DeleteValue<ComputedGridTrackInfo>)
const ComputedGridTrackInfo* GetComputedTemplateRows()
{
return static_cast<nsTArray<nscoord>*>(Properties().Get(GridRowTrackSizes()));
return static_cast<ComputedGridTrackInfo*>(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<uint32_t>& 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<uint32_t>& 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<TrackSize>& 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<TrackSize>& aTrackSizes,
void ToPositionAndLengthForAbsPos(const Tracks& aTracks,
nscoord aGridOrigin,
nscoord* aPos, nscoord* aLength) const;
+5 -3
View File
@@ -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<const EmphasisMarkInfo*>(
@@ -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; ) {
+1
View File
@@ -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;
@@ -0,0 +1,133 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Reference: grid abs.pos. child in grid with gutters</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1230695">
<style type="text/css">
body { width:800px; }
.grid {
display: block;
position: relative;
grid-template-columns: repeat(5, 20px);
grid-auto-rows: 10px;
grid-gap: 100px 10px;
border: 1px solid;
padding: 0 3px 0 5px;
height: 40px;
margin-bottom: 2px;
}
.grid.r {
grid-template-columns: 20px;
grid-template-rows: repeat(5, 20px);
height: 160px;
padding: 2px 3px 4px 5px;
float: left;
min-width: 70px;
margin-right: 2px;
}
x {
position: absolute;
width: 20px;
height: 10px;
background: lime;
}
a {
position: absolute;
left:0; right:0; bottom:20px; height: 3px;
background: black;
}
b {
position: absolute;
left:0; right:0; bottom:10px; height: 3px;
background: grey;
}
c {
position: absolute;
left:0; right:0; bottom:0; height: 3px;
background: blue;
}
.r a {
left:50px; top:0; bottom:0; width: 3px; height:auto;
}
.r b {
left:40px; top:0; bottom:0; width: 3px; height:auto;
}
.r c {
left:30px; top:0; bottom:0; width: 3px; height:auto;
}
x:nth-of-type(1) { left:5px; }
x:nth-of-type(2) { left:125px; }
x:nth-of-type(3) { left:245px; }
x:nth-of-type(4) { left:365px; }
.r x { left:5px; height:20px; }
.r x:nth-of-type(1) { top:2px; }
.r x:nth-of-type(2) { top:32px; }
.r x:nth-of-type(3) { top:62px; }
.r x:nth-of-type(4) { top:92px; }
.s x:nth-of-type(1) { left:120px; }
.s x:nth-of-type(2) { left:255px; }
.s x:nth-of-type(3) { left:390px; }
.s x:nth-of-type(4) { left:525px; }
</style>
</head>
<body>
<div class="grid">
<x></x><x></x><x></x><x></x>
<a style="left:125px; width:140px"></a><b style="width:265px"></b><c style="left:365px"></c>
</div>
<div class="grid">
<x></x><x></x><x></x><x></x>
<a style="left:5px; width:260px"></a><b style="width:5px"></b><c style="left:5px"></c>
</div>
<div class="grid">
<x></x><x></x><x></x><x></x>
<a style="left:795px"></a><b style="width:505px"></b><c style="left:795px"></c>
</div>
<div class="grid s">
<x></x><x></x><x></x><x></x>
<a style="left:255px; width:155px"></a><b style="width:410px"></b><c style="left:525px"></c>
</div>
<div class="grid s">
<x></x><x></x><x></x><x></x>
<a style="left:120px; width:290px"></a><b style="width:5px"></b><c style="left:120px"></c>
</div>
<div class="grid s">
<x></x><x></x><x></x><x></x>
<a style="left:795px"></a><b style="width:680px"></b><c style="left:795px"></c>
</div>
<div class="grid r">
<x></x><x></x><x></x><x></x>
<a style="top:32px; height:50px"></a><b style="height:82px"></b><c style="top:92px"></c>
</div>
<div class="grid r">
<x></x><x></x><x></x><x></x>
<a style="top:2px; height:80px"></a><b style="height:2px"></b><c style="top:2px"></c>
</div>
<div class="grid r">
<x></x><x></x><x></x><x></x>
<a style="top:162px"></a><b style="height:142px"></b><c style="top:162px"></c>
</div>
</body>
</html>
@@ -0,0 +1,120 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: grid abs.pos. child in grid with gutters</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1230695">
<link rel="help" href="https://drafts.csswg.org/css-grid/#abspos">
<link rel="match" href="grid-abspos-items-013-ref.html">
<style type="text/css">
body { width:800px; }
.grid {
display: grid;
position: relative;
grid-template-columns: repeat(5, 20px);
grid-auto-rows: 10px;
grid-gap: 100px 10px;
border: 1px solid;
padding: 0 3px 0 5px;
height: 40px;
margin-bottom: 2px;
}
.grid.r {
grid-template-columns: 20px;
grid-template-rows: repeat(5, 20px);
height: 160px;
padding: 2px 3px 4px 5px;
float: left;
min-width: 70px;
margin-right: 2px;
}
.c.s {
justify-content: space-evenly;
grid-gap: 0;
}
x {
background: lime;
}
a {
position: absolute;
left:0; right:0; bottom:20px; height: 3px;
background: black;
}
b {
position: absolute;
left:0; right:0; bottom:10px; height: 3px;
background: grey;
}
c {
position: absolute;
left:0; right:0; bottom:0; height: 3px;
background: blue;
}
.r a {
left:50px; top:0; bottom:0; width: 3px; height:auto;
}
.r b {
left:40px; top:0; bottom:0; width: 3px; height:auto;
}
.r c {
left:30px; top:0; bottom:0; width: 3px; height:auto;
}
</style>
</head>
<body>
<div class="grid c">
<x></x><x></x><x></x><x></x>
<a style="grid-column:2/4"></a><b style="grid-column:auto/4"></b><c style="grid-column:4/auto"></c>
</div>
<div class="grid c">
<x></x><x></x><x></x><x></x>
<a style="grid-column:1/4"></a><b style="grid-column:auto/1"></b><c style="grid-column:1/auto"></c>
</div>
<div class="grid c">
<x></x><x></x><x></x><x></x>
<a style="grid-column:6/6"></a><b style="grid-column:auto/6"></b><c style="grid-column:6/auto"></c>
</div>
<div class="grid c s">
<x></x><x></x><x></x><x></x>
<a style="grid-column:2/4"></a><b style="grid-column:auto/4"></b><c style="grid-column:4/auto"></c>
</div>
<div class="grid c s">
<x></x><x></x><x></x><x></x>
<a style="grid-column:1/4"></a><b style="grid-column:auto/1"></b><c style="grid-column:1/auto"></c>
</div>
<div class="grid c s">
<x></x><x></x><x></x><x></x>
<a style="grid-column:6/6"></a><b style="grid-column:auto/6"></b><c style="grid-column:6/auto"></c>
</div>
<div class="grid r">
<x></x><x></x><x></x><x></x>
<a style="grid-row:2/4"></a><b style="grid-row:auto/4"></b><c style="grid-row:4/auto"></c>
</div>
<div class="grid r">
<x></x><x></x><x></x><x></x>
<a style="grid-row:1/4"></a><b style="grid-row:auto/1"></b><c style="grid-row:1/auto"></c>
</div>
<div class="grid r">
<x></x><x></x><x></x><x></x>
<a style="grid-row:6/6"></a><b style="grid-row:auto/6"></b><c style="grid-row:6/auto"></c>
</div>
</body>
</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 {
</div>
<div class="grid">
<span class="d abs" style="height:50px;top:11px">d</span>
<span class="d abs" style="height:3px; top:58px"></span>
</div>
<div class="grid">
@@ -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 {
<div class="grid">
<span class="negative"></span>
<span class="d abs">d</span>
<span class="d abs"></span>
</div>
<div class="grid">
@@ -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 {
<div class="grid r0"><x></x><x></x><a></a><b></b><x></x></div>
<div class="grid ra"><x></x><x></x><a></a><b></b><x></x></div>
<div class="grid w r01" style="min-height:0"><a></a><b></b></div>
<div class="grid w r01" style="max-height:0"><a></a><b></b></div>
<div class="grid w r01" style="height:0"><a></a><b></b></div>
<div class="grid w r01" style="min-height:0; height:0"><a></a><b></b></div>
<div class="grid w r01" style="max-height:0"><a></a><b></b></div>
<div class="grid w r0"><a></a><b></b></div>
<div class="grid w r01" style="max-height:0"><a></a><b></b></div>
<div class="grid w r0a"><a></a><b></b></div>
<br clear="all">
@@ -0,0 +1,177 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Reference: repeat(auto-fit) with grid-aligned abs.pos. with removed start/middle tracks</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1237805">
<style type="text/css">
html,body {
color:black; background-color:white; font-size:16px; padding:0; margin:0;
}
.grid {
display: grid;
position: relative;
border: 1px solid;
grid-auto-rows: 30px;
grid-template-columns: [a] repeat(auto-fit, [b] 20px [c]) [d] 20px;
grid-gap: 2px;
width: 160px;
height: 30px;
}
.c1 { width: 160px; }
.c2 { width: 150px; }
.c3 { width: 140px; }
.p1 { padding-left:5px; }
.t2 { grid-template-columns: [a] repeat(auto-fit, [b] 20px [c]) [d]; }
x {
width: 18px;
border:1px solid;
background: grey;
}
a {
position: absolute;
left:0; top:0; height:3px; right:0;
background: cyan;
grid-column: -1 / auto;
}
b {
position: absolute;
left:0; bottom:0; height:3px; right:0;
background: brown;
grid-column: auto / -1;
}
c {
position: absolute;
left:0; bottom:5px; height:3px; right:0;
background: pink;
grid-column: -2 / auto;
}
d {
position: absolute;
left:0; bottom:10px; height:3px; right:0;
background: silver;
grid-column: 2 / -3;
}
e {
position: absolute;
left:0; bottom:15px; height:3px; right:0;
background: magenta;
grid-column: 3 / -1;
}
f {
position: absolute;
left:0; bottom:20px; height:3px; right:0;
background: orange;
grid-column: auto / -2;
}
x:first-child {
background: lime;
}
x:last-child {
background: blue;
}
.t1 x:last-child {
grid-column-end:-1;
}
.x5 x:first-child , .x3 x:first-child , .x2 x:first-child {
background: cyan;
}
.x5.t1 x:nth-child(2) , .x4 x:nth-child(2) , .x3 x:nth-child(2) {
background: purple;
}
float { float:left; margin-right:20px; }
.x5 { grid-template-columns: repeat(5,20px); }
.x4 { grid-template-columns: repeat(4,20px); }
.x3 { grid-template-columns: repeat(3,20px); }
.x2 { grid-template-columns: repeat(2,20px); }
.t1.x5 a { grid-column:5/auto; }
.c2.t1.x5 a , .c3.t1.x5 a { display:none; }
.c1.t1.x4 a { grid-column:4/auto; }
.c1.t1.x3 a { grid-column:3/auto; }
.c1.t1.x2 a { grid-column:2/auto; }
.t1.x5 c { grid-column:-3/-2; }
.t2.x5 c { grid-column:-2/-1; }
.c1.t1.x4 c { grid-column:-2/auto; }
.x4 c { grid-column:-2/-1; }
.c1.t1.x3 c, .c1.t1.x2 c { grid-column:-2/auto; }
.c2.t1.x3 c, .c3.t1.x3 c, .c2.t1.x2 c, .c3.t1.x2 c { grid-column:-2/-1; }
.t2.x3 c, .t2.x2 c { grid-column:-1/auto; }
.t1.x5 f , .t2.x4 f { grid-column:auto/4; }
.t2.x5 f { grid-column:auto/5; }
.t2 f { grid-column:auto/-1; }
.t2.x5 e , .t2.x4 e , .x3 e { grid-column:2/-1; }
.t1.x5 e , .c1.t1.x4 e, .c3.t1.x2 e { grid-column:2/-2; }
.c2.t1.x4 e, .c3.t1.x4 e { grid-column:2/-1; }
.c1.t1.x2 e { grid-column:2/auto; }
.c1.t1.x3 e , .x2 e { grid-column:2/3; }
.t2.x5 d, .t2.x4 d , .t1.x4 d { grid-column:2/-2; }
.t1.x3 d, .t1.x2 d { grid-column:2/3; }
.t2.x3 d { grid-column:2/-1; }
.t1.x2 d { grid-column:2/auto; }
.t2.x2 d { grid-column:2/3; }
.c1.t1 b , .c2.t1.x5 b , .c3.t1.x5 b { grid-column:auto/-2; }
</style>
</head>
<body>
<float>
<div class="grid c1 t1 x5"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 x5"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f></div>
<div class="grid c3 t1 x5"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f></div>
<div class="grid c1 t2 x5"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 x5"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 x5"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t1 x4"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 x4"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 x4"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 x4"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 x4"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 x4"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t1 x3"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 x3"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 x3"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 x3"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 x3"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 x3"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
</float>
<float>
<div class="grid c1 t1 x2"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 x2"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 x2"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 x2"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 x2"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 x2"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
</float>
</body>
</html>
@@ -0,0 +1,195 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html class="reftest-wait"><head>
<meta charset="utf-8">
<title>CSS Grid Test: repeat(auto-fit) with grid-aligned abs.pos. with removed start/middle tracks</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1237805">
<link rel="help" href="https://drafts.csswg.org/css-grid/#valdef-repeat-auto-fill">
<link rel="match" href="grid-repeat-auto-fill-fit-007-ref.html">
<style type="text/css">
html,body {
color:black; background-color:white; font-size:16px; padding:0; margin:0;
}
.grid {
display: grid;
position: relative;
border: 1px solid;
grid-auto-rows: 30px;
grid-template-columns: [a] repeat(auto-fit, [b] 20px [c]) [d] 20px;
grid-gap: 2px;
width: 160px;
height: 30px;
}
.c1 { width: 160px; }
.c2 { width: 150px; }
.c3 { width: 140px; }
.p1 { padding-left:5px; }
.t2 { grid-template-columns: [a] repeat(auto-fit, [b] 20px [c]) [d]; }
x {
width: 18px;
border:1px solid;
background: grey;
}
a {
position: absolute;
left:0; top:0; height:3px; right:0;
background: cyan;
grid-column: 7 / auto;
}
b {
position: absolute;
left:0; bottom:0; height:3px; right:0;
background: brown;
grid-column: auto / 7;
}
c {
position: absolute;
left:0; bottom:5px; height:3px; right:0;
background: pink;
grid-column: 6 / 7;
}
d {
position: absolute;
left:0; bottom:10px; height:3px; right:0;
background: silver;
grid-column: 3 / 6;
}
e {
position: absolute;
left:0; bottom:15px; height:3px; right:0;
background: magenta;
grid-column: 3 / 7;
}
f {
position: absolute;
left:0; bottom:20px; height:3px; right:0;
background: orange;
grid-column: auto / 6;
}
x:first-child {
background: lime;
}
x:last-child {
background: blue;
}
.t1 x:last-child {
grid-column-end:-1;
}
float { float:left; margin-right:20px; }
.m x:first-child , .n x:first-child {
background: cyan;
grid-column:2;
}
.n x:nth-child(2) , .o x:nth-child(2) {
background: purple;
grid-column:4;
}
</style>
</head>
<body>
<float>
<div class="grid c1 t1 n"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 n"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 n"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 m"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 m"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 m"><x></x><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t1 o"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 o"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 o"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 o"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 o"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 o"><x></x><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t1 n"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 n"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 n"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 n"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 n"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 n"><x></x><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
</float>
<float>
<div class="grid c1 t1 n"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 n"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 n"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 n"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 n"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 n"><x></x><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
</float>
<script>
function testGridTemplateColumns(elem, expected) {
var actual = window.getComputedStyle(elem).gridTemplateColumns;
if (actual != expected) {
var err = "FAIL: gridTemplateColumns " + elem.className +
", GOT=" + actual +
", EXPECTED=" + expected;
document.body.appendChild(document.createTextNode(err));
}
}
var a1 = [
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c d] 20px",
"[a b] 20px [c d] 20px",
"[a b] 20px [c d] 20px"
];
var a2 = [
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c d]"
];
function runTest() {
var t1 = document.querySelectorAll('.t1');
for (var i = 0; i < t1.length; ++i) {
testGridTemplateColumns(t1[i], a1[i]);
}
var t2 = document.querySelectorAll('.t2');
for (var i = 0; i < t2.length; ++i) {
testGridTemplateColumns(t2[i], a2[i]);
}
document.documentElement.className='';
}
document.addEventListener('MozReftestInvalidate', runTest, false);
</script>
</body>
</html>
@@ -0,0 +1,194 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: repeat(auto-fit) with grid-aligned abs.pos. with removed start/middle tracks and implicit tracks on either/both sides</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239036">
<style type="text/css">
html,body {
color:black; background-color:white; font-size:16px; padding:0; margin:0;
}
.grid {
display: grid;
position: relative;
border: 1px solid;
grid-auto-rows: 30px;
grid-auto-columns: 3px;
grid-template-columns: [a] repeat(auto-fit, [b] 20px [c]) [d] 20px;
height: 30px;
}
.c1 { width: 165px; }
.c2 { width: 155px; }
.c3 { width: 150px; }
.p1 { padding-left:5px; }
.t2 { grid-template-columns: [a] repeat(auto-fit, [b] 20px [c]) [d]; }
x {
width: 18px;
border:1px solid;
background: grey;
}
a {
position: absolute;
top:0; height:3px; right:0;
background: cyan;
grid-column: auto / auto;
}
b {
position: absolute;
left:0; bottom:0; height:3px; width:103px;
background: brown;
grid-column: auto / auto;
}
.c2 b {width:100px;}
c {
position: absolute;
left:0; bottom:5px; height:3px; right:0;
background: pink;
grid-column: auto / auto;
}
d {
position: absolute;
left:23px; bottom:10px; height:3px; width:60px;
background: silver;
grid-column: auto / auto;
}
e {
position: absolute;
left:0; bottom:15px; height:3px; right:0;
background: magenta;
grid-column: auto / auto;
}
f {
position: absolute;
left:0; bottom:20px; height:3px; width:83px;
background: orange;
grid-column: auto / auto;
}
.c2 f {width:80px;}
x:first-of-type {
background: lime;
}
x:nth-of-type(1) { grid-area:1/1; }
x:nth-of-type(2) { grid-area:1/2; }
x:nth-of-type(3) { grid-area:1/3; }
x:nth-of-type(4) { grid-area:1/4; }
x:nth-of-type(5) { grid-area:1/5; }
x:last-of-type {
background: blue;
}
.t1 x:last-of-type {
grid-column-end:-1;
}
float { float:left; margin-right:20px; }
.m x:first-of-type , .n x:first-of-type {
background: cyan;
grid-area:1/2;
}
.n x:nth-of-type(2) , .o x:nth-of-type(2) {
background: purple;
grid-area:1/4;
}
.c1 y, .c3 y:first-of-type { grid-column: span X / 1; background:black; }
.c2 y, .c3 y:last-of-type { grid-column: -1 / span X; background:black; }
.s2 { left: 23px; }
.s2a { left: 20px; }
.e5 { right: 82px; }
.e5a { right: 75px; }
.e5b { right: 67px; }
.e6 { right: 62px; }
.e6a { right: 55px; }
.e6b { right: 47px; }
.c2 d { left:20px; }
.t2.x4 f, .t2.x3 f { width:63px; }
.c2.t2.x4 f, .c2.t2.x3 f { width:60px; }
.t2.x4 d, .t2.x3 d { width:40px; }
.x2 d { width:20px; }
.x2 f { width:43px; }
.c2.x2 f { width:40px; }
.t2.x5 b { width:83px; }
.c2.t2.x5 b { width:80px; }
.t2.x4 b, .t2.x3 b { width:63px; }
.c2.t2.x4 b, .c2.t2.x3 b { width:60px; }
.x2 b { width:43px; }
.c2.x2 b { width:40px; }
.t1.x5 c, .t1.x4 c, .t1.x3 c { left:83px; width:20px; right:auto; }
.c2.x5 c , .c2.t1.x4 c , .c2.t1.x3 c { left:80px; }
.t2.x5 c { left:83px; }
.c2.t2.x5 c { left:80px; }
.t2.x4 c , .t2.x3 c { left:63px; }
.c2.t2.x4 c , .c2.t2.x3 c { left:60px; }
.t1.x2 c , .t2.x2 c { left:43px; }
.c2.t2.x2 c , .c2.t1.x2 c { left:40px;}
.x2 e { left:23px; width:20px; right:auto; }
.c2.x2 e { left:20px; }
.t1.c3.x2 e { width:40px; }
.t1.c3.x2 b { width:63px; }
.t1.c3.x2 c { width:20px; right:auto;}
.t2.x5 e { left:23px; width:60px; }
.x4 e , .x3 e , .x2 e { left:23px; }
.c2.x4 e , .c2.x3 e , .c2.x2 e { left:20px; }
.c2.t2.x5 e { left:20px; }
.t1.x4 e , .t1.x3 e { width:80px; }
.t2.x4 e , .t2.x3 e { width:40px; }
</style>
</head>
<body>
<float>
<div class="grid c1 t1 n x5"><x></x><x></x><x></x><x></x><y></y><a style="width:62px"></a><b></b><c></c><d></d><e class="s2 e6"></e><f class="e5"></f><x></x></div>
<div class="grid c2 t1 n x5"><x></x><x></x><x></x><x></x><y></y><a style="width:55px"></a><b></b><c></c><d></d><e class="s2a e6a"></e><f class="e5a"></f><x></x></div>
<div class="grid c3 t1 n x5"><x></x><x></x><x></x><x></x><y></y><y></y><a style="width:47px"></a><b></b><c></c><d></d><e class="s2 e6b"></e><f class="e5b"></f><x></x></div>
<div class="grid c1 t2 m x5"><x></x><x></x><x></x><x></x><y></y><a style="width:82px"></a><b></b><c></c><d></d><e class="s2"></e><f class="e5"></f><x></x></div>
<div class="grid c2 t2 m x5"><x></x><x></x><x></x><x></x><y></y><a style="width:75px"></a><b></b><c></c><d></d><e class="s2e"></e><f class="e5"></f><x></x></div>
<div class="grid c3 t2 m x5"><x></x><x></x><x></x><x></x><y></y><y></y><a style="width:67px"></a><b></b><c></c><d></d><e></e><f class="e5"></f><x></x></div>
<div class="grid c1 t1 o x4"><x></x><x></x><x></x><y></y><a style="width:62px"></a><b></b><c></c><d></d><e></e><f class="e5"></f><x></x></div>
<div class="grid c2 t1 o x4"><x></x><x></x><x></x><y></y><a style="width:55px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 o x4"><x></x><x></x><x></x><y></y><y></y><a style="width:47px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 o x4"><x></x><x></x><x></x><y></y><a style="width:102px"></a><b></b><c></c><d></d><e></e><f class="e5"></f><x></x></div>
<div class="grid c2 t2 o x4"><x></x><x></x><x></x><y></y><a style="width:95px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 o x4"><x></x><x></x><x></x><y></y><y></y><a style="width:87px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t1 n x3"><x></x><x></x><y></y><a style="width:62px"></a><b></b><c></c><d></d><e></e><f class="e5"></f><x></x></div>
<div class="grid c2 t1 n x3"><x></x><x></x><y></y><a style="width:55px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 n x3"><x></x><x></x><y></y><y></y><a style="width:47px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 n x3"><x></x><x></x><y></y><a style="width:102px"></a><b></b><c></c><d></d><e></e><f class="e5"></f><x></x></div>
<div class="grid c2 t2 n x3"><x></x><x></x><y></y><a style="width:95px"></a><b></b><c></c><d></d><e></e><f class="e5"></f><x></x></div>
<div class="grid c3 t2 n x3"><x></x><x></x><y></y><y></y><a style="width:87px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
</float>
<float>
<div class="grid c1 t1 n x2"><x></x><y></y><a style="width:122px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 n x2"><x></x><y></y><a style="width:115px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 n x2"><x></x><y></y><y></y><a style="width:87px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 n x2"><x></x><y></y><a style="width:122px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 n x2"><x></x><y></y><a style="width:115px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 n x2"><x></x><y></y><y></y><a style="width:107px"></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
</float>
</body>
</html>
@@ -0,0 +1,204 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html class="reftest-wait"><head>
<meta charset="utf-8">
<title>CSS Grid Test: repeat(auto-fit) with grid-aligned abs.pos. with removed start/middle tracks and implicit tracks on either/both sides</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239036">
<link rel="help" href="https://drafts.csswg.org/css-grid/#valdef-repeat-auto-fill">
<link rel="match" href="grid-repeat-auto-fill-fit-008-ref.html">
<style type="text/css">
html,body {
color:black; background-color:white; font-size:16px; padding:0; margin:0;
}
.grid {
display: grid;
position: relative;
border: 1px solid;
grid-auto-rows: 30px;
grid-auto-columns: 3px;
grid-template-columns: [a] repeat(auto-fit, [b] 20px [c]) [d] 20px;
height: 30px;
}
.c1 { width: 165px; }
.c2 { width: 155px; }
.c3 { width: 150px; }
.p1 { padding-left:5px; }
.t2 { grid-template-columns: [a] repeat(auto-fit, [b] 20px [c]) [d]; }
x {
width: 18px;
border:1px solid;
background: grey;
}
a {
position: absolute;
left:0; top:0; height:3px; right:0;
background: cyan;
grid-column: 7 / auto;
}
b {
position: absolute;
left:0; bottom:0; height:3px; right:0;
background: brown;
grid-column: auto / 7;
}
c {
position: absolute;
left:0; bottom:5px; height:3px; right:0;
background: pink;
grid-column: 6 / 7;
}
d {
position: absolute;
left:0; bottom:10px; height:3px; right:0;
background: silver;
grid-column: 3 / 6;
}
e {
position: absolute;
left:0; bottom:15px; height:3px; right:0;
background: magenta;
grid-column: 3 / 7;
}
f {
position: absolute;
left:0; bottom:20px; height:3px; right:0;
background: orange;
grid-column: auto / 6;
}
x:first-of-type {
background: lime;
}
x:nth-of-type(1) { grid-area:1/1; }
x:nth-of-type(2) { grid-area:1/2; }
x:nth-of-type(3) { grid-area:1/3; }
x:nth-of-type(4) { grid-area:1/4; }
x:nth-of-type(5) { grid-area:1/5; }
x:last-of-type {
background: blue;
}
.t1 x:last-of-type {
grid-column-end:-1;
}
float { float:left; margin-right:20px; }
.m x:first-of-type , .n x:first-of-type {
background: cyan;
grid-area:1/2;
}
.n x:nth-of-type(2) , .o x:nth-of-type(2) {
background: purple;
grid-area:1/4;
}
.c1 y, .c3 y:first-of-type { grid-column: span X / 1; background:black; }
.c2 y, .c3 y:last-of-type { grid-column: -1 / span X; background:black; }
</style>
</head>
<body>
<float>
<div class="grid c1 t1 n"><x></x><x></x><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 n"><x></x><x></x><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 n"><x></x><x></x><x></x><x></x><y></y><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 m"><x></x><x></x><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 m"><x></x><x></x><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 m"><x></x><x></x><x></x><x></x><y></y><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t1 o"><x></x><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 o"><x></x><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 o"><x></x><x></x><x></x><y></y><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 o"><x></x><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 o"><x></x><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 o"><x></x><x></x><x></x><y></y><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t1 n"><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 n"><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 n"><x></x><x></x><y></y><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 n"><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 n"><x></x><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 n"><x></x><x></x><y></y><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
</float>
<float>
<div class="grid c1 t1 n"><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t1 n"><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t1 n"><x></x><y></y><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c1 t2 n"><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c2 t2 n"><x></x><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
<div class="grid c3 t2 n"><x></x><y></y><y></y><a></a><b></b><c></c><d></d><e></e><f></f><x></x></div>
</float>
<script>
function testGridTemplateColumns(elem, expected) {
var actual = window.getComputedStyle(elem).gridTemplateColumns;
if (actual != expected) {
var err = "FAIL: gridTemplateColumns " + elem.className +
", GOT=" + actual +
", EXPECTED=" + expected;
document.body.appendChild(document.createTextNode(err));
}
}
var a1 = [
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 20px 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c d] 20px",
"[a b] 20px [c b] 20px [c d] 20px 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c d] 20px 3px"
];
var a2 = [
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c d] 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c b] 20px [c d] 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c b] 20px [c d] 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c d]",
"[a b] 20px [c b] 20px [c d] 3px",
"3px [a b] 20px [c b] 20px [c b] 20px [c d] 3px"
];
function runTest() {
var t1 = document.querySelectorAll('.t1');
for (var i = 0; i < t1.length; ++i) {
testGridTemplateColumns(t1[i], a1[i]);
}
var t2 = document.querySelectorAll('.t2');
for (var i = 0; i < t2.length; ++i) {
testGridTemplateColumns(t2[i], a2[i]);
}
document.documentElement.className='';
}
document.addEventListener('MozReftestInvalidate', runTest, false);
runTest()
</script>
</body>
</html>
+3
View File
@@ -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
+11 -12
View File
@@ -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<uint64_t>(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<KeyframeEffectReadOnly> destEffect =
new KeyframeEffectReadOnly(mPresContext->Document(), aTarget,
+2 -2
View File
@@ -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
+85 -58
View File
@@ -2454,8 +2454,9 @@ nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrackList,
const nsTArray<nscoord>* 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<bool> isAutoFill =
aTrackList.HasRepeatAuto() && aTrackList.mIsAutoFill;
DebugOnly<bool> isAutoFit =
aTrackList.HasRepeatAuto() && !aTrackList.mIsAutoFill;
DebugOnly<uint32_t> 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 <track-list> is represented as "none" in syntax.
if (numSizes == 0) {
RefPtr<nsROCSSPrimitiveValue> 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<nsDOMCSSValueList> 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(<positive-integer>, 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<nscoord>& 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<nsROCSSPrimitiveValue> 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<nsString>& 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<nsString>& 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<nsString>& 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<nsString>& lineNames = aTrackList.mLineNameLists[j];
AppendGridLineNames(valueList, lineNames);
}
} else if (i == endOfRepeat) {
const nsTArray<nsString>& 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<nsString>& lineNames = aTrackList.mLineNameLists[j];
const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
AppendGridLineNames(valueList, lineNames);
}
} else {
const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
AppendGridLineNames(valueList, lineNames);
}
if (uint32_t(i) == numSizes) {
break;
if (uint32_t(i) == numExplicitTracks) {
break;
}
RefPtr<nsROCSSPrimitiveValue> 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<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetAppUnits((*aTrackSizes)[i]);
val->SetAppUnits(trackSizes[i]);
valueList->AppendCSSValue(val.forget());
}
} else {
@@ -2634,31 +2661,31 @@ nsComputedDOMStyle::DoGetGridAutoRows()
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetGridTemplateColumns()
{
const nsTArray<nscoord>* trackSizes = nullptr;
const ComputedGridTrackInfo* info = nullptr;
if (mInnerFrame) {
nsIFrame* gridContainerCandidate = mInnerFrame->GetContentInsertionFrame();
if (gridContainerCandidate &&
gridContainerCandidate->GetType() == nsGkAtoms::gridContainerFrame) {
auto gridContainer = static_cast<nsGridContainerFrame*>(gridContainerCandidate);
trackSizes = gridContainer->GetComputedTemplateColumns();
info = static_cast<nsGridContainerFrame*>(gridContainerCandidate)->
GetComputedTemplateColumns();
}
}
return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns, trackSizes);
return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns, info);
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetGridTemplateRows()
{
const nsTArray<nscoord>* trackSizes = nullptr;
const ComputedGridTrackInfo* info = nullptr;
if (mInnerFrame) {
nsIFrame* gridContainerCandidate = mInnerFrame->GetContentInsertionFrame();
if (gridContainerCandidate &&
gridContainerCandidate->GetType() == nsGkAtoms::gridContainerFrame) {
auto gridContainer = static_cast<nsGridContainerFrame*>(gridContainerCandidate);
trackSizes = gridContainer->GetComputedTemplateRows();
}
info = static_cast<nsGridContainerFrame*>(gridContainerCandidate)->
GetComputedTemplateRows();
}
}
return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows, trackSizes);
return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows, info);
}
already_AddRefed<CSSValue>
+2 -1
View File
@@ -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<CSSValue> GetGridTemplateColumnsRows(
const nsStyleGridTemplate& aTrackList,
const nsTArray<nscoord>* aTrackSizes);
const mozilla::ComputedGridTrackInfo* aTrackInfo);
already_AddRefed<CSSValue> GetGridLine(const nsStyleGridLine& aGridLine);
bool GetLineHeightCoord(nscoord& aCoord);
+8 -7
View File
@@ -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<ElementPropertyTransition> pt =
new ElementPropertyTransition(aElement->OwnerDoc(), aElement,
+2 -2
View File
@@ -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)
@@ -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;
}
</style>
</head>
@@ -36,6 +43,10 @@
<div style="grid-column-start:1; width:50px"></div>
<div style="grid-column-start:9; width:50px"></div>
</div>
<div id="grid2">
<div style="grid-column: span X / 1"></div>
<div style="grid-column: 1 / span X 2"></div>
</div>
<div>
<script>
@@ -73,9 +84,21 @@
test_grid_template(assert_not_equals, 420, 340,
"test computed grid-template-{columns,rows} values, display: none on parent");
gridElement.parentNode.style.display = '';
function test_grid2() {
gridElement = document.getElementById("grid2");
test(function() {
assert_equals(getComputedStyle(gridElement).gridTemplateColumns,
"10px 10px 10px");
assert_equals(getComputedStyle(gridElement, "").gridTemplateRows,
"400px");
}, "test #grid2 computed grid-template-{columns,rows} values");
}
test(function() {
assert_equals(getComputedStyle(gridElement).gridAutoColumns, "3fr");
assert_equals(getComputedStyle(gridElement).gridAutoRows, "2fr");
test_grid2();
}, "test computed grid-auto-{columns,rows} values");
</script>
+3
View File
@@ -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
+12
View File
@@ -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"
}
@@ -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
@@ -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
@@ -0,0 +1,126 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Animatable.animate tests</title>
<link rel="help" href="http://w3c.github.io/web-animations/#dom-animatable-animate">
<link rel="author" title="Brian Birtles" href="mailto:bbirtles@mozilla.com">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
<body>
<div id="log"></div>
<iframe src="data:text/html;charset=utf-8," width="10" height="10"
id="iframe"></iframe>
<script>
'use strict';
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
assert_class_string(anim, 'Animation', 'Returned object is an Animation');
}, 'Element.animate() creates an Animation object');
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
assert_class_string(anim.effect, 'KeyframeEffect',
'Returned Animation has a KeyframeEffect');
}, 'Element.animate() creates an Animation object with a KeyframeEffect');
// Animatable.animate() passes its |frames| argument to the KeyframeEffect
// constructor. As a result, detailed tests of the handling of that argument
// are found in the tests for that constructor. Here we just check that the
// different types of arguments are correctly passed along.
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
assert_equals(anim.effect.getFrames().length, 2);
assert_equals(anim.effect.getFrames()[0].opacity, '0');
assert_equals(anim.effect.getFrames()[1].opacity, '1');
}, 'Element.animate() accepts a property-indexed keyframe specification');
test(function(t) {
var div = createDiv(t);
var anim = div.animate([ { opacity: 0 }, { opacity: 1 } ], 2000);
assert_equals(anim.effect.getFrames().length, 2);
assert_equals(anim.effect.getFrames()[0].opacity, '0');
assert_equals(anim.effect.getFrames()[1].opacity, '1');
}, 'Element.animate() accepts a frame-indexed keyframe specification');
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: 0 }, 2000);
assert_equals(anim.effect.getFrames().length, 1);
assert_equals(anim.effect.getFrames()[0].opacity, '0');
}, 'Element.animate() accepts a single-valued keyframe specification');
// As with the |frames| argument, Animatable.animate() passes its |options|
// argument to the KeyframeEffect constructor as well. As a result, detailed
// tests of the handling of that argument are found in the tests for that
// constructor. Here we just check that the different types of arguments are
// correctly passed along.
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
assert_equals(anim.effect.timing.duration, 2000);
// Also check that unspecified parameters receive their default values
assert_equals(anim.effect.timing.fill, 'auto');
}, 'Element.animate() accepts a double as an options argument');
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] },
{ duration: Infinity, fill: 'forwards' });
assert_equals(anim.effect.timing.duration, Infinity);
assert_equals(anim.effect.timing.fill, 'forwards');
// Also check that unspecified parameters receive their default values
assert_equals(anim.effect.timing.direction, 'normal');
}, 'Element.animate() accepts a KeyframeAnimationOptions argument');
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] });
assert_equals(anim.effect.timing.duration, 'auto');
}, 'Element.animate() accepts an absent options argument');
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
assert_equals(anim.id, '');
}, 'Element.animate() correctly sets the id attribute when no id is specified');
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] }, { id: 'test' });
assert_equals(anim.id, 'test');
}, 'Element.animate() correctly sets the id attribute');
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
assert_equals(anim.timeline, document.timeline);
}, 'Element.animate() correctly sets the Animation\'s timeline');
async_test(function(t) {
var iframe = document.getElementById('iframe');
iframe.addEventListener('load', t.step_func(function() {
var div = createDiv(t, iframe.contentDocument);
var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
assert_equals(anim.timeline, iframe.contentDocument.timeline);
t.done();
}));
}, 'Element.animate() correctly sets the Animation\'s timeline when ' +
'triggered on an element in a different document');
test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
assert_equals(anim.playState, 'pending');
}, 'Element.animate() calls play on the Animation');
// TODO: Test the same on CSSPseudoElement
</script>
</body>
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Animation constructor tests</title>
<link rel="help" href="http://w3c.github.io/web-animations/#dom-animation-animation">
<link rel="author" title="Hiroyuki Ikezoe" href="mailto:hiikezoe@mozilla-japan.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
<body>
<div id="log"></div>
<div id="target"></div>
<script>
"use strict";
var gTarget = document.getElementById("target");
var gEffect = new KeyframeEffectReadOnly(gTarget, { opacity: [0, 1] });
var gTestArguments = [
{
effect: null,
timeline: null,
description: "with null effect and null timeline"
},
{
effect: null,
timeline: document.timeline,
description: "with null effect and non-null timeline"
},
{
effect: gEffect,
timeline: null,
description: "with non-null effect and null timeline"
},
{
effect: gEffect,
timeline: document.timeline,
description: "with non-null effect and non-null timeline"
},
];
gTestArguments.forEach(function(args) {
test(function(t) {
var animation = new Animation(args.effect, args.timeline);
assert_not_equals(animation, null,
"An animation sohuld be created");
assert_equals(animation.effect, args.effect,
"Animation returns the same effect passed to " +
"the Constructor");
assert_equals(animation.timeline, args.timeline,
"Animation returns the same timeline passed to " +
"the Constructor");
assert_equals(animation.playState, "idle",
"Animation.playState should be initially 'idle'");
}, "Animation can be constructed " + args.description);
});
</script>
</body>
@@ -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();
</script>
</body>
@@ -0,0 +1,195 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>KeyframeEffectReadOnly getComputedTiming() tests</title>
<link rel="help" href="https://w3c.github.io/web-animations/#dom-animationeffectreadonly-getcomputedtiming">
<link rel="author" title="Boris Chiou" href="mailto:boris.chiou@gmail.com">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
<body>
<div id="log"></div>
<div id="target"></div>
<script>
"use strict";
var target = document.getElementById("target");
test(function(t) {
var effect = new KeyframeEffectReadOnly(target,
{left: ["10px", "20px"]});
var ct = effect.getComputedTiming();
assert_equals(ct.delay, 0, "computed delay");
assert_equals(ct.fill, "none", "computed fill");
assert_equals(ct.iterations, 1.0, "computed iterations");
assert_equals(ct.duration, 0, "computed duration");
assert_equals(ct.direction, "normal", "computed direction");
}, "values of getComputedTiming() when a KeyframeEffectReadOnly is " +
"constructed without any KeyframeEffectOptions object");
var gGetComputedTimingTests = [
{ desc: "an empty KeyframeEffectOption",
input: {},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "a normal KeyframeEffectOption",
input: {delay: 1000,
fill: "auto",
iterations: 5.5,
duration: "auto",
direction: "alternate"},
expected: {delay: 1000,
fill: "none",
iterations: 5.5,
duration: 0,
direction: "alternate"} },
{ desc: "a double value",
input: 3000,
timing: {delay: 0,
fill: "auto",
iterations: 1,
duration: 3000,
direction: "normal"},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 3000,
direction: "normal"} },
{ desc: "+Infinity",
input: Infinity,
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: Infinity,
direction: "normal"} },
{ desc: "-Infinity",
input: -Infinity,
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "NaN",
input: NaN,
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "a negative value",
input: -1,
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "an Infinity duration",
input: {duration: Infinity},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: Infinity,
direction: "normal"} },
{ desc: "a negative Infinity duration",
input: {duration: -Infinity},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "a NaN duration",
input: {duration: NaN},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "a negative duration",
input: {duration: -1},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "a string duration",
input: {duration: "merrychristmas"},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "an auto duration",
input: {duration: "auto"},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "an Infinity iterations",
input: {iterations: Infinity},
expected: {delay: 0,
fill: "none",
iterations: Infinity,
duration: 0,
direction: "normal"} },
{ desc: "a negative Infinity iterations",
input: {iterations: -Infinity},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "a NaN iterations",
input: {iterations: NaN},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "a negative iterations",
input: {iterations: -1},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "an auto fill",
input: {fill: "auto"},
expected: {delay: 0,
fill: "none",
iterations: 1,
duration: 0,
direction: "normal"} },
{ desc: "a forwards fill",
input: {fill: "forwards"},
expected: {delay: 0,
fill: "forwards",
iterations: 1,
duration: 0,
direction: "normal"} }
];
gGetComputedTimingTests.forEach(function(stest) {
test(function(t) {
var effect = new KeyframeEffectReadOnly(target,
{left: ["10px", "20px"]},
stest.input);
var ct = effect.getComputedTiming();
assert_equals(ct.delay, stest.expected.delay, "computed delay");
assert_equals(ct.fill, stest.expected.fill, "computed fill");
assert_equals(ct.iterations, stest.expected.iterations,
"computed iterations");
assert_equals(ct.duration, stest.expected.duration, "computed duration");
assert_equals(ct.direction, stest.expected.direction, "computed direction");
}, "values of getComputedTiming() when a KeyframeEffectReadOnly is " +
"constructed by " + stest.desc);
});
done();
</script>
</body>
@@ -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;