--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -51,16 +51,17 @@
#include "nsSMILMappedAttribute.h"
#include "SVGMotionSMILAttr.h"
#include "nsAttrValueOrString.h"
#include "nsSMILAnimationController.h"
#include "mozilla/dom/SVGElementBinding.h"
#include "mozilla/unused.h"
#include "mozilla/RestyleManagerHandle.h"
#include "mozilla/RestyleManagerHandleInlines.h"
+#include "mozilla/CSSVariableRegistration.h"
using namespace mozilla;
using namespace mozilla::dom;
// This is needed to ensure correct handling of calls to the
// vararg-list methods in this file:
// nsSVGElement::GetAnimated{Length,Number,Integer}Values
// See bug 547964 for details:
@@ -1190,17 +1191,18 @@ MappedAttrParser::~MappedAttrParser()
"into a style rule (and had its pointer cleared)");
}
void
MappedAttrParser::ParseMappedAttrValue(nsIAtom* aMappedAttrName,
const nsAString& aMappedAttrValue)
{
if (!mDecl) {
- mDecl = new css::Declaration();
+ nsIDocument* doc = mElement->OwnerDoc();
+ mDecl = new css::Declaration(CSSVariableRegistrationsOfDocument(doc));
mDecl->InitializeEmpty();
}
// Get the nsCSSPropertyID ID for our mapped attribute.
nsCSSPropertyID propertyID =
nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName),
CSSEnabledState::eForAllContent);
if (propertyID != eCSSProperty_UNKNOWN) {
--- a/layout/style/CSSVariableDeclarations.cpp
+++ b/layout/style/CSSVariableDeclarations.cpp
@@ -3,193 +3,444 @@
/* 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/. */
/* CSS Custom Property assignments for a Declaration at a given priority */
#include "CSSVariableDeclarations.h"
-#include "CSSVariableResolver.h"
-#include "nsCSSScanner.h"
+#include "mozilla/CSSVariableRegistration.h"
+#include "mozilla/CSSVariableResolver.h"
+#include "nsCSSParser.h"
#include "nsRuleData.h"
-// These three special string values are used to represent specified values of
-// 'initial', 'inherit' and 'unset'. (Note that none of these are valid
-// variable values.)
-#define INITIAL_VALUE "!"
-#define INHERIT_VALUE ";"
-#define UNSET_VALUE ")"
+#ifdef CSSVAR_DEBUG
+#define CSSVAR_PRINTF(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define CSSVAR_PRINTF(...)
+#endif
namespace mozilla {
-CSSVariableDeclarations::CSSVariableDeclarations()
+CSSVariableDeclarations::CSSVariableDeclarations(
+ const CSSVariableRegistrations* aRegistrations)
+ : mRegistrations(aRegistrations)
+ , mTotalGeneration(-1)
+ , mHasImportant(false)
+ , mImmutable(false)
+ , mNeverComputed(true)
{
MOZ_COUNT_CTOR(CSSVariableDeclarations);
}
CSSVariableDeclarations::CSSVariableDeclarations(const CSSVariableDeclarations& aOther)
+ : mRegistrations(aOther.mRegistrations)
+ , mDeclarations(aOther.mDeclarations)
+ , mUsedDeclarations(aOther.mUsedDeclarations)
+ , mVariableGenerations(aOther.mVariableGenerations)
+ , mTotalGeneration(aOther.mTotalGeneration)
+ , mVariableNames(aOther.mVariableNames)
+ , mHasImportant(aOther.mHasImportant)
+ , mImmutable(false)
+ , mNeverComputed(true)
{
MOZ_COUNT_CTOR(CSSVariableDeclarations);
- CopyVariablesFrom(aOther);
+ mVariableIDs.Clear();
+ for (auto iter = aOther.mVariableIDs.ConstIter(); !iter.Done(); iter.Next()) {
+ mVariableIDs.Put(iter.Key(), iter.UserData());
+ }
}
#ifdef DEBUG
CSSVariableDeclarations::~CSSVariableDeclarations()
{
MOZ_COUNT_DTOR(CSSVariableDeclarations);
}
#endif
CSSVariableDeclarations&
CSSVariableDeclarations::operator=(const CSSVariableDeclarations& aOther)
{
if (this == &aOther) {
return *this;
}
- mVariables.Clear();
- CopyVariablesFrom(aOther);
+ mRegistrations = aOther.mRegistrations;
+ mDeclarations = aOther.mDeclarations;
+ mUsedDeclarations = aOther.mUsedDeclarations;
+ mVariableGenerations = aOther.mVariableGenerations;
+ mTotalGeneration = aOther.mTotalGeneration;
+ mVariableNames = aOther.mVariableNames;
+
+ mVariableIDs.Clear();
+ for (auto iter = aOther.mVariableIDs.ConstIter(); !iter.Done(); iter.Next()) {
+ mVariableIDs.Put(iter.Key(), iter.UserData());
+ }
+
+ mHasImportant = aOther.mHasImportant;
+ mImmutable = false;
+ mNeverComputed = true;
return *this;
}
-void
-CSSVariableDeclarations::CopyVariablesFrom(const CSSVariableDeclarations& aOther)
-{
- for (auto iter = aOther.mVariables.ConstIter(); !iter.Done(); iter.Next()) {
- mVariables.Put(iter.Key(), iter.UserData());
- }
-}
bool
CSSVariableDeclarations::Has(const nsAString& aName) const
{
- nsString value;
- return mVariables.Get(aName, &value);
+ size_t id;
+ if (!mVariableIDs.Get(aName, &id)) {
+ return false;
+ }
+ RecomputeSingleValidity(aName);
+ return mUsedDeclarations[id] != (size_t) -1;
+}
+
+bool
+CSSVariableDeclarations::Get(const nsAString& aName, Type& aType,
+ nsAString& aExpr, bool& aImportant,
+ CSSVariableExprContext& aContext) const
+{
+ RecomputeSingleValidity(aName);
+ size_t id;
+ if (!mVariableIDs.Get(aName, &id) || mUsedDeclarations[id] == (size_t) -1) {
+ return false;
+ }
+ const Declaration& decl = mDeclarations[mUsedDeclarations[id]];
+ aType = decl.mType;
+ aExpr = decl.mExpr;
+ aImportant = decl.mImportant;
+ aContext = decl.mContext;
+ return true;
}
bool
-CSSVariableDeclarations::Get(const nsAString& aName,
- Type& aType,
- nsString& aTokenStream) const
+CSSVariableDeclarations::IsUsedDecl(size_t aID) const
{
- nsString value;
- if (!mVariables.Get(aName, &value)) {
- return false;
- }
- if (value.EqualsLiteral(INITIAL_VALUE)) {
- aType = eInitial;
- aTokenStream.Truncate();
- } else if (value.EqualsLiteral(INHERIT_VALUE)) {
- aType = eInitial;
- aTokenStream.Truncate();
- } else if (value.EqualsLiteral(UNSET_VALUE)) {
- aType = eUnset;
- aTokenStream.Truncate();
- } else {
- aType = eTokenStream;
- aTokenStream = value;
- }
- return true;
+ RecomputeValidities();
+ const Declaration& decl = mDeclarations[aID];
+ return aID == mUsedDeclarations[decl.mVarID];
}
void
-CSSVariableDeclarations::PutTokenStream(const nsAString& aName,
- const nsString& aTokenStream)
+CSSVariableDeclarations::GetDeclName(size_t aID, nsAString& aName) const
{
- MOZ_ASSERT(!aTokenStream.EqualsLiteral(INITIAL_VALUE) &&
- !aTokenStream.EqualsLiteral(INHERIT_VALUE) &&
- !aTokenStream.EqualsLiteral(UNSET_VALUE));
- mVariables.Put(aName, aTokenStream);
+ // Don't need to recompute validities because all of the declarations for a
+ // given variable are, of course, for that variable.
+ const Declaration& decl = mDeclarations[aID];
+ aName = mVariableNames[decl.mVarID];
}
-void
-CSSVariableDeclarations::PutInitial(const nsAString& aName)
+static bool
+ComputeValidity(const CSSVariableRegistrations::Data& aRegs,
+ const nsAString& aName, CSSVariableDeclarations::Type aType,
+ const nsAString& aExpr, nsCSSValue& aValue,
+ CSSValueType& aValueType, const CSSVariableExprContext& aContext,
+ nsCSSTokenSerializationType& aFirstToken,
+ nsCSSTokenSerializationType& aLastToken, bool& aParsed)
{
- mVariables.Put(aName, NS_LITERAL_STRING(INITIAL_VALUE));
+ nsCSSParser parser;
+ CSSVariableRegistration* reg;
+ // So far, we've parsed the name and the value.
+ // Then if this custom property isn't registered or the value is one one of the
+ // CSS-wide keywords, there's no concept of an 'illegal' value that we
+ // ignore, so the last declaration wins.
+ if (aRegs.Get(aName, ®) &&
+ !(aType == CSSVariableDeclarations::Type::Initial ||
+ aType == CSSVariableDeclarations::Type::Unset ||
+ aType == CSSVariableDeclarations::Type::Inherit)) {
+ // If the custom property is registered and has a value, we need to type
+ // it against the registered syntax. NB: if the value (really an
+ // expression) contains a variable reference:
+ // If a property contains one or more var() functions, and those functions
+ // are syntactically valid, the entire property’s grammar must be assumed
+ // to be valid at parse time. It is only syntax-checked at computed-value
+ // time, after var() functions have been substituted.
+ // -- CSS Variables
+ bool hasVariables = false;
+ bool parsed = parser.EnumerateVariableReferences(
+ aExpr,
+ [](const nsAString& aName, void* aData) {
+ *static_cast<bool*>(aData) = true;
+ },
+ &hasVariables);
+
+ if (!parsed) {
+ // If EnumerateVariableReferences couldn't parse it, it's definitely
+ // invalid.
+ // TODO(jyc) Should we even keep it around at this point? Actually, can
+ // this even happen? I think a parse error would be caught earlier.
+ return false;
+ } else if (hasVariables) {
+ // If it has variables, we have to just add it anyways.
+ return true;
+ } else {
+ if (!parser.ParseTypedValue(reg->mSyntax, aExpr, aContext.mSheetURI,
+ aContext.mBaseURI, aContext.mSheetPrincipal,
+ aValue, aValueType)) {
+ return false;
+ }
+ // We use ResolveVariableValue only to find the first and last token here.
+ // In the future, ResolveVariableValue could be refactored so that we can
+ // separate the code for conversion between token types and the code for
+ // variable expansion.
+ // It might seem excessive parsing three times here. But unless
+ // nsCSSParser is restructured, we certainly need the first two, and
+ // using three here prevents us from using five total for properly typed
+ // declarations (2 to enumerate then parse here and 3 in
+ // CSSVariableResolver to enumerate, resolve, then parse).
+ nsAutoString result;
+ DebugOnly<bool> ok =
+ parser.ResolveVariableValue(aExpr, nullptr, result, aFirstToken,
+ aLastToken);
+ MOZ_ASSERT(ok);
+ aParsed = true;
+ return true;
+ }
+ }
+ // So now, we must be in at least one of the following cases:
+ // 1) aName is not a registered property
+ // 2) aType is initial, unset, or inherit
+ return true;
}
-void
-CSSVariableDeclarations::PutInherit(const nsAString& aName)
+size_t
+CSSVariableDeclarations::Add(const nsAString& aName, Type aType,
+ const nsAString& aExpr, bool aImportant,
+ bool aOverrideImportant,
+ CSSVariableExprContext aContext)
{
- mVariables.Put(aName, NS_LITERAL_STRING(INHERIT_VALUE));
-}
+ size_t varID;
+ if (!mVariableIDs.Get(aName, &varID)) {
+ // Don't use |mVariableIDs|, as variables might have been removed.
+ // |mVariableNames|, on the other hand, is only appended to.
+ varID = mVariableNames.Length();
+ mVariableIDs.Put(aName, varID);
+ mUsedDeclarations.AppendElement(-1);
+ if (mRegistrations) {
+ mVariableGenerations.AppendElement(mRegistrations->mGeneration);
+ }
+ mVariableNames.AppendElement(aName);
+ }
-void
-CSSVariableDeclarations::PutUnset(const nsAString& aName)
-{
- mVariables.Put(aName, NS_LITERAL_STRING(UNSET_VALUE));
+ size_t declID = mDeclarations.Length();
+ mDeclarations.AppendElement(Declaration(varID, aType, aExpr, aImportant,
+ aOverrideImportant, aContext));
+ if (!mRegistrations) {
+ if (DeclPriorityGte(declID, mUsedDeclarations[varID])) {
+ mUsedDeclarations[varID] = declID;
+ CSSVAR_PRINTF("mUsedDeclarations[%zu] = %zu\n", varID, declID);
+ mHasImportant = mHasImportant || aImportant;
+ }
+ } else {
+ CSSVAR_PRINTF("Triggering a recompute.\n");
+ // Trigger a recompute.
+ mTotalGeneration = -1;
+ mVariableGenerations[varID] = -1;
+ CSSVAR_PRINTF("mUsedDeclarations[%zu] = %zu\n", varID, declID);
+ }
+ return declID;
}
void
CSSVariableDeclarations::Remove(const nsAString& aName)
{
- mVariables.Remove(aName);
+ mVariableIDs.Remove(aName);
+ // TODO(jyc) We don't clean up the garbage declarations. Should we? Doesn't
+ // seem like removing properties completely is a very common thing.
+ // We also don't remove mHasImportant, but we didn't remove it before either.
}
void
-CSSVariableDeclarations::MapRuleInfoInto(nsRuleData* aRuleData)
+CSSVariableDeclarations::MapRuleInfoInto(nsRuleData* aRuleData, bool aImportant) const
{
if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Variables))) {
return;
}
+ RecomputeValidities();
+
+ CSSVAR_PRINTF("CSSVariableDeclarations::MapRuleInfoInto\n");
if (!aRuleData->mVariables) {
- aRuleData->mVariables = new CSSVariableDeclarations(*this);
- } else {
- for (auto iter = mVariables.Iter(); !iter.Done(); iter.Next()) {
- nsDataHashtable<nsStringHashKey, nsString>& variables =
- aRuleData->mVariables->mVariables;
- const nsAString& aName = iter.Key();
- if (!variables.Contains(aName)) {
- variables.Put(aName, iter.UserData());
- }
+ aRuleData->mVariables = new CSSVariableDeclarations(nullptr);
+ }
+
+ for (auto iter = mVariableIDs.ConstIter(); !iter.Done(); iter.Next()) {
+ const nsAString& name = iter.Key();
+ size_t varID = iter.UserData();
+ CSSVAR_PRINTF("Considering mapping variable %s.\n", NS_ConvertUTF16toUTF8(name).get());
+ if (aRuleData->mVariables->Has(name)) {
+ // MapRuleInfoInto is called on all the applicable rules (ours is a parent
+ // Declaration) in order of *decreasing* specificity.
+ // If there's already an entry, it was put by a more specific applicable
+ // rule.
+ CSSVAR_PRINTF("We already have a variable with that name. Skipping...\n");
+ continue;
}
+ size_t declID = mUsedDeclarations[varID];
+ if (declID == (size_t) -1) {
+ CSSVAR_PRINTF("No usable declarations. Skipping.\n");
+ continue;
+ }
+ const Declaration& decl = mDeclarations[declID];
+ if (decl.mImportant != aImportant) {
+ CSSVAR_PRINTF("Importance doesn't match. Skipping...\n");
+ continue;
+ }
+ CSSVAR_PRINTF("Adding!\n");
+ aRuleData->mVariables->Add(name, decl.mType, decl.mExpr, decl.mImportant,
+ decl.mOverrideImportant, decl.mContext);
}
}
void
-CSSVariableDeclarations::AddVariablesToResolver(
- CSSVariableResolver* aResolver) const
+CSSVariableDeclarations::AddVariablesToResolver(CSSVariableResolver* aResolver) const
{
- for (auto iter = mVariables.ConstIter(); !iter.Done(); iter.Next()) {
+ CSSVAR_PRINTF("CSSVariableDeclarations::AddVariablesToResolver\n");
+ RecomputeValidities();
+ for (auto iter = mVariableIDs.ConstIter(); !iter.Done(); iter.Next()) {
const nsAString& name = iter.Key();
- nsString value = iter.UserData();
- if (value.EqualsLiteral(INITIAL_VALUE)) {
+ CSSVAR_PRINTF("Considering adding variable %s.\n", NS_ConvertUTF16toUTF8(name).get());
+ size_t varID = iter.UserData();
+ size_t declID = mUsedDeclarations[varID];
+ if (declID == (size_t) -1) {
+ CSSVAR_PRINTF("Not adding because no usable declaration.\n");
+ continue;
+ }
+ const Declaration& decl = mDeclarations[declID];
+ switch (decl.mType) {
+ case Type::Initial:
// Values of 'initial' are treated the same as an invalid value in the
// variable resolver.
aResolver->Put(name, EmptyString(),
eCSSTokenSerialization_Nothing,
eCSSTokenSerialization_Nothing,
false);
- } else if (value.EqualsLiteral(INHERIT_VALUE) ||
- value.EqualsLiteral(UNSET_VALUE)) {
- // Values of 'inherit' and 'unset' don't need any handling, since it means
- // we just need to keep whatever value is currently in the resolver. This
- // is because the specified variable declarations already have only the
- // winning declaration for the variable and no longer have any of the
- // others.
- } else {
+ break;
+ case Type::Inherit:
+ break;
+ case Type::Unset:
+ break;
+ case Type::TokenStream:
// At this point, we don't know what token types are at the start and end
// of the specified variable value. These will be determined later during
// the resolving process.
- aResolver->Put(name, value,
+ aResolver->Put(name, decl.mExpr,
eCSSTokenSerialization_Nothing,
eCSSTokenSerialization_Nothing,
false);
+ break;
}
}
}
+CSSVariableDeclarations::Iterator
+CSSVariableDeclarations::Iter() const
+{
+ return mVariableIDs.ConstIter();
+}
+
size_t
-CSSVariableDeclarations::SizeOfIncludingThis(
- mozilla::MallocSizeOf aMallocSizeOf) const
+CSSVariableDeclarations::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
+ // TODO(jyc) verify
size_t n = aMallocSizeOf(this);
- n += mVariables.ShallowSizeOfExcludingThis(aMallocSizeOf);
- for (auto iter = mVariables.ConstIter(); !iter.Done(); iter.Next()) {
+ n += mDeclarations.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ for (const auto& decl : mDeclarations) {
+ n += aMallocSizeOf(&decl);
+ n += decl.mExpr.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+ }
+ n += mUsedDeclarations.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ n += sizeof(size_t) * mUsedDeclarations.Length();
+ n += mVariableGenerations.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ n += sizeof(uint32_t) * mVariableGenerations.Length();
+ for (auto iter = mVariableIDs.ConstIter(); !iter.Done(); iter.Next()) {
n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
- n += iter.Data().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+ n += sizeof(size_t);
+ }
+ if (mRegistrations) {
+ n += aMallocSizeOf(mRegistrations);
}
return n;
}
+bool
+CSSVariableDeclarations::DeclPriorityGte(size_t aFirst, size_t aSecond) const
+{
+ if (aSecond == (size_t) -1) {
+ return true;
+ }
+ const Declaration& first = mDeclarations[aFirst];
+ const Declaration& second = mDeclarations[aSecond];
+ int nFirst = 0;
+ if (first.mImportant) nFirst += 1;
+ if (first.mOverrideImportant) nFirst += 2;
+ int nSecond = 0;
+ if (second.mImportant) nSecond += 1;
+ if (second.mOverrideImportant) nSecond += 2;
+
+ // I = important
+ // O = override important
+ // IO = important + override important
+ // down = first, across = second
+ // _ I O IO
+ // _ ≥ < < <
+ // I ≥ ≥ < <
+ // O ≥ ≥ ≥ <
+ // IO ≥ ≥ ≥ ≥
+
+ return nFirst >= nSecond;
+}
+
+void
+CSSVariableDeclarations::RecomputeSingleValidity(const nsAString& aName) const
+{
+ if (!mRegistrations || (mImmutable && !mNeverComputed)) {
+ return;
+ }
+ mNeverComputed = false;
+ size_t varID = mVariableIDs.Get(aName);
+ if (mVariableGenerations[varID] == mRegistrations->mGeneration) {
+ return;
+ }
+ for (size_t declID = 0; declID < mDeclarations.Length(); declID++) {
+ const Declaration& decl = mDeclarations[declID];
+ if (decl.mVarID != varID) {
+ continue;
+ }
+ bool valid = ComputeValidity(mRegistrations->mData, aName, decl.mType,
+ decl.mExpr, decl.mValue, decl.mValueType,
+ decl.mContext, decl.mFirstToken,
+ decl.mLastToken, decl.mParsed);
+ if (valid && DeclPriorityGte(declID, mUsedDeclarations[varID])) {
+ mUsedDeclarations[varID] = declID;
+ mHasImportant = mHasImportant || decl.mImportant;
+ }
+ }
+ mVariableGenerations[varID] = mRegistrations->mGeneration;
+}
+
+void
+CSSVariableDeclarations::RecomputeValidities() const
+{
+ if (!mRegistrations || mTotalGeneration == mRegistrations->mGeneration ||
+ (mImmutable && !mNeverComputed)) {
+ return;
+ }
+ mNeverComputed = false;
+ for (size_t declID = 0; declID < mDeclarations.Length(); declID++) {
+ const Declaration& decl = mDeclarations[declID];
+ size_t varID = decl.mVarID;
+ bool valid = ComputeValidity(mRegistrations->mData, mVariableNames[varID],
+ decl.mType, decl.mExpr, decl.mValue,
+ decl.mValueType, decl.mContext,
+ decl.mFirstToken, decl.mLastToken,
+ decl.mParsed);
+ CSSVAR_PRINTF("declID=%zu, varID=%zu, valid=%d\n", declID, varID, valid);
+ if (valid && DeclPriorityGte(declID, mUsedDeclarations[varID])) {
+ mUsedDeclarations[varID] = declID;
+ mHasImportant = mHasImportant || decl.mImportant;
+ }
+ }
+ mTotalGeneration = mRegistrations->mGeneration;
+}
+
} // namespace mozilla
--- a/layout/style/CSSVariableDeclarations.h
+++ b/layout/style/CSSVariableDeclarations.h
@@ -3,29 +3,35 @@
* 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/. */
/* CSS Custom Property assignments for a Declaration at a given priority */
#ifndef mozilla_CSSVariableDeclarations_h
#define mozilla_CSSVariableDeclarations_h
+#include "mozilla/CSSVariableRegistrations.h"
+#include "mozilla/CSSVariableSyntax.h"
+
+#include "nsCSSScanner.h"
+#include "nsCSSValue.h"
#include "nsDataHashtable.h"
namespace mozilla {
class CSSVariableResolver;
} // namespace mozilla
struct nsRuleData;
namespace mozilla {
class CSSVariableDeclarations
{
public:
- CSSVariableDeclarations();
+ explicit CSSVariableDeclarations(const CSSVariableRegistrations*
+ aRegistrations);
CSSVariableDeclarations(const CSSVariableDeclarations& aOther);
#ifdef DEBUG
~CSSVariableDeclarations();
#endif
CSSVariableDeclarations& operator=(const CSSVariableDeclarations& aOther);
/**
* Returns whether this set of variable declarations includes a variable
@@ -34,106 +40,148 @@ public:
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name).
*/
bool Has(const nsAString& aName) const;
/**
* Represents the type of a variable value.
*/
- enum Type {
- eTokenStream, // a stream of CSS tokens (the usual type for variables)
- eInitial, // 'initial'
- eInherit, // 'inherit'
- eUnset // 'unset'
+ enum class Type : uint8_t {
+ Initial, // 'initial'
+ Inherit, // 'inherit'
+ Unset, // 'unset'
+ TokenStream, // a stream of CSS tokens (the default type for variables)
};
- /**
- * Gets the value of a variable in this set of variable declarations.
- *
- * @param aName The variable name (not including any "--" prefix that would
- * be part of the custom property name).
- * @param aType Out parameter into which the type of the variable value will
- * be stored.
- * @param aValue Out parameter into which the value of the variable will
- * be stored. If the variable is 'initial', 'inherit' or 'unset', this will
- * be the empty string.
- * @return Whether a variable with the given name was found. When false
- * is returned, aType and aValue will not be modified.
- */
- bool Get(const nsAString& aName, Type& aType, nsString& aValue) const;
-
- /**
- * Adds or modifies an existing entry in this set of variable declarations
- * to have the value 'initial'.
- *
- * @param aName The variable name (not including any "--" prefix that would
- * be part of the custom property name) whose value is to be set.
- */
- void PutInitial(const nsAString& aName);
+ bool Get(const nsAString& aName, Type& aType, nsAString& aExpr,
+ bool& aImportant, CSSVariableExprContext& aContext) const;
- /**
- * Adds or modifies an existing entry in this set of variable declarations
- * to have the value 'inherit'.
- *
- * @param aName The variable name (not including any "--" prefix that would
- * be part of the custom property name) whose value is to be set.
- */
- void PutInherit(const nsAString& aName);
+ bool IsUsedDecl(size_t aID) const;
+ void GetDeclName(size_t aID, nsAString& aName) const;
- /**
- * Adds or modifies an existing entry in this set of variable declarations
- * to have the value 'unset'.
- *
- * @param aName The variable name (not including any "--" prefix that would
- * be part of the custom property name) whose value is to be set.
- */
- void PutUnset(const nsAString& aName);
-
- /**
- * Adds or modifies an existing entry in this set of variable declarations
- * to have a token stream value.
- *
- * @param aName The variable name (not including any "--" prefix that would
- * be part of the custom property name) whose value is to be set.
- * @param aTokenStream The CSS token stream.
- */
- void PutTokenStream(const nsAString& aName, const nsString& aTokenStream);
+ size_t Add(const nsAString& aName, Type aType, const nsAString& aExpr,
+ bool aImportant, bool aOverrideImportant,
+ CSSVariableExprContext aContext);
/**
* Removes an entry in this set of variable declarations.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name) whose entry is to be removed.
*/
void Remove(const nsAString& aName);
/**
- * Returns the number of entries in this set of variable declarations.
+ * Returns the number of variable declarations.
+ * Double-counts multiple declarations of the same variable.
*/
- uint32_t Count() const { return mVariables.Count(); }
+ uint32_t DeclCount() const { return mDeclarations.Length(); }
+
+ /**
+ * Returns the number of variables declared in this set of variable declarations.
+ * Does not double-count multiple declarations of the same variable.
+ */
+ uint32_t Count() const { return mVariableIDs.Count(); }
/**
* Copies each variable value from this object into aRuleData, unless that
- * variable already exists on aRuleData.
+ * variable already exists on aRuleData. Only values whose importance
+ * match aImportant are copied.
*/
- void MapRuleInfoInto(nsRuleData* aRuleData);
+ void MapRuleInfoInto(nsRuleData* aRuleData, bool aImportant) const;
/**
* Copies the variables from this object into aResolver, marking them as
* specified values.
*/
void AddVariablesToResolver(CSSVariableResolver* aResolver) const;
+ bool HasImportant() const {
+ RecomputeValidities();
+ return mHasImportant;
+ }
+
+ typedef nsDataHashtable<nsStringHashKey, size_t>::Iterator Iterator;
+ Iterator Iter() const;
+
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+ void SetImmutable() const { mImmutable = true; }
+
private:
- /**
- * Adds all the variable declarations from aOther into this object.
- */
- void CopyVariablesFrom(const CSSVariableDeclarations& aOther);
+ bool DeclPriorityGte(size_t aFirst, size_t aSecond) const;
+
+ void RecomputeSingleValidity(const nsAString& aName) const;
+ void RecomputeValidities() const;
+
+ struct Declaration
+ {
+ Declaration(size_t aVarID, Type aType, const nsAString& aExpr,
+ bool aImportant, bool aOverrideImportant,
+ CSSVariableExprContext aContext)
+ : mVarID(aVarID)
+ , mType(aType)
+ , mExpr(aExpr)
+ , mImportant(aImportant)
+ , mOverrideImportant(aOverrideImportant)
+ , mContext(aContext)
+ , mParsed(false)
+ { }
+
+ size_t mVarID;
+ Type mType;
+ nsString mExpr;
+ bool mImportant;
+ bool mOverrideImportant;
+ CSSVariableExprContext mContext;
- nsDataHashtable<nsStringHashKey, nsString> mVariables;
+ // These member variables are only valid if this is a registered custom
+ // property and the type is correct or was correct at some point.
+ // Just because these are present doesn't mean that we can use them as-is:
+ // this same declaration may parse as a different type given a different
+ // syntax.
+ mutable nsCSSValue mValue;
+ mutable CSSValueType mValueType;
+ mutable nsCSSTokenSerializationType mFirstToken;
+ mutable nsCSSTokenSerializationType mLastToken;
+ mutable bool mParsed;
+ };
+
+ RefPtr<const CSSVariableRegistrations> mRegistrations;
+
+ // Declaration ID -> |Declaration|
+ // The order corresponds to the declaration order.
+ nsTArray<Declaration> mDeclarations;
+ // Variable ID -> Declaration ID
+ // (or -1 = 0xFFF... if there is no valid declaration)
+ mutable nsTArray<size_t> mUsedDeclarations;
+ // Variable ID -> mRegistrations.mGeneration at the last time we recomputed the
+ // valid declaration
+ mutable nsTArray<uint32_t> mVariableGenerations;
+ // mRegistrations.mGeneration at the last time we recomputed all the valid
+ // declarations
+ mutable uint32_t mTotalGeneration;
+ // variable name (without --) -> Variable ID
+ nsDataHashtable<nsStringHashKey, size_t> mVariableIDs;
+ // Variable ID -> variable name
+ nsTArray<nsString> mVariableNames;
+
+ // Currently, removing a variable removes its name -> ID mapping in
+ // |mVariableIDs| but doesn't touch anything else (in particular,
+ // |mVariableNames| still holds the old variable name).
+ // That means that mVariableIDs is not injective if a specific variable name
+ // is removed and then added back.
+ // This seems to be the simplest thing to do for now, even though it might
+ // waste space (as declarations and other info relevant to the variable rior
+ // to the removal are kept around, but refer to the old variable ID).
+
+ mutable bool mHasImportant;
+ mutable bool mImmutable;
+ // If |mImmutable| but |mNeverComputed|, that means we can and should
+ // recompute validities. The user has never read them before (causing a
+ // compute), so this will not cause the data to change from under them.
+ mutable bool mNeverComputed;
};
} // namespace mozilla
#endif
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -3,22 +3,21 @@
* 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/. */
/*
* representation of a declaration block (or style attribute) in a CSS
* stylesheet
*/
+#include "gfxFontConstants.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/MemoryReporting.h"
-
#include "mozilla/css/Declaration.h"
#include "nsPrintfCString.h"
-#include "gfxFontConstants.h"
#include "nsStyleUtil.h"
namespace mozilla {
namespace css {
NS_IMPL_QUERY_INTERFACE(ImportantStyleData, nsIStyleRule)
NS_IMPL_ADDREF_USING_AGGREGATOR(ImportantStyleData, Declaration())
NS_IMPL_RELEASE_USING_AGGREGATOR(ImportantStyleData, Declaration())
@@ -45,34 +44,34 @@ ImportantStyleData::List(FILE* out, int3
str.AppendLiteral(" ");
}
str.AppendLiteral("! important rule\n");
fprintf_stderr(out, "%s", str.get());
}
#endif
-Declaration::Declaration()
- : mImmutable(false)
+Declaration::Declaration(const CSSVariableRegistrations* aRegistrations)
+ : mRegistrations(aRegistrations)
+ , mExposedOrderDirty(false)
+ , mImmutable(false)
{
mContainer.mRaw = uintptr_t(0);
}
Declaration::Declaration(const Declaration& aCopy)
: mOrder(aCopy.mOrder),
- mVariableOrder(aCopy.mVariableOrder),
+ mExposedOrder(aCopy.mExposedOrder),
mData(aCopy.mData ? aCopy.mData->Clone() : nullptr),
mImportantData(aCopy.mImportantData ?
aCopy.mImportantData->Clone() : nullptr),
mVariables(aCopy.mVariables ?
new CSSVariableDeclarations(*aCopy.mVariables) :
nullptr),
- mImportantVariables(aCopy.mImportantVariables ?
- new CSSVariableDeclarations(*aCopy.mImportantVariables) :
- nullptr),
+ mExposedOrderDirty(aCopy.mExposedOrderDirty),
mImmutable(false)
{
mContainer.mRaw = uintptr_t(0);
}
Declaration::~Declaration()
{
}
@@ -92,52 +91,55 @@ NS_IMPL_ADDREF(Declaration)
NS_IMPL_RELEASE(Declaration)
/* virtual */ void
Declaration::MapRuleInfoInto(nsRuleData* aRuleData)
{
MOZ_ASSERT(mData, "must call only while compressed");
mData->MapRuleInfoInto(aRuleData);
if (mVariables) {
- mVariables->MapRuleInfoInto(aRuleData);
+ mVariables->MapRuleInfoInto(aRuleData, false);
}
}
/* virtual */ bool
Declaration::MightMapInheritedStyleData()
{
MOZ_ASSERT(mData, "must call only while compressed");
if (mVariables && mVariables->Count() != 0) {
+ // Some custom properties might be inherited. All variables are.
return true;
}
return mData->HasInheritedStyleData();
}
bool
Declaration::MapsImportantInheritedStyleData() const
{
MOZ_ASSERT(mData, "must call only while compressed");
MOZ_ASSERT(HasImportantData(), "must only be called for Declarations with "
"important data");
- if (mImportantVariables && mImportantVariables->Count() != 0) {
+ if (mVariables && mVariables->Count() != 0 && mVariables->HasImportant()) {
+ // Some custom properties might be inherited. All variables are.
return true;
}
return mImportantData ? mImportantData->HasInheritedStyleData() : false;
}
void
Declaration::ValueAppended(nsCSSPropertyID aProperty)
{
MOZ_ASSERT(!mData && !mImportantData,
"should only be called while expanded");
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
"shorthands forbidden");
// order IS important for CSS, so remove and add to the end
mOrder.RemoveElement(static_cast<uint32_t>(aProperty));
mOrder.AppendElement(static_cast<uint32_t>(aProperty));
+ mExposedOrderDirty = true;
}
void
Declaration::RemoveProperty(nsCSSPropertyID aProperty)
{
MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT);
nsCSSExpandedDataBlock data;
@@ -149,16 +151,17 @@ Declaration::RemoveProperty(nsCSSPropert
CSSEnabledState::eForAllContent) {
data.ClearLonghandProperty(*p);
mOrder.RemoveElement(static_cast<uint32_t>(*p));
}
} else {
data.ClearLonghandProperty(aProperty);
mOrder.RemoveElement(static_cast<uint32_t>(aProperty));
}
+ mExposedOrderDirty = true;
CompressFrom(&data);
}
bool
Declaration::HasProperty(nsCSSPropertyID aProperty) const
{
MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
@@ -467,16 +470,29 @@ Declaration::GetImageLayerPositionValue(
}
return;
}
aValue.Append(char16_t(','));
aValue.Append(char16_t(' '));
}
}
+bool
+Declaration::HasVariables() const
+{
+ return !!mVariables;
+}
+
+CSSVariableDeclarations::Iterator
+Declaration::IterVariables() const
+{
+ MOZ_ASSERT(mVariables);
+ return mVariables->Iter();
+}
+
void
Declaration::GetValue(nsCSSPropertyID aProperty, nsAString& aValue,
nsCSSValue::Serialization aSerialization) const
{
aValue.Truncate(0);
// simple properties are easy.
if (!nsCSSProps::IsShorthand(aProperty)) {
@@ -1500,50 +1516,42 @@ Declaration::AppendVariableAndValueToStr
{
nsAutoString localName;
localName.AppendLiteral("--");
localName.Append(aName);
nsStyleUtil::AppendEscapedCSSIdent(localName, aResult);
CSSVariableDeclarations::Type type;
nsString value;
bool important;
+ CSSVariableExprContext context;
- if (mImportantVariables && mImportantVariables->Get(aName, type, value)) {
- important = true;
- } else {
- MOZ_ASSERT(mVariables);
- MOZ_ASSERT(mVariables->Has(aName));
- mVariables->Get(aName, type, value);
- important = false;
- }
+ DebugOnly<bool> found = mVariables->Get(aName, type, value, important, context);
+ MOZ_ASSERT(found);
switch (type) {
- case CSSVariableDeclarations::eTokenStream:
+ case CSSVariableDeclarations::Type::TokenStream:
if (value.IsEmpty()) {
aResult.Append(':');
} else {
aResult.AppendLiteral(": ");
aResult.Append(value);
}
break;
- case CSSVariableDeclarations::eInitial:
+ case CSSVariableDeclarations::Type::Initial:
aResult.AppendLiteral("initial");
break;
- case CSSVariableDeclarations::eInherit:
+ case CSSVariableDeclarations::Type::Inherit:
aResult.AppendLiteral("inherit");
break;
- case CSSVariableDeclarations::eUnset:
+ case CSSVariableDeclarations::Type::Unset:
aResult.AppendLiteral("unset");
break;
-
- default:
- MOZ_ASSERT(false, "unexpected variable value type");
}
if (important) {
aResult.AppendLiteral("! important");
}
aResult.AppendLiteral("; ");
}
@@ -1558,25 +1566,29 @@ Declaration::ToString(nsAString& aString
GetValueIsImportant(eCSSProperty__x_system_font) ? mImportantData : mData;
const nsCSSValue *systemFont =
systemFontData->ValueFor(eCSSProperty__x_system_font);
const bool haveSystemFont = systemFont &&
systemFont->GetUnit() != eCSSUnit_None &&
systemFont->GetUnit() != eCSSUnit_Null;
bool didSystemFont = false;
- int32_t count = mOrder.Length();
+ UpdateExposedOrder();
+ int32_t count = mExposedOrder.Length();
int32_t index;
AutoTArray<nsCSSPropertyID, 16> shorthandsUsed;
for (index = 0; index < count; index++) {
nsCSSPropertyID property = GetPropertyAt(index);
if (property == eCSSPropertyExtra_variable) {
- uint32_t variableIndex = mOrder[index] - eCSSProperty_COUNT;
- AppendVariableAndValueToString(mVariableOrder[variableIndex], aString);
+ MOZ_ASSERT(mVariables);
+ uint32_t declID = mExposedOrder[index] - eCSSProperty_COUNT;
+ nsAutoString varName;
+ mVariables->GetDeclName(declID, varName);
+ AppendVariableAndValueToString(varName, aString);
continue;
}
if (!nsCSSProps::IsEnabled(property, CSSEnabledState::eForAllContent)) {
continue;
}
bool doneProperty = false;
@@ -1685,17 +1697,18 @@ Declaration::List(FILE* out, int32_t aIn
fprintf_stderr(out, "%s", str.get());
}
#endif
bool
Declaration::GetNthProperty(uint32_t aIndex, nsAString& aReturn) const
{
aReturn.Truncate();
- if (aIndex < mOrder.Length()) {
+ UpdateExposedOrder();
+ if (aIndex < mExposedOrder.Length()) {
nsCSSPropertyID property = GetPropertyAt(aIndex);
if (property == eCSSPropertyExtra_variable) {
GetCustomPropertyNameAt(aIndex, aReturn);
return true;
}
if (0 <= property) {
AppendASCIItoUTF16(nsCSSProps::GetStringValue(property), aReturn);
return true;
@@ -1719,149 +1732,152 @@ Declaration::EnsureMutable()
if (!IsMutable()) {
result = new Declaration(*this);
} else {
result = this;
}
return result.forget();
}
+void
+Declaration::SetImmutable() const
+{
+ mImmutable = true;
+ if (mVariables) {
+ mVariables->SetImmutable();
+ }
+}
+
size_t
Declaration::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
n += mOrder.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ n += mExposedOrder.ShallowSizeOfExcludingThis(aMallocSizeOf);
n += mData ? mData ->SizeOfIncludingThis(aMallocSizeOf) : 0;
n += mImportantData ? mImportantData->SizeOfIncludingThis(aMallocSizeOf) : 0;
if (mVariables) {
n += mVariables->SizeOfIncludingThis(aMallocSizeOf);
}
- if (mImportantVariables) {
- n += mImportantVariables->SizeOfIncludingThis(aMallocSizeOf);
- }
return n;
}
void
Declaration::GetVariableDeclaration(const nsAString& aName,
nsAString& aValue) const
{
aValue.Truncate();
CSSVariableDeclarations::Type type;
nsString value;
+ bool important;
+ CSSVariableExprContext context;
- if ((mImportantVariables && mImportantVariables->Get(aName, type, value)) ||
- (mVariables && mVariables->Get(aName, type, value))) {
+ if (mVariables && mVariables->Get(aName, type, value, important, context)) {
switch (type) {
- case CSSVariableDeclarations::eTokenStream:
+ case CSSVariableDeclarations::Type::TokenStream:
aValue.Append(value);
break;
- case CSSVariableDeclarations::eInitial:
+ case CSSVariableDeclarations::Type::Initial:
aValue.AppendLiteral("initial");
break;
- case CSSVariableDeclarations::eInherit:
+ case CSSVariableDeclarations::Type::Inherit:
aValue.AppendLiteral("inherit");
break;
- case CSSVariableDeclarations::eUnset:
+ case CSSVariableDeclarations::Type::Unset:
aValue.AppendLiteral("unset");
break;
-
- default:
- MOZ_ASSERT(false, "unexpected variable value type");
}
}
}
void
Declaration::AddVariableDeclaration(const nsAString& aName,
CSSVariableDeclarations::Type aType,
- const nsString& aValue,
+ const nsAString& aValue,
bool aIsImportant,
- bool aOverrideImportant)
+ bool aOverrideImportant,
+ CSSVariableExprContext aContext)
{
MOZ_ASSERT(IsMutable());
- nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName);
- if (index == nsTArray<nsString>::NoIndex) {
- index = mVariableOrder.Length();
- mVariableOrder.AppendElement(aName);
- }
+ if (!mVariables) {
+ mVariables = new CSSVariableDeclarations(mRegistrations);
+ }
- if (!aIsImportant && !aOverrideImportant &&
- mImportantVariables && mImportantVariables->Has(aName)) {
+ // Hope we don't get too many declarations...
+ size_t szDeclID = mVariables->Add(aName, aType, aValue, aIsImportant,
+ aOverrideImportant, aContext);
+ if (szDeclID > (uint32_t) -1) {
+ // Wow. That's a lot of declarations.
return;
}
-
- CSSVariableDeclarations* variables;
- if (aIsImportant) {
- if (mVariables) {
- mVariables->Remove(aName);
- }
- if (!mImportantVariables) {
- mImportantVariables = new CSSVariableDeclarations;
- }
- variables = mImportantVariables;
- } else {
- if (mImportantVariables) {
- mImportantVariables->Remove(aName);
- }
- if (!mVariables) {
- mVariables = new CSSVariableDeclarations;
- }
- variables = mVariables;
- }
-
- switch (aType) {
- case CSSVariableDeclarations::eTokenStream:
- variables->PutTokenStream(aName, aValue);
- break;
-
- case CSSVariableDeclarations::eInitial:
- MOZ_ASSERT(aValue.IsEmpty());
- variables->PutInitial(aName);
- break;
-
- case CSSVariableDeclarations::eInherit:
- MOZ_ASSERT(aValue.IsEmpty());
- variables->PutInherit(aName);
- break;
-
- case CSSVariableDeclarations::eUnset:
- MOZ_ASSERT(aValue.IsEmpty());
- variables->PutUnset(aName);
- break;
-
- default:
- MOZ_ASSERT(false, "unexpected aType value");
- }
-
- uint32_t propertyIndex = index + eCSSProperty_COUNT;
- mOrder.RemoveElement(propertyIndex);
- mOrder.AppendElement(propertyIndex);
+ uint32_t declID = (uint32_t) szDeclID;
+ mOrder.AppendElement(eCSSProperty_COUNT + declID);
+ mExposedOrderDirty = true;
}
void
Declaration::RemoveVariableDeclaration(const nsAString& aName)
{
+ MOZ_ASSERT(IsMutable());
+
if (mVariables) {
mVariables->Remove(aName);
}
- if (mImportantVariables) {
- mImportantVariables->Remove(aName);
+ AutoTArray<uint32_t, 8> oldOrder = mOrder;
+ mOrder.Clear();
+ for (uint32_t id : oldOrder) {
+ if (id >= eCSSProperty_COUNT) {
+ uint32_t declID = id - eCSSProperty_COUNT;
+ nsAutoString declName;
+ mVariables->GetDeclName(declID, declName);
+ if (declName.Equals(aName)) {
+ continue;
+ }
+ }
+ mOrder.AppendElement(id);
}
- nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName);
- if (index != nsTArray<nsString>::NoIndex) {
- mOrder.RemoveElement(index + eCSSProperty_COUNT);
- }
+ mExposedOrderDirty = true;
}
bool
Declaration::GetVariableValueIsImportant(const nsAString& aName) const
{
- return mImportantVariables && mImportantVariables->Has(aName);
+ CSSVariableDeclarations::Type type;
+ nsString value;
+ bool important;
+ CSSVariableExprContext context;
+ return mVariables ? mVariables->Get(aName, type, value, important, context) && important
+ : false;
+}
+
+void
+Declaration::UpdateExposedOrder() const
+{
+ if (!mExposedOrderDirty) {
+ return;
+ }
+
+ mExposedOrder.Clear();
+ for (size_t i = 0; i < mOrder.Length(); i++) {
+ if (mOrder[i] < eCSSProperty_COUNT) {
+ // Not a custom property. Just pass it along.
+ mExposedOrder.AppendElement(mOrder[i]);
+ } else {
+ // A custom property. Check if it's the valid declaration for its
+ // variable and if the variable it was added for wasn't removed.
+ MOZ_ASSERT(mVariables);
+ uint32_t declID = mOrder[i] - eCSSProperty_COUNT;
+ if (mVariables->IsUsedDecl(declID)) {
+ mExposedOrder.AppendElement(mOrder[i]);
+ }
+ }
+ }
+
+ mExposedOrderDirty = false;
}
} // namespace css
} // namespace mozilla
--- a/layout/style/Declaration.h
+++ b/layout/style/Declaration.h
@@ -14,17 +14,18 @@
// This header is in EXPORTS because it's used in several places in content/,
// but it's not really a public interface.
#ifndef MOZILLA_INTERNAL_API
#error "This file should only be included within libxul"
#endif
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
-#include "CSSVariableDeclarations.h"
+#include "mozilla/CSSVariableDeclarations.h"
+#include "mozilla/CSSVariableRegistrations.h"
#include "nsCSSDataBlock.h"
#include "nsCSSPropertyID.h"
#include "nsCSSProps.h"
#include "nsIStyleRule.h"
#include "nsStringFwd.h"
#include "nsTArray.h"
#include <stdio.h>
@@ -81,18 +82,22 @@ private:
// |EnsureMutable|.
class Declaration final : public nsIStyleRule {
public:
/**
* Construct an |Declaration| that is in an invalid state (null
* |mData|) and cannot be used until its |CompressFrom| method or
* |InitializeEmpty| method is called.
+ *
+ * |aRegistrations| is either a pointer to the custom property registrations
+ * of the owning window, or null. If it is null, variable declarations in
+ * this |Declaration| will not make use of types.
*/
- Declaration();
+ explicit Declaration(const CSSVariableRegistrations* aRegistrations);
Declaration(const Declaration& aCopy);
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_DECLARATION_IMPL_CID)
NS_DECL_ISUPPORTS
private:
@@ -117,37 +122,39 @@ public:
void RemoveProperty(nsCSSPropertyID aProperty);
bool HasProperty(nsCSSPropertyID aProperty) const;
void GetValue(nsCSSPropertyID aProperty, nsAString& aValue) const;
void GetAuthoredValue(nsCSSPropertyID aProperty, nsAString& aValue) const;
bool HasImportantData() const {
- return mImportantData || mImportantVariables;
+ return mImportantData ||
+ (mVariables && mVariables->HasImportant());
}
bool GetValueIsImportant(nsCSSPropertyID aProperty) const;
bool GetValueIsImportant(const nsAString& aProperty) const;
/**
- * Adds a custom property declaration to this object.
+ * Puts a custom property declaration to this object.
*
* @param aName The variable name (i.e., without the "--" prefix).
* @param aType The type of value the variable has.
* @param aValue The value of the variable, if aType is
* CSSVariableDeclarations::eTokenStream.
* @param aIsImportant Whether the declaration is !important.
* @param aOverrideImportant When aIsImportant is false, whether an
* existing !important declaration will be overridden.
*/
void AddVariableDeclaration(const nsAString& aName,
CSSVariableDeclarations::Type aType,
- const nsString& aValue,
+ const nsAString& aValue,
bool aIsImportant,
- bool aOverrideImportant);
+ bool aOverrideImportant,
+ CSSVariableExprContext aContext);
/**
* Removes a custom property declaration from this object.
*
* @param aName The variable name (i.e., without the "--" prefix).
*/
void RemoveVariableDeclaration(const nsAString& aName);
@@ -163,18 +170,21 @@ public:
void GetVariableDeclaration(const nsAString& aName, nsAString& aValue) const;
/**
* Returns whether the custom property declaration for a variable with
* the given name was !important.
*/
bool GetVariableValueIsImportant(const nsAString& aName) const;
+ void UpdateExposedOrder() const;
+
uint32_t Count() const {
- return mOrder.Length();
+ UpdateExposedOrder();
+ return mExposedOrder.Length();
}
// Returns whether we actually had a property at aIndex
bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
void ToString(nsAString& aString) const;
nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; }
@@ -188,16 +198,17 @@ public:
/**
* Transfer all of the state from |aExpandedData| into this declaration.
* After calling, |aExpandedData| should be in its initial state.
* Callers must make sure mOrder is updated as necessary.
*/
void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
MOZ_ASSERT(!mData, "oops");
MOZ_ASSERT(!mImportantData, "oops");
+ // Compress ignores custom properties.
aExpandedData->Compress(getter_Transfers(mData),
getter_Transfers(mImportantData),
mOrder);
aExpandedData->AssertInitialState();
}
/**
* Transfer all of the state from this declaration into
@@ -211,23 +222,22 @@ public:
aExpandedData->AssertInitialState();
MOZ_ASSERT(mData, "oops");
aExpandedData->Expand(mData.forget(), mImportantData.forget());
}
void MapImportantRuleInfoInto(nsRuleData *aRuleData) const {
MOZ_ASSERT(mData, "called while expanded");
- MOZ_ASSERT(mImportantData || mImportantVariables,
- "must have important data or variables");
+ MOZ_ASSERT(HasImportantData(), "must have important data or variables");
if (mImportantData) {
mImportantData->MapRuleInfoInto(aRuleData);
}
- if (mImportantVariables) {
- mImportantVariables->MapRuleInfoInto(aRuleData);
+ if (mVariables) {
+ mVariables->MapRuleInfoInto(aRuleData, true);
}
}
bool MapsImportantInheritedStyleData() const;
/**
* Attempt to replace the value for |aProperty| stored in this
* declaration with the matching value from |aFromBlock|.
@@ -290,30 +300,30 @@ public:
void AssertMutable() const {
MOZ_ASSERT(IsMutable(), "someone forgot to call EnsureMutable");
}
/**
* Mark this declaration as unmodifiable. It's 'const' so it can
* be called from ToString.
*/
- void SetImmutable() const { mImmutable = true; }
+ void SetImmutable() const;
/**
* Clear the data, in preparation for its replacement with entirely
* new data by a call to |CompressFrom|.
*/
void ClearData() {
AssertMutable();
mData = nullptr;
mImportantData = nullptr;
mVariables = nullptr;
- mImportantVariables = nullptr;
mOrder.Clear();
- mVariableOrder.Clear();
+ mExposedOrder.Clear();
+ mExposedOrderDirty = false;
}
void SetOwningRule(Rule* aRule) {
MOZ_ASSERT(!mContainer.mOwningRule || !aRule,
"should never overwrite one rule with another");
mContainer.mOwningRule = aRule;
}
@@ -382,63 +392,73 @@ private:
public:
/**
* Returns the property at the given index in the ordered list of
* declarations. For custom properties, eCSSPropertyExtra_variable
* is returned.
*/
nsCSSPropertyID GetPropertyAt(uint32_t aIndex) const {
- uint32_t value = mOrder[aIndex];
+ UpdateExposedOrder();
+ uint32_t value = mExposedOrder[aIndex];
if (value >= eCSSProperty_COUNT) {
return eCSSPropertyExtra_variable;
}
return nsCSSPropertyID(value);
}
/**
* Gets the name of the custom property at the given index in the ordered
* list of declarations.
*/
void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const {
- MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT);
- uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT;
+ UpdateExposedOrder();
+ MOZ_ASSERT(mExposedOrder[aIndex] >= eCSSProperty_COUNT);
+ MOZ_ASSERT(mVariables);
+ uint32_t declID = mOrder[aIndex] - eCSSProperty_COUNT;
aResult.Truncate();
aResult.AppendLiteral("--");
- aResult.Append(mVariableOrder[variableIndex]);
+ nsAutoString varName;
+ mVariables->GetDeclName(declID, varName);
+ aResult.Append(varName);
}
+ bool HasVariables() const;
+
+ /**
+ * Returns an iterator over the names of variable in this declaration
+ * (without the leading --).
+ *
+ * It is an error to call this if |!HasVariables()|.
+ */
+ CSSVariableDeclarations::Iterator IterVariables() const;
+
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
private:
// The order of properties in this declaration. Longhand properties are
// represented by their nsCSSPropertyID value, and each custom property (--*)
// is represented by a value that begins at eCSSProperty_COUNT.
//
// Subtracting eCSSProperty_COUNT from those values that represent custom
// properties results in an index into mVariableOrder, which identifies the
// specific variable the custom property declaration is for.
AutoTArray<uint32_t, 8> mOrder;
-
- // variable names of custom properties found in mOrder
- nsTArray<nsString> mVariableOrder;
+ mutable AutoTArray<uint32_t, 8> mExposedOrder;
// never null, except while expanded, or before the first call to
// InitializeEmpty or CompressFrom.
nsAutoPtr<nsCSSCompressedDataBlock> mData;
// may be null
nsAutoPtr<nsCSSCompressedDataBlock> mImportantData;
// may be null
nsAutoPtr<CSSVariableDeclarations> mVariables;
- // may be null
- nsAutoPtr<CSSVariableDeclarations> mImportantVariables;
-
union {
// We only ever have one of these since we have an
// nsHTMLCSSStyleSheet only for style attributes, and style
// attributes never have an owning rule.
// It's an nsHTMLCSSStyleSheet if the low bit is set.
uintptr_t mRaw;
@@ -449,16 +469,23 @@ private:
// The nsHTMLCSSStyleSheet that is responsible for this declaration.
// Only non-null for style attributes.
nsHTMLCSSStyleSheet* mHTMLCSSStyleSheet;
} mContainer;
friend class ImportantStyleData;
ImportantStyleData mImportantStyleData;
+ // Custom property registrations of the owning window.
+ // TODO(jyc) Do we change this to the owning document?
+ // We do not own this. Only used by |mVariables|.
+ RefPtr<const CSSVariableRegistrations> mRegistrations;
+
+ mutable bool mExposedOrderDirty;
+
// set when declaration put in the rule tree;
// also by ToString (hence the 'mutable').
mutable bool mImmutable;
};
inline ::mozilla::css::Declaration*
ImportantStyleData::Declaration()
{
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -172,17 +172,19 @@ FontFaceSet::ParseFontShorthandForMatchi
const nsAString& aFont,
RefPtr<FontFamilyListRefCnt>& aFamilyList,
uint32_t& aWeight,
int32_t& aStretch,
uint8_t& aStyle,
ErrorResult& aRv)
{
// Parse aFont as a 'font' property value.
- RefPtr<Declaration> declaration = new Declaration;
+ // Null custom property registrations is OK because we're only using this for
+ // the font property.
+ RefPtr<Declaration> declaration = new Declaration(nullptr);
declaration->InitializeEmpty();
bool changed = false;
nsCSSParser parser;
parser.ParseProperty(eCSSProperty_font,
aFont,
mDocument->GetDocumentURI(),
mDocument->GetDocumentURI(),
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -2794,17 +2794,19 @@ StyleAnimationValue::AddWeighted(nsCSSPr
already_AddRefed<css::StyleRule>
BuildStyleRule(nsCSSPropertyID aProperty,
dom::Element* aTargetElement,
const nsAString& aSpecifiedValue,
bool aUseSVGMode)
{
// Set up an empty CSS Declaration
- RefPtr<css::Declaration> declaration(new 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) ?
@@ -2837,17 +2839,19 @@ BuildStyleRule(nsCSSPropertyID aProperty
"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
- RefPtr<css::Declaration> declaration(new 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);
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -1924,17 +1924,18 @@ CSSParserImpl::ParseLonghandProperty(con
nsIURI* aSheetURL,
nsIURI* aBaseURL,
nsIPrincipal* aSheetPrincipal,
nsCSSValue& aValue)
{
MOZ_ASSERT(aPropID < eCSSProperty_COUNT_no_shorthands,
"ParseLonghandProperty must only take a longhand property");
- RefPtr<css::Declaration> declaration = new css::Declaration;
+ RefPtr<css::Declaration> declaration =
+ new css::Declaration(GetVariableRegistrations());
declaration->InitializeEmpty();
bool changed;
ParseProperty(aPropID, aPropValue, aSheetURL, aBaseURL, aSheetPrincipal,
declaration, &changed,
/* aIsImportant */ false,
/* aIsSVGMode */ false);
@@ -1945,17 +1946,19 @@ CSSParserImpl::ParseLonghandProperty(con
}
}
bool
CSSParserImpl::ParseTransformProperty(const nsAString& aPropValue,
bool aDisallowRelativeValues,
nsCSSValue& aValue)
{
- RefPtr<css::Declaration> declaration = new css::Declaration();
+ // OK to have custom property registrations as null because we're only
+ // parsing the transform property, not custom property registrations.
+ RefPtr<css::Declaration> declaration = new css::Declaration(nullptr);
declaration->InitializeEmpty();
mData.AssertInitialState();
mTempData.AssertInitialState();
nsCSSScanner scanner(aPropValue, 0);
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, nullptr);
InitScanner(scanner, reporter, nullptr, nullptr, nullptr);
@@ -2106,17 +2109,20 @@ CSSParserImpl::ParseVariable(const nsASt
if (!parsedOK) {
REPORT_UNEXPECTED_P(PEValueParsingError, NS_LITERAL_STRING("--") +
aVariableName);
REPORT_UNEXPECTED(PEDeclDropped);
OUTPUT_ERROR();
} else {
CLEAR_ERROR();
aDeclaration->AddVariableDeclaration(aVariableName, variableType,
- variableValue, aIsImportant, true);
+ variableValue, aIsImportant, true,
+ CSSVariableExprContext(mSheetURI,
+ mBaseURI,
+ mSheetPrincipal));
*aChanged = true;
}
mTempData.AssertInitialState();
ReleaseScanner();
}
@@ -3237,17 +3243,17 @@ CSSParserImpl::ParseTypedValue(const CSS
CSSVariableSyntax::Type syntaxType = aSyntax.GetType();
if (syntaxType == CSSVariableSyntax::Type::Anything) {
CSSVariableDeclarations::Type type;
nsString result;
if (!ParseVariableDeclaration(&type, aAllowVariableReferences, result)) {
return false;
}
- if (type != CSSVariableDeclarations::Type::eTokenStream) {
+ if (type != CSSVariableDeclarations::Type::TokenStream) {
return false;
}
nsCSSValueTokenStream* tokenStream = new nsCSSValueTokenStream;
// Can't use eCSSPropertyExtra_UNKNOWN because that would cause
// KeyframeUtils::IsInvalidValuePair to think these values were invalid.
tokenStream->mPropertyID = eCSSPropertyExtra_variable;
tokenStream->mTokenStream = result;
tokenStream->mBaseURI = mBaseURI;
@@ -6836,17 +6842,18 @@ CSSParserImpl::ParseDeclarationBlock(uin
if (checkForBraces) {
if (!ExpectSymbol('{', true)) {
REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart);
OUTPUT_ERROR();
return nullptr;
}
}
- RefPtr<css::Declaration> declaration = new css::Declaration();
+ RefPtr<css::Declaration> declaration =
+ new css::Declaration(GetVariableRegistrations());
mData.AssertInitialState();
for (;;) {
bool changed = false;
if (!ParseDeclaration(declaration, aFlags, true, &changed, aContext)) {
if (!SkipDeclaration(checkForBraces)) {
break;
}
if (checkForBraces) {
@@ -7635,17 +7642,20 @@ CSSParserImpl::ParseDeclaration(css::Dec
}
if (customProperty) {
MOZ_ASSERT(Substring(propertyName, 0,
CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--"));
// remove '--'
nsDependentString varName(propertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH);
aDeclaration->AddVariableDeclaration(varName, variableType, variableValue,
- status == ePriority_Important, false);
+ status == ePriority_Important, false,
+ CSSVariableExprContext(mSheetURI,
+ mBaseURI,
+ mSheetPrincipal));
} else {
*aChanged |= mData.TransferFromBlock(mTempData, propID, EnabledState(),
status == ePriority_Important,
false, aMustCallValueAppended,
aDeclaration, GetDocument());
}
return true;
@@ -11637,19 +11647,20 @@ CSSParserImpl::ParseProperty(nsCSSProper
}
CSSVariableDeclarations::Type type;
bool dropBackslash;
nsString impliedCharacters;
nsCSSValue value;
if (ParseValueWithVariables(&type, &dropBackslash, impliedCharacters,
nullptr, nullptr)) {
- MOZ_ASSERT(type == CSSVariableDeclarations::eTokenStream,
+ MOZ_ASSERT(type == CSSVariableDeclarations::Type::TokenStream,
"a non-custom property reparsed since it contained variable "
- "references should not have been 'initial' or 'inherit'");
+ "references should not have been 'initial', 'inherit' or "
+ "'unset'");
nsString propertyValue;
if (!mInSupportsCondition) {
// If we are in an @supports condition, we don't need to store the
// actual token stream on the nsCSSValue.
mScanner->StopRecording(propertyValue);
if (dropBackslash) {
@@ -17497,33 +17508,33 @@ CSSParserImpl::ParseVariableDeclaration(
gotDisallowedVariableReference) {
if (!mInSupportsCondition) {
mScanner->StopRecording();
}
return false;
}
if (!mInSupportsCondition) {
- if (type == CSSVariableDeclarations::eTokenStream) {
+ if (type == CSSVariableDeclarations::Type::TokenStream) {
// This was indeed a token stream value, so store it in variableValue.
mScanner->StopRecording(variableValue);
if (dropBackslash) {
MOZ_ASSERT(!variableValue.IsEmpty() &&
variableValue[variableValue.Length() - 1] == '\\');
variableValue.Truncate(variableValue.Length() - 1);
}
variableValue.Append(impliedCharacters);
} else {
// This was either 'inherit' or 'initial'; we don't need the recorded
// input.
mScanner->StopRecording();
}
}
- if (mHavePushBack && type == CSSVariableDeclarations::eTokenStream) {
+ if (mHavePushBack && type == CSSVariableDeclarations::Type::TokenStream) {
// If we came to the end of a valid variable declaration and a token was
// pushed back, then it would have been ended by '!', ')', ';', ']' or '}'.
// We need to remove it from the recorded variable value.
MOZ_ASSERT(mToken.IsSymbol('!') ||
mToken.IsSymbol(')') ||
mToken.IsSymbol(';') ||
mToken.IsSymbol(']') ||
mToken.IsSymbol('}'));
@@ -17679,37 +17690,37 @@ CSSParserImpl::ParseValueWithVariables(C
REPORT_UNEXPECTED_TOKEN(PEVariableEmpty);
return false;
}
if (mToken.mType == eCSSToken_Whitespace) {
if (!GetToken(true)) {
// Variable value was white space only. This is valid.
MOZ_ASSERT(!BackslashDropped());
- *aType = CSSVariableDeclarations::eTokenStream;
+ *aType = CSSVariableDeclarations::Type::TokenStream;
*aDropBackslash = false;
AppendImpliedEOFCharacters(aImpliedCharacters);
return true;
}
}
// Look for 'initial', 'inherit' or 'unset' as the first non-white space
// token.
- CSSVariableDeclarations::Type type = CSSVariableDeclarations::eTokenStream;
+ CSSVariableDeclarations::Type type = CSSVariableDeclarations::Type::TokenStream;
if (mToken.mType == eCSSToken_Ident) {
if (mToken.mIdent.LowerCaseEqualsLiteral("initial")) {
- type = CSSVariableDeclarations::eInitial;
+ type = CSSVariableDeclarations::Type::Initial;
} else if (mToken.mIdent.LowerCaseEqualsLiteral("inherit")) {
- type = CSSVariableDeclarations::eInherit;
+ type = CSSVariableDeclarations::Type::Inherit;
} else if (mToken.mIdent.LowerCaseEqualsLiteral("unset")) {
- type = CSSVariableDeclarations::eUnset;
- }
- }
-
- if (type != CSSVariableDeclarations::eTokenStream) {
+ type = CSSVariableDeclarations::Type::Unset;
+ }
+ }
+
+ if (type != CSSVariableDeclarations::Type::TokenStream) {
if (!GetToken(true)) {
// Variable value was 'initial' or 'inherit' followed by EOF.
MOZ_ASSERT(!BackslashDropped());
*aType = type;
*aDropBackslash = false;
AppendImpliedEOFCharacters(aImpliedCharacters);
return true;
}
@@ -17738,33 +17749,33 @@ CSSParserImpl::ParseValueWithVariables(C
stack.AppendElement(']');
} else if (mToken.mSymbol == '{') {
stack.AppendElement('}');
} else if (mToken.mSymbol == ';' ||
mToken.mSymbol == '!') {
if (stack.IsEmpty()) {
UngetToken();
MOZ_ASSERT(!BackslashDropped());
- *aType = CSSVariableDeclarations::eTokenStream;
+ *aType = CSSVariableDeclarations::Type::TokenStream;
*aDropBackslash = false;
return true;
} else if (!references.IsEmpty() &&
references.LastElement() == stack.Length() - 1) {
REPORT_UNEXPECTED_TOKEN(PEInvalidVariableTokenFallback);
SkipUntilAllOf(stack);
return false;
}
} else if (mToken.mSymbol == ')' ||
mToken.mSymbol == ']' ||
mToken.mSymbol == '}') {
for (;;) {
if (stack.IsEmpty()) {
UngetToken();
MOZ_ASSERT(!BackslashDropped());
- *aType = CSSVariableDeclarations::eTokenStream;
+ *aType = CSSVariableDeclarations::Type::TokenStream;
*aDropBackslash = false;
return true;
}
char16_t c = stack.LastElement();
stack.TruncateLength(stack.Length() - 1);
if (!references.IsEmpty() &&
references.LastElement() == stack.Length()) {
references.TruncateLength(references.Length() - 1);
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -12,16 +12,17 @@
#include "mozilla/dom/Element.h"
#include "nsIDocument.h"
#include "nsIDOMMutationEvent.h"
#include "nsIURI.h"
#include "nsNodeUtils.h"
#include "nsWrapperCacheInlines.h"
#include "nsIFrame.h"
#include "ActiveLayerTracker.h"
+#include "mozilla/CSSVariableRegistration.h"
using namespace mozilla;
nsDOMCSSAttributeDeclaration::nsDOMCSSAttributeDeclaration(dom::Element* aElement,
bool aIsSMILOverride)
: mElement(aElement)
, mIsSMILOverride(aIsSMILOverride)
{
@@ -121,18 +122,22 @@ nsDOMCSSAttributeDeclaration::GetCSSDecl
if (declaration) {
return declaration;
}
if (aOperation != eOperation_Modify) {
return nullptr;
}
+ CSSParsingEnvironment env;
+ GetCSSParsingEnvironment(env);
+
// cannot fail
- RefPtr<css::Declaration> decl = new css::Declaration();
+ RefPtr<css::Declaration> decl =
+ new css::Declaration(CSSVariableRegistrationsOfDocument(env.mDocument));
decl->InitializeEmpty();
// this *can* fail (inside SetAttrAndNotify, at least).
nsresult rv;
if (mIsSMILOverride)
rv = mElement->SetSMILOverrideStyleDeclaration(decl, false);
else
rv = mElement->SetInlineStyleDeclaration(decl, nullptr, false);
@@ -149,16 +154,17 @@ nsDOMCSSAttributeDeclaration::GetCSSPars
{
NS_ASSERTION(mElement, "Something is severely broken -- there should be an Element here!");
nsIDocument* doc = mElement->OwnerDoc();
aCSSParseEnv.mSheetURI = doc->GetDocumentURI();
aCSSParseEnv.mBaseURI = mElement->GetBaseURI();
aCSSParseEnv.mPrincipal = mElement->NodePrincipal();
aCSSParseEnv.mCSSLoader = doc->CSSLoader();
+ aCSSParseEnv.mDocument = doc;
}
NS_IMETHODIMP
nsDOMCSSAttributeDeclaration::GetParentRule(nsIDOMCSSRule **aParent)
{
NS_ENSURE_ARG_POINTER(aParent);
*aParent = nullptr;
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -15,16 +15,17 @@
#include "nsCSSProps.h"
#include "nsCOMPtr.h"
#include "mozAutoDocUpdate.h"
#include "nsIURI.h"
#include "mozilla/dom/BindingUtils.h"
#include "nsContentUtils.h"
#include "nsQueryObject.h"
#include "mozilla/layers/ScrollLinkedEffectDetector.h"
+#include "mozilla/CSSVariableRegistration.h"
using namespace mozilla;
nsDOMCSSDeclaration::~nsDOMCSSDeclaration()
{
}
/* virtual */ JSObject*
@@ -143,17 +144,20 @@ nsDOMCSSDeclaration::SetCssText(const ns
// For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
// Attribute setting code, which leads in turn to BeginUpdate. We
// need to start the update now so that the old rule doesn't get used
// between when we mutate the declaration and when we set the new
// rule (see stack in bug 209575).
mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
- RefPtr<css::Declaration> decl(new css::Declaration());
+ const CSSVariableRegistrations* regs =
+ env.mDocument ? CSSVariableRegistrationsOfDocument(env.mDocument)
+ : nullptr;
+ RefPtr<css::Declaration> decl(new css::Declaration(regs));
decl->InitializeEmpty();
nsCSSParser cssParser(env.mCSSLoader);
bool changed;
nsresult result = cssParser.ParseDeclarations(aCssText, env.mSheetURI,
env.mBaseURI,
env.mPrincipal, decl, &changed);
if (NS_FAILED(result) || !changed) {
return result;
@@ -311,24 +315,26 @@ nsDOMCSSDeclaration::RemoveProperty(cons
/* static */ void
nsDOMCSSDeclaration::GetCSSParsingEnvironmentForRule(css::Rule* aRule,
CSSParsingEnvironment& aCSSParseEnv)
{
CSSStyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
if (!sheet) {
aCSSParseEnv.mPrincipal = nullptr;
+ aCSSParseEnv.mDocument = nullptr;
return;
}
nsIDocument* document = sheet->GetOwningDocument();
aCSSParseEnv.mSheetURI = sheet->GetSheetURI();
aCSSParseEnv.mBaseURI = sheet->GetBaseURI();
aCSSParseEnv.mPrincipal = sheet->Principal();
aCSSParseEnv.mCSSLoader = document ? document->CSSLoader() : nullptr;
+ aCSSParseEnv.mDocument = document;
}
nsresult
nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSPropertyID aPropID,
const nsAString& aPropValue,
bool aIsImportant)
{
css::Declaration* olddecl = GetCSSDeclaration(eOperation_Modify);
--- a/layout/style/nsDOMCSSDeclaration.h
+++ b/layout/style/nsDOMCSSDeclaration.h
@@ -128,27 +128,30 @@ protected:
// Information neded to parse a declaration. We need the mSheetURI
// for error reporting, mBaseURI to resolve relative URIs,
// mPrincipal for subresource loads, and mCSSLoader for determining
// whether we're in quirks mode. mBaseURI needs to be a strong
// pointer because of xml:base possibly creating base URIs on the
// fly. This is why we don't use CSSParsingEnvironment as a return
// value, to avoid multiple-refcounting of mBaseURI.
+ // |mDocument| is used when creating new declarations so that we handle
+ // custom properties appropriately.
struct CSSParsingEnvironment {
nsIURI* MOZ_UNSAFE_REF("user of CSSParsingEnviroment must hold an owning "
"reference; reference counting here has unacceptable "
"performance overhead (see bug 649163)") mSheetURI;
nsCOMPtr<nsIURI> mBaseURI;
nsIPrincipal* MOZ_UNSAFE_REF("user of CSSParsingEnviroment must hold an owning "
"reference; reference counting here has unacceptable "
"performance overhead (see bug 649163)") mPrincipal;
mozilla::css::Loader* MOZ_UNSAFE_REF("user of CSSParsingEnviroment must hold an owning "
"reference; reference counting here has unacceptable "
"performance overhead (see bug 649163)") mCSSLoader;
+ nsIDocument* mDocument;
};
// On failure, mPrincipal should be set to null in aCSSParseEnv.
// If mPrincipal is null, the other members may not be set to
// anything meaningful.
virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) = 0;
// An implementation for GetCSSParsingEnvironment for callers wrapping