mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
589b3b4774
We add a new class CSSVariableResolver whose job is to take the inherited computed variables and the specified variable declarations and to perform cycle removal and resolution of the variables, storing the result in the CSSVariableValues object on an nsStyleVariables. We use CSSVariableResolver in nsRuleNode::ComputeVariablesData. The variable resolver does this: 1. Asks the CSSVariableValues and CSSVariableDeclarations objects to add their variables to it. 2. Calls in to a new nsCSSParser function EnumerateVariableReferences that informs the resolver which other variables a given variable references, and by doing so, builds a graph of variable dependencies. 3. Removes variables involved in cyclic references using Tarjan's strongly connected component algorithm, setting those variables to have an invalid value. 4. Calls in to a new nsCSSParser function ResolveVariableValue to resolve the remaining valid variables by substituting variable references. We extend nsCSSParser::ParseValueWithVariables to take a callback function to be invoked when encountering a variable reference. This lets EnumerateVariableReferences re-use ParseValueWithVariables. CSSParserImpl::ResolveValueWithVariableReferences needs different error handling behaviour from ParseValueWithVariables, so we don't re-use it. CSSParserImpl::AppendImpliedEOFCharacters is used to take the value returned from nsCSSScanner::GetImpliedEOFCharacters while resolving variable references that were declared using custom properties that encountered EOF before being closed properly. The SeparatorRequiredBetweenTokens helper function in nsCSSParser.cpp implements the serialization rules in CSS Syntax Module Level 3: https://dvcs.w3.org/hg/csswg/raw-file/3479cdefc59a/css-syntax/Overview.html#serialization
213 lines
6.3 KiB
C++
213 lines
6.3 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/* CSS Custom Property assignments for a Declaration at a given priority */
|
|
|
|
#include "CSSVariableDeclarations.h"
|
|
|
|
#include "CSSVariableResolver.h"
|
|
#include "nsCSSScanner.h"
|
|
#include "nsRuleData.h"
|
|
|
|
// These two special string values are used to represent specified values of
|
|
// 'initial' and 'inherit'. (Note that neither is a valid variable value.)
|
|
#define INITIAL_VALUE "!"
|
|
#define INHERIT_VALUE ";"
|
|
|
|
namespace mozilla {
|
|
|
|
CSSVariableDeclarations::CSSVariableDeclarations()
|
|
{
|
|
MOZ_COUNT_CTOR(CSSVariableDeclarations);
|
|
}
|
|
|
|
CSSVariableDeclarations::CSSVariableDeclarations(const CSSVariableDeclarations& aOther)
|
|
{
|
|
MOZ_COUNT_CTOR(CSSVariableDeclarations);
|
|
CopyVariablesFrom(aOther);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
CSSVariableDeclarations::~CSSVariableDeclarations()
|
|
{
|
|
MOZ_COUNT_DTOR(CSSVariableDeclarations);
|
|
}
|
|
#endif
|
|
|
|
CSSVariableDeclarations&
|
|
CSSVariableDeclarations::operator=(const CSSVariableDeclarations& aOther)
|
|
{
|
|
if (this == &aOther) {
|
|
return *this;
|
|
}
|
|
|
|
mVariables.Clear();
|
|
CopyVariablesFrom(aOther);
|
|
return *this;
|
|
}
|
|
|
|
/* static */ PLDHashOperator
|
|
CSSVariableDeclarations::EnumerateVariableForCopy(const nsAString& aName,
|
|
nsString aValue,
|
|
void* aData)
|
|
{
|
|
CSSVariableDeclarations* variables = static_cast<CSSVariableDeclarations*>(aData);
|
|
variables->mVariables.Put(aName, aValue);
|
|
return PL_DHASH_NEXT;
|
|
}
|
|
|
|
void
|
|
CSSVariableDeclarations::CopyVariablesFrom(const CSSVariableDeclarations& aOther)
|
|
{
|
|
aOther.mVariables.EnumerateRead(EnumerateVariableForCopy, this);
|
|
}
|
|
|
|
bool
|
|
CSSVariableDeclarations::Has(const nsAString& aName) const
|
|
{
|
|
nsString value;
|
|
return mVariables.Get(aName, &value);
|
|
}
|
|
|
|
bool
|
|
CSSVariableDeclarations::Get(const nsAString& aName,
|
|
Type& aType,
|
|
nsString& aTokenStream) 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 {
|
|
aType = eTokenStream;
|
|
aTokenStream = value;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
CSSVariableDeclarations::PutTokenStream(const nsAString& aName,
|
|
const nsString& aTokenStream)
|
|
{
|
|
MOZ_ASSERT(!aTokenStream.EqualsLiteral(INITIAL_VALUE) &&
|
|
!aTokenStream.EqualsLiteral(INHERIT_VALUE));
|
|
mVariables.Put(aName, aTokenStream);
|
|
}
|
|
|
|
void
|
|
CSSVariableDeclarations::PutInitial(const nsAString& aName)
|
|
{
|
|
mVariables.Put(aName, NS_LITERAL_STRING(INITIAL_VALUE));
|
|
}
|
|
|
|
void
|
|
CSSVariableDeclarations::PutInherit(const nsAString& aName)
|
|
{
|
|
mVariables.Put(aName, NS_LITERAL_STRING(INHERIT_VALUE));
|
|
}
|
|
|
|
void
|
|
CSSVariableDeclarations::Remove(const nsAString& aName)
|
|
{
|
|
mVariables.Remove(aName);
|
|
}
|
|
|
|
/* static */ PLDHashOperator
|
|
CSSVariableDeclarations::EnumerateVariableForMapRuleInfoInto(
|
|
const nsAString& aName,
|
|
nsString aValue,
|
|
void* aData)
|
|
{
|
|
nsDataHashtable<nsStringHashKey, nsString>* variables =
|
|
static_cast<nsDataHashtable<nsStringHashKey, nsString>*>(aData);
|
|
if (!variables->Contains(aName)) {
|
|
variables->Put(aName, aValue);
|
|
}
|
|
return PL_DHASH_NEXT;
|
|
}
|
|
|
|
void
|
|
CSSVariableDeclarations::MapRuleInfoInto(nsRuleData* aRuleData)
|
|
{
|
|
if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Variables))) {
|
|
return;
|
|
}
|
|
|
|
if (!aRuleData->mVariables) {
|
|
aRuleData->mVariables = new CSSVariableDeclarations(*this);
|
|
} else {
|
|
mVariables.EnumerateRead(EnumerateVariableForMapRuleInfoInto,
|
|
aRuleData->mVariables.get());
|
|
}
|
|
}
|
|
|
|
/* static */ PLDHashOperator
|
|
CSSVariableDeclarations::EnumerateVariableForAddVariablesToResolver(
|
|
const nsAString& aName,
|
|
nsString aValue,
|
|
void* aData)
|
|
{
|
|
CSSVariableResolver* resolver = static_cast<CSSVariableResolver*>(aData);
|
|
if (aValue.EqualsLiteral(INITIAL_VALUE)) {
|
|
// Values of 'initial' are treated the same as an invalid value in the
|
|
// variable resolver.
|
|
resolver->Put(aName, EmptyString(),
|
|
eCSSTokenSerialization_Nothing,
|
|
eCSSTokenSerialization_Nothing,
|
|
false);
|
|
} else if (aValue.EqualsLiteral(INHERIT_VALUE)) {
|
|
// Values of 'inherit' 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 {
|
|
// 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.
|
|
resolver->Put(aName, aValue,
|
|
eCSSTokenSerialization_Nothing,
|
|
eCSSTokenSerialization_Nothing,
|
|
false);
|
|
}
|
|
return PL_DHASH_NEXT;
|
|
}
|
|
|
|
void
|
|
CSSVariableDeclarations::AddVariablesToResolver(
|
|
CSSVariableResolver* aResolver) const
|
|
{
|
|
mVariables.EnumerateRead(EnumerateVariableForAddVariablesToResolver,
|
|
aResolver);
|
|
}
|
|
|
|
static size_t
|
|
SizeOfTableEntry(const nsAString& aKey,
|
|
const nsString& aValue,
|
|
MallocSizeOf aMallocSizeOf,
|
|
void* aUserArg)
|
|
{
|
|
size_t n = 0;
|
|
n += aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
|
n += aValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
|
return n;
|
|
}
|
|
|
|
size_t
|
|
CSSVariableDeclarations::SizeOfIncludingThis(
|
|
mozilla::MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
size_t n = aMallocSizeOf(this);
|
|
n += mVariables.SizeOfExcludingThis(SizeOfTableEntry, aMallocSizeOf);
|
|
return n;
|
|
}
|
|
|
|
} // namespace mozilla
|