Closed Bug 1330172 Opened 7 years ago Closed 7 years ago

Property value with variable reference is not idempotent with assigning cssText


(Core :: CSS Parsing and Computation, defect)

Not set



Tracking Status
firefox53 --- fixed


(Reporter: xidorn, Assigned: xidorn)




(2 files)

Assuming there is a `decl` which refers to "display: var(--a);". `decl.display` would be " var(--a)", and `decl.cssText` would be "display:  var(--a);" (notice the change on the whitespaces). If you do `decl.cssText = decl.cssText;`, `decl.display` would now be "  var(--a)", and `decl.cssText` would become "display:   var(--a);", which is not idempotent.
It is not completely clear to me what is the right approach to fix this.

CSSOM spec says we should append a whitespace after ":", and we preserve all whitespaces after ":" when parsing, and thus the issue.

It seems Blink currently strips the whitespaces at the beginning, and collapse continuous whitespaces inside. I guess we may at least want to strip the whitespaces at the beginning, since that doesn't really make sense for properties.
This is also an issue for custom properties.

It seems for custom properties, Blink doesn't strip whitespaces (but it still collapse continuous whitespaces, FWIW), and it doesn't append a whitespace after ":" in that case.
I don't feel too strongly about it, but I think there is a similarity to regular properties with variable references and custom properties (with whatever value), in that they are both token streams.  So I think we should be trimming or not trimming spaces for both of them or neither of them.  It definitely makes sense to me to preserve the space for custom properties, so I would say to preserve the space for regular properties with token stream values, even though we know that in reality no regular property will care about that space.

The idempotency sounds like something we can solve.  Easiest seems to be to change CSSOM to not emit the space after the colon if the value is a token stream.
It is a common failure pattern on stylo that, assigning "var(--a)" to a property produces "property:var(--a);", but we currently expect "property: var(--a);". So are you proposing we should align to servo's behavior on this?

I'm a bit concerned about how to change the spec given the inconsistency between impls.
If the implementations are inconsistent then it might make it easier to tighten the spec.  I propose we:

* file an issue on Custom Properties to make clear that leading and trailing spaces are part of the value of both regular and custom properties with token stream values (not sure what the right spec term is for token streams)

* file an issue on CSSOM to omit the space after the colon if the value of the property is a token stream

* change Gecko to follow this

Then Servo doesn't need to change, I think.
I can probably understand why Blink chose the other way.

Declaration serialization and value serialization is pretty far in code, and the latter is invoked in various places, so passing extra information from value serialization to declaration serialization could be painful (need changes to lots of places with little usefulness).

I'd like to choose a different way that we adding whitespace according to whether the value already has preceding and trailing whitesapces. If it doesn't, we add one between it and ":" and "!important", otherwise we leave it as is. It would solve the idempotent issue of cssText, but property value would be changed by assigning cssText.

But changing Servo code to that behavior also seems painful: we would need to serialize the value into a string and then append that string to result, rather than simply writing the result in one pass.
(The difference of handling this accounts for ~5.5k failures in style system mochitests, as a record.)
Assignee: nobody → xidorn+moz
Comment on attachment 8828765 [details]
Bug 1330172 part 1 - Fix serialization of CSS-wide keyword in variable.
Attachment #8828765 - Flags: review?(cam) → review+
Comment on attachment 8828766 [details]
Bug 1330172 part 2 - Fix serialization of property declaration with variable reference.

::: layout/style/Declaration.cpp:1751
(Diff revision 1)
>          continue;
>      }
>      // Try to use this property in a shorthand.
>      nsAutoString value;
> +    bool isTokenStream;

Move the isTokenStream declaration inside the loop?

::: layout/style/Declaration.cpp:1770
(Diff revision 1)
>        if (shorthand == eCSSProperty_font_variant &&
>            value.EqualsLiteral("-moz-use-system-font")) {
>          continue;
>        }
>        // If GetPropertyValueByID gives us a non-empty string back, we can


::: layout/style/Declaration.cpp:1811
(Diff revision 1)
>      MOZ_ASSERT(value.IsEmpty(), "value should be empty now");
> -    AppendPropertyAndValueToString(property, value, aString);
> +    AppendPropertyAndValueToString(property, aString, value, isTokenStream);

If value is empty here, then the aValueIsTokenStream argument value doesn't matter.  So maybe we should just pass in false so it doesn't look like isTokenStream's value is important here.
Attachment #8828766 - Flags: review?(cam) → review+
Pushed by
part 1 - Fix serialization of CSS-wide keyword in variable. r=heycam
part 2 - Fix serialization of property declaration with variable reference. r=heycam
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla53
You need to log in before you can comment on or make changes to this bug.