Commit 3a6f12a2 authored by Anders Hartvoll Ruud's avatar Anders Hartvoll Ruud Committed by Commit Bot

Ribbon: Implement CustomProperty::ParseSingleValue.

This CL makes it possible to parse custom properties though the CSSProperty
API (like other properties).

We need different parsing behavior, depending on the situation:

 * kTyped: Parsed according to registered syntax. This is needed by e.g.
   CSS Typed OM.
 * kUntyped: Parsed as if unregistered. This is needed by the CSS parser,
   where registrations should just be ignored.
 * kUntypedValidated: Parsed as if unregistered, but tokens must also match
   the registered syntax. This is needed by CSS OM, where values should be
   validated against the registered syntax when arriving through
   setProperty, yet still behave as unregistered once the value has been
   accepted.

Change-Id: I656cbd63b14b2516ad6bf014e433c34b5c6a72a8
Reviewed-on: https://chromium-review.googlesource.com/c/1343103
Commit-Queue: Anders Ruud <andruud@chromium.org>
Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610008}
parent 0bcc565d
...@@ -7,7 +7,10 @@ ...@@ -7,7 +7,10 @@
namespace blink { namespace blink {
CSSParserLocalContext::CSSParserLocalContext() CSSParserLocalContext::CSSParserLocalContext()
: use_alias_parsing_(false), current_shorthand_(CSSPropertyInvalid) {} : use_alias_parsing_(false),
is_animation_tainted_(false),
current_shorthand_(CSSPropertyInvalid),
variable_mode_(VariableMode::kTyped) {}
CSSParserLocalContext CSSParserLocalContext::WithAliasParsing( CSSParserLocalContext CSSParserLocalContext::WithAliasParsing(
bool use_alias_parsing) const { bool use_alias_parsing) const {
...@@ -16,6 +19,13 @@ CSSParserLocalContext CSSParserLocalContext::WithAliasParsing( ...@@ -16,6 +19,13 @@ CSSParserLocalContext CSSParserLocalContext::WithAliasParsing(
return context; return context;
} }
CSSParserLocalContext CSSParserLocalContext::WithAnimationTainted(
bool is_animation_tainted) const {
CSSParserLocalContext context = *this;
context.is_animation_tainted_ = is_animation_tainted;
return context;
}
CSSParserLocalContext CSSParserLocalContext::WithCurrentShorthand( CSSParserLocalContext CSSParserLocalContext::WithCurrentShorthand(
CSSPropertyID current_shorthand) const { CSSPropertyID current_shorthand) const {
CSSParserLocalContext context = *this; CSSParserLocalContext context = *this;
...@@ -23,12 +33,28 @@ CSSParserLocalContext CSSParserLocalContext::WithCurrentShorthand( ...@@ -23,12 +33,28 @@ CSSParserLocalContext CSSParserLocalContext::WithCurrentShorthand(
return context; return context;
} }
CSSParserLocalContext CSSParserLocalContext::WithVariableMode(
VariableMode variable_mode) const {
CSSParserLocalContext context = *this;
context.variable_mode_ = variable_mode;
return context;
}
bool CSSParserLocalContext::UseAliasParsing() const { bool CSSParserLocalContext::UseAliasParsing() const {
return use_alias_parsing_; return use_alias_parsing_;
} }
bool CSSParserLocalContext::IsAnimationTainted() const {
return is_animation_tainted_;
}
CSSPropertyID CSSParserLocalContext::CurrentShorthand() const { CSSPropertyID CSSParserLocalContext::CurrentShorthand() const {
return current_shorthand_; return current_shorthand_;
} }
CSSParserLocalContext::VariableMode CSSParserLocalContext::GetVariableMode()
const {
return variable_mode_;
}
} // namespace blink } // namespace blink
...@@ -18,15 +18,43 @@ class CORE_EXPORT CSSParserLocalContext { ...@@ -18,15 +18,43 @@ class CORE_EXPORT CSSParserLocalContext {
public: public:
CSSParserLocalContext(); CSSParserLocalContext();
// When parsing registered custom properties, a different result is required
// depending on the context.
enum class VariableMode {
// The custom property is parsed according to the registered syntax (if
// available).
kTyped,
// The registration of the custom property (if any) is ignored; the custom
// property will parse as if unregistered.
kUntyped,
// The custom property will be parsed as if unregistered (that is,
// a CSSCustomPropertyDeclaration will be returned), but the tokens must
// also match the registered syntax (if any). This is useful for CSSOM,
// where incoming values must validate against the registered syntax, but
// are otherwise treated as unregistered.
kValidatedUntyped
};
CSSParserLocalContext WithAliasParsing(bool) const; CSSParserLocalContext WithAliasParsing(bool) const;
CSSParserLocalContext WithAnimationTainted(bool) const;
CSSParserLocalContext WithCurrentShorthand(CSSPropertyID) const; CSSParserLocalContext WithCurrentShorthand(CSSPropertyID) const;
CSSParserLocalContext WithVariableMode(VariableMode) const;
bool UseAliasParsing() const; bool UseAliasParsing() const;
// Any custom property used in a @keyframes rule becomes animation-tainted,
// which prevents the custom property from being substituted into the
// 'animation' property, or one of its longhands.
//
// https://drafts.csswg.org/css-variables/#animation-tainted
bool IsAnimationTainted() const;
CSSPropertyID CurrentShorthand() const; CSSPropertyID CurrentShorthand() const;
VariableMode GetVariableMode() const;
private: private:
bool use_alias_parsing_; bool use_alias_parsing_;
bool is_animation_tainted_;
CSSPropertyID current_shorthand_; CSSPropertyID current_shorthand_;
VariableMode variable_mode_;
}; };
} // namespace blink } // namespace blink
......
...@@ -8,9 +8,13 @@ ...@@ -8,9 +8,13 @@
namespace blink { namespace blink {
using VariableMode = CSSParserLocalContext::VariableMode;
TEST(CSSParserLocalContextTest, Constructor) { TEST(CSSParserLocalContextTest, Constructor) {
EXPECT_FALSE(CSSParserLocalContext().UseAliasParsing()); EXPECT_FALSE(CSSParserLocalContext().UseAliasParsing());
EXPECT_FALSE(CSSParserLocalContext().IsAnimationTainted());
EXPECT_EQ(CSSPropertyInvalid, CSSParserLocalContext().CurrentShorthand()); EXPECT_EQ(CSSPropertyInvalid, CSSParserLocalContext().CurrentShorthand());
EXPECT_EQ(VariableMode::kTyped, CSSParserLocalContext().GetVariableMode());
} }
TEST(CSSParserLocalContextTest, WithAliasParsing) { TEST(CSSParserLocalContextTest, WithAliasParsing) {
...@@ -19,6 +23,12 @@ TEST(CSSParserLocalContextTest, WithAliasParsing) { ...@@ -19,6 +23,12 @@ TEST(CSSParserLocalContextTest, WithAliasParsing) {
EXPECT_TRUE(context.WithAliasParsing(true).UseAliasParsing()); EXPECT_TRUE(context.WithAliasParsing(true).UseAliasParsing());
} }
TEST(CSSParserLocalContextTest, WithAnimationTainted) {
const CSSParserLocalContext context;
EXPECT_FALSE(context.WithAnimationTainted(false).IsAnimationTainted());
EXPECT_TRUE(context.WithAnimationTainted(true).IsAnimationTainted());
}
TEST(CSSParserLocalContextTest, WithCurrentShorthand) { TEST(CSSParserLocalContextTest, WithCurrentShorthand) {
const CSSParserLocalContext context; const CSSParserLocalContext context;
const CSSPropertyID shorthand = CSSPropertyBackground; const CSSPropertyID shorthand = CSSPropertyBackground;
...@@ -26,18 +36,54 @@ TEST(CSSParserLocalContextTest, WithCurrentShorthand) { ...@@ -26,18 +36,54 @@ TEST(CSSParserLocalContextTest, WithCurrentShorthand) {
context.WithCurrentShorthand(shorthand).CurrentShorthand()); context.WithCurrentShorthand(shorthand).CurrentShorthand());
} }
TEST(CSSParserLocalContextTest, WithVariableMode) {
auto mode = VariableMode::kUntyped;
auto context = CSSParserLocalContext().WithVariableMode(mode);
EXPECT_EQ(mode, context.GetVariableMode());
}
TEST(CSSParserLocalContextTest, LocalMutation) { TEST(CSSParserLocalContextTest, LocalMutation) {
CSSParserLocalContext context; CSSParserLocalContext context;
context = context.WithAliasParsing(true); context = context.WithAliasParsing(true);
context = context.WithAnimationTainted(true);
context = context.WithCurrentShorthand(CSSPropertyBackground); context = context.WithCurrentShorthand(CSSPropertyBackground);
context = context.WithVariableMode(VariableMode::kUntyped);
// WithAliasParsing only changes that member. // WithAliasParsing only changes that member.
EXPECT_EQ(CSSPropertyBackground, {
context.WithAliasParsing(false).CurrentShorthand()); auto local_context = context.WithAliasParsing(false);
EXPECT_FALSE(local_context.UseAliasParsing());
EXPECT_EQ(CSSPropertyBackground, local_context.CurrentShorthand());
EXPECT_TRUE(local_context.IsAnimationTainted());
EXPECT_EQ(VariableMode::kUntyped, local_context.GetVariableMode());
}
// WithAnimationTainted only changes that member.
{
auto local_context = context.WithAnimationTainted(false);
EXPECT_TRUE(local_context.UseAliasParsing());
EXPECT_EQ(CSSPropertyBackground, local_context.CurrentShorthand());
EXPECT_FALSE(local_context.IsAnimationTainted());
EXPECT_EQ(VariableMode::kUntyped, local_context.GetVariableMode());
}
// WithCurrentShorthand only changes that member. // WithCurrentShorthand only changes that member.
EXPECT_TRUE( {
context.WithCurrentShorthand(CSSPropertyInvalid).UseAliasParsing()); auto local_context = context.WithCurrentShorthand(CSSPropertyPadding);
EXPECT_TRUE(local_context.UseAliasParsing());
EXPECT_EQ(CSSPropertyPadding, local_context.CurrentShorthand());
EXPECT_TRUE(local_context.IsAnimationTainted());
EXPECT_EQ(VariableMode::kUntyped, local_context.GetVariableMode());
}
// WithVariableMode only changes that member.
{
auto local_context = context.WithVariableMode(VariableMode::kTyped);
EXPECT_TRUE(local_context.UseAliasParsing());
EXPECT_EQ(CSSPropertyBackground, local_context.CurrentShorthand());
EXPECT_TRUE(local_context.IsAnimationTainted());
EXPECT_EQ(VariableMode::kTyped, local_context.GetVariableMode());
}
} }
} // namespace blink } // namespace blink
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h" #include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h"
#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h" #include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
#include "third_party/blink/renderer/core/css/parser/css_variable_parser.h"
#include "third_party/blink/renderer/core/css/property_registration.h" #include "third_party/blink/renderer/core/css/property_registration.h"
#include "third_party/blink/renderer/core/css/property_registry.h" #include "third_party/blink/renderer/core/css/property_registry.h"
#include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/computed_style.h"
...@@ -80,6 +82,24 @@ void CustomProperty::ApplyValue(StyleResolverState& state, ...@@ -80,6 +82,24 @@ void CustomProperty::ApplyValue(StyleResolverState& state,
} }
} }
const CSSValue* CustomProperty::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context) const {
using VariableMode = CSSParserLocalContext::VariableMode;
switch (local_context.GetVariableMode()) {
case VariableMode::kTyped:
return ParseTyped(range, context, local_context);
case VariableMode::kUntyped:
return ParseUntyped(range, context, local_context);
case VariableMode::kValidatedUntyped:
if (registration_ && !ParseTyped(range, context, local_context))
return nullptr;
return ParseUntyped(range, context, local_context);
}
}
const CSSValue* CustomProperty::CSSValueFromComputedStyleInternal( const CSSValue* CustomProperty::CSSValueFromComputedStyleInternal(
const ComputedStyle& style, const ComputedStyle& style,
const SVGComputedStyle&, const SVGComputedStyle&,
...@@ -103,4 +123,22 @@ const CSSValue* CustomProperty::CSSValueFromComputedStyleInternal( ...@@ -103,4 +123,22 @@ const CSSValue* CustomProperty::CSSValueFromComputedStyleInternal(
return CSSCustomPropertyDeclaration::Create(name_, data); return CSSCustomPropertyDeclaration::Create(name_, data);
} }
const CSSValue* CustomProperty::ParseUntyped(
CSSParserTokenRange range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context) const {
return CSSVariableParser::ParseDeclarationValue(
name_, range, local_context.IsAnimationTainted(), context);
}
const CSSValue* CustomProperty::ParseTyped(
CSSParserTokenRange range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context) const {
if (!registration_)
return ParseUntyped(range, context, local_context);
return registration_->Syntax().Parse(range, &context,
local_context.IsAnimationTainted());
}
} // namespace blink } // namespace blink
...@@ -35,6 +35,10 @@ class CORE_EXPORT CustomProperty : public Variable { ...@@ -35,6 +35,10 @@ class CORE_EXPORT CustomProperty : public Variable {
void ApplyInherit(StyleResolverState&) const override; void ApplyInherit(StyleResolverState&) const override;
void ApplyValue(StyleResolverState&, const CSSValue&) const override; void ApplyValue(StyleResolverState&, const CSSValue&) const override;
const CSSValue* ParseSingleValue(CSSParserTokenRange&,
const CSSParserContext&,
const CSSParserLocalContext&) const override;
const CSSValue* CSSValueFromComputedStyleInternal( const CSSValue* CSSValueFromComputedStyleInternal(
const ComputedStyle&, const ComputedStyle&,
const SVGComputedStyle&, const SVGComputedStyle&,
...@@ -45,6 +49,13 @@ class CORE_EXPORT CustomProperty : public Variable { ...@@ -45,6 +49,13 @@ class CORE_EXPORT CustomProperty : public Variable {
void Trace(blink::Visitor* visitor) { visitor->Trace(registration_); } void Trace(blink::Visitor* visitor) { visitor->Trace(registration_); }
private: private:
const CSSValue* ParseUntyped(CSSParserTokenRange,
const CSSParserContext&,
const CSSParserLocalContext&) const;
const CSSValue* ParseTyped(CSSParserTokenRange,
const CSSParserContext&,
const CSSParserLocalContext&) const;
AtomicString name_; AtomicString name_;
Member<const PropertyRegistration> registration_; Member<const PropertyRegistration> registration_;
}; };
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h" #include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h" #include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_test_helpers.h" #include "third_party/blink/renderer/core/css/css_test_helpers.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h" #include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/html/html_element.h" #include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/core/testing/page_test_base.h"
...@@ -14,6 +16,7 @@ ...@@ -14,6 +16,7 @@
namespace blink { namespace blink {
using namespace css_test_helpers; using namespace css_test_helpers;
using VariableMode = CSSParserLocalContext::VariableMode;
namespace { namespace {
...@@ -31,6 +34,16 @@ class CustomPropertyTest : public PageTestBase { ...@@ -31,6 +34,16 @@ class CustomPropertyTest : public PageTestBase {
nullptr /* layout_object*/, node, nullptr /* layout_object*/, node,
false /* allow_visisted_style */); false /* allow_visisted_style */);
} }
const CSSValue* ParseValue(const Longhand& property,
const String& value,
const CSSParserLocalContext& local_context) {
CSSTokenizer tokenizer(value);
const auto tokens = tokenizer.TokenizeToEOF();
CSSParserTokenRange range(tokens);
CSSParserContext* context = CSSParserContext::Create(GetDocument());
return property.ParseSingleValue(range, *context, local_context);
}
}; };
} // namespace } // namespace
...@@ -124,4 +137,61 @@ TEST_F(CustomPropertyTest, ComputedCSSValueLateRegistration) { ...@@ -124,4 +137,61 @@ TEST_F(CustomPropertyTest, ComputedCSSValueLateRegistration) {
EXPECT_EQ("100px", value->CssText()); EXPECT_EQ("100px", value->CssText());
} }
TEST_F(CustomPropertyTest, ParseSingleValueUnregistered) {
CustomProperty property("--x", GetDocument());
const CSSValue* value =
ParseValue(property, "100px", CSSParserLocalContext());
ASSERT_TRUE(value->IsCustomPropertyDeclaration());
EXPECT_EQ("100px", value->CssText());
}
TEST_F(CustomPropertyTest, ParseSingleValueAnimationTainted) {
CustomProperty property("--x", GetDocument());
const CSSValue* value1 = ParseValue(
property, "100px", CSSParserLocalContext().WithAnimationTainted(true));
const CSSValue* value2 = ParseValue(
property, "100px", CSSParserLocalContext().WithAnimationTainted(false));
EXPECT_TRUE(
ToCSSCustomPropertyDeclaration(value1)->Value()->IsAnimationTainted());
EXPECT_FALSE(
ToCSSCustomPropertyDeclaration(value2)->Value()->IsAnimationTainted());
}
TEST_F(CustomPropertyTest, ParseSingleValueTyped) {
RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
CustomProperty property("--x", GetDocument());
const CSSValue* value1 =
ParseValue(property, "100px", CSSParserLocalContext());
EXPECT_TRUE(value1->IsPrimitiveValue());
EXPECT_EQ(100, ToCSSPrimitiveValue(value1)->GetIntValue());
const CSSValue* value2 =
ParseValue(property, "maroon", CSSParserLocalContext());
EXPECT_FALSE(value2);
}
TEST_F(CustomPropertyTest, ParseSingleValueUntyped) {
RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
CustomProperty property("--x", GetDocument());
const CSSValue* value = ParseValue(
property, "maroon",
CSSParserLocalContext().WithVariableMode(VariableMode::kUntyped));
ASSERT_TRUE(value->IsCustomPropertyDeclaration());
EXPECT_EQ("maroon", value->CssText());
}
TEST_F(CustomPropertyTest, ParseSingleValueValidatedUntyped) {
RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
CustomProperty property("--x", GetDocument());
auto local_context =
CSSParserLocalContext().WithVariableMode(VariableMode::kValidatedUntyped);
const CSSValue* value1 = ParseValue(property, "100px", local_context);
ASSERT_TRUE(value1->IsCustomPropertyDeclaration());
EXPECT_EQ("100px", value1->CssText());
const CSSValue* value2 = ParseValue(property, "maroon", local_context);
EXPECT_FALSE(value2);
}
} // 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