Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

FAIL Simple CSSOM manipulation of subrules ss.cssRules[0].insertRule is not a function. (In 'ss.cssRules[0].insertRule('& .b { color: green; }')', 'ss.cssRules[0].insertRule' is undefined)
FAIL Simple CSSOM manipulation of subrules 1 assert_throws_dom: function "() => { ss.cssRules[0].insertRule('& .broken {}', 3); }" threw object "TypeError: ss.cssRules[0].insertRule is not a function. (In 'ss.cssRules[0].insertRule('& .broken {}', 3)', 'ss.cssRules[0].insertRule' is undefined)" that is not a DOMException IndexSizeError: property "code" is equal to undefined, expected 1
FAIL Simple CSSOM manipulation of subrules 2 assert_throws_dom: function "() => { ss.cssRules[0].insertRule('& .broken {}', -1); }" threw object "TypeError: ss.cssRules[0].insertRule is not a function. (In 'ss.cssRules[0].insertRule('& .broken {}', -1)', 'ss.cssRules[0].insertRule' is undefined)" that is not a DOMException IndexSizeError: property "code" is equal to undefined, expected 1
FAIL Simple CSSOM manipulation of subrules 3 assert_throws_dom: function "() => { ss.cssRules[0].deleteRule(5); }" threw object "TypeError: ss.cssRules[0].deleteRule is not a function. (In 'ss.cssRules[0].deleteRule(5)', 'ss.cssRules[0].deleteRule' is undefined)" that is not a DOMException IndexSizeError: property "code" is equal to undefined, expected 1
FAIL Simple CSSOM manipulation of subrules 4 undefined is not an object (evaluating 'ss.cssRules[0].cssRules[2]')
FAIL Simple CSSOM manipulation of subrules 5 assert_throws_dom: function "() => { ss.cssRules[0].insertRule('% {}'); }" threw object "TypeError: ss.cssRules[0].insertRule is not a function. (In 'ss.cssRules[0].insertRule('% {}')', 'ss.cssRules[0].insertRule' is undefined)" that is not a DOMException SyntaxError: property "code" is equal to undefined, expected 12
FAIL Simple CSSOM manipulation of subrules 6 undefined is not an object (evaluating 'ss.cssRules[0].cssRules[1]')
FAIL Simple CSSOM manipulation of subrules 7 ss.cssRules[0].insertRule is not a function. (In 'ss.cssRules[0].insertRule('@supports selector(&) { & div { font-size: 10px; }}', 1)', 'ss.cssRules[0].insertRule' is undefined)
FAIL Simple CSSOM manipulation of subrules 8 assert_equals: color is changed, new rule is ignored expected ".a {\n color: olivedrab;\n & .b { color: green; }\n & .c { color: blue; }\n}" but got ".a {\n color: olivedrab;& .b { color: green; }\n}& .c { color: blue; }\n}"
FAIL Simple CSSOM manipulation of subrules 9 undefined is not an object (evaluating 'ss.cssRules[0].cssRules[0]')
PASS Simple CSSOM manipulation of subrules
PASS Simple CSSOM manipulation of subrules 1
PASS Simple CSSOM manipulation of subrules 2
PASS Simple CSSOM manipulation of subrules 3
PASS Simple CSSOM manipulation of subrules 4
PASS Simple CSSOM manipulation of subrules 5
PASS Simple CSSOM manipulation of subrules 6
FAIL Simple CSSOM manipulation of subrules 7 assert_equals: @supports is added expected ".a {\n color: red;\n & .b { color: green; }\n @supports selector(&) {\n & div { font-size: 10px; }\n}\n & .c { color: blue; }\n}" but got ".a {\n color: red;\n & .b { color: green; }\n @supports selector(&) {\n}\n & .c { color: blue; }\n}"
FAIL Simple CSSOM manipulation of subrules 8 assert_equals: color is changed, new rule is ignored expected ".a {\n color: olivedrab;\n & .b { color: green; }\n & .c { color: blue; }\n}" but got ".a {\n color: olivedrab;\n & .b { color: green; }\n @supports selector(&) {\n}\n & .c { color: blue; }\n}"
FAIL Simple CSSOM manipulation of subrules 9 assert_throws_dom: function "() => { ss.cssRules[0].insertRule('div & {}'); }" did not throw
FAIL Simple CSSOM manipulation of subrules 10 assert_equals: invalid rule containing ampersand is kept in serialization expected ".a {\n :is(!& .foo, .b) { color: green; }\n}" but got ".a {\n :is(.b) { color: green; }\n}"

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

