|
| 1 | +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Anders Hartvoll Ruud < [email protected]> |
| 3 | +Date: Wed, 25 Feb 2026 03:25:14 -0800 |
| 4 | +Subject: Stringify CSSUnparsedValues via toString, as normal |
| 5 | + |
| 6 | +CSSUnparsedValue exposes a special stringification function |
| 7 | +ToUnparsedString() in addition to the regular toString(). |
| 8 | +The documentation says it returns "tokens without substituting |
| 9 | +variables", but it's not clear what this means; we don't substitute |
| 10 | +any variables in CSSStyleValue::toString() either. |
| 11 | + |
| 12 | +This CL makes ToUnparsedString() private (and renames it). |
| 13 | +Clients needing to serialize a CSSUnparsedValue can do so via |
| 14 | +the normal toString() function. (If ToUnparsedString() existed |
| 15 | +for performance reasons, that should have been documented.) |
| 16 | + |
| 17 | +Also, the /**/-"fixup" pass over the value has been folded into |
| 18 | +ToStringInternal(). This is to make it easy to find the canonical string |
| 19 | +representation of this value within CSSUnparsedValue (without going |
| 20 | +through a CSSValue). |
| 21 | + |
| 22 | +The main point of this CL is to prepare for validating |
| 23 | +the "argument grammar" of the value during the StyleValue-to-CSSValue |
| 24 | +conversion in StylePropertyMap (which requires item (2) above). |
| 25 | + |
| 26 | +We now jump through additional hoops to ultimately get a string |
| 27 | +from the outside of CSSUnparsedValue, but there should otherwise |
| 28 | +be no behavior change. |
| 29 | + |
| 30 | +Bug: 484751092 |
| 31 | +Change-Id: I5db45ad85f780c67a2ea3ba8482c390ebab10068 |
| 32 | +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7600415 |
| 33 | +Commit-Queue: Anders Hartvoll Ruud < [email protected]> |
| 34 | +Reviewed-by: Steinar H Gunderson < [email protected]> |
| 35 | +Cr-Commit-Position: refs/heads/main@{#1590041} |
| 36 | + |
| 37 | +diff --git a/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc b/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc |
| 38 | +index dcc2eccbc84e6cd5710ab51cee2dab49661467c1..86d42c87a6bd10838a3e059c9227868e5bfc0798 100644 |
| 39 | +--- a/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc |
| 40 | ++++ b/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc |
| 41 | +@@ -19,12 +19,12 @@ |
| 42 | + #include "third_party/blink/renderer/core/css/cssom/css_keyword_value.h" |
| 43 | + #include "third_party/blink/renderer/core/css/cssom/css_style_value.h" |
| 44 | + #include "third_party/blink/renderer/core/css/cssom/css_unit_value.h" |
| 45 | +-#include "third_party/blink/renderer/core/css/cssom/css_unparsed_value.h" |
| 46 | + #include "third_party/blink/renderer/core/css/cssom/css_unsupported_color.h" |
| 47 | + #include "third_party/blink/renderer/platform/scheduler/public/non_main_thread.h" |
| 48 | + #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" |
| 49 | + #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_std.h" |
| 50 | + #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" |
| 51 | ++#include "third_party/blink/renderer/platform/wtf/wtf.h" |
| 52 | + |
| 53 | + namespace blink { |
| 54 | + |
| 55 | +@@ -152,8 +152,7 @@ TEST_F(CrossThreadStyleValueTest, CrossThreadUnparsedValueToCSSStyleValue) { |
| 56 | + CSSStyleValue* style_value = value->ToCSSStyleValue(); |
| 57 | + EXPECT_EQ(style_value->GetType(), |
| 58 | + CSSStyleValue::StyleValueType::kUnparsedType); |
| 59 | +- EXPECT_EQ(static_cast<CSSUnparsedValue*>(style_value)->ToUnparsedString(), |
| 60 | +- "Unparsed"); |
| 61 | ++ EXPECT_EQ(style_value->toString(), "Unparsed"); |
| 62 | + } |
| 63 | + |
| 64 | + TEST_F(CrossThreadStyleValueTest, PassKeywordValueCrossThread) { |
| 65 | +diff --git a/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc b/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc |
| 66 | +index 67a4afde452f94ffb9ecbaeea104a3997c65b7b3..9c6bb62d044f804b0ce7bc8df398d77695cf950c 100644 |
| 67 | +--- a/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc |
| 68 | ++++ b/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc |
| 69 | +@@ -124,16 +124,26 @@ IndexedPropertySetterResult CSSUnparsedValue::AnonymousIndexedSetter( |
| 70 | + } |
| 71 | + |
| 72 | + const CSSValue* CSSUnparsedValue::ToCSSValue() const { |
| 73 | +- String unparsed_string = ToUnparsedString(); |
| 74 | +- CSSParserTokenStream stream(unparsed_string); |
| 75 | ++ String unparsed_string = ToStringInternal(); |
| 76 | + |
| 77 | +- if (stream.AtEnd()) { |
| 78 | ++ if (unparsed_string.IsNull()) { |
| 79 | + return MakeGarbageCollected<CSSUnparsedDeclarationValue>( |
| 80 | + MakeGarbageCollected<CSSVariableData>()); |
| 81 | + } |
| 82 | + |
| 83 | +- // The string we just parsed has /**/ inserted between every token |
| 84 | +- // to make sure we get back the correct sequence of tokens. |
| 85 | ++ // TODO(crbug.com/985028): We should probably propagate the CSSParserContext |
| 86 | ++ // to here. |
| 87 | ++ return MakeGarbageCollected<CSSUnparsedDeclarationValue>( |
| 88 | ++ CSSVariableData::Create(unparsed_string, false /* is_animation_tainted */, |
| 89 | ++ false /* is_attr_tainted */, |
| 90 | ++ false /* needs_variable_resolution */)); |
| 91 | ++} |
| 92 | ++ |
| 93 | ++String CSSUnparsedValue::ToStringInternal() const { |
| 94 | ++ String serialized = SerializeSegments(); |
| 95 | ++ |
| 96 | ++ // The serialization above defensively inserted /**/ between segments |
| 97 | ++ // to make sure that e.g. ['foo', 'bar'] does not collapse into 'foobar'. |
| 98 | + // The spec mentions nothing of the sort: |
| 99 | + // https://drafts.css-houdini.org/css-typed-om-1/#unparsedvalue-serialization |
| 100 | + // |
| 101 | +@@ -147,6 +157,10 @@ const CSSValue* CSSUnparsedValue::ToCSSValue() const { |
| 102 | + // the original contents of any comments will be lost, but Typed OM does |
| 103 | + // not have anywhere to store that kind of data, so it is expected. |
| 104 | + StringBuilder builder; |
| 105 | ++ CSSParserTokenStream stream(serialized); |
| 106 | ++ if (stream.AtEnd()) { |
| 107 | ++ return g_null_atom; |
| 108 | ++ } |
| 109 | + CSSParserToken token = stream.ConsumeRaw(); |
| 110 | + token.Serialize(builder); |
| 111 | + while (!stream.Peek().IsEOF()) { |
| 112 | +@@ -156,17 +170,10 @@ const CSSValue* CSSUnparsedValue::ToCSSValue() const { |
| 113 | + token = stream.ConsumeRaw(); |
| 114 | + token.Serialize(builder); |
| 115 | + } |
| 116 | +- String original_text = builder.ReleaseString(); |
| 117 | +- |
| 118 | +- // TODO(crbug.com/985028): We should probably propagate the CSSParserContext |
| 119 | +- // to here. |
| 120 | +- return MakeGarbageCollected<CSSUnparsedDeclarationValue>( |
| 121 | +- CSSVariableData::Create(original_text, false /* is_animation_tainted */, |
| 122 | +- false /* is_attr_tainted */, |
| 123 | +- false /* needs_variable_resolution */)); |
| 124 | ++ return builder.ReleaseString(); |
| 125 | + } |
| 126 | + |
| 127 | +-String CSSUnparsedValue::ToUnparsedString() const { |
| 128 | ++String CSSUnparsedValue::SerializeSegments() const { |
| 129 | + StringBuilder builder; |
| 130 | + HeapHashSet<Member<const CSSUnparsedValue>> values_on_stack; |
| 131 | + if (AppendUnparsedString(builder, values_on_stack)) { |
| 132 | +diff --git a/third_party/blink/renderer/core/css/cssom/css_unparsed_value.h b/third_party/blink/renderer/core/css/cssom/css_unparsed_value.h |
| 133 | +index 5d1961b170f14ae21ca8f69b3c3cd8af28f4478a..ec7e3ed708f406d7a61fdb370b2eed8a8297cffb 100644 |
| 134 | +--- a/third_party/blink/renderer/core/css/cssom/css_unparsed_value.h |
| 135 | ++++ b/third_party/blink/renderer/core/css/cssom/css_unparsed_value.h |
| 136 | +@@ -67,15 +67,9 @@ class CORE_EXPORT CSSUnparsedValue final : public CSSStyleValue { |
| 137 | + CSSStyleValue::Trace(visitor); |
| 138 | + } |
| 139 | + |
| 140 | +- // Unlike CSSStyleValue::toString(), this returns tokens without |
| 141 | +- // substituting variables. There are extra /**/ inserted between |
| 142 | +- // every token to ensure there are no ambiguities, which is fine |
| 143 | +- // because this value is never presented directly to the user |
| 144 | +- // (ToCSSValue() will parse to a token range and then re-serialize |
| 145 | +- // using extra /**/ only where needed). |
| 146 | +- String ToUnparsedString() const; |
| 147 | +- |
| 148 | + private: |
| 149 | ++ String ToStringInternal() const; |
| 150 | ++ String SerializeSegments() const; |
| 151 | + // Return 'false' if there is a cycle in the serialization. |
| 152 | + bool AppendUnparsedString( |
| 153 | + StringBuilder&, |
| 154 | +diff --git a/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc b/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc |
| 155 | +index f81fa39423a9235bc58e1600ca7a250affd3d9bb..2ee4dd7e591095b8460ca559b29b78e37ab71729 100644 |
| 156 | +--- a/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc |
| 157 | ++++ b/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc |
| 158 | +@@ -5,6 +5,7 @@ |
| 159 | + #include "third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h" |
| 160 | + |
| 161 | + #include <memory> |
| 162 | ++ |
| 163 | + #include "base/synchronization/waitable_event.h" |
| 164 | + #include "base/task/single_thread_task_runner.h" |
| 165 | + #include "testing/gtest/include/gtest/gtest.h" |
| 166 | +@@ -13,7 +14,6 @@ |
| 167 | + #include "third_party/blink/renderer/core/css/cssom/css_keyword_value.h" |
| 168 | + #include "third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h" |
| 169 | + #include "third_party/blink/renderer/core/css/cssom/css_unit_value.h" |
| 170 | +-#include "third_party/blink/renderer/core/css/cssom/css_unparsed_value.h" |
| 171 | + #include "third_party/blink/renderer/core/css/cssom/css_unsupported_color.h" |
| 172 | + #include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h" |
| 173 | + #include "third_party/blink/renderer/core/dom/element.h" |
| 174 | +@@ -23,6 +23,7 @@ |
| 175 | + #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" |
| 176 | + #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h" |
| 177 | + #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" |
| 178 | ++#include "third_party/blink/renderer/platform/wtf/wtf.h" |
| 179 | + |
| 180 | + namespace blink { |
| 181 | + |
| 182 | +@@ -66,8 +67,7 @@ class PaintWorkletStylePropertyMapTest : public PageTestBase { |
| 183 | + CSSStyleValue* style_value = data.at("--x")->ToCSSStyleValue(); |
| 184 | + EXPECT_EQ(style_value->GetType(), |
| 185 | + CSSStyleValue::StyleValueType::kUnparsedType); |
| 186 | +- EXPECT_EQ(static_cast<CSSUnparsedValue*>(style_value)->ToUnparsedString(), |
| 187 | +- "50"); |
| 188 | ++ EXPECT_EQ(style_value->toString(), "50"); |
| 189 | + waitable_event->Signal(); |
| 190 | + } |
| 191 | + |
| 192 | +diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc |
| 193 | +index 1db0fd72478d708008f1b95a6aff206b28f60a6a..b52d8065c770aba822e9977c251c540643972629 100644 |
| 194 | +--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc |
| 195 | ++++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc |
| 196 | +@@ -4872,7 +4872,7 @@ ComputedStyleUtils::CrossThreadStyleValueFromCSSStyleValue( |
| 197 | + To<CSSUnsupportedColor>(style_value)->Value()); |
| 198 | + case CSSStyleValue::StyleValueType::kUnparsedType: |
| 199 | + return std::make_unique<CrossThreadUnparsedValue>( |
| 200 | +- To<CSSUnparsedValue>(style_value)->ToUnparsedString()); |
| 201 | ++ To<CSSUnparsedValue>(style_value)->toString()); |
| 202 | + default: |
| 203 | + return std::make_unique<CrossThreadUnsupportedValue>( |
| 204 | + style_value->toString()); |
0 commit comments