Commit 72cfabf0 authored by Anders Hartvoll Ruud's avatar Anders Hartvoll Ruud Committed by Commit Bot

[scroll-animations] Add support for parsing <id-selector>

This CL introduces CSSIdSelectorValue, and accompanying function
in css_parsing_utils which can parse such a value.

It's not very different from CSSCustomIdentValue, but my experience
with re-using "close enough" CSSValues in the past has been less than
optimal, hence I think the proper way to do it is to add a full
CSSValue subclass.

Bug: 1074052
Change-Id: I54727a339b5525af4107d5217c78281182b825ad
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2238070Reviewed-by: default avatarMajid Valipour <majidvp@chromium.org>
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779225}
parent 3383d181
...@@ -79,6 +79,8 @@ blink_core_sources("css") { ...@@ -79,6 +79,8 @@ blink_core_sources("css") {
"css_grid_template_areas_value.h", "css_grid_template_areas_value.h",
"css_grouping_rule.cc", "css_grouping_rule.cc",
"css_grouping_rule.h", "css_grouping_rule.h",
"css_id_selector_value.cc",
"css_id_selector_value.h",
"css_identifier_value.cc", "css_identifier_value.cc",
"css_identifier_value.h", "css_identifier_value.h",
"css_image_generator_value.cc", "css_image_generator_value.cc",
...@@ -602,6 +604,7 @@ blink_core_tests("unit_tests") { ...@@ -602,6 +604,7 @@ blink_core_tests("unit_tests") {
"css_computed_style_declaration_test.cc", "css_computed_style_declaration_test.cc",
"css_font_face_source_test.cc", "css_font_face_source_test.cc",
"css_gradient_value_test.cc", "css_gradient_value_test.cc",
"css_id_selector_value_test.cc",
"css_invalid_variable_value_test.cc", "css_invalid_variable_value_test.cc",
"css_light_dark_value_pair_test.cc", "css_light_dark_value_pair_test.cc",
"css_math_expression_node_test.cc", "css_math_expression_node_test.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/css/css_id_selector_value.h"
#include "third_party/blink/renderer/core/css/css_markup.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
namespace cssvalue {
CSSIdSelectorValue::CSSIdSelectorValue(const String& id)
: CSSValue(kIdSelectorClass), id_(id) {}
String CSSIdSelectorValue::CustomCSSText() const {
StringBuilder builder;
builder.Append('#');
SerializeIdentifier(id_, builder);
return builder.ToString();
}
void CSSIdSelectorValue::TraceAfterDispatch(blink::Visitor* visitor) const {
CSSValue::TraceAfterDispatch(visitor);
}
} // namespace cssvalue
} // namespace blink
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_ID_SELECTOR_VALUE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_ID_SELECTOR_VALUE_H_
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
namespace cssvalue {
class CORE_EXPORT CSSIdSelectorValue : public CSSValue {
public:
explicit CSSIdSelectorValue(const String&);
const AtomicString& Id() const { return id_; }
String CustomCSSText() const;
bool Equals(const CSSIdSelectorValue& other) const {
return id_ == other.id_;
}
void TraceAfterDispatch(blink::Visitor*) const;
private:
AtomicString id_;
};
} // namespace cssvalue
template <>
struct DowncastTraits<cssvalue::CSSIdSelectorValue> {
static bool AllowFrom(const CSSValue& value) {
return value.IsIdSelectorValue();
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_ID_SELECTOR_VALUE_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/css/css_id_selector_value.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
using CSSIdSelectorValue = cssvalue::CSSIdSelectorValue;
TEST(CSSIdSelectorValueTest, Id) {
EXPECT_EQ("test", MakeGarbageCollected<CSSIdSelectorValue>("test")->Id());
}
TEST(CSSIdSelectorValueTest, Equals) {
EXPECT_EQ(*MakeGarbageCollected<CSSIdSelectorValue>("foo"),
*MakeGarbageCollected<CSSIdSelectorValue>("foo"));
EXPECT_NE(*MakeGarbageCollected<CSSIdSelectorValue>("foo"),
*MakeGarbageCollected<CSSIdSelectorValue>("bar"));
EXPECT_NE(*MakeGarbageCollected<CSSIdSelectorValue>("bar"),
*MakeGarbageCollected<CSSIdSelectorValue>("foo"));
}
TEST(CSSIdSelectorValueTest, CustomCSSText) {
EXPECT_EQ("#foo",
MakeGarbageCollected<CSSIdSelectorValue>("foo")->CustomCSSText());
// The identifier part must follow the serialization rules of:
// https://drafts.csswg.org/cssom/#serialize-an-identifier
EXPECT_EQ("#\\31 23",
MakeGarbageCollected<CSSIdSelectorValue>("123")->CustomCSSText());
}
} // namespace blink
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h" #include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h"
#include "third_party/blink/renderer/core/css/css_grid_line_names_value.h" #include "third_party/blink/renderer/core/css/css_grid_line_names_value.h"
#include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h" #include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h"
#include "third_party/blink/renderer/core/css/css_id_selector_value.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h" #include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_image_set_value.h" #include "third_party/blink/renderer/core/css/css_image_set_value.h"
#include "third_party/blink/renderer/core/css/css_image_value.h" #include "third_party/blink/renderer/core/css/css_image_value.h"
...@@ -278,6 +279,8 @@ bool CSSValue::operator==(const CSSValue& other) const { ...@@ -278,6 +279,8 @@ bool CSSValue::operator==(const CSSValue& other) const {
return CompareCSSValues<CSSInvalidVariableValue>(*this, other); return CompareCSSValues<CSSInvalidVariableValue>(*this, other);
case kLightDarkValuePairClass: case kLightDarkValuePairClass:
return CompareCSSValues<CSSLightDarkValuePair>(*this, other); return CompareCSSValues<CSSLightDarkValuePair>(*this, other);
case kIdSelectorClass:
return CompareCSSValues<cssvalue::CSSIdSelectorValue>(*this, other);
} }
NOTREACHED(); NOTREACHED();
return false; return false;
...@@ -398,6 +401,8 @@ String CSSValue::CssText() const { ...@@ -398,6 +401,8 @@ String CSSValue::CssText() const {
return To<CSSInvalidVariableValue>(this)->CustomCSSText(); return To<CSSInvalidVariableValue>(this)->CustomCSSText();
case kLightDarkValuePairClass: case kLightDarkValuePairClass:
return To<CSSLightDarkValuePair>(this)->CustomCSSText(); return To<CSSLightDarkValuePair>(this)->CustomCSSText();
case kIdSelectorClass:
return To<cssvalue::CSSIdSelectorValue>(this)->CustomCSSText();
} }
NOTREACHED(); NOTREACHED();
return String(); return String();
...@@ -578,6 +583,9 @@ void CSSValue::FinalizeGarbageCollectedObject() { ...@@ -578,6 +583,9 @@ void CSSValue::FinalizeGarbageCollectedObject() {
case kLightDarkValuePairClass: case kLightDarkValuePairClass:
To<CSSLightDarkValuePair>(this)->~CSSLightDarkValuePair(); To<CSSLightDarkValuePair>(this)->~CSSLightDarkValuePair();
return; return;
case kIdSelectorClass:
To<cssvalue::CSSIdSelectorValue>(this)->~CSSIdSelectorValue();
return;
} }
NOTREACHED(); NOTREACHED();
} }
...@@ -757,6 +765,9 @@ void CSSValue::Trace(Visitor* visitor) const { ...@@ -757,6 +765,9 @@ void CSSValue::Trace(Visitor* visitor) const {
case kLightDarkValuePairClass: case kLightDarkValuePairClass:
To<CSSLightDarkValuePair>(this)->TraceAfterDispatch(visitor); To<CSSLightDarkValuePair>(this)->TraceAfterDispatch(visitor);
return; return;
case kIdSelectorClass:
To<cssvalue::CSSIdSelectorValue>(this)->TraceAfterDispatch(visitor);
return;
} }
NOTREACHED(); NOTREACHED();
} }
......
...@@ -176,12 +176,14 @@ class CORE_EXPORT CSSValue : public GarbageCollected<CSSValue> { ...@@ -176,12 +176,14 @@ class CORE_EXPORT CSSValue : public GarbageCollected<CSSValue> {
bool IsLightDarkValuePair() const { bool IsLightDarkValuePair() const {
return class_type_ == kLightDarkValuePairClass; return class_type_ == kLightDarkValuePairClass;
} }
bool IsIdSelectorValue() const { return class_type_ == kIdSelectorClass; }
bool HasFailedOrCanceledSubresources() const; bool HasFailedOrCanceledSubresources() const;
bool MayContainUrl() const; bool MayContainUrl() const;
void ReResolveUrl(const Document&) const; void ReResolveUrl(const Document&) const;
bool operator==(const CSSValue&) const; bool operator==(const CSSValue&) const;
bool operator!=(const CSSValue& o) const { return !(*this == o); }
void FinalizeGarbageCollectedObject(); void FinalizeGarbageCollectedObject();
void TraceAfterDispatch(blink::Visitor* visitor) const {} void TraceAfterDispatch(blink::Visitor* visitor) const {}
...@@ -206,6 +208,7 @@ class CORE_EXPORT CSSValue : public GarbageCollected<CSSValue> { ...@@ -206,6 +208,7 @@ class CORE_EXPORT CSSValue : public GarbageCollected<CSSValue> {
kURIClass, kURIClass,
kValuePairClass, kValuePairClass,
kLightDarkValuePairClass, kLightDarkValuePairClass,
kIdSelectorClass,
// Basic shape classes. // Basic shape classes.
// TODO(sashab): Represent these as a single subclass, BasicShapeClass. // TODO(sashab): Represent these as a single subclass, BasicShapeClass.
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h" #include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h"
#include "third_party/blink/renderer/core/css/css_grid_line_names_value.h" #include "third_party/blink/renderer/core/css/css_grid_line_names_value.h"
#include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h" #include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h"
#include "third_party/blink/renderer/core/css/css_id_selector_value.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h" #include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_image_set_value.h" #include "third_party/blink/renderer/core/css/css_image_set_value.h"
#include "third_party/blink/renderer/core/css/css_image_value.h" #include "third_party/blink/renderer/core/css/css_image_value.h"
...@@ -1090,6 +1091,14 @@ cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange& range, ...@@ -1090,6 +1091,14 @@ cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange& range,
url_string, context.CompleteURL(url_string)); url_string, context.CompleteURL(url_string));
} }
CSSValue* ConsumeIdSelector(CSSParserTokenRange& range) {
if (!IsHashIdentifier(range.Peek()))
return nullptr;
auto token = range.ConsumeIncludingWhitespace();
return MakeGarbageCollected<cssvalue::CSSIdSelectorValue>(
token.Value().ToString());
}
static int ClampRGBComponent(const CSSPrimitiveValue& value) { static int ClampRGBComponent(const CSSPrimitiveValue& value) {
double result = value.GetDoubleValue(); double result = value.GetDoubleValue();
if (value.IsPercentage()) { if (value.IsPercentage()) {
...@@ -2597,6 +2606,12 @@ bool IsDefaultKeyword(StringView keyword) { ...@@ -2597,6 +2606,12 @@ bool IsDefaultKeyword(StringView keyword) {
return EqualIgnoringASCIICase(keyword, "default"); return EqualIgnoringASCIICase(keyword, "default");
} }
// https://drafts.csswg.org/css-syntax/#typedef-hash-token
bool IsHashIdentifier(const CSSParserToken& token) {
return token.GetType() == kHashToken &&
token.GetHashTokenType() == kHashTokenId;
}
CSSValue* ConsumeScrollOffset(CSSParserTokenRange& range, CSSValue* ConsumeScrollOffset(CSSParserTokenRange& range,
const CSSParserContext& context) { const CSSParserContext& context) {
range.ConsumeWhitespace(); range.ConsumeWhitespace();
......
...@@ -129,6 +129,7 @@ StringView ConsumeUrlAsStringView(CSSParserTokenRange&, ...@@ -129,6 +129,7 @@ StringView ConsumeUrlAsStringView(CSSParserTokenRange&,
const CSSParserContext&); const CSSParserContext&);
cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange&, cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange&,
const CSSParserContext&); const CSSParserContext&);
CORE_EXPORT CSSValue* ConsumeIdSelector(CSSParserTokenRange&);
CSSValue* ConsumeColor(CSSParserTokenRange&, CSSValue* ConsumeColor(CSSParserTokenRange&,
const CSSParserContext&, const CSSParserContext&,
...@@ -232,6 +233,7 @@ CORE_EXPORT bool IsCSSWideKeyword(CSSValueID); ...@@ -232,6 +233,7 @@ CORE_EXPORT bool IsCSSWideKeyword(CSSValueID);
CORE_EXPORT bool IsCSSWideKeyword(StringView); CORE_EXPORT bool IsCSSWideKeyword(StringView);
bool IsRevertKeyword(StringView); bool IsRevertKeyword(StringView);
bool IsDefaultKeyword(StringView); bool IsDefaultKeyword(StringView);
bool IsHashIdentifier(const CSSParserToken&);
CSSValue* ConsumeScrollOffset(CSSParserTokenRange&, const CSSParserContext&); CSSValue* ConsumeScrollOffset(CSSParserTokenRange&, const CSSParserContext&);
CSSValue* ConsumeSelfPositionOverflowPosition(CSSParserTokenRange&, CSSValue* ConsumeSelfPositionOverflowPosition(CSSParserTokenRange&,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h" #include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
#include "third_party/blink/renderer/core/html/html_html_element.h" #include "third_party/blink/renderer/core/html/html_html_element.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
...@@ -11,6 +12,8 @@ ...@@ -11,6 +12,8 @@
namespace blink { namespace blink {
using css_parsing_utils::ConsumeIdSelector;
TEST(CSSParsingUtilsTest, BasicShapeUseCount) { TEST(CSSParsingUtilsTest, BasicShapeUseCount) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
...@@ -36,4 +39,63 @@ TEST(CSSParsingUtilsTest, Revert) { ...@@ -36,4 +39,63 @@ TEST(CSSParsingUtilsTest, Revert) {
} }
} }
TEST(CSSParsingUtilsTest, ConsumeIdSelector) {
{
String text = "#foo";
auto tokens = CSSTokenizer(text).TokenizeToEOF();
CSSParserTokenRange range(tokens);
EXPECT_EQ("#foo", ConsumeIdSelector(range)->CssText());
}
{
String text = "#bar ";
auto tokens = CSSTokenizer(text).TokenizeToEOF();
CSSParserTokenRange range(tokens);
EXPECT_EQ("#bar", ConsumeIdSelector(range)->CssText());
EXPECT_TRUE(range.AtEnd())
<< "ConsumeIdSelector cleans up trailing whitespace";
}
{
String text = "#123";
auto tokens = CSSTokenizer(text).TokenizeToEOF();
CSSParserTokenRange range(tokens);
ASSERT_TRUE(range.Peek().GetType() == kHashToken &&
range.Peek().GetHashTokenType() == kHashTokenUnrestricted);
EXPECT_FALSE(ConsumeIdSelector(range))
<< "kHashTokenUnrestricted is not a valid <id-selector>";
}
{
String text = "#";
auto tokens = CSSTokenizer(text).TokenizeToEOF();
CSSParserTokenRange range(tokens);
EXPECT_FALSE(ConsumeIdSelector(range));
}
{
String text = " #foo";
auto tokens = CSSTokenizer(text).TokenizeToEOF();
CSSParserTokenRange range(tokens);
EXPECT_FALSE(ConsumeIdSelector(range))
<< "ConsumeIdSelector does not accept preceding whitespace";
EXPECT_EQ(kWhitespaceToken, range.Peek().GetType());
}
{
String text = "foo";
auto tokens = CSSTokenizer(text).TokenizeToEOF();
CSSParserTokenRange range(tokens);
EXPECT_FALSE(ConsumeIdSelector(range));
}
{
String text = "##";
auto tokens = CSSTokenizer(text).TokenizeToEOF();
CSSParserTokenRange range(tokens);
EXPECT_FALSE(ConsumeIdSelector(range));
}
{
String text = "10px";
auto tokens = CSSTokenizer(text).TokenizeToEOF();
CSSParserTokenRange range(tokens);
EXPECT_FALSE(ConsumeIdSelector(range));
}
}
} // namespace blink } // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment