зеркало из https://github.com/mozilla/gecko-dev.git
Bug 773296 - Part 23: Support variables in CSSStyleDelcaration methods. r=dbaron
This adds support for custom properties on the remainder of the CSSStyleDeclaration methods. A shorthand that was specified using a variable reference is serialized to its originally specified value, rather than by concatenating the serializations of its longhand components. A shorthand that was not specified using a variable references but which has a component longhand that was is serialized to the empty string.
This commit is contained in:
Родитель
99b85f3cd1
Коммит
5e31fc11d0
|
@ -175,8 +175,15 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue) const
|
|||
// Since we're doing this check for 'inherit' and 'initial' up front,
|
||||
// we can also simplify the property serialization code by serializing
|
||||
// those values up front as well.
|
||||
//
|
||||
// Additionally, if a shorthand property was set using a value with a
|
||||
// variable reference and none of its component longhand properties were
|
||||
// then overridden on the declaration, we return the token stream
|
||||
// assigned to the shorthand.
|
||||
const nsCSSValue* tokenStream = nullptr;
|
||||
uint32_t totalCount = 0, importantCount = 0,
|
||||
initialCount = 0, inheritCount = 0, unsetCount = 0;
|
||||
initialCount = 0, inheritCount = 0, unsetCount = 0,
|
||||
matchingTokenStreamCount = 0;
|
||||
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) {
|
||||
if (*p == eCSSProperty__x_system_font ||
|
||||
nsCSSProps::PropHasFlags(*p, CSS_PROPERTY_DIRECTIONAL_SOURCE)) {
|
||||
|
@ -201,6 +208,10 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue) const
|
|||
++initialCount;
|
||||
} else if (val->GetUnit() == eCSSUnit_Unset) {
|
||||
++unsetCount;
|
||||
} else if (val->GetUnit() == eCSSUnit_TokenStream &&
|
||||
val->GetTokenStreamValue()->mShorthandPropertyID == aProperty) {
|
||||
tokenStream = val;
|
||||
++matchingTokenStreamCount;
|
||||
}
|
||||
}
|
||||
if (importantCount != 0 && importantCount != totalCount) {
|
||||
|
@ -226,6 +237,16 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue) const
|
|||
// Case (2): partially initial, inherit or unset.
|
||||
return;
|
||||
}
|
||||
if (tokenStream) {
|
||||
if (matchingTokenStreamCount == totalCount) {
|
||||
// Shorthand was specified using variable references and all of its
|
||||
// longhand components were set by the shorthand.
|
||||
aValue.Append(tokenStream->GetTokenStreamValue()->mTokenStream);
|
||||
} else {
|
||||
// In all other cases, serialize to the empty string.
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nsCSSCompressedDataBlock *data = importantCount ? mImportantData : mData;
|
||||
switch (aProperty) {
|
||||
|
@ -1210,7 +1231,8 @@ void
|
|||
Declaration::AddVariableDeclaration(const nsAString& aName,
|
||||
CSSVariableDeclarations::Type aType,
|
||||
const nsString& aValue,
|
||||
bool aIsImportant)
|
||||
bool aIsImportant,
|
||||
bool aOverrideImportant)
|
||||
{
|
||||
MOZ_ASSERT(IsMutable());
|
||||
|
||||
|
@ -1220,7 +1242,8 @@ Declaration::AddVariableDeclaration(const nsAString& aName,
|
|||
mVariableOrder.AppendElement(aName);
|
||||
}
|
||||
|
||||
if (!aIsImportant && mImportantVariables && mImportantVariables->Has(aName)) {
|
||||
if (!aIsImportant && !aOverrideImportant &&
|
||||
mImportantVariables && mImportantVariables->Has(aName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1234,6 +1257,9 @@ Declaration::AddVariableDeclaration(const nsAString& aName,
|
|||
}
|
||||
variables = mImportantVariables;
|
||||
} else {
|
||||
if (mImportantVariables) {
|
||||
mImportantVariables->Remove(aName);
|
||||
}
|
||||
if (!mVariables) {
|
||||
mVariables = new CSSVariableDeclarations;
|
||||
}
|
||||
|
|
|
@ -78,11 +78,14 @@ public:
|
|||
* @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,
|
||||
bool aIsImportant);
|
||||
bool aIsImportant,
|
||||
bool aOverrideImportant);
|
||||
|
||||
/**
|
||||
* Removes a custom property declaration from this object.
|
||||
|
|
|
@ -131,6 +131,15 @@ public:
|
|||
nsMediaList* aMediaList,
|
||||
bool aHTMLMode);
|
||||
|
||||
nsresult ParseVariable(const nsAString& aVariableName,
|
||||
const nsAString& aPropValue,
|
||||
nsIURI* aSheetURL,
|
||||
nsIURI* aBaseURL,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
css::Declaration* aDeclaration,
|
||||
bool* aChanged,
|
||||
bool aIsImportant);
|
||||
|
||||
bool ParseColorString(const nsSubstring& aBuffer,
|
||||
nsIURI* aURL, // for error reporting
|
||||
uint32_t aLineNumber, // for error reporting
|
||||
|
@ -1257,6 +1266,7 @@ CSSParserImpl::ParseRule(const nsAString& aRule,
|
|||
#pragma warning( push )
|
||||
#pragma warning( disable : 4748 )
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
|
||||
const nsAString& aPropValue,
|
||||
|
@ -1331,6 +1341,63 @@ CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
|
|||
ReleaseScanner();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CSSParserImpl::ParseVariable(const nsAString& aVariableName,
|
||||
const nsAString& aPropValue,
|
||||
nsIURI* aSheetURI,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
css::Declaration* aDeclaration,
|
||||
bool* aChanged,
|
||||
bool aIsImportant)
|
||||
{
|
||||
NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
|
||||
NS_PRECONDITION(aBaseURI, "need base URI");
|
||||
NS_PRECONDITION(aDeclaration, "Need declaration to parse into!");
|
||||
NS_PRECONDITION(nsLayoutUtils::CSSVariablesEnabled(),
|
||||
"expected Variables to be enabled");
|
||||
|
||||
mData.AssertInitialState();
|
||||
mTempData.AssertInitialState();
|
||||
aDeclaration->AssertMutable();
|
||||
|
||||
nsCSSScanner scanner(aPropValue, 0);
|
||||
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
|
||||
InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
|
||||
mSection = eCSSSection_General;
|
||||
|
||||
*aChanged = false;
|
||||
|
||||
CSSVariableDeclarations::Type variableType;
|
||||
nsString variableValue;
|
||||
|
||||
bool parsedOK = ParseVariableDeclaration(&variableType, variableValue);
|
||||
|
||||
// We should now be at EOF
|
||||
if (parsedOK && GetToken(true)) {
|
||||
REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);
|
||||
parsedOK = false;
|
||||
}
|
||||
|
||||
if (!parsedOK) {
|
||||
REPORT_UNEXPECTED_P(PEValueParsingError, NS_LITERAL_STRING("var-") +
|
||||
aVariableName);
|
||||
REPORT_UNEXPECTED(PEDeclDropped);
|
||||
OUTPUT_ERROR();
|
||||
} else {
|
||||
CLEAR_ERROR();
|
||||
aDeclaration->AddVariableDeclaration(aVariableName, variableType,
|
||||
variableValue, aIsImportant, true);
|
||||
*aChanged = true;
|
||||
}
|
||||
|
||||
mTempData.AssertInitialState();
|
||||
|
||||
ReleaseScanner();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#pragma optimize( "", on )
|
||||
|
@ -5541,6 +5608,7 @@ CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration,
|
|||
NS_PRECONDITION(aContext == eCSSContext_General ||
|
||||
aContext == eCSSContext_Page,
|
||||
"Must be page or general context");
|
||||
|
||||
bool checkForBraces = (aFlags & eParseDeclaration_InBraces) != 0;
|
||||
|
||||
mTempData.AssertInitialState();
|
||||
|
@ -5683,7 +5751,7 @@ CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration,
|
|||
0, VAR_PREFIX_LENGTH).EqualsLiteral("var-"));
|
||||
nsDependentString varName(propertyName, VAR_PREFIX_LENGTH); // remove 'var-'
|
||||
aDeclaration->AddVariableDeclaration(varName, variableType, variableValue,
|
||||
status == ePriority_Important);
|
||||
status == ePriority_Important, false);
|
||||
} else {
|
||||
*aChanged |= mData.TransferFromBlock(mTempData, propID,
|
||||
status == ePriority_Important,
|
||||
|
@ -12667,6 +12735,21 @@ nsCSSParser::ParseProperty(const nsCSSProperty aPropID,
|
|||
aIsImportant, aIsSVGMode);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSParser::ParseVariable(const nsAString& aVariableName,
|
||||
const nsAString& aPropValue,
|
||||
nsIURI* aSheetURI,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
css::Declaration* aDeclaration,
|
||||
bool* aChanged,
|
||||
bool aIsImportant)
|
||||
{
|
||||
return static_cast<CSSParserImpl*>(mImpl)->
|
||||
ParseVariable(aVariableName, aPropValue, aSheetURI, aBaseURI,
|
||||
aSheetPrincipal, aDeclaration, aChanged, aIsImportant);
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSParser::ParseMediaList(const nsSubstring& aBuffer,
|
||||
nsIURI* aURI,
|
||||
|
|
|
@ -129,6 +129,15 @@ public:
|
|||
bool aIsImportant,
|
||||
bool aIsSVGMode = false);
|
||||
|
||||
// The same as ParseProperty but for a variable.
|
||||
nsresult ParseVariable(const nsAString& aVariableName,
|
||||
const nsAString& aPropValue,
|
||||
nsIURI* aSheetURL,
|
||||
nsIURI* aBaseURL,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
mozilla::css::Declaration* aDeclaration,
|
||||
bool* aChanged,
|
||||
bool aIsImportant);
|
||||
/**
|
||||
* Parse aBuffer into a media list |aMediaList|, which must be
|
||||
* non-null, replacing its current contents. If aHTMLMode is true,
|
||||
|
|
|
@ -52,6 +52,26 @@ nsDOMCSSDeclaration::GetPropertyValue(const nsCSSProperty aPropID,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Length of the "var-" prefix of custom property names.
|
||||
#define VAR_PREFIX_LENGTH 4
|
||||
|
||||
void
|
||||
nsDOMCSSDeclaration::GetCustomPropertyValue(const nsAString& aPropertyName,
|
||||
nsAString& aValue)
|
||||
{
|
||||
MOZ_ASSERT(Substring(aPropertyName,
|
||||
0, VAR_PREFIX_LENGTH).EqualsLiteral("var-"));
|
||||
|
||||
css::Declaration* decl = GetCSSDeclaration(false);
|
||||
if (!decl) {
|
||||
aValue.Truncate();
|
||||
return;
|
||||
}
|
||||
|
||||
decl->GetVariableDeclaration(Substring(aPropertyName, VAR_PREFIX_LENGTH),
|
||||
aValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMCSSDeclaration::SetPropertyValue(const nsCSSProperty aPropID,
|
||||
const nsAString& aValue)
|
||||
|
@ -156,6 +176,11 @@ nsDOMCSSDeclaration::GetPropertyValue(const nsAString& aPropertyName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (propID == eCSSPropertyExtra_variable) {
|
||||
GetCustomPropertyValue(aPropertyName, aReturn);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return GetPropertyValue(propID, aReturn);
|
||||
}
|
||||
|
||||
|
@ -189,19 +214,26 @@ nsDOMCSSDeclaration::SetProperty(const nsAString& aPropertyName,
|
|||
// If the new value of the property is an empty string we remove the
|
||||
// property.
|
||||
// XXX this ignores the priority string, should it?
|
||||
if (propID == eCSSPropertyExtra_variable) {
|
||||
return RemoveCustomProperty(aPropertyName);
|
||||
}
|
||||
return RemoveProperty(propID);
|
||||
}
|
||||
|
||||
bool important;
|
||||
if (aPriority.IsEmpty()) {
|
||||
return ParsePropertyValue(propID, aValue, false);
|
||||
important = false;
|
||||
} else if (aPriority.EqualsLiteral("important")) {
|
||||
important = true;
|
||||
} else {
|
||||
// XXX silent failure?
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aPriority.EqualsLiteral("important")) {
|
||||
return ParsePropertyValue(propID, aValue, true);
|
||||
if (propID == eCSSPropertyExtra_variable) {
|
||||
return ParseCustomPropertyValue(aPropertyName, aValue, important);
|
||||
}
|
||||
|
||||
// XXX silent failure?
|
||||
return NS_OK;
|
||||
return ParsePropertyValue(propID, aValue, important);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -215,6 +247,11 @@ nsDOMCSSDeclaration::RemoveProperty(const nsAString& aPropertyName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (propID == eCSSPropertyExtra_variable) {
|
||||
RemoveCustomProperty(aPropertyName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = GetPropertyValue(propID, aReturn);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -278,6 +315,49 @@ nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSProperty aPropID,
|
|||
return SetCSSDeclaration(decl);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
|
||||
const nsAString& aPropValue,
|
||||
bool aIsImportant)
|
||||
{
|
||||
MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
|
||||
|
||||
css::Declaration* olddecl = GetCSSDeclaration(true);
|
||||
if (!olddecl) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CSSParsingEnvironment env;
|
||||
GetCSSParsingEnvironment(env);
|
||||
if (!env.mPrincipal) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// 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);
|
||||
css::Declaration* decl = olddecl->EnsureMutable();
|
||||
|
||||
nsCSSParser cssParser(env.mCSSLoader);
|
||||
bool changed;
|
||||
nsresult result = cssParser.ParseVariable(Substring(aPropertyName,
|
||||
VAR_PREFIX_LENGTH),
|
||||
aPropValue, env.mSheetURI,
|
||||
env.mBaseURI, env.mPrincipal, decl,
|
||||
&changed, aIsImportant);
|
||||
if (NS_FAILED(result) || !changed) {
|
||||
if (decl != olddecl) {
|
||||
delete decl;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return SetCSSDeclaration(decl);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMCSSDeclaration::RemoveProperty(const nsCSSProperty aPropID)
|
||||
{
|
||||
|
@ -297,3 +377,26 @@ nsDOMCSSDeclaration::RemoveProperty(const nsCSSProperty aPropID)
|
|||
decl->RemoveProperty(aPropID);
|
||||
return SetCSSDeclaration(decl);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMCSSDeclaration::RemoveCustomProperty(const nsAString& aPropertyName)
|
||||
{
|
||||
MOZ_ASSERT(Substring(aPropertyName,
|
||||
0, VAR_PREFIX_LENGTH).EqualsLiteral("var-"));
|
||||
|
||||
css::Declaration* decl = GetCSSDeclaration(false);
|
||||
if (!decl) {
|
||||
return NS_OK; // no decl, so nothing to remove
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
decl = decl->EnsureMutable();
|
||||
decl->RemoveVariableDeclaration(Substring(aPropertyName, VAR_PREFIX_LENGTH));
|
||||
return SetCSSDeclaration(decl);
|
||||
}
|
||||
|
|
|
@ -138,6 +138,12 @@ protected:
|
|||
// return the old value; it just does a straight removal.
|
||||
nsresult RemoveProperty(const nsCSSProperty aPropID);
|
||||
|
||||
void GetCustomPropertyValue(const nsAString& aPropertyName, nsAString& aValue);
|
||||
nsresult RemoveCustomProperty(const nsAString& aPropertyName);
|
||||
nsresult ParseCustomPropertyValue(const nsAString& aPropertyName,
|
||||
const nsAString& aPropValue,
|
||||
bool aIsImportant);
|
||||
|
||||
protected:
|
||||
virtual ~nsDOMCSSDeclaration();
|
||||
nsDOMCSSDeclaration()
|
||||
|
|
Загрузка…
Ссылка в новой задаче