michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* CSS Custom Property assignments for a Declaration at a given priority */ michael@0: michael@0: #include "CSSVariableDeclarations.h" michael@0: michael@0: #include "CSSVariableResolver.h" michael@0: #include "nsCSSScanner.h" michael@0: #include "nsRuleData.h" michael@0: michael@0: // These three special string values are used to represent specified values of michael@0: // 'initial', 'inherit' and 'unset'. (Note that none of these are valid michael@0: // variable values.) michael@0: #define INITIAL_VALUE "!" michael@0: #define INHERIT_VALUE ";" michael@0: #define UNSET_VALUE ")" michael@0: michael@0: namespace mozilla { michael@0: michael@0: CSSVariableDeclarations::CSSVariableDeclarations() michael@0: { michael@0: MOZ_COUNT_CTOR(CSSVariableDeclarations); michael@0: } michael@0: michael@0: CSSVariableDeclarations::CSSVariableDeclarations(const CSSVariableDeclarations& aOther) michael@0: { michael@0: MOZ_COUNT_CTOR(CSSVariableDeclarations); michael@0: CopyVariablesFrom(aOther); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: CSSVariableDeclarations::~CSSVariableDeclarations() michael@0: { michael@0: MOZ_COUNT_DTOR(CSSVariableDeclarations); michael@0: } michael@0: #endif michael@0: michael@0: CSSVariableDeclarations& michael@0: CSSVariableDeclarations::operator=(const CSSVariableDeclarations& aOther) michael@0: { michael@0: if (this == &aOther) { michael@0: return *this; michael@0: } michael@0: michael@0: mVariables.Clear(); michael@0: CopyVariablesFrom(aOther); michael@0: return *this; michael@0: } michael@0: michael@0: /* static */ PLDHashOperator michael@0: CSSVariableDeclarations::EnumerateVariableForCopy(const nsAString& aName, michael@0: nsString aValue, michael@0: void* aData) michael@0: { michael@0: CSSVariableDeclarations* variables = static_cast(aData); michael@0: variables->mVariables.Put(aName, aValue); michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: void michael@0: CSSVariableDeclarations::CopyVariablesFrom(const CSSVariableDeclarations& aOther) michael@0: { michael@0: aOther.mVariables.EnumerateRead(EnumerateVariableForCopy, this); michael@0: } michael@0: michael@0: bool michael@0: CSSVariableDeclarations::Has(const nsAString& aName) const michael@0: { michael@0: nsString value; michael@0: return mVariables.Get(aName, &value); michael@0: } michael@0: michael@0: bool michael@0: CSSVariableDeclarations::Get(const nsAString& aName, michael@0: Type& aType, michael@0: nsString& aTokenStream) const michael@0: { michael@0: nsString value; michael@0: if (!mVariables.Get(aName, &value)) { michael@0: return false; michael@0: } michael@0: if (value.EqualsLiteral(INITIAL_VALUE)) { michael@0: aType = eInitial; michael@0: aTokenStream.Truncate(); michael@0: } else if (value.EqualsLiteral(INHERIT_VALUE)) { michael@0: aType = eInitial; michael@0: aTokenStream.Truncate(); michael@0: } else if (value.EqualsLiteral(UNSET_VALUE)) { michael@0: aType = eUnset; michael@0: aTokenStream.Truncate(); michael@0: } else { michael@0: aType = eTokenStream; michael@0: aTokenStream = value; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: CSSVariableDeclarations::PutTokenStream(const nsAString& aName, michael@0: const nsString& aTokenStream) michael@0: { michael@0: MOZ_ASSERT(!aTokenStream.EqualsLiteral(INITIAL_VALUE) && michael@0: !aTokenStream.EqualsLiteral(INHERIT_VALUE) && michael@0: !aTokenStream.EqualsLiteral(UNSET_VALUE)); michael@0: mVariables.Put(aName, aTokenStream); michael@0: } michael@0: michael@0: void michael@0: CSSVariableDeclarations::PutInitial(const nsAString& aName) michael@0: { michael@0: mVariables.Put(aName, NS_LITERAL_STRING(INITIAL_VALUE)); michael@0: } michael@0: michael@0: void michael@0: CSSVariableDeclarations::PutInherit(const nsAString& aName) michael@0: { michael@0: mVariables.Put(aName, NS_LITERAL_STRING(INHERIT_VALUE)); michael@0: } michael@0: michael@0: void michael@0: CSSVariableDeclarations::PutUnset(const nsAString& aName) michael@0: { michael@0: mVariables.Put(aName, NS_LITERAL_STRING(UNSET_VALUE)); michael@0: } michael@0: michael@0: void michael@0: CSSVariableDeclarations::Remove(const nsAString& aName) michael@0: { michael@0: mVariables.Remove(aName); michael@0: } michael@0: michael@0: /* static */ PLDHashOperator michael@0: CSSVariableDeclarations::EnumerateVariableForMapRuleInfoInto( michael@0: const nsAString& aName, michael@0: nsString aValue, michael@0: void* aData) michael@0: { michael@0: nsDataHashtable* variables = michael@0: static_cast*>(aData); michael@0: if (!variables->Contains(aName)) { michael@0: variables->Put(aName, aValue); michael@0: } michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: void michael@0: CSSVariableDeclarations::MapRuleInfoInto(nsRuleData* aRuleData) michael@0: { michael@0: if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Variables))) { michael@0: return; michael@0: } michael@0: michael@0: if (!aRuleData->mVariables) { michael@0: aRuleData->mVariables = new CSSVariableDeclarations(*this); michael@0: } else { michael@0: mVariables.EnumerateRead(EnumerateVariableForMapRuleInfoInto, michael@0: aRuleData->mVariables.get()); michael@0: } michael@0: } michael@0: michael@0: /* static */ PLDHashOperator michael@0: CSSVariableDeclarations::EnumerateVariableForAddVariablesToResolver( michael@0: const nsAString& aName, michael@0: nsString aValue, michael@0: void* aData) michael@0: { michael@0: CSSVariableResolver* resolver = static_cast(aData); michael@0: if (aValue.EqualsLiteral(INITIAL_VALUE)) { michael@0: // Values of 'initial' are treated the same as an invalid value in the michael@0: // variable resolver. michael@0: resolver->Put(aName, EmptyString(), michael@0: eCSSTokenSerialization_Nothing, michael@0: eCSSTokenSerialization_Nothing, michael@0: false); michael@0: } else if (aValue.EqualsLiteral(INHERIT_VALUE) || michael@0: aValue.EqualsLiteral(UNSET_VALUE)) { michael@0: // Values of 'inherit' and 'unset' don't need any handling, since it means michael@0: // we just need to keep whatever value is currently in the resolver. michael@0: // Values of 'inherit' and 'unset' don't need any handling, since it means michael@0: // we just need to keep whatever value is currently in the resolver. This michael@0: // is because the specified variable declarations already have only the michael@0: // winning declaration for the variable and no longer have any of the michael@0: // others. michael@0: } else { michael@0: // At this point, we don't know what token types are at the start and end michael@0: // of the specified variable value. These will be determined later during michael@0: // the resolving process. michael@0: resolver->Put(aName, aValue, michael@0: eCSSTokenSerialization_Nothing, michael@0: eCSSTokenSerialization_Nothing, michael@0: false); michael@0: } michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: void michael@0: CSSVariableDeclarations::AddVariablesToResolver( michael@0: CSSVariableResolver* aResolver) const michael@0: { michael@0: mVariables.EnumerateRead(EnumerateVariableForAddVariablesToResolver, michael@0: aResolver); michael@0: } michael@0: michael@0: static size_t michael@0: SizeOfTableEntry(const nsAString& aKey, michael@0: const nsString& aValue, michael@0: MallocSizeOf aMallocSizeOf, michael@0: void* aUserArg) michael@0: { michael@0: size_t n = 0; michael@0: n += aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf); michael@0: n += aValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf); michael@0: return n; michael@0: } michael@0: michael@0: size_t michael@0: CSSVariableDeclarations::SizeOfIncludingThis( michael@0: mozilla::MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: size_t n = aMallocSizeOf(this); michael@0: n += mVariables.SizeOfExcludingThis(SizeOfTableEntry, aMallocSizeOf); michael@0: return n; michael@0: } michael@0: michael@0: } // namespace mozilla