--- a/dom/animation/AnimValuesStyleRule.cpp
+++ b/dom/animation/AnimValuesStyleRule.cpp
@@ -1,15 +1,17 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AnimValuesStyleRule.h"
+#include "mozilla/CSSVariableDeclarations.h"
+#include "mozilla/CSSVariableRegistration.h"
#include "nsRuleData.h"
#include "nsStyleContext.h"
namespace mozilla {
NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
void
@@ -29,28 +31,65 @@ AnimValuesStyleRule::MapRuleInfoInto(nsR
// a pseduo-element, so that we don't incorrectly return a struct that
// is only appropriate for non-pseudo-elements.
aRuleData->mConditions.SetUncacheable();
return;
}
for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
PropertyStyleAnimationValuePair& pair = mPropertyValuePairs[i];
- if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(
- nsCSSProps::kSIDTable[pair.mProperty]))
- {
- nsCSSValue *prop = aRuleData->ValueFor(pair.mProperty);
+ if (!(aRuleData->mSIDs &
+ nsCachedStyleData::GetBitForSID(pair.mProperty.GetStyleStructID()))) {
+ continue;
+ }
+ if (pair.mProperty.IsFixed()) {
+ nsCSSPropertyID property = pair.mProperty.AsFixed();
+ nsCSSValue *prop = aRuleData->ValueFor(property);
if (prop->GetUnit() == eCSSUnit_Null) {
#ifdef DEBUG
bool ok =
#endif
StyleAnimationValue::UncomputeValue(pair.mProperty, pair.mValue,
*prop);
MOZ_ASSERT(ok, "could not store computed value");
}
+ } else {
+ nsString specVal, name;
+ MOZ_ALWAYS_TRUE(StyleAnimationValue::UncomputeValue(pair.mProperty,
+ pair.mValue,
+ specVal));
+
+ // URL values need a principal to be set in the parser.
+ // Otherwise we should be able to supply a context of all nulls (not
+ // uninitialized!) because this is already a computed value.
+ // See CSSParserImpl::SetValueToURL.
+ CSSVariableExprContext context;
+ if (pair.mValue.GetUnit() == StyleAnimationValue::eUnit_URL) {
+ nsCSSValue cssVal;
+ MOZ_ALWAYS_TRUE(StyleAnimationValue::UncomputeValue(pair.mProperty,
+ pair.mValue,
+ cssVal));
+ MOZ_ASSERT(cssVal.GetUnit() == eCSSUnit_URL);
+ css::URLValue* url = cssVal.GetURLStructValue();
+ context.mSheetURI = url->mReferrer.get();
+ context.mBaseURI = nullptr;
+ context.mSheetPrincipal = url->mOriginPrincipal.get();
+ }
+
+ pair.mProperty.AsCustom()->ToString(name);
+ if (!aRuleData->mVariables) {
+ aRuleData->mVariables = new CSSVariableDeclarations(nullptr);
+ }
+ if (!aRuleData->mVariables->Has(name)) {
+ aRuleData->mVariables->Add(name,
+ CSSVariableDeclarations::Type::TokenStream,
+ specVal, /* aImportant = */ false,
+ /* aOverrideImportant = */ false,
+ context);
+ }
}
}
}
bool
AnimValuesStyleRule::MightMapInheritedStyleData()
{
return mStyleBits & NS_STYLE_INHERITED_STRUCT_MASK;
@@ -62,17 +101,24 @@ AnimValuesStyleRule::List(FILE* out, int
{
nsAutoCString str;
for (int32_t index = aIndent; --index >= 0; ) {
str.AppendLiteral(" ");
}
str.AppendLiteral("[anim values] { ");
for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
const PropertyStyleAnimationValuePair& pair = mPropertyValuePairs[i];
- str.Append(nsCSSProps::GetStringValue(pair.mProperty));
+ if (pair.mProperty.IsFixed()) {
+ str.Append(nsCSSProps::GetStringValue(pair.mProperty.AsFixed()));
+ } else {
+ nsAutoString name;
+ pair.mProperty.AsCustom()->ToString(name);
+ str.AppendLiteral("--");
+ AppendUTF16toUTF8(name, str);
+ }
str.AppendLiteral(": ");
nsAutoString value;
StyleAnimationValue::UncomputeValue(pair.mProperty, pair.mValue, value);
AppendUTF16toUTF8(value, str);
str.AppendLiteral("; ");
}
str.AppendLiteral("}\n");
fprintf_stderr(out, "%s", str.get());
--- a/dom/animation/AnimValuesStyleRule.h
+++ b/dom/animation/AnimValuesStyleRule.h
@@ -4,17 +4,16 @@
* 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_AnimValuesStyleRule_h
#define mozilla_AnimValuesStyleRule_h
#include "mozilla/StyleAnimationValue.h"
#include "nsCSSPropertyID.h"
-#include "nsCSSPropertyIDSet.h"
#include "nsIStyleRule.h"
#include "nsISupportsImpl.h" // For NS_DECL_ISUPPORTS
#include "nsRuleNode.h" // For nsCachedStyleData
#include "nsTArray.h" // For nsTArray
namespace mozilla {
/**
@@ -31,31 +30,29 @@ public:
// nsIStyleRule implementation
void MapRuleInfoInto(nsRuleData* aRuleData) override;
bool MightMapInheritedStyleData() override;
#ifdef DEBUG
void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
- void AddValue(nsCSSPropertyID aProperty, const StyleAnimationValue &aStartValue)
+ void AddValue(CSSProperty aProperty, const StyleAnimationValue &aStartValue)
{
PropertyStyleAnimationValuePair pair = { aProperty, aStartValue };
mPropertyValuePairs.AppendElement(pair);
- mStyleBits |=
- nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]);
+ mStyleBits |= nsCachedStyleData::GetBitForSID(aProperty.GetStyleStructID());
}
- void AddValue(nsCSSPropertyID aProperty, StyleAnimationValue&& aStartValue)
+ void AddValue(CSSProperty aProperty, StyleAnimationValue&& aStartValue)
{
PropertyStyleAnimationValuePair* pair = mPropertyValuePairs.AppendElement();
pair->mProperty = aProperty;
pair->mValue = Move(aStartValue);
- mStyleBits |=
- nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]);
+ mStyleBits |= nsCachedStyleData::GetBitForSID(aProperty.GetStyleStructID());
}
private:
~AnimValuesStyleRule() {}
InfallibleTArray<PropertyStyleAnimationValuePair> mPropertyValuePairs;
uint32_t mStyleBits;
};
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -8,16 +8,17 @@
#include "AnimationUtils.h"
#include "mozilla/dom/AnimationBinding.h"
#include "mozilla/dom/AnimationPlaybackEvent.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/AsyncEventDispatcher.h" // For AsyncEventDispatcher
#include "mozilla/Maybe.h" // For Maybe
+#include "mozilla/CSSPropertySet.h"
#include "nsAnimationManager.h" // For CSSAnimation
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
#include "nsIDocument.h" // For nsIDocument
#include "nsIPresShell.h" // For nsIPresShell
#include "nsThreadUtils.h" // For nsRunnableMethod and nsRevocableEventPtr
#include "nsTransitionManager.h" // For CSSTransition
#include "PendingAnimationTracker.h" // For PendingAnimationTracker
@@ -764,17 +765,17 @@ Animation::HasLowerCompositeOrderThan(co
// 3. Finally, generic animations sort by their position in the global
// animation array.
return mAnimationIndex < aOther.mAnimationIndex;
}
void
Animation::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
- nsCSSPropertyIDSet& aSetProperties)
+ CSSPropertySet& aSetProperties)
{
if (!mEffect) {
return;
}
if (!IsInEffect()) {
return;
}
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -28,23 +28,23 @@
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount().
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
struct JSContext;
-class nsCSSPropertyIDSet;
class nsIDocument;
class nsPresContext;
namespace mozilla {
class AnimValuesStyleRule;
+class CSSPropertySet;
namespace dom {
class CSSAnimation;
class CSSTransition;
class Animation
: public DOMEventTargetHelper
@@ -308,17 +308,17 @@ public:
bool CanThrottle() const;
/**
* Updates |aStyleRule| with the animation values of this animation's effect,
* if any.
* Any properties already contained in |aSetProperties| are not changed. Any
* properties that are changed are added to |aSetProperties|.
*/
void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
- nsCSSPropertyIDSet& aSetProperties);
+ CSSPropertySet& aSetProperties);
void NotifyEffectTimingUpdated();
protected:
void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
void SilentlySetPlaybackRate(double aPlaybackRate);
void CancelNoUpdate();
void PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior);
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -593,17 +593,17 @@ EffectCompositor::ComposeAnimationRule(d
RefPtr<AnimValuesStyleRule>& animationRule =
effects->AnimationRule(aCascadeLevel);
animationRule = nullptr;
// If multiple animations specify behavior for the same property the
// animation with the *highest* composite order wins.
// As a result, we iterate from last animation to first and, if a
// property has already been set, we don't change it.
- nsCSSPropertyIDSet properties;
+ CSSPropertySet properties;
for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) {
effect->GetAnimation()->ComposeStyle(animationRule, properties);
}
MOZ_ASSERT(effects == EffectSet::GetEffectSet(aElement, aPseudoType),
"EffectSet should not change while composing style");
@@ -616,21 +616,22 @@ EffectCompositor::GetOverriddenPropertie
nsCSSPropertyIDSet&
aPropertiesOverridden)
{
AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
{
nsCSSPropertyIDSet propertiesToTrackAsSet;
for (KeyframeEffectReadOnly* effect : aEffectSet) {
for (const AnimationProperty& property : effect->Properties()) {
- if (nsCSSProps::PropHasFlags(property.mProperty,
+ if (property.mProperty.IsFixed() &&
+ nsCSSProps::PropHasFlags(property.mProperty.AsFixed(),
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
- !propertiesToTrackAsSet.HasProperty(property.mProperty)) {
- propertiesToTrackAsSet.AddProperty(property.mProperty);
- propertiesToTrack.AppendElement(property.mProperty);
+ !propertiesToTrackAsSet.HasProperty(property.mProperty.AsFixed())) {
+ propertiesToTrackAsSet.AddProperty(property.mProperty.AsFixed());
+ propertiesToTrack.AppendElement(property.mProperty.AsFixed());
}
}
// Skip iterating over the rest of the effects if we've already
// found all the compositor-animatable properties.
if (propertiesToTrack.Length() == LayerAnimationInfo::kRecords) {
break;
}
}
@@ -671,17 +672,17 @@ EffectCompositor::UpdateCascadeResults(E
// since we will apply other properties on the main thread where the usual
// cascade applies.
nsCSSPropertyIDSet overriddenProperties;
if (aStyleContext) {
GetOverriddenProperties(aStyleContext, aEffectSet, overriddenProperties);
}
bool changed = false;
- nsCSSPropertyIDSet animatedProperties;
+ CSSPropertySet animatedProperties;
// Iterate from highest to lowest composite order.
for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) {
MOZ_ASSERT(effect->GetAnimation(),
"Effects on a target element should have an Animation");
bool inEffect = effect->IsInEffect();
for (AnimationProperty& prop : effect->Properties()) {
@@ -700,17 +701,18 @@ EffectCompositor::UpdateCascadeResults(E
// cascade, we need to check that the property isn't being set by
// something with higher priority in the cascade.
//
// We only do this, however, for properties that can be animated on
// the compositor. For properties animated on the main thread the usual
// cascade ensures these animations will be correctly overridden.
if (winsInCascade &&
effect->GetAnimation()->CascadeLevel() == CascadeLevel::Animations &&
- overriddenProperties.HasProperty(prop.mProperty)) {
+ prop.mProperty.IsFixed() &&
+ overriddenProperties.HasProperty(prop.mProperty.AsFixed())) {
winsInCascade = false;
}
if (winsInCascade != prop.mWinsInCascade) {
changed = true;
}
prop.mWinsInCascade = winsInCascade;
}
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -4,24 +4,25 @@
* 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/KeyframeEffect.h"
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
#include "mozilla/AnimationUtils.h"
+#include "mozilla/CSSVariableRegistrations.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
+#include "mozilla/CSSPropertySet.h"
#include "mozilla/KeyframeUtils.h"
#include "mozilla/StyleAnimationValue.h"
#include "Layers.h" // For Layer
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
#include "nsContentUtils.h" // nsContentUtils::ReportToConsole
-#include "nsCSSPropertyIDSet.h"
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
#include "nsIPresShell.h" // For nsIPresShell
#include "nsIScriptError.h"
namespace mozilla {
@@ -491,17 +492,17 @@ KeyframeEffectReadOnly::SetKeyframes(nsT
}
}
const AnimationProperty*
KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSPropertyID aProperty) const
{
for (size_t propIdx = 0, propEnd = mProperties.Length();
propIdx != propEnd; ++propIdx) {
- if (aProperty == mProperties[propIdx].mProperty) {
+ if (mProperties[propIdx].mProperty == aProperty) {
const AnimationProperty* result = &mProperties[propIdx];
if (!result->mWinsInCascade) {
result = nullptr;
}
return result;
}
}
return nullptr;
@@ -570,35 +571,39 @@ KeyframeEffectReadOnly::UpdateProperties
mKeyframes.SwapElements(keyframesCopy);
}
if (mProperties == properties) {
return;
}
// Preserve the state of mWinsInCascade and mIsRunningOnCompositor flags.
- nsCSSPropertyIDSet winningInCascadeProperties;
+ CSSPropertySet winningInCascadeProperties;
nsCSSPropertyIDSet runningOnCompositorProperties;
for (const AnimationProperty& property : mProperties) {
if (property.mWinsInCascade) {
winningInCascadeProperties.AddProperty(property.mProperty);
}
if (property.mIsRunningOnCompositor) {
- runningOnCompositorProperties.AddProperty(property.mProperty);
+ MOZ_ASSERT(property.mProperty.IsFixed(),
+ "Custom properties are non-compositable.");
+ runningOnCompositorProperties.AddProperty(property.mProperty.AsFixed());
}
}
mProperties = Move(properties);
for (AnimationProperty& property : mProperties) {
property.mWinsInCascade =
winningInCascadeProperties.HasProperty(property.mProperty);
property.mIsRunningOnCompositor =
- runningOnCompositorProperties.HasProperty(property.mProperty);
+ property.mProperty.IsCustom()
+ ? false
+ : runningOnCompositorProperties.HasProperty(property.mProperty.AsFixed());
}
CalculateCumulativeChangeHint(aStyleContext);
if (mTarget) {
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
mTarget->mPseudoType);
if (effectSet) {
@@ -606,17 +611,17 @@ KeyframeEffectReadOnly::UpdateProperties
}
RequestRestyle(EffectCompositor::RestyleType::Layer);
}
}
void
KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
- nsCSSPropertyIDSet& aSetProperties)
+ CSSPropertySet& aSetProperties)
{
ComputedTiming computedTiming = GetComputedTiming();
mProgressOnLastCompose = computedTiming.mProgress;
// If the progress is null, we don't have fill data for the current
// time so we shouldn't animate.
if (computedTiming.mProgress.IsNull()) {
return;
@@ -773,27 +778,28 @@ KeyframeEffectOptionsFromUnion(
MOZ_ASSERT(aOptions.IsKeyframeAnimationOptions());
return aOptions.GetAsKeyframeAnimationOptions();
}
template <class OptionsType>
static KeyframeEffectParams
KeyframeEffectParamsFromUnion(const OptionsType& aOptions,
nsAString& aInvalidPacedProperty,
+ const CSSVariableRegistrations* aRegistrations,
ErrorResult& aRv)
{
KeyframeEffectParams result;
if (!aOptions.IsUnrestrictedDouble()) {
const KeyframeEffectOptions& options =
KeyframeEffectOptionsFromUnion(aOptions);
KeyframeEffectParams::ParseSpacing(options.mSpacing,
result.mSpacingMode,
result.mPacedProperty,
aInvalidPacedProperty,
- aRv);
+ Move(aRegistrations), aRv);
}
return result;
}
static Maybe<OwningAnimationTarget>
ConvertTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
{
// Return value optimization.
@@ -833,18 +839,21 @@ KeyframeEffectReadOnly::ConstructKeyfram
TimingParams timingParams =
TimingParams::FromOptionsUnion(aOptions, doc, aRv);
if (aRv.Failed()) {
return nullptr;
}
nsAutoString invalidPacedProperty;
+ const CSSVariableRegistrations* registrations =
+ CSSVariableRegistrationsOfDocument(doc);
KeyframeEffectParams effectOptions =
- KeyframeEffectParamsFromUnion(aOptions, invalidPacedProperty, aRv);
+ KeyframeEffectParamsFromUnion(aOptions, invalidPacedProperty,
+ Move(registrations), aRv);
if (aRv.Failed()) {
return nullptr;
}
if (!invalidPacedProperty.IsEmpty()) {
const char16_t* params[] = { invalidPacedProperty.get() };
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Animation"),
@@ -942,17 +951,23 @@ KeyframeEffectReadOnly::GetTargetStyleCo
pseudo, shell);
}
#ifdef DEBUG
void
DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties)
{
for (auto& p : aAnimationProperties) {
- printf("%s\n", nsCSSProps::GetStringValue(p.mProperty).get());
+ if (p.mProperty.IsFixed()) {
+ printf("%s\n", nsCSSProps::GetStringValue(p.mProperty.AsFixed()).get());
+ } else {
+ nsAutoString name;
+ p.mProperty.AsCustom()->ToString(name);
+ printf("--%s\n", NS_ConvertUTF16toUTF8(name).get());
+ }
for (auto& s : p.mSegments) {
nsString fromValue, toValue;
StyleAnimationValue::UncomputeValue(p.mProperty,
s.mFromValue,
fromValue);
StyleAnimationValue::UncomputeValue(p.mProperty,
s.mToValue,
toValue);
@@ -1000,17 +1015,17 @@ KeyframeEffectReadOnly::GetTarget(
default:
NS_NOTREACHED("Animation of unsupported pseudo-type");
aRv.SetNull();
}
}
static void
-CreatePropertyValue(nsCSSPropertyID aProperty,
+CreatePropertyValue(CSSProperty aProperty,
float aOffset,
const Maybe<ComputedTimingFunction>& aTimingFunction,
const StyleAnimationValue& aValue,
AnimationPropertyValueDetails& aResult)
{
aResult.mOffset = aOffset;
nsString stringValue;
@@ -1029,18 +1044,17 @@ CreatePropertyValue(nsCSSPropertyID aPro
void
KeyframeEffectReadOnly::GetProperties(
nsTArray<AnimationPropertyDetails>& aProperties,
ErrorResult& aRv) const
{
for (const AnimationProperty& property : mProperties) {
AnimationPropertyDetails propertyDetails;
- propertyDetails.mProperty =
- NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(property.mProperty));
+ property.mProperty.ToString(propertyDetails.mProperty);
propertyDetails.mRunningOnCompositor = property.mIsRunningOnCompositor;
nsXPIDLString localizedString;
if (property.mPerformanceWarning &&
property.mPerformanceWarning->ToLocalizedString(localizedString)) {
propertyDetails.mWarning.Construct(localizedString);
}
@@ -1121,34 +1135,43 @@ KeyframeEffectReadOnly::GetKeyframes(JSC
JS::Rooted<JS::Value> keyframeJSValue(aCx);
if (!ToJSValue(aCx, keyframeDict, &keyframeJSValue)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
JS::Rooted<JSObject*> keyframeObject(aCx, &keyframeJSValue.toObject());
for (const PropertyValuePair& propertyValue : keyframe.mPropertyValues) {
+ nsCString name;
+ if (propertyValue.mProperty.IsFixed()) {
+ name = nsCSSProps::PropertyIDLName(propertyValue.mProperty.AsFixed());
+ } else {
+ nsString utf16Name;
+ propertyValue.mProperty.ToString(utf16Name);
+ name = ToNewUTF8String(utf16Name);
+ }
- const char* name = nsCSSProps::PropertyIDLName(propertyValue.mProperty);
-
- // nsCSSValue::AppendToString does not accept shorthands properties but
+ // nsCSSValue::AppendToString does not accept shorthand properties, but
// works with token stream values if we pass eCSSProperty_UNKNOWN as
// the property.
+ // It works with variables if we supply eCSSProperty_UNKNOQN, because for
+ // all types we might set the nsCSSValue to, we don't run into a case
+ // where we need to know the specific proprty.
nsCSSPropertyID propertyForSerializing =
- nsCSSProps::IsShorthand(propertyValue.mProperty)
+ (propertyValue.mProperty.IsCustom() || propertyValue.mProperty.IsShorthand())
? eCSSProperty_UNKNOWN
- : propertyValue.mProperty;
+ : propertyValue.mProperty.AsFixed();
nsAutoString stringValue;
propertyValue.mValue.AppendToString(
propertyForSerializing, stringValue, nsCSSValue::eNormalized);
JS::Rooted<JS::Value> value(aCx);
if (!ToJSValue(aCx, stringValue, &value) ||
- !JS_DefineProperty(aCx, keyframeObject, name, value,
+ !JS_DefineProperty(aCx, keyframeObject, name.get(), value,
JSPROP_ENUMERATE)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
}
aResult.AppendElement(keyframeObject);
}
@@ -1413,17 +1436,18 @@ KeyframeEffectReadOnly::ShouldBlockAsync
for (const AnimationProperty& property : mProperties) {
// If a property is overridden in the CSS cascade, it should not block other
// animations from running on the compositor.
if (!property.mWinsInCascade) {
continue;
}
// Check for geometric properties
- if (IsGeometricProperty(property.mProperty)) {
+ if (property.mProperty.IsFixed() &&
+ IsGeometricProperty(property.mProperty.AsFixed())) {
aPerformanceWarning =
AnimationPerformanceWarning::Type::TransformWithGeometricProperties;
return true;
}
// Check for unsupported transform animations
if (property.mProperty == eCSSProperty_transform) {
if (!CanAnimateTransformOnCompositor(aFrame,
@@ -1454,17 +1478,17 @@ KeyframeEffectReadOnly::SetPerformanceWa
AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement);
}
return;
}
}
}
static already_AddRefed<nsStyleContext>
-CreateStyleContextForAnimationValue(nsCSSPropertyID aProperty,
+CreateStyleContextForAnimationValue(CSSProperty aProperty,
StyleAnimationValue aValue,
nsStyleContext* aBaseStyleContext)
{
MOZ_ASSERT(aBaseStyleContext,
"CreateStyleContextForAnimationValue needs to be called "
"with a valid nsStyleContext");
RefPtr<AnimValuesStyleRule> styleRule = new AnimValuesStyleRule();
@@ -1478,17 +1502,17 @@ CreateStyleContextForAnimationValue(nsCS
nsStyleSet* styleSet =
aBaseStyleContext->PresContext()->StyleSet()->AsGecko();
RefPtr<nsStyleContext> styleContext =
styleSet->ResolveStyleByAddingRules(aBaseStyleContext, rules);
// We need to call StyleData to generate cached data for the style context.
// Otherwise CalcStyleDifference returns no meaningful result.
- styleContext->StyleData(nsCSSProps::kSIDTable[aProperty]);
+ styleContext->StyleData(aProperty.GetStyleStructID());
return styleContext.forget();
}
void
KeyframeEffectReadOnly::CalculateCumulativeChangeHint(
nsStyleContext *aStyleContext)
{
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -27,44 +27,44 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/TimingParams.h"
#include "mozilla/dom/AnimationEffectReadOnly.h"
#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Nullable.h"
struct JSContext;
-class nsCSSPropertyIDSet;
class nsIContent;
class nsIDocument;
class nsIFrame;
class nsIPresShell;
class nsPresContext;
namespace mozilla {
class AnimValuesStyleRule;
enum class CSSPseudoElementType : uint8_t;
+class CSSPropertySet;
namespace dom {
class ElementOrCSSPseudoElement;
class OwningElementOrCSSPseudoElement;
class UnrestrictedDoubleOrKeyframeAnimationOptions;
class UnrestrictedDoubleOrKeyframeEffectOptions;
enum class IterationCompositeOperation : uint32_t;
enum class CompositeOperation : uint32_t;
struct AnimationPropertyDetails;
}
/**
* A property-value pair specified on a keyframe.
*/
struct PropertyValuePair
{
- nsCSSPropertyID mProperty;
+ CSSProperty mProperty;
// The specified value for the property. For shorthand properties or invalid
// property values, we store the specified property value as a token stream
// (string).
nsCSSValue mValue;
bool operator==(const PropertyValuePair& aOther) const {
return mProperty == aOther.mProperty &&
mValue == aOther.mValue;
@@ -129,17 +129,17 @@ struct AnimationPropertySegment
}
bool operator!=(const AnimationPropertySegment& aOther) const {
return !(*this == aOther);
}
};
struct AnimationProperty
{
- nsCSSPropertyID mProperty = eCSSProperty_UNKNOWN;
+ CSSProperty mProperty;
// Does this property win in the CSS Cascade?
//
// For CSS transitions, this is true as long as a CSS animation on the
// same property and element is not running, in which case we set this
// to false so that the animation (lower in the cascade) can win. We
// then use this to decide whether to apply the style both in the CSS
// cascade and for OMTA.
@@ -305,17 +305,17 @@ public:
// |aStyleContext| to resolve specified values.
void UpdateProperties(nsStyleContext* aStyleContext);
// Updates |aStyleRule| with the animation values produced by this
// AnimationEffect for the current time except any properties already
// contained in |aSetProperties|.
// Any updated properties are added to |aSetProperties|.
void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
- nsCSSPropertyIDSet& aSetProperties);
+ CSSPropertySet& aSetProperties);
// Returns true if at least one property is being animated on compositor.
bool IsRunningOnCompositor() const;
void SetIsRunningOnCompositor(nsCSSPropertyID aProperty, bool aIsRunning);
void ResetIsRunningOnCompositor();
// Returns true if this effect, applied to |aFrame|, contains properties
// that mean we shouldn't run transform compositor animations on this element.
//
--- a/dom/animation/KeyframeEffectParams.cpp
+++ b/dom/animation/KeyframeEffectParams.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/KeyframeEffectParams.h"
+#include "mozilla/CSSVariableRegistrations.h"
#include "mozilla/KeyframeUtils.h"
#include "mozilla/RangedPtr.h"
#include "nsReadableUtils.h"
namespace mozilla {
static inline bool
IsLetter(char16_t aCh)
@@ -100,18 +101,20 @@ ConsumeIdentToken(RangedPtr<const char16
}
++aIter;
}
}
/* static */ void
KeyframeEffectParams::ParseSpacing(const nsAString& aSpacing,
SpacingMode& aSpacingMode,
- nsCSSPropertyID& aPacedProperty,
+ CSSProperty& aPacedProperty,
nsAString& aInvalidPacedProperty,
+ const CSSVariableRegistrations*
+ aRegistrations,
ErrorResult& aRv)
{
aInvalidPacedProperty.Truncate();
// Parse spacing.
// distribute | paced({ident})
// https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-spacing
// 1. distribute spacing.
@@ -133,28 +136,37 @@ KeyframeEffectParams::ParseSpacing(const
nsAutoString identToken;
ConsumeIdentToken(iter, end, identToken);
if (identToken.IsEmpty()) {
aRv.ThrowTypeError<dom::MSG_INVALID_SPACING_MODE_ERROR>(aSpacing);
return;
}
- aPacedProperty =
+ nsCSSPropertyID property =
nsCSSProps::LookupProperty(identToken, CSSEnabledState::eForAllContent);
- if (aPacedProperty == eCSSProperty_UNKNOWN ||
- aPacedProperty == eCSSPropertyExtra_variable ||
- !KeyframeUtils::IsAnimatableProperty(aPacedProperty)) {
- aPacedProperty = eCSSProperty_UNKNOWN;
+ if (property == eCSSPropertyExtra_variable) {
+ aPacedProperty =
+ nsCSSProps::LookupCustomProperty(aRegistrations, identToken,
+ CSSEnabledState::eForAllContent);
+ if (aPacedProperty == eCSSProperty_UNKNOWN) {
+ aInvalidPacedProperty = identToken;
+ }
+ } else if (property == eCSSProperty_UNKNOWN ||
+ !KeyframeUtils::IsAnimatableProperty(property)) {
+ aPacedProperty = CSSProperty(eCSSProperty_UNKNOWN);
aInvalidPacedProperty = identToken;
+ } else {
+ aPacedProperty = CSSProperty(property);
}
if (end - iter.get() != 1 || *iter != ')') {
aRv.ThrowTypeError<dom::MSG_INVALID_SPACING_MODE_ERROR>(aSpacing);
return;
}
- aSpacingMode = aPacedProperty == eCSSProperty_UNKNOWN
+ aSpacingMode = (aPacedProperty.IsFixed() &&
+ aPacedProperty.AsFixed() == eCSSProperty_UNKNOWN)
? SpacingMode::distribute
: SpacingMode::paced;
}
} // namespace mozilla
--- a/dom/animation/KeyframeEffectParams.h
+++ b/dom/animation/KeyframeEffectParams.h
@@ -2,36 +2,48 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_KeyframeEffectParams_h
#define mozilla_KeyframeEffectParams_h
+#include "mozilla/CSSProperty.h"
+#include "nsCSSPropertyID.h"
#include "nsCSSProps.h"
#include "nsString.h"
namespace mozilla {
+struct CSSVariableRegistrations;
+
enum class SpacingMode
{
distribute,
paced
};
struct KeyframeEffectParams
{
void GetSpacingAsString(nsAString& aSpacing) const
{
if (mSpacingMode == SpacingMode::distribute) {
aSpacing.AssignLiteral("distribute");
} else {
aSpacing.AssignLiteral("paced(");
- aSpacing.AppendASCII(nsCSSProps::GetStringValue(mPacedProperty).get());
+ if (mPacedProperty.IsFixed()) {
+ aSpacing.AppendASCII(nsCSSProps::GetStringValue(mPacedProperty.AsFixed()).get());
+ } else {
+ nsAutoString name, unprefixedName;
+ mPacedProperty.AsCustom()->ToString(unprefixedName);
+ name.AppendLiteral("--");
+ name.Append(unprefixedName);
+ aSpacing.Append(name);
+ }
aSpacing.AppendLiteral(")");
}
}
/**
* Parse spacing string.
*
* @param aSpacing The input spacing string.
@@ -40,21 +52,22 @@ struct KeyframeEffectParams
* @param [out] aInvalidPacedProperty A string that, if we parsed a string of
* the form 'paced(<ident>)' where <ident>
* is not a recognized animatable property,
* will be set to <ident>.
* @param [out] aRv The error result.
*/
static void ParseSpacing(const nsAString& aSpacing,
SpacingMode& aSpacingMode,
- nsCSSPropertyID& aPacedProperty,
+ CSSProperty& aPacedProperty,
nsAString& aInvalidPacedProperty,
+ const CSSVariableRegistrations* aRegistrations,
ErrorResult& aRv);
// FIXME: Bug 1216843: Add IterationCompositeOperations and
// Bug 1216844: Add CompositeOperation
SpacingMode mSpacingMode = SpacingMode::distribute;
- nsCSSPropertyID mPacedProperty = eCSSProperty_UNKNOWN;
+ CSSProperty mPacedProperty = CSSProperty(eCSSProperty_UNKNOWN);
};
} // namespace mozilla
#endif // mozilla_KeyframeEffectParams_h
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -1,18 +1,22 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/KeyframeUtils.h"
#include "mozilla/AnimationUtils.h"
+#include "mozilla/CSSVariableRegistration.h"
+#include "mozilla/CSSVariableRegistrations.h"
#include "mozilla/ErrorResult.h"
+#include "mozilla/CSSPropertySet.h"
#include "mozilla/Move.h"
+#include "mozilla/RefPtr.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/TimingParams.h"
#include "mozilla/dom/BaseKeyframeTypesBinding.h" // For FastBaseKeyframe etc.
#include "mozilla/dom/Element.h"
#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
#include "jsapi.h" // For ForOfIterator etc.
#include "nsClassHashtable.h"
@@ -34,19 +38,20 @@ namespace mozilla {
// we set its cumulative distance to kNotPaceable, so we can use this to check.
const double kNotPaceable = -1.0;
// For the aAllowList parameter of AppendStringOrStringSequence and
// GetPropertyValuesPairs.
enum class ListAllowance { eDisallow, eAllow };
/**
- * A comparator to sort nsCSSPropertyID values such that longhands are sorted
+ * A comparator to sort CSSProperty values such that longhands are sorted
* before shorthands, and shorthands with fewer components are sorted before
* shorthands with more components.
+ * Custom properties come last.
*
* Using this allows us to prioritize values specified by longhands (or smaller
* shorthand subsets) when longhands and shorthands are both specified
* on the one keyframe.
*
* Example orderings that result from this:
*
* margin-left, margin
@@ -56,50 +61,63 @@ enum class ListAllowance { eDisallow, eA
* border-top-color, border-color, border-top, border
*/
class PropertyPriorityComparator
{
public:
PropertyPriorityComparator()
: mSubpropertyCountInitialized(false) {}
- bool Equals(nsCSSPropertyID aLhs, nsCSSPropertyID aRhs) const
+ bool Equals(CSSProperty aLhs, CSSProperty aRhs) const
{
return aLhs == aRhs;
}
- bool LessThan(nsCSSPropertyID aLhs,
- nsCSSPropertyID aRhs) const
+ bool LessThan(CSSProperty aLhs,
+ CSSProperty aRhs) const
{
- bool isShorthandLhs = nsCSSProps::IsShorthand(aLhs);
- bool isShorthandRhs = nsCSSProps::IsShorthand(aRhs);
+ // First, ensure that custom properties sort last.
+ // Between custom properties, we sort by name.
+ if (aLhs.IsCustom() && aRhs.IsCustom()) {
+ return aLhs.IsCustomLessThan(aRhs);
+ } else if (aLhs.IsCustom()) {
+ return false;
+ } else if (aRhs.IsCustom()) {
+ return true;
+ }
+
+ nsCSSPropertyID left = aLhs.AsFixed();
+ nsCSSPropertyID right = aRhs.AsFixed();
+
+ bool isShorthandLhs = nsCSSProps::IsShorthand(left);
+ bool isShorthandRhs = nsCSSProps::IsShorthand(right);
if (isShorthandLhs) {
if (isShorthandRhs) {
- // First, sort shorthands by the number of longhands they have.
- uint32_t subpropCountLhs = SubpropertyCount(aLhs);
- uint32_t subpropCountRhs = SubpropertyCount(aRhs);
+ // Next, sort shorthands by the number of longhands they have.
+ uint32_t subpropCountLhs = SubpropertyCount(left);
+ uint32_t subpropCountRhs = SubpropertyCount(right);
if (subpropCountLhs != subpropCountRhs) {
return subpropCountLhs < subpropCountRhs;
}
// Otherwise, sort by IDL name below.
} else {
// Put longhands before shorthands.
return false;
}
} else {
if (isShorthandRhs) {
// Put longhands before shorthands.
return true;
}
}
// For two longhand properties, or two shorthand with the same number
// of longhand components, sort by IDL name.
- return nsCSSProps::PropertyIDLNameSortPosition(aLhs) <
- nsCSSProps::PropertyIDLNameSortPosition(aRhs);
+ return nsCSSProps::PropertyIDLNameSortPosition(left) <
+ nsCSSProps::PropertyIDLNameSortPosition(right);
}
uint32_t SubpropertyCount(nsCSSPropertyID aProperty) const
{
if (!mSubpropertyCountInitialized) {
PodZero(&mSubpropertyCount);
mSubpropertyCountInitialized = true;
}
@@ -200,17 +218,17 @@ public:
};
Iter begin() { return Iter(*this); }
Iter end() { return Iter::EndIter(*this); }
private:
struct PropertyAndIndex
{
- nsCSSPropertyID mProperty;
+ CSSProperty mProperty;
size_t mIndex; // Index of mProperty within mProperties
typedef TPropertyPriorityComparator<PropertyAndIndex> Comparator;
};
const nsTArray<PropertyValuePair>& mProperties;
nsTArray<PropertyAndIndex> mSortedPropertyIndices;
};
@@ -220,75 +238,93 @@ private:
* discovered on a regular keyframe or property-indexed keyframe object.
*
* Single values (as required by a regular keyframe, and as also supported
* on property-indexed keyframes) are stored as the only element in
* mValues.
*/
struct PropertyValuesPair
{
- nsCSSPropertyID mProperty;
+ CSSProperty mProperty;
nsTArray<nsString> mValues;
typedef TPropertyPriorityComparator<PropertyValuesPair> Comparator;
};
/**
* An additional property (for a property-values pair) found on a
* BaseKeyframe or BasePropertyIndexedKeyframe object.
*/
struct AdditionalProperty
{
- nsCSSPropertyID mProperty;
+ CSSProperty mProperty;
size_t mJsidIndex; // Index into |ids| in GetPropertyValuesPairs.
struct PropertyComparator
{
bool Equals(const AdditionalProperty& aLhs,
const AdditionalProperty& aRhs) const
{
return aLhs.mProperty == aRhs.mProperty;
}
bool LessThan(const AdditionalProperty& aLhs,
const AdditionalProperty& aRhs) const
{
- return nsCSSProps::PropertyIDLNameSortPosition(aLhs.mProperty) <
- nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty);
+ if (aLhs.mProperty.IsCustom() && aRhs.mProperty.IsCustom()) {
+ return aLhs.mProperty.IsCustomLessThan(aRhs.mProperty);
+ } else if (aLhs.mProperty.IsCustom()) {
+ return false;
+ } else if (aRhs.mProperty.IsCustom()) {
+ return true;
+ }
+ return nsCSSProps::PropertyIDLNameSortPosition(aLhs.mProperty.AsFixed()) <
+ nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty.AsFixed());
}
};
};
/**
* Data for a segment in a keyframe animation of a given property
* whose value is a StyleAnimationValue.
*
* KeyframeValueEntry is used in GetAnimationPropertiesFromKeyframes
* to gather data for each individual segment.
*/
struct KeyframeValueEntry
{
- nsCSSPropertyID mProperty;
+ CSSProperty mProperty;
StyleAnimationValue mValue;
float mOffset;
Maybe<ComputedTimingFunction> mTimingFunction;
struct PropertyOffsetComparator
{
static bool Equals(const KeyframeValueEntry& aLhs,
const KeyframeValueEntry& aRhs)
{
return aLhs.mProperty == aRhs.mProperty &&
aLhs.mOffset == aRhs.mOffset;
}
static bool LessThan(const KeyframeValueEntry& aLhs,
const KeyframeValueEntry& aRhs)
{
- // First, sort by property IDL name.
- int32_t order = nsCSSProps::PropertyIDLNameSortPosition(aLhs.mProperty) -
- nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty);
+ // First, make custom properties sort greater than all fixed properties.
+ // Sort custom properties by name.
+ if (aLhs.mProperty.IsCustom() && aRhs.mProperty.IsCustom()) {
+ return aLhs.mProperty.IsCustomLessThan(aRhs.mProperty);
+ } else if (aLhs.mProperty.IsCustom()) {
+ return false;
+ } else if (aRhs.mProperty.IsCustom()) {
+ return true;
+ }
+
+ // Next, sort by property IDL name.
+ int32_t order =
+ nsCSSProps::PropertyIDLNameSortPosition(aLhs.mProperty.AsFixed()) -
+ nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty.AsFixed());
if (order != 0) {
return order < 0;
}
// Then, by offset.
return aLhs.mOffset < aRhs.mOffset;
}
};
@@ -321,17 +357,17 @@ IsInvalidValuePair(const PropertyValuePa
//
// * Shorthand values (where we manually extract the token stream's string
// value) and pass that along to various parsing methods
// * Longhand values with variable references
// * Invalid values
//
// We can distinguish between the last two cases because for invalid values
// we leave the token stream's mPropertyID as eCSSProperty_UNKNOWN.
- return !nsCSSProps::IsShorthand(aPair.mProperty) &&
+ return !aPair.mProperty.IsShorthand() &&
aPair.mValue.GetUnit() == eCSSUnit_TokenStream &&
aPair.mValue.GetTokenStreamValue()->mPropertyID
== eCSSProperty_UNKNOWN;
}
// ------------------------------------------------------------------
//
@@ -351,31 +387,32 @@ ConvertKeyframeSequence(JSContext* aCx,
nsIDocument* aDocument,
JS::ForOfIterator& aIterator,
nsTArray<Keyframe>& aResult);
static bool
GetPropertyValuesPairs(JSContext* aCx,
JS::Handle<JSObject*> aObject,
ListAllowance aAllowLists,
- nsTArray<PropertyValuesPair>& aResult);
+ nsTArray<PropertyValuesPair>& aResult,
+ const CSSVariableRegistrations* aRegistrations);
static bool
AppendStringOrStringSequenceToArray(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ListAllowance aAllowLists,
nsTArray<nsString>& aValues);
static bool
AppendValueAsString(JSContext* aCx,
nsTArray<nsString>& aValues,
JS::Handle<JS::Value> aValue);
static PropertyValuePair
-MakePropertyValuePair(nsCSSPropertyID aProperty, const nsAString& aStringValue,
+MakePropertyValuePair(CSSProperty aProperty, const nsAString& aStringValue,
nsCSSParser& aParser, nsIDocument* aDocument);
static bool
HasValidOffsets(const nsTArray<Keyframe>& aKeyframes);
static void
MarkAsComputeValuesFailureKey(PropertyValuePair& aPair);
@@ -406,17 +443,17 @@ static void
DistributeRange(const Range<Keyframe>& aSpacingRange);
static void
PaceRange(const Range<Keyframe>& aKeyframes,
const Range<double>& aCumulativeDistances);
static nsTArray<double>
GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
- nsCSSPropertyID aProperty);
+ CSSProperty aProperty);
// ------------------------------------------------------------------
//
// Public API
//
// ------------------------------------------------------------------
/* static */ nsTArray<Keyframe>
@@ -469,26 +506,30 @@ KeyframeUtils::GetKeyframesFromObject(JS
}
return keyframes;
}
/* static */ void
KeyframeUtils::ApplySpacing(nsTArray<Keyframe>& aKeyframes,
SpacingMode aSpacingMode,
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
nsTArray<ComputedKeyframeValues>& aComputedValues)
{
if (aKeyframes.IsEmpty()) {
return;
}
nsTArray<double> cumulativeDistances;
if (aSpacingMode == SpacingMode::paced) {
- MOZ_ASSERT(IsAnimatableProperty(aProperty),
+ // We check if the custom property is registered (meaning we should try to
+ // animate it) in ParseSpacing. If we fail to animate anyways, one of the
+ // StyleAnimationValue functions should report failure.
+ MOZ_ASSERT(aProperty.IsCustom() ||
+ IsAnimatableProperty(aProperty.AsFixed()),
"Paced property should be animatable");
cumulativeDistances = GetCumulativeDistances(aComputedValues, aProperty);
// Reset the computed offsets if using paced spacing.
for (Keyframe& keyframe : aKeyframes) {
keyframe.mComputedOffset = Keyframe::kComputedOffsetNotSet;
}
}
@@ -571,47 +612,47 @@ KeyframeUtils::ApplySpacing(nsTArray<Key
keyframeA = keyframeB;
}
}
/* static */ void
KeyframeUtils::ApplyDistributeSpacing(nsTArray<Keyframe>& aKeyframes)
{
nsTArray<ComputedKeyframeValues> emptyArray;
- ApplySpacing(aKeyframes, SpacingMode::distribute, eCSSProperty_UNKNOWN,
- emptyArray);
+ ApplySpacing(aKeyframes, SpacingMode::distribute,
+ CSSProperty(eCSSProperty_UNKNOWN), emptyArray);
}
/* static */ nsTArray<ComputedKeyframeValues>
KeyframeUtils::GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
dom::Element* aElement,
nsStyleContext* aStyleContext)
{
MOZ_ASSERT(aStyleContext);
MOZ_ASSERT(aElement);
const size_t len = aKeyframes.Length();
nsTArray<ComputedKeyframeValues> result(len);
for (const Keyframe& frame : aKeyframes) {
- nsCSSPropertyIDSet propertiesOnThisKeyframe;
+ CSSPropertySet propertiesOnThisKeyframe;
ComputedKeyframeValues* computedValues = result.AppendElement();
for (const PropertyValuePair& pair :
PropertyPriorityIterator(frame.mPropertyValues)) {
if (IsInvalidValuePair(pair)) {
continue;
}
// Expand each value into the set of longhands and produce
// a KeyframeValueEntry for each value.
nsTArray<PropertyStyleAnimationValuePair> values;
// For shorthands, we store the string as a token stream so we need to
// extract that first.
- if (nsCSSProps::IsShorthand(pair.mProperty)) {
+ if (pair.mProperty.IsShorthand()) {
nsCSSValueTokenStream* tokenStream = pair.mValue.GetTokenStreamValue();
if (!StyleAnimationValue::ComputeValues(pair.mProperty,
CSSEnabledState::eForAllContent, aElement, aStyleContext,
tokenStream->mTokenStream, /* aUseSVGMode */ false, values) ||
IsComputeValuesFailureKey(pair)) {
continue;
}
} else {
@@ -794,36 +835,40 @@ ConvertKeyframeSequence(JSContext* aCx,
if (rv.MaybeSetPendingException(aCx)) {
return false;
}
// Look for additional property-values pairs on the object.
nsTArray<PropertyValuesPair> propertyValuePairs;
if (value.isObject()) {
JS::Rooted<JSObject*> object(aCx, &value.toObject());
+ const CSSVariableRegistrations* registrations =
+ CSSVariableRegistrationsOfDocument(aDocument);
if (!GetPropertyValuesPairs(aCx, object,
ListAllowance::eDisallow,
- propertyValuePairs)) {
+ propertyValuePairs,
+ Move(registrations))) {
return false;
}
}
for (PropertyValuesPair& pair : propertyValuePairs) {
MOZ_ASSERT(pair.mValues.Length() == 1);
keyframe->mPropertyValues.AppendElement(
MakePropertyValuePair(pair.mProperty, pair.mValues[0], parser,
aDocument));
// When we go to convert keyframes into arrays of property values we
// call StyleAnimation::ComputeValues. This should normally return true
// but in order to test the case where it does not, BaseKeyframeDict
// includes a chrome-only member that can be set to indicate that
// ComputeValues should fail for shorthand property values on that
// keyframe.
- if (nsCSSProps::IsShorthand(pair.mProperty) &&
+ if (pair.mProperty.IsFixed() &&
+ nsCSSProps::IsShorthand(pair.mProperty.AsFixed()) &&
keyframeDict.mSimulateComputeValuesFailure) {
MarkAsComputeValuesFailureKey(keyframe->mPropertyValues.LastElement());
}
}
}
return true;
}
@@ -839,17 +884,18 @@ ConvertKeyframeSequence(JSContext* aCx,
* pairs will be stored.
* @return false on failure or JS exception thrown while interacting
* with aObject; true otherwise.
*/
static bool
GetPropertyValuesPairs(JSContext* aCx,
JS::Handle<JSObject*> aObject,
ListAllowance aAllowLists,
- nsTArray<PropertyValuesPair>& aResult)
+ nsTArray<PropertyValuesPair>& aResult,
+ const CSSVariableRegistrations* aRegistrations)
{
nsTArray<AdditionalProperty> properties;
// Iterate over all the properties on aObject and append an
// entry to properties for them.
//
// We don't compare the jsids that we encounter with those for
// the explicit dictionary members, since we know that none
@@ -858,23 +904,37 @@ GetPropertyValuesPairs(JSContext* aCx,
if (!JS_Enumerate(aCx, aObject, &ids)) {
return false;
}
for (size_t i = 0, n = ids.length(); i < n; i++) {
nsAutoJSString propName;
if (!propName.init(aCx, ids[i])) {
return false;
}
- nsCSSPropertyID property =
- nsCSSProps::LookupPropertyByIDLName(propName,
- CSSEnabledState::eForAllContent);
- if (KeyframeUtils::IsAnimatableProperty(property)) {
- AdditionalProperty* p = properties.AppendElement();
- p->mProperty = property;
- p->mJsidIndex = i;
+ // "If property follows the <custom-property-name> production, return
+ // property."
+ // https://w3c.github.io/web-animations/#property-name-conversion
+ if (nsCSSProps::IsCustomPropertyName(propName)) {
+ CSSProperty property =
+ nsCSSProps::LookupCustomProperty(aRegistrations, propName,
+ CSSEnabledState::eForAllContent);
+ if (property != eCSSProperty_UNKNOWN) {
+ AdditionalProperty* p = properties.AppendElement();
+ p->mProperty = Move(property);
+ p->mJsidIndex = i;
+ }
+ } else {
+ nsCSSPropertyID property =
+ nsCSSProps::LookupPropertyByIDLName(propName,
+ CSSEnabledState::eForAllContent);
+ if (KeyframeUtils::IsAnimatableProperty(property)) {
+ AdditionalProperty* p = properties.AppendElement();
+ p->mProperty = CSSProperty(property);
+ p->mJsidIndex = i;
+ }
}
}
// Sort the entries by IDL name and then get each value and
// convert it either to a DOMString or to a
// (DOMString or sequence<DOMString>), depending on aAllowLists,
// and build up aResult.
properties.Sort(AdditionalProperty::PropertyComparator());
@@ -959,29 +1019,47 @@ AppendValueAsString(JSContext* aCx,
*
* @param aProperty The CSS property.
* @param aStringValue The property value to parse.
* @param aParser The CSS parser object to use.
* @param aDocument The document to use when parsing.
* @return The constructed PropertyValuePair object.
*/
static PropertyValuePair
-MakePropertyValuePair(nsCSSPropertyID aProperty, const nsAString& aStringValue,
+MakePropertyValuePair(CSSProperty aProperty, const nsAString& aStringValue,
nsCSSParser& aParser, nsIDocument* aDocument)
{
MOZ_ASSERT(aDocument);
nsCSSValue value;
- if (!nsCSSProps::IsShorthand(aProperty)) {
- aParser.ParseLonghandProperty(aProperty,
- aStringValue,
- aDocument->GetDocumentURI(),
- aDocument->GetDocumentURI(),
- aDocument->NodePrincipal(),
- value);
+ if (aProperty.IsFixed()) {
+ nsCSSPropertyID propID = aProperty.AsFixed();
+ if (!nsCSSProps::IsShorthand(propID)) {
+ aParser.ParseLonghandProperty(propID,
+ aStringValue,
+ aDocument->GetDocumentURI(),
+ aDocument->GetDocumentURI(),
+ aDocument->NodePrincipal(),
+ value);
+ }
+ } else {
+ const CSSVariableRegistrations* registrations =
+ CSSVariableRegistrationsOfDocument(aDocument);
+ CSSVariableRegistration* registration;
+ nsString name;
+ aProperty.AsCustom()->ToString(name);
+ if (registrations && registrations->mData.Get(name, ®istration)) {
+ CSSValueType type;
+ aParser.ParseTypedValue(registration->mSyntax,
+ aStringValue,
+ aDocument->GetDocumentURI(),
+ aDocument->GetDocumentURI(),
+ aDocument->NodePrincipal(),
+ value, type);
+ }
}
if (value.GetUnit() == eCSSUnit_Null) {
// Either we have a shorthand, or we failed to parse a longhand.
// In either case, store the string value as a token stream.
nsCSSValueTokenStream* tokenStream = new nsCSSValueTokenStream;
tokenStream->mTokenStream = aStringValue;
@@ -1035,17 +1113,18 @@ HasValidOffsets(const nsTArray<Keyframe>
* that value we should behave as if that function had failed.
*
* @param aPair The PropertyValuePair to modify. |aPair.mProperty| must be
* a shorthand property.
*/
static void
MarkAsComputeValuesFailureKey(PropertyValuePair& aPair)
{
- MOZ_ASSERT(nsCSSProps::IsShorthand(aPair.mProperty),
+ MOZ_ASSERT(aPair.mProperty.IsFixed() &&
+ nsCSSProps::IsShorthand(aPair.mProperty.AsFixed()),
"Only shorthand property values can be marked as failure values");
// We store shorthand values as nsCSSValueTokenStream objects whose mProperty
// and mShorthandPropertyID are eCSSProperty_UNKNOWN and whose mTokenStream
// member contains the shorthand property's value as a string.
//
// We need to leave mShorthandPropertyID as eCSSProperty_UNKNOWN so that
// nsCSSValue::AppendToString returns the mTokenStream value, but we can
@@ -1064,17 +1143,18 @@ MarkAsComputeValuesFailureKey(PropertyVa
* value).
*
* @param aPair The property-value pair to test.
* @return True if |aPair| represents a failure value.
*/
static bool
IsComputeValuesFailureKey(const PropertyValuePair& aPair)
{
- return nsCSSProps::IsShorthand(aPair.mProperty) &&
+ return aPair.mProperty.IsFixed() &&
+ nsCSSProps::IsShorthand(aPair.mProperty.AsFixed()) &&
aPair.mValue.GetTokenStreamValue()->mPropertyID ==
eCSSPropertyExtra_no_properties;
}
/**
* Builds an array of AnimationProperty objects to represent the keyframe
* animation segments in aEntries.
*/
@@ -1111,17 +1191,17 @@ BuildSegmentsFromValueEntries(nsStyleCon
// one KeyframeValueEntry with offset 0.0, and at least one with offset 1.0.
// However, since it is possible that when building |aEntries|, the call to
// StyleAnimationValue::ComputeValues might fail, this can't be guaranteed.
// Furthermore, since we don't yet implement additive animation and hence
// don't have sensible fallback behavior when these values are missing, the
// following loop takes care to identify properties that lack a value at
// offset 0.0/1.0 and drops those properties from |aResult|.
- nsCSSPropertyID lastProperty = eCSSProperty_UNKNOWN;
+ CSSProperty lastProperty = CSSProperty(eCSSProperty_UNKNOWN);
AnimationProperty* animationProperty = nullptr;
size_t i = 0, n = aEntries.Length();
while (i < n) {
// Check that the last property ends with an entry at offset 1.
if (i + 1 == n) {
if (aEntries[i].mOffset != 1.0f && animationProperty) {
@@ -1252,18 +1332,20 @@ GetKeyframeListFromPropertyIndexedKeyfra
TimingParams::ParseEasing(keyframeDict.mEasing, aDocument, aRv);
if (aRv.Failed()) {
return;
}
// Get all the property--value-list pairs off the object.
JS::Rooted<JSObject*> object(aCx, &aValue.toObject());
nsTArray<PropertyValuesPair> propertyValuesPairs;
+ const CSSVariableRegistrations* registrations =
+ CSSVariableRegistrationsOfDocument(aDocument);
if (!GetPropertyValuesPairs(aCx, object, ListAllowance::eAllow,
- propertyValuesPairs)) {
+ propertyValuesPairs, registrations)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
// Create a set of keyframes for each property.
nsCSSParser parser(aDocument->CSSLoader());
nsClassHashtable<nsFloatHashKey, Keyframe> processedKeyframes;
for (const PropertyValuesPair& pair : propertyValuesPairs) {
@@ -1326,21 +1408,21 @@ RequiresAdditiveAnimation(const nsTArray
// StyleAnimationValue since doing that requires a target element bound to
// a document which we might not always have at the point where we want to
// perform this check.
//
// This is only a temporary measure until we implement additive animation.
// So as long as this check catches most cases, and we don't do anything
// horrible in one of the cases we can't detect, it should be sufficient.
- nsCSSPropertyIDSet properties; // All properties encountered.
- nsCSSPropertyIDSet propertiesWithFromValue; // Those with a defined 0% value.
- nsCSSPropertyIDSet propertiesWithToValue; // Those with a defined 100% value.
+ CSSPropertySet properties; // All properties encountered.
+ CSSPropertySet propertiesWithFromValue; // Those with a defined 0% value.
+ CSSPropertySet propertiesWithToValue; // Those with a defined 100% value.
- auto addToPropertySets = [&](nsCSSPropertyID aProperty, double aOffset) {
+ auto addToPropertySets = [&](CSSProperty aProperty, double aOffset) {
properties.AddProperty(aProperty);
if (aOffset == 0.0) {
propertiesWithFromValue.AddProperty(aProperty);
} else if (aOffset == 1.0) {
propertiesWithToValue.AddProperty(aProperty);
}
};
@@ -1358,26 +1440,27 @@ RequiresAdditiveAnimation(const nsTArray
? frame.mOffset.value()
: computedOffset;
for (const PropertyValuePair& pair : frame.mPropertyValues) {
if (IsInvalidValuePair(pair)) {
continue;
}
- if (nsCSSProps::IsShorthand(pair.mProperty)) {
+ if (pair.mProperty.IsFixed() &&
+ nsCSSProps::IsShorthand(pair.mProperty.AsFixed())) {
nsCSSValueTokenStream* tokenStream = pair.mValue.GetTokenStreamValue();
nsCSSParser parser(aDocument->CSSLoader());
- if (!parser.IsValueValidForProperty(pair.mProperty,
+ if (!parser.IsValueValidForProperty(pair.mProperty.AsFixed(),
tokenStream->mTokenStream)) {
continue;
}
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
- prop, pair.mProperty, CSSEnabledState::eForAllContent) {
- addToPropertySets(*prop, offsetToUse);
+ prop, pair.mProperty.AsFixed(), CSSEnabledState::eForAllContent) {
+ addToPropertySets(CSSProperty(*prop), offsetToUse);
}
} else {
addToPropertySets(pair.mProperty, offsetToUse);
}
}
}
return !propertiesWithFromValue.Equals(properties) ||
@@ -1495,27 +1578,28 @@ PaceRange(const Range<Keyframe>& aKeyfra
*
* @param aValues The computed values returned by GetComputedKeyframeValues.
* @param aPacedProperty The paced property.
* @return The cumulative distances for the paced property. The length will be
* the same as aValues.
*/
static nsTArray<double>
GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
- nsCSSPropertyID aPacedProperty)
+ CSSProperty aPacedProperty)
{
// a) If aPacedProperty is a shorthand property, get its components.
// Otherwise, just add the longhand property into the set.
size_t pacedPropertyCount = 0;
- nsCSSPropertyIDSet pacedPropertySet;
- bool isShorthand = nsCSSProps::IsShorthand(aPacedProperty);
+ CSSPropertySet pacedPropertySet;
+ bool isShorthand = aPacedProperty.IsFixed() &&
+ nsCSSProps::IsShorthand(aPacedProperty.AsFixed());
if (isShorthand) {
- CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPacedProperty,
+ CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPacedProperty.AsFixed(),
CSSEnabledState::eForAllContent) {
- pacedPropertySet.AddProperty(*p);
+ pacedPropertySet.AddProperty(CSSProperty(*p));
++pacedPropertyCount;
}
} else {
pacedPropertySet.AddProperty(aPacedProperty);
pacedPropertyCount = 1;
}
// b) Search each component (shorthand) or the longhand property, and
@@ -1547,17 +1631,17 @@ GetCumulativeDistances(const nsTArray<Co
// This is the first paceable keyframe so its cumulative distance is 0.0.
cumulativeDistances[i] = 0.0;
} else {
double dist = 0.0;
if (isShorthand) {
// Apply the distance by the square root of the sum of squares of
// longhand component distances.
for (size_t propIdx = 0; propIdx < pacedPropertyCount; ++propIdx) {
- nsCSSPropertyID prop = prevPacedValues[propIdx].mProperty;
+ CSSProperty prop = prevPacedValues[propIdx].mProperty;
MOZ_ASSERT(pacedValues[propIdx].mProperty == prop,
"Property mismatch");
double componentDistance = 0.0;
if (StyleAnimationValue::ComputeDistance(
prop,
prevPacedValues[propIdx].mValue,
pacedValues[propIdx].mValue,
--- a/dom/animation/KeyframeUtils.h
+++ b/dom/animation/KeyframeUtils.h
@@ -93,17 +93,17 @@ public:
* any value, e.g. eCSSProperty_UNKNOWN.
* @param aComputedValues The set of computed keyframe values as returned by
* GetComputedKeyframeValues. Only used when |aSpacingMode| is
* SpacingMode::paced. In all other cases this parameter is unused and may
* be any value including an empty array.
*/
static void ApplySpacing(nsTArray<Keyframe>& aKeyframes,
SpacingMode aSpacingMode,
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
nsTArray<ComputedKeyframeValues>& aComputedValues);
/**
* Wrapper for ApplySpacing to simplify using distribute spacing.
*
* @param aKeyframes The set of keyframes to adjust.
*/
static void ApplyDistributeSpacing(nsTArray<Keyframe>& aKeyframes);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -105,16 +105,19 @@
#include "nsCSSPseudoElements.h" // for CSSPseudoElementType
#include "nsNetUtil.h"
#include "nsDocument.h"
#include "HTMLImageElement.h"
#include "mozilla/css/ImageLoader.h"
#include "mozilla/layers/APZCTreeManager.h" // for layers::ZoomToRectBehavior
#include "mozilla/dom/Promise.h"
#include "mozilla/CSSStyleSheet.h"
+#include "mozilla/CSSVariableRegistration.h"
+#include "mozilla/CSSVariableRegistrations.h"
+#include "nsCSSPropertyID.h"
#ifdef XP_WIN
#undef GetClassName
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
@@ -2410,32 +2413,33 @@ nsDOMWindowUtils::BeginTabSwitch()
return NS_ERROR_FAILURE;
mgr->BeginTabSwitch();
return NS_OK;
}
static bool
-ComputeAnimationValue(nsCSSPropertyID aProperty,
+ComputeAnimationValue(CSSProperty aProperty,
Element* aElement,
const nsAString& aInput,
StyleAnimationValue& aOutput)
{
nsIDocument* doc = aElement->GetUncomposedDoc();
nsIPresShell* shell = doc->GetShell();
if (!shell) {
return false;
}
RefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElement(aElement, nullptr, shell);
- if (!StyleAnimationValue::ComputeValue(aProperty, aElement, styleContext,
- aInput, false, aOutput)) {
+ if (!StyleAnimationValue::ComputeValue(aProperty,
+ aElement, styleContext, aInput, false,
+ aOutput)) {
return false;
}
return true;
}
NS_IMETHODIMP
nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds)
{
@@ -2670,25 +2674,33 @@ nsDOMWindowUtils::ComputeAnimationDistan
const nsAString& aValue1,
const nsAString& aValue2,
double* aResult)
{
nsresult rv;
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
NS_ENSURE_SUCCESS(rv, rv);
- nsCSSPropertyID property =
+ CSSProperty property;
+ nsCSSPropertyID fixed =
nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eIgnoreEnabledState);
- if (property != eCSSProperty_UNKNOWN && nsCSSProps::IsShorthand(property)) {
- property = eCSSProperty_UNKNOWN;
+ if (fixed == eCSSPropertyExtra_variable) {
+ nsIDocument* doc = content->OwnerDoc();
+ const CSSVariableRegistrations* registrations =
+ CSSVariableRegistrationsOfDocument(doc);
+ property =
+ nsCSSProps::LookupCustomProperty(registrations, aProperty,
+ CSSEnabledState::eIgnoreEnabledState);
+ } else if (fixed != eCSSProperty_UNKNOWN && nsCSSProps::IsShorthand(fixed)) {
+ property = CSSProperty(eCSSProperty_UNKNOWN);
+ } else {
+ property = CSSProperty(fixed);
}
- MOZ_ASSERT(property == eCSSProperty_UNKNOWN ||
- !nsCSSProps::IsShorthand(property),
- "should not have shorthand");
+ MOZ_ASSERT(!property.IsShorthand(), "should not have shorthand");
StyleAnimationValue v1, v2;
if (property == eCSSProperty_UNKNOWN ||
!ComputeAnimationValue(property, content->AsElement(), aValue1, v1) ||
!ComputeAnimationValue(property, content->AsElement(), aValue2, v2)) {
return NS_ERROR_ILLEGAL_VALUE;
}
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -246,17 +246,17 @@ nsSMILCSSValueType::Add(nsSMILValue& aDe
}
// Handle barely-initialized "zero" destination.
if (!destWrapper) {
aDest.mU.mPtr = destWrapper =
new ValueWrapper(property, *destValue);
}
- return StyleAnimationValue::Add(property,
+ return StyleAnimationValue::Add(CSSProperty(property),
destWrapper->mCSSValue, *valueToAdd, aCount) ?
NS_OK : NS_ERROR_FAILURE;
}
nsresult
nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
const nsSMILValue& aTo,
double& aDistance) const
@@ -271,17 +271,17 @@ nsSMILCSSValueType::ComputeDistance(cons
const StyleAnimationValue* fromCSSValue = fromWrapper ?
&fromWrapper->mCSSValue : nullptr;
const StyleAnimationValue* toCSSValue = &toWrapper->mCSSValue;
if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) {
return NS_ERROR_FAILURE;
}
- return StyleAnimationValue::ComputeDistance(toWrapper->mPropID,
+ return StyleAnimationValue::ComputeDistance(CSSProperty(toWrapper->mPropID),
*fromCSSValue, *toCSSValue,
aDistance) ?
NS_OK : NS_ERROR_FAILURE;
}
nsresult
nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
const nsSMILValue& aEndVal,
@@ -304,17 +304,17 @@ nsSMILCSSValueType::Interpolate(const ns
const StyleAnimationValue* startCSSValue = startWrapper ?
&startWrapper->mCSSValue : nullptr;
const StyleAnimationValue* endCSSValue = &endWrapper->mCSSValue;
if (!FinalizeStyleAnimationValues(startCSSValue, endCSSValue)) {
return NS_ERROR_FAILURE;
}
StyleAnimationValue resultValue;
- if (StyleAnimationValue::Interpolate(endWrapper->mPropID,
+ if (StyleAnimationValue::Interpolate(CSSProperty(endWrapper->mPropID),
*startCSSValue, *endCSSValue,
aUnitDistance, resultValue)) {
aResult.mU.mPtr = new ValueWrapper(endWrapper->mPropID, resultValue);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
@@ -361,17 +361,18 @@ ValueFromStringHelper(nsCSSPropertyID aP
}
RefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElement(aTargetElement, nullptr,
aPresContext->PresShell());
if (!styleContext) {
return false;
}
nsDependentSubstring subString(aString, subStringBegin);
- if (!StyleAnimationValue::ComputeValue(aPropID, aTargetElement, styleContext,
+ if (!StyleAnimationValue::ComputeValue(CSSProperty(aPropID),
+ aTargetElement, styleContext,
subString, true, aStyleAnimValue,
aIsContextSensitive)) {
return false;
}
if (isNegative) {
InvertSign(aStyleAnimValue);
}
@@ -420,17 +421,17 @@ nsSMILCSSValueType::ValueFromString(nsCS
bool
nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
nsAString& aString)
{
MOZ_ASSERT(aValue.mType == &nsSMILCSSValueType::sSingleton,
"Unexpected SMIL value type");
const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
return !wrapper ||
- StyleAnimationValue::UncomputeValue(wrapper->mPropID,
+ StyleAnimationValue::UncomputeValue(CSSProperty(wrapper->mPropID),
wrapper->mCSSValue, aString);
}
// static
nsCSSPropertyID
nsSMILCSSValueType::PropertyFromValue(const nsSMILValue& aValue)
{
if (aValue.mType != &nsSMILCSSValueType::sSingleton) {
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -556,18 +556,18 @@ static void
SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart,
StyleAnimationValue& aEnd, Animatable* aValue, Layer* aLayer)
{
StyleAnimationValue interpolatedValue;
NS_ASSERTION(aStart.GetUnit() == aEnd.GetUnit() ||
aStart.GetUnit() == StyleAnimationValue::eUnit_None ||
aEnd.GetUnit() == StyleAnimationValue::eUnit_None,
"Must have same unit");
- StyleAnimationValue::Interpolate(aAnimation.property(), aStart, aEnd,
- aPortion, interpolatedValue);
+ StyleAnimationValue::Interpolate(CSSProperty(aAnimation.property()),
+ aStart, aEnd, aPortion, interpolatedValue);
if (aAnimation.property() == eCSSProperty_opacity) {
*aValue = interpolatedValue.GetFloatValue();
return;
}
nsCSSValueSharedList* interpolatedList =
interpolatedValue.GetCSSValueSharedListValue();
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -421,17 +421,19 @@ AddAnimationForProperty(nsIFrame* aFrame
: aAnimation->AnimationTimeToTimeStamp(
StickyTimeDuration(timing.mDelay));
animation->initialCurrentTime() = aAnimation->GetCurrentTime().Value()
- timing.mDelay;
animation->duration() = computedTiming.mDuration;
animation->iterations() = computedTiming.mIterations;
animation->iterationStart() = computedTiming.mIterationStart;
animation->direction() = static_cast<uint32_t>(timing.mDirection);
- animation->property() = aProperty.mProperty;
+ // Only certain properties can be animated on the compositor, and it doesn't
+ // make sense to animate custom properties.
+ animation->property() = aProperty.mProperty.AsFixed();
animation->playbackRate() = aAnimation->PlaybackRate();
animation->data() = aData;
animation->easingFunction() = ToTimingFunction(timing.mFunction);
for (uint32_t segIdx = 0; segIdx < aProperty.mSegments.Length(); segIdx++) {
const AnimationPropertySegment& segment = aProperty.mSegments[segIdx];
AnimationSegment* animSegment = animation->segments().AppendElement();
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -11,16 +11,17 @@
#include "mozilla/RuleNodeCacheConditions.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/UniquePtr.h"
#include "nsStyleTransformMatrix.h"
#include "nsAutoPtr.h"
#include "nsCOMArray.h"
#include "nsIStyleRule.h"
#include "mozilla/css/StyleRule.h"
+#include "nsLayoutUtils.h"
#include "nsString.h"
#include "nsStyleContext.h"
#include "nsStyleSet.h"
#include "nsComputedDOMStyle.h"
#include "nsCSSParser.h"
#include "nsCSSPseudoElements.h"
#include "mozilla/css/Declaration.h"
#include "mozilla/dom/Element.h"
@@ -49,44 +50,48 @@ using namespace mozilla::gfx;
*
* @param aFirstUnit One unit to resolve.
* @param aFirstUnit The other unit to resolve.
* @return A "common" unit that both source units can be converted into, or
* eUnit_Null if that's not possible.
*/
static
StyleAnimationValue::Unit
-GetCommonUnit(nsCSSPropertyID aProperty,
+GetCommonUnit(CSSProperty aProperty,
StyleAnimationValue::Unit aFirstUnit,
StyleAnimationValue::Unit aSecondUnit)
{
if (aFirstUnit != aSecondUnit) {
- if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_STORES_CALC) &&
+ if ((aProperty.IsCustom() ||
+ nsCSSProps::PropHasFlags(aProperty.AsFixed(),
+ CSS_PROPERTY_STORES_CALC)) &&
(aFirstUnit == StyleAnimationValue::eUnit_Coord ||
aFirstUnit == StyleAnimationValue::eUnit_Percent ||
aFirstUnit == StyleAnimationValue::eUnit_Calc) &&
(aSecondUnit == StyleAnimationValue::eUnit_Coord ||
aSecondUnit == StyleAnimationValue::eUnit_Percent ||
aSecondUnit == StyleAnimationValue::eUnit_Calc)) {
// We can use calc() as the common unit.
return StyleAnimationValue::eUnit_Calc;
}
return StyleAnimationValue::eUnit_Null;
}
return aFirstUnit;
}
static
nsCSSUnit
-GetCommonUnit(nsCSSPropertyID aProperty,
+GetCommonUnit(CSSProperty aProperty,
nsCSSUnit aFirstUnit,
nsCSSUnit aSecondUnit)
{
if (aFirstUnit != aSecondUnit) {
- if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_STORES_CALC) &&
+ if ((aProperty.IsCustom() ||
+ nsCSSProps::PropHasFlags(aProperty.AsFixed(),
+ CSS_PROPERTY_STORES_CALC)) &&
(aFirstUnit == eCSSUnit_Pixel ||
aFirstUnit == eCSSUnit_Percent ||
aFirstUnit == eCSSUnit_Calc) &&
(aSecondUnit == eCSSUnit_Pixel ||
aSecondUnit == eCSSUnit_Percent ||
aSecondUnit == eCSSUnit_Calc)) {
// We can use calc() as the common unit.
return eCSSUnit_Calc;
@@ -479,17 +484,17 @@ CalcPositionCoordSquareDistance(const ns
float diffpct = calcVal2.mPercent - calcVal1.mPercent;
return difflen * difflen + diffpct * diffpct;
}
// CLASS METHODS
// -------------
bool
-StyleAnimationValue::ComputeDistance(nsCSSPropertyID aProperty,
+StyleAnimationValue::ComputeDistance(CSSProperty aProperty,
const StyleAnimationValue& aStartValue,
const StyleAnimationValue& aEndValue,
double& aDistance)
{
Unit commonUnit =
GetCommonUnit(aProperty, aStartValue.GetUnit(), aEndValue.GetUnit());
switch (commonUnit) {
@@ -498,17 +503,20 @@ StyleAnimationValue::ComputeDistance(nsC
case eUnit_None:
case eUnit_Normal:
case eUnit_UnparsedString:
case eUnit_URL:
case eUnit_CurrentColor:
return false;
case eUnit_Enumerated:
- switch (aProperty) {
+ if (aProperty.IsCustom()) {
+ return false;
+ }
+ switch (aProperty.AsFixed()) {
case eCSSProperty_font_stretch: {
// just like eUnit_Integer.
int32_t startInt = aStartValue.GetIntValue();
int32_t endInt = aEndValue.GetIntValue();
aDistance = Abs(endInt - startInt);
return true;
}
default:
@@ -847,19 +855,19 @@ StyleAnimationValue::ComputeDistance(nsC
(color1.GetColorValue(), StyleAnimationValue::ColorConstructor);
StyleAnimationValue color2Value
(color2.GetColorValue(), StyleAnimationValue::ColorConstructor);
double colorDistance;
#ifdef DEBUG
bool ok =
#endif
- StyleAnimationValue::ComputeDistance(eCSSProperty_color,
- color1Value, color2Value,
- colorDistance);
+ StyleAnimationValue::ComputeDistance(
+ CSSProperty(eCSSProperty_color), color1Value, color2Value,
+ colorDistance);
MOZ_ASSERT(ok, "should not fail");
squareDistance += colorDistance * colorDistance;
}
shadow1 = shadow1->mNext;
shadow2 = shadow2->mNext;
MOZ_ASSERT(!shadow1 == !shadow2, "lists should be same length");
}
@@ -1032,19 +1040,24 @@ RestrictValue(uint32_t aRestrictions, T
MOZ_ASSERT(false, "bad value restriction");
break;
}
return result;
}
template <typename T>
T
-RestrictValue(nsCSSPropertyID aProperty, T aValue)
+RestrictValue(CSSProperty aProperty, T aValue)
{
- return RestrictValue(nsCSSProps::ValueRestrictions(aProperty), aValue);
+ if (aProperty.IsCustom()) {
+ return aValue;
+ } else {
+ return RestrictValue(nsCSSProps::ValueRestrictions(aProperty.AsFixed()),
+ aValue);
+ }
}
static inline void
AddCSSValuePixel(double aCoeff1, const nsCSSValue &aValue1,
double aCoeff2, const nsCSSValue &aValue2,
nsCSSValue &aResult, uint32_t aValueRestrictions = 0)
{
MOZ_ASSERT(aValue1.GetUnit() == eCSSUnit_Pixel, "unexpected unit");
@@ -1215,17 +1228,17 @@ AddShadowItems(double aCoeff1, const nsC
StyleAnimationValue color1Value
(color1.GetColorValue(), StyleAnimationValue::ColorConstructor);
StyleAnimationValue color2Value
(color2.GetColorValue(), StyleAnimationValue::ColorConstructor);
StyleAnimationValue resultColorValue;
#ifdef DEBUG
bool ok =
#endif
- StyleAnimationValue::AddWeighted(eCSSProperty_color,
+ StyleAnimationValue::AddWeighted(CSSProperty(eCSSProperty_color),
aCoeff1, color1Value,
aCoeff2, color2Value,
resultColorValue);
MOZ_ASSERT(ok, "should not fail");
resultArray->Item(4).SetColorValue(resultColorValue.GetColorValue());
}
MOZ_ASSERT(inset1 == inset2, "should match");
@@ -1854,17 +1867,17 @@ AddPositions(double aCoeff1, const nsCSS
const nsCSSValue& v2 = posArray2->Item(i);
nsCSSValue& vr = resultPosArray->Item(i);
AddCSSValueCanonicalCalc(aCoeff1, v1,
aCoeff2, v2, vr);
}
}
static Maybe<nsCSSValuePair>
-AddCSSValuePair(nsCSSPropertyID aProperty, uint32_t aRestrictions,
+AddCSSValuePair(CSSProperty aProperty, uint32_t aRestrictions,
double aCoeff1, const nsCSSValuePair* aPair1,
double aCoeff2, const nsCSSValuePair* aPair2)
{
MOZ_ASSERT(aPair1, "expected pair");
MOZ_ASSERT(aPair2, "expected pair");
Maybe<nsCSSValuePair> result;
nsCSSUnit unit[2];
@@ -1893,32 +1906,35 @@ AddCSSValuePair(nsCSSPropertyID aPropert
return result; // Nothing() (returning |result| for RVO)
}
}
return result;
}
static UniquePtr<nsCSSValuePairList>
-AddCSSValuePairList(nsCSSPropertyID aProperty,
+AddCSSValuePairList(CSSProperty aProperty,
double aCoeff1, const nsCSSValuePairList* aList1,
double aCoeff2, const nsCSSValuePairList* aList2)
{
MOZ_ASSERT(aList1, "Can't add a null list");
MOZ_ASSERT(aList2, "Can't add a null list");
auto result = MakeUnique<nsCSSValuePairList>();
nsCSSValuePairList* resultPtr = result.get();
do {
static nsCSSValue nsCSSValuePairList::* const pairListValues[] = {
&nsCSSValuePairList::mXValue,
&nsCSSValuePairList::mYValue,
};
- uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty);
+ uint32_t restrictions =
+ aProperty.IsCustom()
+ ? 0
+ : nsCSSProps::ValueRestrictions(aProperty.AsFixed());
for (uint32_t i = 0; i < ArrayLength(pairListValues); ++i) {
const nsCSSValue& v1 = aList1->*(pairListValues[i]);
const nsCSSValue& v2 = aList2->*(pairListValues[i]);
nsCSSValue& vr = resultPtr->*(pairListValues[i]);
nsCSSUnit unit =
GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit());
if (unit == eCSSUnit_Null) {
@@ -1945,17 +1961,17 @@ AddCSSValuePairList(nsCSSPropertyID aPro
if (aList1 || aList2) {
return nullptr; // We can't interpolate lists of different lengths
}
return result;
}
static already_AddRefed<nsCSSValue::Array>
-AddShapeFunction(nsCSSPropertyID aProperty,
+AddShapeFunction(CSSProperty aProperty,
double aCoeff1, const nsCSSValue::Array* aArray1,
double aCoeff2, const nsCSSValue::Array* aArray2)
{
MOZ_ASSERT(aArray1 && aArray1->Count() == 2, "expected shape function");
MOZ_ASSERT(aArray2 && aArray2->Count() == 2, "expected shape function");
MOZ_ASSERT(aArray1->Item(0).GetUnit() == eCSSUnit_Function,
"expected function");
MOZ_ASSERT(aArray2->Item(0).GetUnit() == eCSSUnit_Function,
@@ -2259,17 +2275,17 @@ AddPositionCoords(double aCoeff1, const
const nsCSSValue& v1 = posArray1->Item(1);
const nsCSSValue& v2 = posArray2->Item(1);
nsCSSValue& vr = resultPosArray->Item(1);
AddCSSValueCanonicalCalc(aCoeff1, v1,
aCoeff2, v2, vr);
}
bool
-StyleAnimationValue::AddWeighted(nsCSSPropertyID aProperty,
+StyleAnimationValue::AddWeighted(CSSProperty aProperty,
double aCoeff1,
const StyleAnimationValue& aValue1,
double aCoeff2,
const StyleAnimationValue& aValue2,
StyleAnimationValue& aResultValue)
{
Unit commonUnit =
GetCommonUnit(aProperty, aValue1.GetUnit(), aValue2.GetUnit());
@@ -2284,17 +2300,20 @@ StyleAnimationValue::AddWeighted(nsCSSPr
case eUnit_None:
case eUnit_Normal:
case eUnit_UnparsedString:
case eUnit_URL:
case eUnit_CurrentColor:
return false;
case eUnit_Enumerated:
- switch (aProperty) {
+ if (aProperty.IsCustom()) {
+ return false;
+ }
+ switch (aProperty.AsFixed()) {
case eCSSProperty_font_stretch: {
// Animate just like eUnit_Integer.
int32_t result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
aCoeff2 * double(aValue2.GetIntValue()));
if (result < NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED) {
result = NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED;
} else if (result > NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED) {
result = NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED;
@@ -2425,17 +2444,20 @@ StyleAnimationValue::AddWeighted(nsCSSPr
AddPositions(aCoeff1, *position1,
aCoeff2, *position2, *result);
aResultValue.SetAndAdoptCSSValueValue(result.forget(),
eUnit_ObjectPosition);
return true;
}
case eUnit_CSSValuePair: {
- uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty);
+ uint32_t restrictions =
+ aProperty.IsCustom()
+ ? 0
+ : nsCSSProps::ValueRestrictions(aProperty.AsFixed());
Maybe<nsCSSValuePair> result =
AddCSSValuePair(aProperty, restrictions,
aCoeff1, aValue1.GetCSSValuePairValue(),
aCoeff2, aValue2.GetCSSValuePairValue());
if (!result) {
return false;
}
@@ -2460,34 +2482,40 @@ StyleAnimationValue::AddWeighted(nsCSSPr
unit[2] == eCSSUnit_Null) {
return false;
}
nsAutoPtr<nsCSSValueTriplet> result(new nsCSSValueTriplet);
static nsCSSValue nsCSSValueTriplet::* const tripletValues[3] = {
&nsCSSValueTriplet::mXValue, &nsCSSValueTriplet::mYValue, &nsCSSValueTriplet::mZValue
};
- uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty);
+ uint32_t restrictions;
+ if (aProperty.IsCustom()) {
+ restrictions = 0;
+ } else {
+ restrictions = nsCSSProps::ValueRestrictions(aProperty.AsFixed());
+ }
for (uint32_t i = 0; i < 3; ++i) {
nsCSSValue nsCSSValueTriplet::*member = tripletValues[i];
if (!AddCSSValuePixelPercentCalc(restrictions, unit[i],
aCoeff1, &triplet1->*member,
aCoeff2, &triplet2->*member,
result->*member) ) {
MOZ_ASSERT(false, "unexpected unit");
return false;
}
}
aResultValue.SetAndAdoptCSSValueTripletValue(result.forget(),
eUnit_CSSValueTriplet);
return true;
}
case eUnit_CSSRect: {
- MOZ_ASSERT(nsCSSProps::ValueRestrictions(aProperty) == 0,
+ MOZ_ASSERT(aProperty.IsCustom() ||
+ nsCSSProps::ValueRestrictions(aProperty.AsFixed()) == 0,
"must add code for handling value restrictions");
const nsCSSRect *rect1 = aValue1.GetCSSRectValue();
const nsCSSRect *rect2 = aValue2.GetCSSRectValue();
if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() ||
rect1->mRight.GetUnit() != rect2->mRight.GetUnit() ||
rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() ||
rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) {
// At least until we have calc()
@@ -2788,120 +2816,159 @@ StyleAnimationValue::AddWeighted(nsCSSPr
}
}
MOZ_ASSERT(false, "Can't interpolate using the given common unit");
return false;
}
already_AddRefed<css::StyleRule>
-BuildStyleRule(nsCSSPropertyID aProperty,
+BuildStyleRule(CSSProperty aProperty,
dom::Element* aTargetElement,
const nsAString& aSpecifiedValue,
bool aUseSVGMode)
{
// Set up an empty CSS Declaration
// Custom property registrations can be null beacuse we should have that the
// specified value (that we're trying to animate) has the correct type.
RefPtr<css::Declaration> declaration(new css::Declaration(nullptr));
declaration->InitializeEmpty();
bool changed; // ignored, but needed as outparam for ParseProperty
nsIDocument* doc = aTargetElement->OwnerDoc();
nsCOMPtr<nsIURI> baseURI = aTargetElement->GetBaseURI();
nsCSSParser parser(doc->CSSLoader());
- nsCSSPropertyID propertyToCheck = nsCSSProps::IsShorthand(aProperty) ?
- nsCSSProps::SubpropertyEntryFor(aProperty)[0] : aProperty;
-
- // Get a parser, parse the property, and check for CSS parsing errors.
- // If this fails, we bail out and delete the declaration.
- parser.ParseProperty(aProperty, aSpecifiedValue, doc->GetDocumentURI(),
- baseURI, aTargetElement->NodePrincipal(), declaration,
- &changed, false, aUseSVGMode);
-
- // check whether property parsed without CSS parsing errors
- if (!declaration->HasNonImportantValueFor(propertyToCheck)) {
- return nullptr;
+ if (aProperty.IsFixed()) {
+ nsCSSPropertyID fixed = aProperty.AsFixed();
+ nsCSSPropertyID propertyToCheck = nsCSSProps::IsShorthand(fixed) ?
+ nsCSSProps::SubpropertyEntryFor(fixed)[0] : fixed;
+
+ // Get a parser, parse the property, and check for CSS parsing errors.
+ // If this fails, we bail out and delete the declaration.
+ parser.ParseProperty(fixed, aSpecifiedValue, doc->GetDocumentURI(),
+ baseURI, aTargetElement->NodePrincipal(), declaration,
+ &changed, false, aUseSVGMode);
+
+ // check whether property parsed without CSS parsing errors
+ if (!declaration->HasNonImportantValueFor(propertyToCheck)) {
+ return nullptr;
+ }
+ } else {
+ nsString name;
+ aProperty.AsCustom()->ToString(name);
+ parser.ParseVariable(name, aSpecifiedValue, doc->GetDocumentURI(),
+ baseURI, aTargetElement->NodePrincipal(), declaration,
+ &changed, false);
}
RefPtr<css::StyleRule> rule = new css::StyleRule(nullptr,
declaration,
0, 0);
return rule.forget();
}
already_AddRefed<css::StyleRule>
-BuildStyleRule(nsCSSPropertyID aProperty,
+BuildStyleRule(CSSProperty aProperty,
dom::Element* aTargetElement,
const nsCSSValue& aSpecifiedValue,
bool aUseSVGMode)
{
- MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
+ MOZ_ASSERT(!aProperty.IsShorthand(),
"Should be a longhand property");
// Check if longhand failed to parse correctly.
if (aSpecifiedValue.GetUnit() == eCSSUnit_Null) {
return nullptr;
}
// Set up an empty CSS Declaration
// Custom property registrations can be null beacuse we should have that the
// specified value (that we're trying to animate) has the correct type.
RefPtr<css::Declaration> declaration(new css::Declaration(nullptr));
declaration->InitializeEmpty();
- // Add our longhand value
- nsCSSExpandedDataBlock block;
- declaration->ExpandTo(&block);
- block.AddLonghandProperty(aProperty, aSpecifiedValue);
- declaration->ValueAppended(aProperty);
- declaration->CompressFrom(&block);
+ if (aProperty.IsFixed()) {
+ nsCSSPropertyID fixed = aProperty.AsFixed();
+ // Add our longhand value
+ nsCSSExpandedDataBlock block;
+ declaration->ExpandTo(&block);
+ block.AddLonghandProperty(fixed, aSpecifiedValue);
+ declaration->ValueAppended(fixed);
+ declaration->CompressFrom(&block);
+ } else {
+ nsString name, specVal;
+ aProperty.AsCustom()->ToString(name);
+ aSpecifiedValue.AppendToString(eCSSProperty_UNKNOWN, specVal,
+ nsCSSValue::eAuthorSpecified);
+
+ // URL values need a principal to be set in the parser.
+ // Otherwise we should be able to supply a context of all nulls (not
+ // uninitialized!) because this is already a computed value.
+ // See CSSParserImpl::SetValueToURL.
+ // See also: AnimValuesStyleRule::MapRuleInfoInto
+ CSSVariableExprContext context;
+ if (aSpecifiedValue.GetUnit() == eCSSUnit_URL) {
+ css::URLValue* url = aSpecifiedValue.GetURLStructValue();
+ context.mSheetURI = url->mReferrer.get();
+ context.mBaseURI = nullptr;
+ context.mSheetPrincipal = url->mOriginPrincipal.get();
+ }
+
+ declaration
+ ->AddVariableDeclaration(name, CSSVariableDeclarations::Type::TokenStream,
+ specVal, /* aIsImportant = */ false,
+ /* aOverrideImportant = */ false, context);
+ }
RefPtr<css::StyleRule> rule = new css::StyleRule(nullptr, declaration, 0, 0);
return rule.forget();
}
static bool
-ComputeValuesFromStyleRule(nsCSSPropertyID aProperty,
+ComputeValuesFromStyleRule(CSSProperty aProperty,
CSSEnabledState aEnabledState,
dom::Element* aTargetElement,
nsStyleContext* aStyleContext,
css::StyleRule* aStyleRule,
nsTArray<PropertyStyleAnimationValuePair>& aValues,
bool* aIsContextSensitive)
{
MOZ_ASSERT(aStyleContext);
- if (!nsCSSProps::IsEnabled(aProperty, aEnabledState)) {
+ if (aProperty.IsFixed() &&
+ !nsCSSProps::IsEnabled(aProperty.AsFixed(), aEnabledState)) {
return false;
}
MOZ_ASSERT(aStyleContext->PresContext()->StyleSet()->IsGecko(),
"ServoStyleSet should not use StyleAnimationValue for animations");
nsStyleSet* styleSet = aStyleContext->PresContext()->StyleSet()->AsGecko();
RefPtr<nsStyleContext> tmpStyleContext;
if (aIsContextSensitive) {
- MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
+ MOZ_ASSERT(aProperty.IsCustom() ||
+ !nsCSSProps::IsShorthand(aProperty.AsFixed()),
"to correctly set aIsContextSensitive for shorthand properties, "
"this code must be adjusted");
nsCOMArray<nsIStyleRule> ruleArray;
ruleArray.AppendObject(styleSet->InitialStyleRule());
css::Declaration* declaration = aStyleRule->GetDeclaration();
ruleArray.AppendObject(declaration);
declaration->SetImmutable();
tmpStyleContext =
styleSet->ResolveStyleByAddingRules(aStyleContext, ruleArray);
if (!tmpStyleContext) {
return false;
}
// Force walk of rule tree
- nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty];
+ nsStyleStructID sid =
+ aProperty.IsFixed() ? nsCSSProps::kSIDTable[aProperty.AsFixed()]
+ : eStyleStruct_Variables;
tmpStyleContext->StyleData(sid);
// The rule node will have unconditional cached style data if the value is
// not context-sensitive. So if there's nothing cached, it's not context
// sensitive.
*aIsContextSensitive =
!tmpStyleContext->RuleNode()->NodeHasCachedUnconditionalData(sid);
}
@@ -2921,40 +2988,41 @@ ComputeValuesFromStyleRule(nsCSSProperty
styleSet->ResolveStyleByAddingRules(aStyleContext, ruleArray);
if (!tmpStyleContext) {
return false;
}
}
// Extract computed value of our property (or all longhand components, if
// aProperty is a shorthand) from the temporary style rule
- if (nsCSSProps::IsShorthand(aProperty)) {
- CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty, aEnabledState) {
+ if (aProperty.IsFixed() && nsCSSProps::IsShorthand(aProperty.AsFixed())) {
+ CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty.AsFixed(),
+ aEnabledState) {
if (nsCSSProps::kAnimTypeTable[*p] == eStyleAnimType_None) {
// Skip non-animatable component longhands.
continue;
}
PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
- pair->mProperty = *p;
- if (!StyleAnimationValue::ExtractComputedValue(*p, tmpStyleContext,
- pair->mValue)) {
+ pair->mProperty = CSSProperty(*p);
+ if (!StyleAnimationValue::ExtractComputedValue(
+ CSSProperty(*p), tmpStyleContext, pair->mValue)) {
return false;
}
}
return true;
} else {
PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
pair->mProperty = aProperty;
return StyleAnimationValue::ExtractComputedValue(aProperty, tmpStyleContext,
pair->mValue);
}
}
/* static */ bool
-StyleAnimationValue::ComputeValue(nsCSSPropertyID aProperty,
+StyleAnimationValue::ComputeValue(CSSProperty aProperty,
dom::Element* aTargetElement,
nsStyleContext* aStyleContext,
const nsAString& aSpecifiedValue,
bool aUseSVGMode,
StyleAnimationValue& aComputedValue,
bool* aIsContextSensitive)
{
MOZ_ASSERT(aTargetElement, "null target element");
@@ -2964,18 +3032,20 @@ StyleAnimationValue::ComputeValue(nsCSSP
// If it is a pseudo element, use its parent element's OwnerDoc, BaseURI,
// and Principal.
RefPtr<css::StyleRule> styleRule =
BuildStyleRule(aProperty, aTargetElement, aSpecifiedValue, aUseSVGMode);
if (!styleRule) {
return false;
}
- if (nsCSSProps::IsShorthand(aProperty) ||
- nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
+ if (aProperty.IsFixed() &&
+ (nsCSSProps::IsShorthand(aProperty.AsFixed()) ||
+ nsCSSProps::kAnimTypeTable[aProperty.AsFixed()] == eStyleAnimType_None))
+ {
// Just capture the specified value
aComputedValue.SetUnparsedStringValue(nsString(aSpecifiedValue));
if (aIsContextSensitive) {
// Since we're just returning the string as-is, aComputedValue isn't going
// to change depending on the context
*aIsContextSensitive = false;
}
return true;
@@ -2995,17 +3065,17 @@ StyleAnimationValue::ComputeValue(nsCSSP
aComputedValue = values[0].mValue;
return true;
}
template <class T>
bool
ComputeValuesFromSpecifiedValue(
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
CSSEnabledState aEnabledState,
dom::Element* aTargetElement,
nsStyleContext* aStyleContext,
T& aSpecifiedValue,
bool aUseSVGMode,
nsTArray<PropertyStyleAnimationValuePair>& aResult)
{
MOZ_ASSERT(aTargetElement, "null target element");
@@ -3023,48 +3093,48 @@ ComputeValuesFromSpecifiedValue(
aResult.Clear();
return ComputeValuesFromStyleRule(aProperty, aEnabledState, aTargetElement,
aStyleContext, styleRule, aResult,
/* aIsContextSensitive */ nullptr);
}
/* static */ bool
StyleAnimationValue::ComputeValues(
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
CSSEnabledState aEnabledState,
dom::Element* aTargetElement,
nsStyleContext* aStyleContext,
const nsAString& aSpecifiedValue,
bool aUseSVGMode,
nsTArray<PropertyStyleAnimationValuePair>& aResult)
{
return ComputeValuesFromSpecifiedValue(aProperty, aEnabledState,
aTargetElement, aStyleContext,
aSpecifiedValue, aUseSVGMode,
aResult);
}
/* static */ bool
StyleAnimationValue::ComputeValues(
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
CSSEnabledState aEnabledState,
dom::Element* aTargetElement,
nsStyleContext* aStyleContext,
const nsCSSValue& aSpecifiedValue,
bool aUseSVGMode,
nsTArray<PropertyStyleAnimationValuePair>& aResult)
{
return ComputeValuesFromSpecifiedValue(aProperty, aEnabledState,
aTargetElement, aStyleContext,
aSpecifiedValue, aUseSVGMode,
aResult);
}
bool
-StyleAnimationValue::UncomputeValue(nsCSSPropertyID aProperty,
+StyleAnimationValue::UncomputeValue(CSSProperty aProperty,
const StyleAnimationValue& aComputedValue,
nsCSSValue& aSpecifiedValue)
{
Unit unit = aComputedValue.GetUnit();
switch (unit) {
case eUnit_Normal:
aSpecifiedValue.SetNormalValue();
break;
@@ -3170,40 +3240,44 @@ StyleAnimationValue::UncomputeValue(nsCS
break;
case eUnit_List: {
nsCSSValueList* toList = aSpecifiedValue.SetListValue();
const nsTArray<StyleAnimationValue>* fromList =
aComputedValue.mValue.mList;
for (size_t i = 0; i < fromList->Length(); i++) {
const StyleAnimationValue& term = (*fromList)[i];
nsCSSValue value;
- StyleAnimationValue::UncomputeValue(eCSSProperty_UNKNOWN, term, value);
+ StyleAnimationValue::UncomputeValue(CSSProperty(eCSSProperty_UNKNOWN),
+ term, value);
toList->mValue = value;
if (i != fromList->Length() - 1) {
toList->mNext = new nsCSSValueList;
toList = toList->mNext;
}
}
break;
}
case eUnit_UnparsedString: {
RefPtr<nsCSSValueTokenStream> value = new nsCSSValueTokenStream;
- value->mPropertyID = aProperty;
+ // Can't use eCSSPropertyExtra_UNKNOWN because that would cause
+ // KeyframeUtils::IsInvalidValuePair to think these values were invalid.
+ value->mPropertyID = aProperty.IsFixed() ? aProperty.AsFixed()
+ : eCSSPropertyExtra_variable;
aComputedValue.GetStringValue(value->mTokenStream);
aSpecifiedValue.SetTokenStreamValue(value);
break;
}
default:
return false;
}
return true;
}
bool
-StyleAnimationValue::UncomputeValue(nsCSSPropertyID aProperty,
+StyleAnimationValue::UncomputeValue(CSSProperty aProperty,
StyleAnimationValue&& aComputedValue,
nsCSSValue& aSpecifiedValue)
{
Unit unit = aComputedValue.GetUnit();
switch (unit) {
case eUnit_Dasharray:
case eUnit_Shadow:
case eUnit_Filter:
@@ -3228,32 +3302,34 @@ StyleAnimationValue::UncomputeValue(nsCS
break;
default:
return UncomputeValue(aProperty, aComputedValue, aSpecifiedValue);
}
return true;
}
bool
-StyleAnimationValue::UncomputeValue(nsCSSPropertyID aProperty,
+StyleAnimationValue::UncomputeValue(CSSProperty aProperty,
const StyleAnimationValue& aComputedValue,
nsAString& aSpecifiedValue)
{
aSpecifiedValue.Truncate(); // Clear outparam, if it's not already empty
if (aComputedValue.GetUnit() == eUnit_UnparsedString) {
aComputedValue.GetStringValue(aSpecifiedValue);
return true;
}
nsCSSValue val;
if (!StyleAnimationValue::UncomputeValue(aProperty, aComputedValue, val)) {
return false;
}
- val.AppendToString(aProperty, aSpecifiedValue, nsCSSValue::eNormalized);
+ val.AppendToString(aProperty.IsFixed() ? aProperty.AsFixed()
+ : eCSSProperty_UNKNOWN,
+ aSpecifiedValue, nsCSSValue::eNormalized);
return true;
}
inline const void*
StyleDataAtOffset(const void* aStyleStruct, ptrdiff_t aOffset)
{
return reinterpret_cast<const char*>(aStyleStruct) + aOffset;
}
@@ -3652,32 +3728,55 @@ StyleClipBasicShapeToCSSArray(const Styl
MOZ_ASSERT_UNREACHABLE("Unknown shape type");
return false;
}
aResult->Item(1).SetIntValue(aClipPath.GetReferenceBox(),
eCSSUnit_Enumerated);
return true;
}
+static bool
+ExtractComputedCustomValue(nsIAtom* aProperty,
+ nsStyleContext* aStyleContext,
+ StyleAnimationValue& aComputedValue)
+{
+ nsAutoString name;
+ aProperty->ToString(name);
+
+ const mozilla::CSSVariableValues& variables =
+ aStyleContext->StyleVariables()->mVariables;
+ const CSSComputedValue* value;
+ if (!variables.Compute(name, &value)) {
+ return false;
+ }
+
+ return value->GetAsAnimationValue(aComputedValue);
+}
+
bool
-StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty,
+StyleAnimationValue::ExtractComputedValue(CSSProperty aProperty,
nsStyleContext* aStyleContext,
StyleAnimationValue& aComputedValue)
{
- MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
+ if (aProperty.IsCustom()) {
+ return ExtractComputedCustomValue(aProperty.AsCustom(), aStyleContext,
+ aComputedValue);
+ }
+ nsCSSPropertyID property = aProperty.AsFixed();
+ MOZ_ASSERT(0 <= property && property < eCSSProperty_COUNT_no_shorthands,
"bad property");
const void* styleStruct =
- aStyleContext->StyleData(nsCSSProps::kSIDTable[aProperty]);
- ptrdiff_t ssOffset = nsCSSProps::kStyleStructOffsetTable[aProperty];
- nsStyleAnimType animType = nsCSSProps::kAnimTypeTable[aProperty];
+ aStyleContext->StyleData(nsCSSProps::kSIDTable[property]);
+ ptrdiff_t ssOffset = nsCSSProps::kStyleStructOffsetTable[property];
+ nsStyleAnimType animType = nsCSSProps::kAnimTypeTable[property];
MOZ_ASSERT(0 <= ssOffset || animType == eStyleAnimType_Custom,
"must be dealing with animatable property");
switch (animType) {
case eStyleAnimType_Custom:
- switch (aProperty) {
+ switch (property) {
// For border-width, ignore the border-image business (which
// only exists until we update our implementation to the current
// spec) and use GetComputedBorder
#define BORDER_WIDTH_CASE(prop_, side_) \
case prop_: \
aComputedValue.SetCoordValue( \
static_cast<const nsStyleBorder*>(styleStruct)-> \
@@ -4136,17 +4235,17 @@ StyleAnimationValue::ExtractComputedValu
default:
MOZ_ASSERT(false, "missing property implementation");
return false;
};
return true;
case eStyleAnimType_Coord: {
const nsStyleCoord& coord = *static_cast<const nsStyleCoord*>(
StyleDataAtOffset(styleStruct, ssOffset));
- if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_NUMBERS_ARE_PIXELS) &&
+ if (nsCSSProps::PropHasFlags(property, CSS_PROPERTY_NUMBERS_ARE_PIXELS) &&
coord.GetUnit() == eStyleUnit_Coord) {
// For SVG properties where number means the same thing as length,
// we want to animate them the same way. Normalize both to number
// since it has more accuracy (float vs nscoord).
aComputedValue.SetFloatValue(nsPresContext::
AppUnitsToFloatCSSPixels(coord.GetCoordValue()));
return true;
}
@@ -4201,25 +4300,25 @@ StyleAnimationValue::ExtractComputedValu
}
case eStyleAnimType_nscoord:
aComputedValue.SetCoordValue(*static_cast<const nscoord*>(
StyleDataAtOffset(styleStruct, ssOffset)));
return true;
case eStyleAnimType_EnumU8:
aComputedValue.SetIntValue(*static_cast<const uint8_t*>(
StyleDataAtOffset(styleStruct, ssOffset)), eUnit_Enumerated);
- if (aProperty == eCSSProperty_visibility) {
+ if (property == eCSSProperty_visibility) {
aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
eUnit_Visibility);
}
return true;
case eStyleAnimType_float:
aComputedValue.SetFloatValue(*static_cast<const float*>(
StyleDataAtOffset(styleStruct, ssOffset)));
- if (aProperty == eCSSProperty_font_size_adjust &&
+ if (property == eCSSProperty_font_size_adjust &&
aComputedValue.GetFloatValue() == -1.0f) {
// In nsStyleFont, we set mFont.sizeAdjust to -1.0 to represent
// font-size-adjust: none. Here, we have to treat this as a keyword
// instead of a float value, to make sure we don't end up doing
// interpolation with it.
aComputedValue.SetNoneValue();
}
return true;
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -3,16 +3,17 @@
* 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/. */
/* Utilities for animation of computed style values */
#ifndef mozilla_StyleAnimationValue_h_
#define mozilla_StyleAnimationValue_h_
+#include "mozilla/CSSProperty.h"
#include "mozilla/gfx/MatrixFwd.h"
#include "mozilla/UniquePtr.h"
#include "nsStringFwd.h"
#include "nsStringBuffer.h"
#include "nsCoord.h"
#include "nsColor.h"
#include "nsCSSProps.h"
#include "nsCSSValue.h"
@@ -55,17 +56,17 @@ public:
* Note that if |aCount| is 0, then |aDest| will be unchanged. Also, if
* this method fails, then |aDest| will be unchanged.
*
* @param aDest The value to add to.
* @param aValueToAdd The value to add.
* @param aCount The number of times to add aValueToAdd.
* @return true on success, false on failure.
*/
- static bool Add(nsCSSPropertyID aProperty, StyleAnimationValue& aDest,
+ static bool Add(CSSProperty aProperty, StyleAnimationValue& aDest,
const StyleAnimationValue& aValueToAdd, uint32_t aCount) {
return AddWeighted(aProperty, 1.0, aDest, aCount, aValueToAdd, aDest);
}
/**
* Calculates a measure of 'distance' between two values.
*
* This measure of Distance is guaranteed to be proportional to
@@ -78,17 +79,17 @@ public:
*
* @param aStartValue The start of the interval for which the distance
* should be calculated.
* @param aEndValue The end of the interval for which the distance
* should be calculated.
* @param aDistance The result of the calculation.
* @return true on success, false on failure.
*/
- static bool ComputeDistance(nsCSSPropertyID aProperty,
+ static bool ComputeDistance(CSSProperty aProperty,
const StyleAnimationValue& aStartValue,
const StyleAnimationValue& aEndValue,
double& aDistance);
/**
* Calculates an interpolated value that is the specified |aPortion| between
* the two given values.
*
@@ -99,17 +100,17 @@ public:
* interpolation.
* @param aEndValue The value defining the end of the interval of
* interpolation.
* @param aPortion A number in the range [0.0, 1.0] defining the
* distance of the interpolated value in the interval.
* @param [out] aResultValue The resulting interpolated value.
* @return true on success, false on failure.
*/
- static bool Interpolate(nsCSSPropertyID aProperty,
+ static bool Interpolate(CSSProperty aProperty,
const StyleAnimationValue& aStartValue,
const StyleAnimationValue& aEndValue,
double aPortion,
StyleAnimationValue& aResultValue) {
return AddWeighted(aProperty, 1.0 - aPortion, aStartValue,
aPortion, aEndValue, aResultValue);
}
@@ -122,17 +123,17 @@ public:
* @return true on success, false on failure.
*
* NOTE: Current callers always pass aCoeff1 and aCoeff2 >= 0. They
* are currently permitted to be negative; however, if, as we add
* support more value types types, we find that this causes
* difficulty, we might change this to restrict them to being
* positive.
*/
- static bool AddWeighted(nsCSSPropertyID aProperty,
+ static bool AddWeighted(CSSProperty aProperty,
double aCoeff1, const StyleAnimationValue& aValue1,
double aCoeff2, const StyleAnimationValue& aValue2,
StyleAnimationValue& aResultValue);
// Type-conversion methods
// -----------------------
/**
* Creates a computed value for the given specified value
@@ -159,17 +160,17 @@ public:
* a different |aComputedValue| depending on other CSS
* properties on |aTargetElement| or its ancestors.
* false otherwise.
* Note that the operation of this method is
* significantly faster when |aIsContextSensitive| is
* nullptr.
* @return true on success, false on failure.
*/
- static bool ComputeValue(nsCSSPropertyID aProperty,
+ static bool ComputeValue(CSSProperty aProperty,
mozilla::dom::Element* aTargetElement,
nsStyleContext* aStyleContext,
const nsAString& aSpecifiedValue,
bool aUseSVGMode,
StyleAnimationValue& aComputedValue,
bool* aIsContextSensitive = nullptr);
/**
@@ -177,29 +178,29 @@ public:
*
* On success, when aProperty is a longhand, aResult will have a single
* value in it. When aProperty is a shorthand, aResult will be filled with
* values for all of aProperty's longhand components. aEnabledState
* is used to filter the longhand components that will be appended
* to aResult. On failure, aResult might still have partial results
* in it.
*/
- static bool ComputeValues(nsCSSPropertyID aProperty,
+ static bool ComputeValues(CSSProperty aProperty,
mozilla::CSSEnabledState aEnabledState,
mozilla::dom::Element* aTargetElement,
nsStyleContext* aStyleContext,
const nsAString& aSpecifiedValue,
bool aUseSVGMode,
nsTArray<PropertyStyleAnimationValuePair>& aResult);
/**
* A variant on ComputeValues that takes an nsCSSValue as the specified
* value. Only longhand properties are supported.
*/
- static bool ComputeValues(nsCSSPropertyID aProperty,
+ static bool ComputeValues(CSSProperty aProperty,
mozilla::CSSEnabledState aEnabledState,
mozilla::dom::Element* aTargetElement,
nsStyleContext* aStyleContext,
const nsCSSValue& aSpecifiedValue,
bool aUseSVGMode,
nsTArray<PropertyStyleAnimationValuePair>& aResult);
/**
@@ -214,23 +215,23 @@ public:
* transfers ownership for some resources such that the |aComputedValue|
* does not depend on the lifetime of |aSpecifiedValue|.
*
* @param aProperty The property whose value we're uncomputing.
* @param aComputedValue The computed value to be converted.
* @param [out] aSpecifiedValue The resulting specified value.
* @return true on success, false on failure.
*/
- static bool UncomputeValue(nsCSSPropertyID aProperty,
+ static bool UncomputeValue(CSSProperty aProperty,
const StyleAnimationValue& aComputedValue,
nsCSSValue& aSpecifiedValue);
- static bool UncomputeValue(nsCSSPropertyID aProperty,
+ static bool UncomputeValue(CSSProperty aProperty,
StyleAnimationValue&& aComputedValue,
nsCSSValue& aSpecifiedValue);
- static bool UncomputeValue(nsCSSPropertyID aProperty,
+ static bool UncomputeValue(CSSProperty aProperty,
const StyleAnimationValue& aComputedValue,
nsAString& aSpecifiedValue);
/**
* Gets the computed value for the given property from the given style
* context.
*
* Obtaining the computed value allows us to animate properties when the
@@ -238,17 +239,17 @@ public:
* other keyword that isn't directly interpolatable, but which *computes* to
* something interpolatable.
*
* @param aProperty The property whose value we're looking up.
* @param aStyleContext The style context to check for the computed value.
* @param [out] aComputedValue The resulting computed value.
* @return true on success, false on failure.
*/
- static bool ExtractComputedValue(nsCSSPropertyID aProperty,
+ static bool ExtractComputedValue(CSSProperty aMaybeCustomProperty,
nsStyleContext* aStyleContext,
StyleAnimationValue& aComputedValue);
/**
* Interpolates between 2 matrices by decomposing them.
*
* @param aMatrix1 First matrix, using CSS pixel units.
* @param aMatrix2 Second matrix, using CSS pixel units.
@@ -521,15 +522,15 @@ private:
}
static bool IsStringUnit(Unit aUnit) {
return aUnit == eUnit_UnparsedString;
}
};
struct PropertyStyleAnimationValuePair
{
- nsCSSPropertyID mProperty;
+ CSSProperty mProperty;
StyleAnimationValue mValue;
};
} // namespace mozilla
#endif
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -2,26 +2,29 @@
/* 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 "nsAnimationManager.h"
#include "nsTransitionManager.h"
#include "mozilla/dom/CSSAnimationBinding.h"
+#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
+#include "mozilla/CSSPropertySet.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/KeyframeEffect.h"
#include "nsPresContext.h"
#include "nsStyleSet.h"
#include "nsStyleChangeList.h"
+#include "nsTArray.h"
#include "nsCSSRules.h"
#include "mozilla/RestyleManager.h"
#include "nsLayoutUtils.h"
#include "nsIFrame.h"
#include "nsIDocument.h"
#include "nsDOMMutationObserver.h"
#include <algorithm> // std::stable_sort
#include <math.h>
@@ -544,29 +547,29 @@ private:
const nsCSSKeyframesRule* aRule);
Maybe<ComputedTimingFunction> GetKeyframeTimingFunction(
nsPresContext* aPresContext,
nsCSSKeyframeRule* aKeyframeRule,
const Maybe<ComputedTimingFunction>& aInheritedTimingFunction);
nsTArray<PropertyValuePair> GetKeyframePropertyValues(
nsPresContext* aPresContext,
nsCSSKeyframeRule* aKeyframeRule,
- nsCSSPropertyIDSet& aAnimatedProperties);
+ CSSPropertySet& aAnimatedProperties);
void FillInMissingKeyframeValues(
nsPresContext* aPresContext,
- nsCSSPropertyIDSet aAnimatedProperties,
- nsCSSPropertyIDSet aPropertiesSetAtStart,
- nsCSSPropertyIDSet aPropertiesSetAtEnd,
+ CSSPropertySet aAnimatedProperties,
+ const CSSPropertySet aPropertiesSetAtStart,
+ const CSSPropertySet aPropertiesSetAtEnd,
const Maybe<ComputedTimingFunction>& aInheritedTimingFunction,
nsTArray<Keyframe>& aKeyframes);
- void AppendProperty(nsPresContext* aPresContext,
- nsCSSPropertyID aProperty,
+ bool AppendProperty(nsPresContext* aPresContext,
+ CSSProperty aProperty,
nsTArray<PropertyValuePair>& aPropertyValues);
- nsCSSValue GetComputedValue(nsPresContext* aPresContext,
- nsCSSPropertyID aProperty);
+ bool GetComputedValue(nsPresContext* aPresContext, CSSProperty aProperty,
+ nsCSSValue& aValue);
static TimingParams TimingParamsFrom(
const StyleAnimation& aStyleAnimation)
{
TimingParams timing;
timing.mDuration.emplace(StickyTimeDuration::FromMilliseconds(
aStyleAnimation.GetDuration()));
@@ -712,17 +715,17 @@ CSSAnimationBuilder::BuildAnimationFrame
// FIXME: There is a pending spec change to make multiple @keyframes
// rules with the same name cascade but we don't support that yet.
Maybe<ComputedTimingFunction> inheritedTimingFunction =
ConvertTimingFunction(aSrc.GetTimingFunction());
// First, make up Keyframe objects for each rule
nsTArray<Keyframe> keyframes;
- nsCSSPropertyIDSet animatedProperties;
+ CSSPropertySet animatedProperties;
for (auto ruleIdx = 0, ruleEnd = aRule->StyleRuleCount();
ruleIdx != ruleEnd; ++ruleIdx) {
css::Rule* cssRule = aRule->GetStyleRuleAt(ruleIdx);
MOZ_ASSERT(cssRule, "must have rule");
MOZ_ASSERT(cssRule->GetType() == css::Rule::KEYFRAME_RULE,
"must be keyframe rule");
nsCSSKeyframeRule* keyframeRule = static_cast<nsCSSKeyframeRule*>(cssRule);
@@ -749,19 +752,19 @@ CSSAnimationBuilder::BuildAnimationFrame
// Next, stable sort by offset
std::stable_sort(keyframes.begin(), keyframes.end(),
[](const Keyframe& a, const Keyframe& b)
{
return a.mOffset < b.mOffset;
});
// Then walk backwards through the keyframes and drop overridden properties.
- nsCSSPropertyIDSet propertiesSetAtCurrentOffset;
- nsCSSPropertyIDSet propertiesSetAtStart;
- nsCSSPropertyIDSet propertiesSetAtEnd;
+ CSSPropertySet propertiesSetAtCurrentOffset;
+ CSSPropertySet propertiesSetAtStart;
+ CSSPropertySet propertiesSetAtEnd;
double currentOffset = -1.0;
for (size_t keyframeIdx = keyframes.Length();
keyframeIdx > 0;
--keyframeIdx) {
Keyframe& keyframe = keyframes[keyframeIdx - 1];
MOZ_ASSERT(keyframe.mOffset, "Should have filled in the offset");
if (keyframe.mOffset.value() != currentOffset) {
@@ -865,53 +868,70 @@ ConvertTimingFunction(const nsTimingFunc
if (aTimingFunction.mType != nsTimingFunction::Type::Linear) {
result.emplace();
result->Init(aTimingFunction);
}
return result;
}
+static void
+TryAddProperty(CSSProperty aProp, nsStyleContext* aStyleContext,
+ nsTArray<PropertyValuePair>& aResult,
+ CSSPropertySet& aAnimatedProperties)
+{
+ PropertyValuePair pair;
+ pair.mProperty = aProp;
+
+ StyleAnimationValue computedValue;
+ if (!StyleAnimationValue::ExtractComputedValue(aProp, aStyleContext,
+ computedValue)) {
+ return;
+ }
+ DebugOnly<bool> uncomputeResult =
+ StyleAnimationValue::UncomputeValue(aProp, Move(computedValue),
+ pair.mValue);
+ MOZ_ASSERT(uncomputeResult,
+ "Unable to get specified value from computed value");
+ MOZ_ASSERT(pair.mValue.GetUnit() != eCSSUnit_Null,
+ "Not expecting to read invalid properties");
+
+ aResult.AppendElement(Move(pair));
+ aAnimatedProperties.AddProperty(aProp);
+}
+
nsTArray<PropertyValuePair>
CSSAnimationBuilder::GetKeyframePropertyValues(
nsPresContext* aPresContext,
nsCSSKeyframeRule* aKeyframeRule,
- nsCSSPropertyIDSet& aAnimatedProperties)
+ CSSPropertySet& aAnimatedProperties)
{
nsTArray<PropertyValuePair> result;
RefPtr<nsStyleContext> styleContext =
mResolvedStyles.Get(aPresContext, mStyleContext,
aKeyframeRule->Declaration());
for (nsCSSPropertyID prop = nsCSSPropertyID(0);
prop < eCSSProperty_COUNT_no_shorthands;
prop = nsCSSPropertyID(prop + 1)) {
if (nsCSSProps::kAnimTypeTable[prop] == eStyleAnimType_None ||
!aKeyframeRule->Declaration()->HasNonImportantValueFor(prop)) {
continue;
}
- PropertyValuePair pair;
- pair.mProperty = prop;
+ TryAddProperty(CSSProperty(prop), styleContext, result,
+ aAnimatedProperties);
+ }
- StyleAnimationValue computedValue;
- if (!StyleAnimationValue::ExtractComputedValue(prop, styleContext,
- computedValue)) {
- continue;
+ if (aKeyframeRule->Declaration()->HasVariables()) {
+ for (auto iter = aKeyframeRule->Declaration()->IterVariables();
+ !iter.Done(); iter.Next()) {
+ TryAddProperty(CSSProperty(NS_Atomize(iter.Key())), styleContext, result,
+ aAnimatedProperties);
}
- DebugOnly<bool> uncomputeResult =
- StyleAnimationValue::UncomputeValue(prop, Move(computedValue),
- pair.mValue);
- MOZ_ASSERT(uncomputeResult,
- "Unable to get specified value from computed value");
- MOZ_ASSERT(pair.mValue.GetUnit() != eCSSUnit_Null,
- "Not expecting to read invalid properties");
-
- result.AppendElement(Move(pair));
- aAnimatedProperties.AddProperty(prop);
}
return result;
}
// Utility function to walk through |aIter| to find the Keyframe with
// matching offset and timing function but stopping as soon as the offset
// differs from |aOffset| (i.e. it assumes a sorted iterator).
@@ -944,19 +964,19 @@ FindMatchingKeyframe(
++aIndex;
}
return false;
}
void
CSSAnimationBuilder::FillInMissingKeyframeValues(
nsPresContext* aPresContext,
- nsCSSPropertyIDSet aAnimatedProperties,
- nsCSSPropertyIDSet aPropertiesSetAtStart,
- nsCSSPropertyIDSet aPropertiesSetAtEnd,
+ CSSPropertySet aAnimatedProperties,
+ const CSSPropertySet aPropertiesSetAtStart,
+ const CSSPropertySet aPropertiesSetAtEnd,
const Maybe<ComputedTimingFunction>& aInheritedTimingFunction,
nsTArray<Keyframe>& aKeyframes)
{
static const size_t kNotSet = static_cast<size_t>(-1);
// Find/create the keyframe to add start values to
size_t startKeyframeIndex = kNotSet;
if (!aAnimatedProperties.Equals(aPropertiesSetAtStart) &&
@@ -992,73 +1012,102 @@ CSSAnimationBuilder::FillInMissingKeyfra
// Now that we have finished manipulating aKeyframes, it is safe to
// take pointers to its elements.
Keyframe* startKeyframe = startKeyframeIndex == kNotSet
? nullptr : &aKeyframes[startKeyframeIndex];
Keyframe* endKeyframe = endKeyframeIndex == kNotSet
? nullptr : &aKeyframes[endKeyframeIndex];
// Iterate through all properties and fill-in missing values
- for (nsCSSPropertyID prop = nsCSSPropertyID(0);
- prop < eCSSProperty_COUNT_no_shorthands;
- prop = nsCSSPropertyID(prop + 1)) {
+ for (nsCSSPropertyID cssprop = nsCSSPropertyID(0);
+ cssprop < eCSSProperty_COUNT_no_shorthands;
+ cssprop = nsCSSPropertyID(cssprop + 1)) {
+ CSSProperty prop(cssprop);
if (!aAnimatedProperties.HasProperty(prop)) {
continue;
}
+ // If we hit either of these assertion, it probably means we are fetching a
+ // value from the computed style that we don't know how to represent as a
+ // StyleAnimationValue.
if (startKeyframe && !aPropertiesSetAtStart.HasProperty(prop)) {
- AppendProperty(aPresContext, prop, startKeyframe->mPropertyValues);
+ MOZ_ALWAYS_TRUE(AppendProperty(aPresContext, prop,
+ startKeyframe->mPropertyValues));
}
if (endKeyframe && !aPropertiesSetAtEnd.HasProperty(prop)) {
- AppendProperty(aPresContext, prop, endKeyframe->mPropertyValues);
+ MOZ_ALWAYS_TRUE(AppendProperty(aPresContext, prop,
+ endKeyframe->mPropertyValues));
}
}
+
+ // Fill in missing keyframe values for custom properties.
+ // It's possible for custom properties to have no appropriate value we can
+ // fill in (i.e. if CSS.registerProperty is called with no initialValue).
+ // Then we should remove this property from the animation altogether.
+
+ CSSPropertySet incompleteCustomProps;
+ for (auto it = aAnimatedProperties.IterCustomProps(); !it.Done(); it.Next()) {
+ CSSProperty prop(it.UserData().get());
+ if (startKeyframe && !aPropertiesSetAtStart.HasProperty(prop)) {
+ if (!AppendProperty(aPresContext, prop, startKeyframe->mPropertyValues)) {
+ incompleteCustomProps.AddProperty(prop);
+ continue;
+ }
+ }
+ if (endKeyframe && !aPropertiesSetAtEnd.HasProperty(prop)) {
+ if (!AppendProperty(aPresContext, prop, endKeyframe->mPropertyValues)) {
+ incompleteCustomProps.AddProperty(prop);
+ }
+ }
+ }
+
+ for (Keyframe& keyframe : aKeyframes) {
+ keyframe.mPropertyValues
+ .RemoveElementsBy([&](const PropertyValuePair& pair) {
+ return incompleteCustomProps.HasProperty(pair.mProperty);
+ });
+ }
}
-void
+bool
CSSAnimationBuilder::AppendProperty(
nsPresContext* aPresContext,
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
nsTArray<PropertyValuePair>& aPropertyValues)
{
PropertyValuePair propertyValue;
propertyValue.mProperty = aProperty;
- propertyValue.mValue = GetComputedValue(aPresContext, aProperty);
-
+ if (!GetComputedValue(aPresContext, aProperty, propertyValue.mValue)) {
+ return false;
+ }
aPropertyValues.AppendElement(Move(propertyValue));
+ return true;
}
-nsCSSValue
+bool
CSSAnimationBuilder::GetComputedValue(nsPresContext* aPresContext,
- nsCSSPropertyID aProperty)
+ CSSProperty aProperty,
+ nsCSSValue& aValue)
{
- nsCSSValue result;
StyleAnimationValue computedValue;
if (!mStyleWithoutAnimation) {
MOZ_ASSERT(aPresContext->StyleSet()->IsGecko(),
"ServoStyleSet should not use nsAnimationManager for "
"animations");
mStyleWithoutAnimation = aPresContext->StyleSet()->AsGecko()->
ResolveStyleWithoutAnimation(mTarget, mStyleContext,
eRestyle_AllHintsWithAnimations);
}
- if (StyleAnimationValue::ExtractComputedValue(aProperty,
- mStyleWithoutAnimation,
- computedValue)) {
- StyleAnimationValue::UncomputeValue(aProperty, Move(computedValue), result);
- }
-
- // If we hit this assertion, it probably means we are fetching a value from
- // the computed style that we don't know how to represent as
- // a StyleAnimationValue.
- MOZ_ASSERT(result.GetUnit() != eCSSUnit_Null, "Got null computed value");
-
- return result;
+ return
+ StyleAnimationValue::ExtractComputedValue(aProperty,
+ mStyleWithoutAnimation,
+ computedValue) &&
+ StyleAnimationValue::UncomputeValue(aProperty, Move(computedValue), aValue);
}
void
nsAnimationManager::BuildAnimations(nsStyleContext* aStyleContext,
dom::Element* aTarget,
CSSAnimationCollection* aCollection,
OwningCSSAnimationPtrArray& aAnimations)
{
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -6331,31 +6331,38 @@ nsComputedDOMStyle::DoGetTransitionPrope
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
MOZ_ASSERT(display->mTransitionPropertyCount > 0,
"first item must be explicit");
uint32_t i = 0;
do {
const StyleTransition *transition = &display->mTransitions[i];
RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
- nsCSSPropertyID cssprop = transition->GetProperty();
- if (cssprop == eCSSPropertyExtra_all_properties)
- property->SetIdent(eCSSKeyword_all);
- else if (cssprop == eCSSPropertyExtra_no_properties)
- property->SetIdent(eCSSKeyword_none);
- else if (cssprop == eCSSProperty_UNKNOWN ||
- cssprop == eCSSPropertyExtra_variable)
- {
- nsAutoString escaped;
- nsStyleUtil::AppendEscapedCSSIdent(
- nsDependentAtomString(transition->GetUnknownProperty()), escaped);
- property->SetString(escaped); // really want SetIdent
+ CSSProperty prop = transition->GetProperty();
+ if (prop.IsFixed()) {
+ nsCSSPropertyID cssprop = prop.AsFixed();
+ if (cssprop == eCSSPropertyExtra_all_properties)
+ property->SetIdent(eCSSKeyword_all);
+ else if (cssprop == eCSSPropertyExtra_no_properties)
+ property->SetIdent(eCSSKeyword_none);
+ else if (cssprop == eCSSProperty_UNKNOWN ||
+ cssprop == eCSSPropertyExtra_variable)
+ {
+ nsAutoString escaped;
+ nsStyleUtil::AppendEscapedCSSIdent(
+ nsDependentAtomString(transition->GetUnknownProperty()), escaped);
+ property->SetString(escaped); // really want SetIdent
+ }
+ else
+ property->SetString(nsCSSProps::GetStringValue(cssprop));
+ } else {
+ nsString name;
+ prop.AsCustom()->ToString(name);
+ property->SetString(name);
}
- else
- property->SetString(nsCSSProps::GetStringValue(cssprop));
valueList->AppendCSSValue(property.forget());
} while (++i < display->mTransitionPropertyCount);
return valueList.forget();
}
void
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5534,38 +5534,49 @@ nsRuleNode::ComputeDisplayData(void* aSt
} else if (property.unit == eCSSUnit_Inherit) {
MOZ_ASSERT(i < parentDisplay->mTransitionPropertyCount,
"property.num computed incorrectly");
MOZ_ASSERT(!conditions.Cacheable(),
"should have made conditions.Cacheable() false above");
transition->CopyPropertyFrom(parentDisplay->mTransitions[i]);
} else if (property.unit == eCSSUnit_Initial ||
property.unit == eCSSUnit_Unset) {
- transition->SetProperty(eCSSPropertyExtra_all_properties);
+ transition->SetProperty(CSSProperty(eCSSPropertyExtra_all_properties));
} else if (property.unit == eCSSUnit_None) {
- transition->SetProperty(eCSSPropertyExtra_no_properties);
+ transition->SetProperty(CSSProperty(eCSSPropertyExtra_no_properties));
} else if (property.list) {
const nsCSSValue &val = property.list->mValue;
if (val.GetUnit() == eCSSUnit_Ident) {
nsDependentString
propertyStr(property.list->mValue.GetStringBufferValue());
nsCSSPropertyID prop =
nsCSSProps::LookupProperty(propertyStr,
CSSEnabledState::eForAllContent);
- if (prop == eCSSProperty_UNKNOWN ||
- prop == eCSSPropertyExtra_variable) {
+ if (prop == eCSSProperty_UNKNOWN) {
transition->SetUnknownProperty(prop, propertyStr);
+ } else if (prop == eCSSPropertyExtra_variable) {
+ const CSSVariableRegistrations* registrations =
+ CSSVariableRegistrationsOfStyleContext(aContext);
+ CSSProperty property =
+ nsCSSProps::LookupCustomProperty(registrations, propertyStr,
+ CSSEnabledState::eForAllContent);
+ if (property == eCSSProperty_UNKNOWN) {
+ transition->SetUnknownProperty(prop, propertyStr);
+ } else {
+ transition->SetProperty(Move(property));
+ }
} else {
- transition->SetProperty(prop);
+ transition->SetProperty(CSSProperty(prop));
}
} else {
MOZ_ASSERT(val.GetUnit() == eCSSUnit_All,
"Invalid transition property unit");
- transition->SetProperty(eCSSPropertyExtra_all_properties);
+ transition->SetProperty(
+ CSSProperty(eCSSPropertyExtra_all_properties));
}
}
if (i >= timingFunction.num) {
MOZ_ASSERT(timingFunction.num,
"timingFunction.num must be greater than 0");
transition->SetTimingFunction(
display->mTransitions[i % timingFunction.num].GetTimingFunction());
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -12,16 +12,17 @@
#define nsRuleNode_h___
#include "mozilla/ArenaObjectID.h"
#include "mozilla/LinkedList.h"
#include "mozilla/PodOperations.h"
#include "mozilla/RangedArray.h"
#include "mozilla/RuleNodeCacheConditions.h"
#include "mozilla/SheetType.h"
+#include "nsCSSPropertyID.h"
#include "nsPresContext.h"
#include "nsStyleStruct.h"
class nsCSSPropertyIDSet;
class nsCSSValue;
class nsIStyleRule;
class nsStyleContext;
class nsStyleCoord;
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -1396,18 +1396,18 @@ nsStyleContext::Arena()
}
static inline void
ExtractAnimationValue(nsCSSPropertyID aProperty,
nsStyleContext* aStyleContext,
StyleAnimationValue& aResult)
{
DebugOnly<bool> success =
- StyleAnimationValue::ExtractComputedValue(aProperty, aStyleContext,
- aResult);
+ StyleAnimationValue::ExtractComputedValue(CSSProperty(aProperty),
+ aStyleContext, aResult);
MOZ_ASSERT(success,
"aProperty must be extractable by StyleAnimationValue");
}
static nscolor
ExtractColor(nsCSSPropertyID aProperty,
nsStyleContext *aStyleContext)
{
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2518,31 +2518,31 @@ StyleTransition::StyleTransition(const S
}
void
StyleTransition::SetInitialValues()
{
mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
mDuration = 0.0;
mDelay = 0.0;
- mProperty = eCSSPropertyExtra_all_properties;
+ mProperty = CSSProperty(eCSSPropertyExtra_all_properties);
}
void
StyleTransition::SetUnknownProperty(nsCSSPropertyID aProperty,
const nsAString& aPropertyString)
{
MOZ_ASSERT(nsCSSProps::LookupProperty(aPropertyString,
CSSEnabledState::eForAllContent) ==
aProperty,
"property and property string should match");
MOZ_ASSERT(aProperty == eCSSProperty_UNKNOWN ||
aProperty == eCSSPropertyExtra_variable,
"should be either unknown or custom property");
- mProperty = aProperty;
+ mProperty = CSSProperty(aProperty);
mUnknownProperty = NS_Atomize(aPropertyString);
}
bool
StyleTransition::operator==(const StyleTransition& aOther) const
{
return mTimingFunction == aOther.mTimingFunction &&
mDuration == aOther.mDuration &&
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -9,16 +9,17 @@
* internal API for computed style data for an element
*/
#ifndef nsStyleStruct_h___
#define nsStyleStruct_h___
#include "mozilla/ArenaObjectID.h"
#include "mozilla/Attributes.h"
+#include "mozilla/CSSProperty.h"
#include "mozilla/CSSVariableValues.h"
#include "mozilla/Maybe.h"
#include "mozilla/SheetType.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/StyleStructContext.h"
#include "mozilla/UniquePtr.h"
#include "nsColor.h"
#include "nsCoord.h"
@@ -2279,33 +2280,34 @@ struct StyleTransition
void SetInitialValues();
// Delay and Duration are in milliseconds
const nsTimingFunction& GetTimingFunction() const { return mTimingFunction; }
float GetDelay() const { return mDelay; }
float GetDuration() const { return mDuration; }
- nsCSSPropertyID GetProperty() const { return mProperty; }
+ CSSProperty GetProperty() const { return mProperty; }
nsIAtom* GetUnknownProperty() const { return mUnknownProperty; }
float GetCombinedDuration() const {
// http://dev.w3.org/csswg/css-transitions/#combined-duration
return std::max(mDuration, 0.0f) + mDelay;
}
void SetTimingFunction(const nsTimingFunction& aTimingFunction)
{ mTimingFunction = aTimingFunction; }
void SetDelay(float aDelay) { mDelay = aDelay; }
void SetDuration(float aDuration) { mDuration = aDuration; }
- void SetProperty(nsCSSPropertyID aProperty)
+ void SetProperty(CSSProperty aProperty)
{
- NS_ASSERTION(aProperty != eCSSProperty_UNKNOWN &&
- aProperty != eCSSPropertyExtra_variable,
- "invalid property");
+ MOZ_ASSERT(aProperty.IsCustom() ||
+ (aProperty.AsFixed() != eCSSProperty_UNKNOWN &&
+ aProperty.AsFixed() != eCSSPropertyExtra_variable),
+ "invalid property");
mProperty = aProperty;
}
void SetUnknownProperty(nsCSSPropertyID aProperty,
const nsAString& aPropertyString);
void CopyPropertyFrom(const StyleTransition& aOther)
{
mProperty = aOther.mProperty;
mUnknownProperty = aOther.mUnknownProperty;
@@ -2316,18 +2318,18 @@ struct StyleTransition
bool operator==(const StyleTransition& aOther) const;
bool operator!=(const StyleTransition& aOther) const
{ return !(*this == aOther); }
private:
nsTimingFunction mTimingFunction;
float mDuration;
float mDelay;
- nsCSSPropertyID mProperty;
- nsCOMPtr<nsIAtom> mUnknownProperty; // used when mProperty is
+ CSSProperty mProperty;
+ nsCOMPtr<nsIAtom> mUnknownProperty; // used when mProperty is fixed and
// eCSSProperty_UNKNOWN or
// eCSSPropertyExtra_variable
};
struct StyleAnimation
{
StyleAnimation() { /* leaves uninitialized; see also SetInitialValues */ }
explicit StyleAnimation(const StyleAnimation& aCopy);
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -30,16 +30,17 @@
#include "nsCSSProps.h"
#include "nsCSSPseudoElements.h"
#include "nsDisplayList.h"
#include "nsStyleChangeList.h"
#include "nsStyleSet.h"
#include "mozilla/RestyleManagerHandle.h"
#include "mozilla/RestyleManagerHandleInlines.h"
#include "nsDOMMutationObserver.h"
+#include "nsLayoutUtils.h"
using mozilla::TimeStamp;
using mozilla::TimeDuration;
using mozilla::dom::Animation;
using mozilla::dom::AnimationPlayState;
using mozilla::dom::CSSTransition;
using mozilla::dom::DocumentTimeline;
using mozilla::dom::KeyframeEffectReadOnly;
@@ -74,20 +75,22 @@ ElementPropertyTransition::CurrentValueP
}
void
ElementPropertyTransition::UpdateStartValueFromReplacedTransition()
{
if (!mReplacedTransition) {
return;
}
- MOZ_ASSERT(nsCSSProps::PropHasFlags(TransitionProperty(),
+ MOZ_ASSERT(TransitionProperty().IsFixed(),
+ "Custom properties can't be composited.");
+ MOZ_ASSERT(nsCSSProps::PropHasFlags(TransitionProperty().AsFixed(),
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
"The transition property should be able to be run on the "
- "compositor");
+ "compositor.");
MOZ_ASSERT(mTarget && mTarget->mElement->OwnerDoc(),
"We should have a valid document at this moment");
dom::DocumentTimeline* timeline = mTarget->mElement->OwnerDoc()->Timeline();
ComputedTiming computedTiming = GetComputedTimingAt(
dom::CSSTransition::GetCurrentTimeAt(*timeline,
TimeStamp::Now(),
mReplacedTransition->mStartTime,
@@ -137,18 +140,18 @@ CSSTransition::WrapObject(JSContext* aCx
void
CSSTransition::GetTransitionProperty(nsString& aRetVal) const
{
// Once we make the effect property settable (bug 1049975) we will need
// to store the transition property on the CSSTransition itself but for
// now we can just query the effect.
MOZ_ASSERT(mEffect && mEffect->AsTransition(),
"Transitions should have a transition effect");
- nsCSSPropertyID prop = mEffect->AsTransition()->TransitionProperty();
- aRetVal = NS_ConvertUTF8toUTF16(nsCSSProps::GetStringValue(prop));
+ CSSProperty prop = mEffect->AsTransition()->TransitionProperty();
+ prop.ToString(aRetVal);
}
AnimationPlayState
CSSTransition::PlayStateFromJS() const
{
FlushStyle();
return Animation::PlayStateFromJS();
}
@@ -205,17 +208,17 @@ CSSTransition::QueueEvents()
void
CSSTransition::Tick()
{
Animation::Tick();
QueueEvents();
}
-nsCSSPropertyID
+CSSProperty
CSSTransition::TransitionProperty() const
{
// FIXME: Once we support replacing/removing the effect (bug 1049975)
// we'll need to store the original transition property so we keep
// returning the same value in that case.
dom::KeyframeEffectReadOnly* effect = GetEffect();
MOZ_ASSERT(effect && effect->AsTransition(),
"Transition should have a transition effect");
@@ -250,19 +253,28 @@ CSSTransition::HasLowerCompositeOrderTha
return mOwningElement.LessThan(aOther.mOwningElement);
}
// 2. (Same element and pseudo): Sort by transition generation
if (mAnimationIndex != aOther.mAnimationIndex) {
return mAnimationIndex < aOther.mAnimationIndex;
}
+ if (TransitionProperty().IsCustom() &&
+ aOther.TransitionProperty().IsCustom()) {
+ return TransitionProperty().IsCustomLessThan(aOther.TransitionProperty());
+ } else if (TransitionProperty().IsCustom()) {
+ return false;
+ } else if (aOther.TransitionProperty().IsCustom()) {
+ return true;
+ }
+
// 3. (Same transition generation): Sort by transition property
- return nsCSSProps::GetStringValue(TransitionProperty()) <
- nsCSSProps::GetStringValue(aOther.TransitionProperty());
+ return nsCSSProps::GetStringValue(TransitionProperty().AsFixed()) <
+ nsCSSProps::GetStringValue(aOther.TransitionProperty().AsFixed());
}
/* static */ Nullable<TimeDuration>
CSSTransition::GetCurrentTimeAt(const DocumentTimeline& aTimeline,
const TimeStamp& aBaseTime,
const TimeDuration& aStartTime,
double aPlaybackRate)
{
@@ -453,92 +465,107 @@ nsTransitionManager::UpdateTransitions(
MOZ_ASSERT(!aElementTransitions ||
aElementTransitions->mElement == aElement, "Element mismatch");
// Per http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html
// I'll consider only the transitions from the number of items in
// 'transition-property' on down, and later ones will override earlier
// ones (tracked using |whichStarted|).
bool startedAny = false;
- nsCSSPropertyIDSet whichStarted;
+ CSSPropertySet whichStarted;
for (uint32_t i = aDisp->mTransitionPropertyCount; i-- != 0; ) {
const StyleTransition& t = aDisp->mTransitions[i];
// Check the combined duration (combination of delay and duration)
// first, since it defaults to zero, which means we can ignore the
// transition.
if (t.GetCombinedDuration() > 0.0f) {
// We might have something to transition. See if any of the
// properties in question changed and are animatable.
// FIXME: Would be good to find a way to share code between this
// interpretation of transition-property and the one below.
- nsCSSPropertyID property = t.GetProperty();
- if (property == eCSSPropertyExtra_no_properties ||
- property == eCSSPropertyExtra_variable ||
- property == eCSSProperty_UNKNOWN) {
- // Nothing to do, but need to exclude this from cases below.
- } else if (property == eCSSPropertyExtra_all_properties) {
- for (nsCSSPropertyID p = nsCSSPropertyID(0);
- p < eCSSProperty_COUNT_no_shorthands;
- p = nsCSSPropertyID(p + 1)) {
- ConsiderStartingTransition(p, t, aElement, aElementTransitions,
- aOldStyleContext, aNewStyleContext,
- &startedAny, &whichStarted);
- }
- } else if (nsCSSProps::IsShorthand(property)) {
- CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, property,
- CSSEnabledState::eForAllContent)
- {
- ConsiderStartingTransition(*subprop, t, aElement, aElementTransitions,
- aOldStyleContext, aNewStyleContext,
- &startedAny, &whichStarted);
+ CSSProperty maybeCustom = t.GetProperty();
+ if (maybeCustom.IsFixed()) {
+ nsCSSPropertyID property = maybeCustom.AsFixed();
+ if (property == eCSSPropertyExtra_no_properties ||
+ property == eCSSPropertyExtra_variable ||
+ property == eCSSProperty_UNKNOWN) {
+ // Nothing to do, but need to exclude this from cases below.
+ } else if (property == eCSSPropertyExtra_all_properties) {
+ for (nsCSSPropertyID p = nsCSSPropertyID(0);
+ p < eCSSProperty_COUNT_no_shorthands;
+ p = nsCSSPropertyID(p + 1)) {
+ ConsiderStartingTransition(CSSProperty(p), t, aElement,
+ aElementTransitions, aOldStyleContext,
+ aNewStyleContext, &startedAny,
+ &whichStarted);
+ }
+ } else if (nsCSSProps::IsShorthand(property)) {
+ CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, property,
+ CSSEnabledState::eForAllContent)
+ {
+ ConsiderStartingTransition(CSSProperty(*subprop), t,
+ aElement, aElementTransitions,
+ aOldStyleContext, aNewStyleContext,
+ &startedAny, &whichStarted);
+ }
+ } else {
+ ConsiderStartingTransition(maybeCustom, t, aElement,
+ aElementTransitions, aOldStyleContext,
+ aNewStyleContext, &startedAny,
+ &whichStarted);
}
} else {
- ConsiderStartingTransition(property, t, aElement, aElementTransitions,
- aOldStyleContext, aNewStyleContext,
- &startedAny, &whichStarted);
+ ConsiderStartingTransition(maybeCustom, t, aElement,
+ aElementTransitions, aOldStyleContext,
+ aNewStyleContext, &startedAny,
+ &whichStarted);
}
}
}
// Stop any transitions for properties that are no longer in
// 'transition-property', including finished transitions.
// Also stop any transitions (and remove any finished transitions)
// for properties that just changed (and are still in the set of
// properties to transition), but for which we didn't just start the
// transition. This can happen delay and duration are both zero, or
// because the new value is not interpolable.
// Note that we also do the latter set of work in
// nsTransitionManager::PruneCompletedTransitions.
if (aElementTransitions) {
bool checkProperties =
aDisp->mTransitions[0].GetProperty() != eCSSPropertyExtra_all_properties;
- nsCSSPropertyIDSet allTransitionProperties;
+ CSSPropertySet allTransitionProperties;
if (checkProperties) {
for (uint32_t i = aDisp->mTransitionPropertyCount; i-- != 0; ) {
const StyleTransition& t = aDisp->mTransitions[i];
// FIXME: Would be good to find a way to share code between this
// interpretation of transition-property and the one above.
- nsCSSPropertyID property = t.GetProperty();
- if (property == eCSSPropertyExtra_no_properties ||
- property == eCSSPropertyExtra_variable ||
- property == eCSSProperty_UNKNOWN) {
- // Nothing to do, but need to exclude this from cases below.
- } else if (property == eCSSPropertyExtra_all_properties) {
- for (nsCSSPropertyID p = nsCSSPropertyID(0);
- p < eCSSProperty_COUNT_no_shorthands;
- p = nsCSSPropertyID(p + 1)) {
- allTransitionProperties.AddProperty(p);
- }
- } else if (nsCSSProps::IsShorthand(property)) {
- CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
- subprop, property, CSSEnabledState::eForAllContent) {
- allTransitionProperties.AddProperty(*subprop);
+ if (t.GetProperty().IsFixed()) {
+ nsCSSPropertyID property = t.GetProperty().AsFixed();
+ if (property == eCSSPropertyExtra_no_properties ||
+ property == eCSSPropertyExtra_variable ||
+ property == eCSSProperty_UNKNOWN) {
+ // Nothing to do, but need to exclude this from cases below.
+ } else if (property == eCSSPropertyExtra_all_properties) {
+ for (nsCSSPropertyID p = nsCSSPropertyID(0);
+ p < eCSSProperty_COUNT_no_shorthands;
+ p = nsCSSPropertyID(p + 1)) {
+ allTransitionProperties.AddProperty(CSSProperty(p));
+ }
+ } else if (nsCSSProps::IsShorthand(property)) {
+ CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
+ subprop, property, CSSEnabledState::eForAllContent) {
+ allTransitionProperties.AddProperty(CSSProperty(*subprop));
+ }
+ } else {
+ allTransitionProperties.AddProperty(t.GetProperty());
}
} else {
- allTransitionProperties.AddProperty(property);
+ allTransitionProperties.AddProperty(t.GetProperty());
}
}
}
OwningCSSTransitionPtrArray& animations = aElementTransitions->mAnimations;
size_t i = animations.Length();
MOZ_ASSERT(i != 0, "empty transitions list?");
StyleAnimationValue currentValue;
@@ -577,47 +604,48 @@ nsTransitionManager::UpdateTransitions(
}
}
return startedAny;
}
void
nsTransitionManager::ConsiderStartingTransition(
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
const StyleTransition& aTransition,
dom::Element* aElement,
CSSTransitionCollection*& aElementTransitions,
nsStyleContext* aOldStyleContext,
nsStyleContext* aNewStyleContext,
bool* aStartedAny,
- nsCSSPropertyIDSet* aWhichStarted)
+ CSSPropertySet* aWhichStarted)
{
// IsShorthand itself will assert if aProperty is not a property.
- MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
- "property out of range");
+ MOZ_ASSERT(!aProperty.IsShorthand(), "property out of range");
NS_ASSERTION(!aElementTransitions ||
aElementTransitions->mElement == aElement, "Element mismatch");
// Ignore disabled properties. We can arrive here if the transition-property
// is 'all' and the disabled property has a default value which derives value
// from another property, e.g. color.
- if (!nsCSSProps::IsEnabled(aProperty, CSSEnabledState::eForAllContent)) {
+ if (aProperty.IsFixed() &&
+ !nsCSSProps::IsEnabled(aProperty.AsFixed(), CSSEnabledState::eForAllContent)) {
return;
}
if (aWhichStarted->HasProperty(aProperty)) {
// A later item in transition-property already started a
// transition for this property, so we ignore this one.
// See comment above and
// http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html .
return;
}
- if (nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
+ if (aProperty.IsFixed() &&
+ nsCSSProps::kAnimTypeTable[aProperty.AsFixed()] == eStyleAnimType_None) {
return;
}
dom::DocumentTimeline* timeline = aElement->OwnerDoc()->Timeline();
StyleAnimationValue startValue, endValue, dummyValue;
bool haveValues =
StyleAnimationValue::ExtractComputedValue(aProperty,
@@ -858,34 +886,34 @@ nsTransitionManager::ConsiderStartingTra
effectSet->UpdateAnimationGeneration(mPresContext);
}
*aStartedAny = true;
aWhichStarted->AddProperty(aProperty);
}
static Keyframe&
-AppendKeyframe(double aOffset, nsCSSPropertyID aProperty,
+AppendKeyframe(double aOffset, CSSProperty aProperty,
StyleAnimationValue&& aValue, nsTArray<Keyframe>& aKeyframes)
{
Keyframe& frame = *aKeyframes.AppendElement();
frame.mOffset.emplace(aOffset);
PropertyValuePair& pv = *frame.mPropertyValues.AppendElement();
pv.mProperty = aProperty;
DebugOnly<bool> uncomputeResult =
StyleAnimationValue::UncomputeValue(aProperty, Move(aValue), pv.mValue);
MOZ_ASSERT(uncomputeResult,
"Unable to get specified value from computed value");
return frame;
}
nsTArray<Keyframe>
nsTransitionManager::GetTransitionKeyframes(
nsStyleContext* aStyleContext,
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
StyleAnimationValue&& aStartValue,
StyleAnimationValue&& aEndValue,
const nsTimingFunction& aTimingFunction)
{
nsTArray<Keyframe> keyframes(2);
Keyframe& fromFrame = AppendKeyframe(0.0, aProperty, Move(aStartValue),
keyframes);
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -5,16 +5,17 @@
/* Code to start and animate CSS transitions. */
#ifndef nsTransitionManager_h_
#define nsTransitionManager_h_
#include "mozilla/ContentEvents.h"
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
+#include "mozilla/CSSPropertySet.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/KeyframeEffect.h" // For KeyframeEffectReadOnly
#include "AnimationCommon.h"
#include "nsCSSProps.h"
class nsIGlobalObject;
class nsStyleContext;
@@ -47,17 +48,17 @@ struct ElementPropertyTransition : publi
{ }
ElementPropertyTransition* AsTransition() override { return this; }
const ElementPropertyTransition* AsTransition() const override
{
return this;
}
- nsCSSPropertyID TransitionProperty() const {
+ CSSProperty TransitionProperty() const {
MOZ_ASSERT(mKeyframes.Length() == 2,
"Transitions should have exactly two animation keyframes. "
"Perhaps we are using an un-initialized transition?");
MOZ_ASSERT(mKeyframes[0].mPropertyValues.Length() == 1,
"Transitions should have exactly one property in their first "
"frame");
return mKeyframes[0].mPropertyValues[0].mProperty;
}
@@ -165,17 +166,17 @@ public:
// that restyle should target the *transitions* level of the cascade.
// However, once we clear the owning element, CascadeLevel() will begin
// returning CascadeLevel::Animations.
mOwningElement = OwningElementRef();
}
void Tick() override;
- nsCSSPropertyID TransitionProperty() const;
+ CSSProperty TransitionProperty() const;
StyleAnimationValue ToValue() const;
bool HasLowerCompositeOrderThan(const CSSTransition& aOther) const;
EffectCompositor::CascadeLevel CascadeLevel() const override
{
return IsTiedToMarkup() ?
EffectCompositor::CascadeLevel::Transitions :
EffectCompositor::CascadeLevel::Animations;
@@ -271,28 +272,27 @@ struct AnimationTypeTraits<dom::CSSTrans
struct TransitionEventInfo {
RefPtr<dom::Element> mElement;
RefPtr<dom::Animation> mAnimation;
InternalTransitionEvent mEvent;
TimeStamp mTimeStamp;
TransitionEventInfo(dom::Element* aElement,
CSSPseudoElementType aPseudoType,
- nsCSSPropertyID aProperty,
+ CSSProperty aProperty,
StickyTimeDuration aDuration,
const TimeStamp& aTimeStamp,
dom::Animation* aAnimation)
: mElement(aElement)
, mAnimation(aAnimation)
, mEvent(true, eTransitionEnd)
, mTimeStamp(aTimeStamp)
{
// XXX Looks like nobody initialize WidgetEvent::time
- mEvent.mPropertyName =
- NS_ConvertUTF8toUTF16(nsCSSProps::GetStringValue(aProperty));
+ aProperty.ToString(mEvent.mPropertyName);
mEvent.mElapsedTime = aDuration.ToSeconds();
mEvent.mPseudoElement =
AnimationCollection<dom::CSSTransition>::PseudoTypeAsString(aPseudoType);
}
// InternalTransitionEvent doesn't support copy-construction, so we need
// to ourselves in order to work with nsTArray
TransitionEventInfo(const TransitionEventInfo& aOther)
@@ -394,28 +394,28 @@ protected:
bool
UpdateTransitions(const nsStyleDisplay* aDisp,
mozilla::dom::Element* aElement,
CSSTransitionCollection*& aElementTransitions,
nsStyleContext* aOldStyleContext,
nsStyleContext* aNewStyleContext);
void
- ConsiderStartingTransition(nsCSSPropertyID aProperty,
+ ConsiderStartingTransition(mozilla::CSSProperty aProperty,
const mozilla::StyleTransition& aTransition,
mozilla::dom::Element* aElement,
CSSTransitionCollection*& aElementTransitions,
nsStyleContext* aOldStyleContext,
nsStyleContext* aNewStyleContext,
bool* aStartedAny,
- nsCSSPropertyIDSet* aWhichStarted);
+ mozilla::CSSPropertySet* aWhichStarted);
nsTArray<mozilla::Keyframe> GetTransitionKeyframes(
nsStyleContext* aStyleContext,
- nsCSSPropertyID aProperty,
+ mozilla::CSSProperty aProperty,
mozilla::StyleAnimationValue&& aStartValue,
mozilla::StyleAnimationValue&& aEndValue,
const nsTimingFunction& aTimingFunction);
bool mInAnimationOnlyStyleUpdate;
mozilla::DelayedEventDispatcher<mozilla::TransitionEventInfo>
mEventDispatcher;