PASS Simple CSSOM manipulation of subrules
FAIL Simple CSSOM manipulation of subrules 1 assert_throws_dom: function "() => { ss.cssRules[0].cssRules[0].insertRule('@font-face {}', 0); }" threw object "TypeError: undefined is not an object (evaluating 'ss.cssRules[0].cssRules[0]')" that is not a DOMException HierarchyRequestError: property "code" is equal to undefined, expected 3
FAIL Simple CSSOM manipulation of subrules assert_equals: expected "div {\n @media screen {\n &.a { color: red; }\n}\n}" but got "div {\n @media screen {\n :is(div).a { color: red; }\n}\n}"
FAIL Simple CSSOM manipulation of subrules 1 assert_equals: expected "div {\n @media screen {\n &.a { color: red; }\n}\n}" but got "div {\n @media screen {\n :is(div).a { color: red; }\n}\n}"

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

FAIL .foo { & { color: green; } } assert_equals: expected ".foo { color: green; }" but got ".foo {\n & { color: green; }\n}"
PASS .foo { & { color: green; } }
PASS .foo { //color: red; color: green; }
PASS .foo {
&.bar { color: green; }
Expand Down Expand Up @@ -43,14 +43,14 @@ PASS .foo, .bar {
PASS .foo {
& .bar & .baz & .qux { color: green; }
}
FAIL .foo {
PASS .foo {
@media (min-width: 50px) {
& { color: green; }
}
} assert_equals: expected ".foo {\n @media (min-width: 50px) { color: green; }\n}" but got ".foo {\n @media (min-width: 50px) {\n & { color: green; }\n}\n}"
FAIL .foo {
}
PASS .foo {
@media (min-width: 50px) { color: green; }
} assert_equals: expected ".foo {\n @media (min-width: 50px) { color: green; }\n}" but got ".foo {\n @media (min-width: 50px) {\n & { color: green; }\n}\n}"
}
PASS main {
& > section, & > article {
& > header { color: green; }
Expand All @@ -67,9 +67,9 @@ PASS .foo {
PASS .foo {
color: red; ident { color: green; }
}
FAIL .foo {
PASS .foo {
//color: comment; & { color: green; }
} assert_equals: expected ".foo { color: green; }" but got ".foo {\n & { color: green; }\n}"
}
PASS .foo {
.bar {
functionalnotation(div) { color: green; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

FAIL Serialization of declarations in group rules assert_equals: expected "div {\n @media screen { color: red; background-color: green; }\n}" but got "div {\n @media screen {\n & { color: red; background-color: green; }\n}\n}"
FAIL Serialization of declarations in group rules 1 assert_equals: expected "div {\n @supports selector(&) {\n color: red; background-color: green;\n &:hover { color: navy; }\n}\n}" but got "div {\n @supports selector(&) {\n & { color: red; background-color: green; }\n &:hover { color: navy; }\n}\n}"
FAIL Serialization of declarations in group rules 2 assert_equals: expected "div {\n @media screen { color: red; }\n}" but got "div {\n @media screen {\n & { color: red; }\n}\n}"
FAIL Serialization of declarations in group rules 3 assert_equals: expected "div { color: red; }" but got "div {\n & { color: red; }\n}"
PASS Serialization of declarations in group rules
FAIL Serialization of declarations in group rules 1 assert_equals: expected "div {\n @supports selector(&) {\n color: red; background-color: green;\n &:hover { color: navy; }\n}\n}" but got "div {\n @supports selector(&) {\ncolor: red; background-color: green;\n &:hover { color: navy; }\n}\n}"
FAIL Serialization of declarations in group rules 2 assert_equals: expected "div {\n @media screen {\n &.cls { color: red; }\n & { color: red; }\n}\n}" but got "div {\n @media screen {\ncolor: red;\n &.cls { color: red; }\n}\n}"
PASS Serialization of declarations in group rules 3
PASS Serialization of declarations in group rules 4

2 changes: 1 addition & 1 deletion Source/WebCore/css/CSSConditionRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

namespace WebCore {

CSSConditionRule::CSSConditionRule(StyleRuleGroup& group, CSSStyleSheet* parent)
CSSConditionRule::CSSConditionRule(StyleRuleBase& group, CSSStyleSheet* parent)
: CSSGroupingRule(group, parent)
{
}
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/css/CSSConditionRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class CSSConditionRule : public CSSGroupingRule {
virtual String conditionText() const = 0;

protected:
CSSConditionRule(StyleRuleGroup&, CSSStyleSheet* parent);
CSSConditionRule(StyleRuleBase&, CSSStyleSheet* parent);
};

} // namespace WebCore
2 changes: 1 addition & 1 deletion Source/WebCore/css/CSSContainerRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Ref<CSSContainerRule> CSSContainerRule::create(StyleRuleContainer& rule, CSSStyl

const StyleRuleContainer& CSSContainerRule::styleRuleContainer() const
{
return downcast<StyleRuleContainer>(groupRule());
return downcast<StyleRuleContainer>(rule());
}

String CSSContainerRule::cssText() const
Expand Down
80 changes: 57 additions & 23 deletions Source/WebCore/css/CSSGroupingRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,17 @@

namespace WebCore {

CSSGroupingRule::CSSGroupingRule(StyleRuleGroup& groupRule, CSSStyleSheet* parent)
CSSGroupingRule::CSSGroupingRule(StyleRuleBase& rule, CSSStyleSheet* parent)
: CSSRule(parent)
, m_groupRule(groupRule)
, m_childRuleCSSOMWrappers(groupRule.childRules().size())
, m_groupRule(rule)
, m_childRuleCSSOMWrappers(groupRule().childRules().size())
{
ASSERT(rule.isGroupRule());
}

CSSGroupingRule::~CSSGroupingRule()
{
ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size());
ASSERT(m_childRuleCSSOMWrappers.size() == groupRule().childRules().size());
for (auto& wrapper : m_childRuleCSSOMWrappers) {
if (wrapper)
wrapper->setParentRule(nullptr);
Expand All @@ -58,15 +59,17 @@ CSSGroupingRule::~CSSGroupingRule()

ExceptionOr<unsigned> CSSGroupingRule::insertRule(const String& ruleString, unsigned index)
{
ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size());
ASSERT(m_childRuleCSSOMWrappers.size() == groupRule().childRules().size());

if (index > m_groupRule->childRules().size()) {
if (index > groupRule().childRules().size()) {
// IndexSizeError: Raised if the specified index is not a valid insertion point.
return Exception { IndexSizeError };
}

auto allowInsertingNestedRule = styleRuleType() == StyleRuleType::Style || hasStyleRuleAscendant();
auto isNestedContext = allowInsertingNestedRule ? CSSParserEnum::IsNestedContext::Yes : CSSParserEnum::IsNestedContext::No;
CSSStyleSheet* styleSheet = parentStyleSheet();
RefPtr<StyleRuleBase> newRule = CSSParser::parseRule(parserContext(), styleSheet ? &styleSheet->contents() : nullptr, ruleString);
RefPtr<StyleRuleBase> newRule = CSSParser::parseRule(parserContext(), styleSheet ? &styleSheet->contents() : nullptr, ruleString, isNestedContext);
if (!newRule) {
// SyntaxError: Raised if the specified rule has a syntax error and is unparsable.
return Exception { SyntaxError };
Expand All @@ -82,30 +85,33 @@ ExceptionOr<unsigned> CSSGroupingRule::insertRule(const String& ruleString, unsi
// at-rule.
return Exception { HierarchyRequestError };
}
CSSStyleSheet::RuleMutationScope mutationScope(this);

m_groupRule->wrapperInsertRule(index, newRule.releaseNonNull());
if (allowInsertingNestedRule && (!newRule->isStyleRule() && !newRule->isGroupRule()))
return Exception { HierarchyRequestError };

CSSStyleSheet::RuleMutationScope mutationScope(this);
groupRule().wrapperInsertRule(index, newRule.releaseNonNull());

m_childRuleCSSOMWrappers.insert(index, RefPtr<CSSRule>());
return index;
}

ExceptionOr<void> CSSGroupingRule::deleteRule(unsigned index)
{
ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size());
ASSERT(m_childRuleCSSOMWrappers.size() == groupRule().childRules().size());

if (index >= m_groupRule->childRules().size()) {
if (index >= groupRule().childRules().size()) {
// IndexSizeError: Raised if the specified index does not correspond to a
// rule in the media rule list.
return Exception { IndexSizeError };
}

CSSStyleSheet::RuleMutationScope mutationScope(this);

m_groupRule->wrapperRemoveRule(index);
groupRule().wrapperRemoveRule(index);

if (m_childRuleCSSOMWrappers[index])
m_childRuleCSSOMWrappers[index]->setParentRule(0);
m_childRuleCSSOMWrappers[index]->setParentRule(nullptr);
m_childRuleCSSOMWrappers.remove(index);

return { };
Expand Down Expand Up @@ -138,30 +144,45 @@ void CSSGroupingRule::appendCSSTextForItems(StringBuilder& builder) const
return;
}

void CSSGroupingRule::cssTextForDeclsAndRules(StringBuilder&, StringBuilder& rules) const
void CSSGroupingRule::cssTextForDeclsAndRules(StringBuilder& decls, StringBuilder& rules) const
{
auto& childRules = m_groupRule->childRules();

auto& childRules = groupRule().childRules();
for (unsigned index = 0 ; index < childRules.size() ; index++) {
// We put the declarations at the upper level when the rule:
// - is a style rule
// - has just "&" as selector
// - has no child rules
auto childRule = childRules[index];
ASSERT(childRule);
if (childRule->isStyleRuleWithNesting()) {
auto& nestedStyleRule = downcast<StyleRuleWithNesting>(*childRule);
if (nestedStyleRule.originalSelectorList().isNestingSelector() && nestedStyleRule.childRules().isEmpty()) {
decls.append(nestedStyleRule.properties().asText());
continue;
}
}
// Otherwise we print the child rule
auto wrappedRule = item(index);
rules.append("\n ", wrappedRule->cssText());
}

}

unsigned CSSGroupingRule::length() const
{
return m_groupRule->childRules().size();
return groupRule().childRules().size();
}

CSSRule* CSSGroupingRule::item(unsigned index) const
{
if (index >= length())
return nullptr;
ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size());
ASSERT(m_childRuleCSSOMWrappers.size() == groupRule().childRules().size());
auto& rule = m_childRuleCSSOMWrappers[index];
if (!rule)
rule = m_groupRule->childRules()[index]->createCSSOMWrapper(const_cast<CSSGroupingRule&>(*this));
if (!rule) {
auto parent = parentStyleSheet();
parent->transformStyleRuleToNesting();
rule = groupRule().childRules()[index]->createCSSOMWrapper(const_cast<CSSGroupingRule&>(*this));
}
return rule.get();
}

Expand All @@ -174,11 +195,24 @@ CSSRuleList& CSSGroupingRule::cssRules() const

void CSSGroupingRule::reattach(StyleRuleBase& rule)
{
m_groupRule = downcast<StyleRuleGroup>(rule);
ASSERT(rule.isGroupRule());
m_groupRule = rule;
for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) {
if (m_childRuleCSSOMWrappers[i])
m_childRuleCSSOMWrappers[i]->reattach(*m_groupRule.get().childRules()[i]);
m_childRuleCSSOMWrappers[i]->reattach(*groupRule().childRules()[i]);
}
}

const StyleRuleGroup& CSSGroupingRule::groupRule() const
{
auto group = StyleRuleGroup::fromStyleRuleBase(m_groupRule);
ASSERT(group);
return *group;
}

StyleRuleGroup& CSSGroupingRule::groupRule()
{
return const_cast<StyleRuleGroup&>(const_cast<const CSSGroupingRule&>(*this).groupRule());
}

} // namespace WebCore
9 changes: 5 additions & 4 deletions Source/WebCore/css/CSSGroupingRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,18 @@ class CSSGroupingRule : public CSSRule {
CSSRule* item(unsigned index) const;

protected:
CSSGroupingRule(StyleRuleGroup&, CSSStyleSheet* parent);
const StyleRuleGroup& groupRule() const { return m_groupRule; }
StyleRuleGroup& groupRule() { return m_groupRule; }
CSSGroupingRule(StyleRuleBase&, CSSStyleSheet* parent);
const StyleRuleGroup& groupRule() const;
StyleRuleGroup& groupRule();
StyleRuleBase& rule() const { return m_groupRule; }
void reattach(StyleRuleBase&) override;
void appendCSSTextForItems(StringBuilder&) const;

// https://drafts.csswg.org/cssom/#serialize-a-css-rule
void cssTextForDeclsAndRules(StringBuilder& decls, StringBuilder& rules) const;

private:
Ref<StyleRuleGroup> m_groupRule;
Ref<StyleRuleBase> m_groupRule;
mutable Vector<RefPtr<CSSRule>> m_childRuleCSSOMWrappers;
mutable std::unique_ptr<CSSRuleList> m_ruleListCSSOMWrapper;
};
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/css/CSSLayerBlockRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ String CSSLayerBlockRule::cssText() const

String CSSLayerBlockRule::name() const
{
auto& layer = downcast<StyleRuleLayer>(groupRule());
auto& layer = downcast<StyleRuleLayer>(rule());

if (layer.name().isEmpty())
return emptyString();
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/css/CSSMediaRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ CSSMediaRule::~CSSMediaRule()

const MQ::MediaQueryList& CSSMediaRule::mediaQueries() const
{
return downcast<StyleRuleMedia>(groupRule()).mediaQueries();
return downcast<StyleRuleMedia>(rule()).mediaQueries();
}

void CSSMediaRule::setMediaQueries(MQ::MediaQueryList&& queries)
{
downcast<StyleRuleMedia>(groupRule()).setMediaQueries(WTFMove(queries));
downcast<StyleRuleMedia>(rule()).setMediaQueries(WTFMove(queries));
}

String CSSMediaRule::cssText() const
Expand Down
13 changes: 13 additions & 0 deletions Source/WebCore/css/CSSRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,17 @@ const CSSParserContext& CSSRule::parserContext() const
return styleSheet ? styleSheet->contents().parserContext() : strictCSSParserContext();
}


bool CSSRule::hasStyleRuleAscendant() const
{
auto current = this->parentRule();
while (current) {
if (current->styleRuleType() == StyleRuleType::Style)
return true;

current = current->parentRule();
}
return false;
}

} // namespace WebCore
1 change: 1 addition & 0 deletions Source/WebCore/css/CSSRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class CSSRule : public RefCounted<CSSRule> {

bool hasCachedSelectorText() const { return m_hasCachedSelectorText; }
void setHasCachedSelectorText(bool hasCachedSelectorText) const { m_hasCachedSelectorText = hasCachedSelectorText; }
bool hasStyleRuleAscendant() const;

const CSSParserContext& parserContext() const;

Expand Down
18 changes: 18 additions & 0 deletions Source/WebCore/css/CSSSelectorList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,22 @@ bool CSSSelectorList::hasExplicitNestingParent() const

return forEachSelector(functor, this);
}

bool CSSSelectorList::isNestingSelector() const
{
if (componentCount() != 1)
return false;

auto singleSelector = first();

if (!singleSelector)
return false;

// Selector should be a single selector
if (singleSelector->tagHistory())
return false;

return singleSelector->match() == CSSSelector::Match::PseudoClass && singleSelector->pseudoClassType() == CSSSelector::PseudoClassType::PseudoClassNestingParent;
}

} // namespace WebCore
1 change: 1 addition & 0 deletions Source/WebCore/css/CSSSelectorList.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class CSSSelectorList {
bool selectorsNeedNamespaceResolution();
bool hasInvalidSelector() const;
bool hasExplicitNestingParent() const;
bool isNestingSelector() const;

String selectorsText() const;
void buildSelectorsText(StringBuilder&) const;
Expand Down
Loading