Commit 830bbee9 authored by timloh@chromium.org's avatar timloh@chromium.org

CSSStyleSheet::insertRule should respect the default namespace

This patch fixes CSSStyleSheet::insertRule to respect the default
namespace a stylesheet. The default namespace is currently only stored
during initial parsing of a stylesheet, so this moves the value to be
stored on the StyleSheetContents. This is stored separately to the rest
of the namespaces to avoid an extra hash map lookup, but could probably
be added to the m_namespaces map keyed off a null AtomicString.

The added test passes in FF and IE, but fails in Safari.

Review URL: https://codereview.chromium.org/1322543004

git-svn-id: svn://svn.chromium.org/blink/trunk@201712 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 050985bf
<!doctype html>
<style>
@namespace url(banana);
*|div {
width: 100px;
height: 100px;
background-color: green;
}
</style>
<div id=target></div>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script>
test(function(){
document.styleSheets[0].insertRule('#target { background-color: red; }', 1);
assert_equals(getComputedStyle(target).backgroundColor, 'rgb(0, 128, 0)');
}, "CSSStyleSheet::insertRule should respect default namespaces");
</script>
...@@ -60,6 +60,7 @@ unsigned StyleSheetContents::estimatedSizeInBytes() const ...@@ -60,6 +60,7 @@ unsigned StyleSheetContents::estimatedSizeInBytes() const
StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context) StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context)
: m_ownerRule(ownerRule) : m_ownerRule(ownerRule)
, m_originalURL(originalURL) , m_originalURL(originalURL)
, m_defaultNamespace(starAtom)
, m_hasSyntacticallyValidCSSHeader(true) , m_hasSyntacticallyValidCSSHeader(true)
, m_didLoadErrorOccur(false) , m_didLoadErrorOccur(false)
, m_isMutable(false) , m_isMutable(false)
...@@ -77,6 +78,7 @@ StyleSheetContents::StyleSheetContents(const StyleSheetContents& o) ...@@ -77,6 +78,7 @@ StyleSheetContents::StyleSheetContents(const StyleSheetContents& o)
, m_importRules(o.m_importRules.size()) , m_importRules(o.m_importRules.size())
, m_childRules(o.m_childRules.size()) , m_childRules(o.m_childRules.size())
, m_namespaces(o.m_namespaces) , m_namespaces(o.m_namespaces)
, m_defaultNamespace(o.m_defaultNamespace)
, m_hasSyntacticallyValidCSSHeader(o.m_hasSyntacticallyValidCSSHeader) , m_hasSyntacticallyValidCSSHeader(o.m_hasSyntacticallyValidCSSHeader)
, m_didLoadErrorOccur(false) , m_didLoadErrorOccur(false)
, m_isMutable(false) , m_isMutable(false)
...@@ -258,8 +260,11 @@ void StyleSheetContents::wrapperDeleteRule(unsigned index) ...@@ -258,8 +260,11 @@ void StyleSheetContents::wrapperDeleteRule(unsigned index)
void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, const AtomicString& uri) void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, const AtomicString& uri)
{ {
if (uri.isNull() || prefix.isNull()) ASSERT(!uri.isNull());
if (prefix.isNull()) {
m_defaultNamespace = uri;
return; return;
}
PrefixNamespaceURIMap::AddResult result = m_namespaces.add(prefix, uri); PrefixNamespaceURIMap::AddResult result = m_namespaces.add(prefix, uri);
if (result.isNewEntry) if (result.isNewEntry)
return; return;
......
...@@ -64,6 +64,7 @@ public: ...@@ -64,6 +64,7 @@ public:
const CSSParserContext& parserContext() const { return m_parserContext; } const CSSParserContext& parserContext() const { return m_parserContext; }
const AtomicString& defaultNamespace() { return m_defaultNamespace; }
const AtomicString& determineNamespace(const AtomicString& prefix); const AtomicString& determineNamespace(const AtomicString& prefix);
void parseAuthorStyleSheet(const CSSStyleSheetResource*, const SecurityOrigin*); void parseAuthorStyleSheet(const CSSStyleSheetResource*, const SecurityOrigin*);
...@@ -174,6 +175,7 @@ private: ...@@ -174,6 +175,7 @@ private:
WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>> m_childRules; WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>> m_childRules;
typedef HashMap<AtomicString, AtomicString> PrefixNamespaceURIMap; typedef HashMap<AtomicString, AtomicString> PrefixNamespaceURIMap;
PrefixNamespaceURIMap m_namespaces; PrefixNamespaceURIMap m_namespaces;
AtomicString m_defaultNamespace;
bool m_hasSyntacticallyValidCSSHeader : 1; bool m_hasSyntacticallyValidCSSHeader : 1;
bool m_didLoadErrorOccur : 1; bool m_didLoadErrorOccur : 1;
......
...@@ -33,7 +33,7 @@ void CSSParser::parseDeclarationListForInspector(const CSSParserContext& context ...@@ -33,7 +33,7 @@ void CSSParser::parseDeclarationListForInspector(const CSSParserContext& context
void CSSParser::parseSelector(const CSSParserContext& context, const String& selector, CSSSelectorList& selectorList) void CSSParser::parseSelector(const CSSParserContext& context, const String& selector, CSSSelectorList& selectorList)
{ {
CSSTokenizer::Scope scope(selector); CSSTokenizer::Scope scope(selector);
CSSSelectorParser::parseSelector(scope.tokenRange(), context, starAtom, nullptr, selectorList); CSSSelectorParser::parseSelector(scope.tokenRange(), context, nullptr, selectorList);
} }
PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParser::parseRule(const CSSParserContext& context, StyleSheetContents* styleSheet, const String& rule) PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParser::parseRule(const CSSParserContext& context, StyleSheetContents* styleSheet, const String& rule)
......
...@@ -31,7 +31,6 @@ namespace blink { ...@@ -31,7 +31,6 @@ namespace blink {
CSSParserImpl::CSSParserImpl(const CSSParserContext& context, StyleSheetContents* styleSheet) CSSParserImpl::CSSParserImpl(const CSSParserContext& context, StyleSheetContents* styleSheet)
: m_context(context) : m_context(context)
, m_defaultNamespace(starAtom)
, m_styleSheet(styleSheet) , m_styleSheet(styleSheet)
, m_observerWrapper(nullptr) , m_observerWrapper(nullptr)
{ {
...@@ -389,8 +388,6 @@ PassRefPtrWillBeRawPtr<StyleRuleNamespace> CSSParserImpl::consumeNamespaceRule(C ...@@ -389,8 +388,6 @@ PassRefPtrWillBeRawPtr<StyleRuleNamespace> CSSParserImpl::consumeNamespaceRule(C
if (uri.isNull() || !prelude.atEnd()) if (uri.isNull() || !prelude.atEnd())
return nullptr; // Parse error, expected string or URI return nullptr; // Parse error, expected string or URI
if (namespacePrefix.isNull())
m_defaultNamespace = uri;
return StyleRuleNamespace::create(namespacePrefix, uri); return StyleRuleNamespace::create(namespacePrefix, uri);
} }
...@@ -539,7 +536,7 @@ PassRefPtrWillBeRawPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTo ...@@ -539,7 +536,7 @@ PassRefPtrWillBeRawPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTo
OwnPtr<CSSParserSelector> selector; OwnPtr<CSSParserSelector> selector;
if (!typeSelector.isNull() && pseudo.isNull()) { if (!typeSelector.isNull() && pseudo.isNull()) {
selector = CSSParserSelector::create(QualifiedName(nullAtom, typeSelector, m_defaultNamespace)); selector = CSSParserSelector::create(QualifiedName(nullAtom, typeSelector, m_styleSheet->defaultNamespace()));
} else { } else {
selector = CSSParserSelector::create(); selector = CSSParserSelector::create();
if (!pseudo.isNull()) { if (!pseudo.isNull()) {
...@@ -549,7 +546,7 @@ PassRefPtrWillBeRawPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTo ...@@ -549,7 +546,7 @@ PassRefPtrWillBeRawPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTo
return nullptr; // Parse error; unknown page pseudo-class return nullptr; // Parse error; unknown page pseudo-class
} }
if (!typeSelector.isNull()) if (!typeSelector.isNull())
selector->prependTagSelector(QualifiedName(nullAtom, typeSelector, m_defaultNamespace)); selector->prependTagSelector(QualifiedName(nullAtom, typeSelector, m_styleSheet->defaultNamespace()));
} }
if (m_observerWrapper) { if (m_observerWrapper) {
...@@ -602,7 +599,7 @@ static void observeSelectors(CSSParserObserverWrapper& wrapper, CSSParserTokenRa ...@@ -602,7 +599,7 @@ static void observeSelectors(CSSParserObserverWrapper& wrapper, CSSParserTokenRa
PassRefPtrWillBeRawPtr<StyleRule> CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block) PassRefPtrWillBeRawPtr<StyleRule> CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
{ {
CSSSelectorList selectorList; CSSSelectorList selectorList;
CSSSelectorParser::parseSelector(prelude, m_context, m_defaultNamespace, m_styleSheet, selectorList); CSSSelectorParser::parseSelector(prelude, m_context, m_styleSheet, selectorList);
if (!selectorList.isValid()) if (!selectorList.isValid())
return nullptr; // Parse error, invalid selector list return nullptr; // Parse error, invalid selector list
......
...@@ -84,7 +84,7 @@ private: ...@@ -84,7 +84,7 @@ private:
static PassRefPtrWillBeRawPtr<StyleRuleCharset> consumeCharsetRule(CSSParserTokenRange prelude); static PassRefPtrWillBeRawPtr<StyleRuleCharset> consumeCharsetRule(CSSParserTokenRange prelude);
PassRefPtrWillBeRawPtr<StyleRuleImport> consumeImportRule(CSSParserTokenRange prelude); PassRefPtrWillBeRawPtr<StyleRuleImport> consumeImportRule(CSSParserTokenRange prelude);
PassRefPtrWillBeRawPtr<StyleRuleNamespace> consumeNamespaceRule(CSSParserTokenRange prelude); // This can set m_defaultNamespace PassRefPtrWillBeRawPtr<StyleRuleNamespace> consumeNamespaceRule(CSSParserTokenRange prelude);
PassRefPtrWillBeRawPtr<StyleRuleMedia> consumeMediaRule(CSSParserTokenRange prelude, CSSParserTokenRange block); PassRefPtrWillBeRawPtr<StyleRuleMedia> consumeMediaRule(CSSParserTokenRange prelude, CSSParserTokenRange block);
PassRefPtrWillBeRawPtr<StyleRuleSupports> consumeSupportsRule(CSSParserTokenRange prelude, CSSParserTokenRange block); PassRefPtrWillBeRawPtr<StyleRuleSupports> consumeSupportsRule(CSSParserTokenRange prelude, CSSParserTokenRange block);
PassRefPtrWillBeRawPtr<StyleRuleViewport> consumeViewportRule(CSSParserTokenRange prelude, CSSParserTokenRange block); PassRefPtrWillBeRawPtr<StyleRuleViewport> consumeViewportRule(CSSParserTokenRange prelude, CSSParserTokenRange block);
...@@ -106,7 +106,6 @@ private: ...@@ -106,7 +106,6 @@ private:
WillBeHeapVector<CSSProperty, 256> m_parsedProperties; WillBeHeapVector<CSSProperty, 256> m_parsedProperties;
CSSParserContext m_context; CSSParserContext m_context;
AtomicString m_defaultNamespace;
RawPtrWillBeMember<StyleSheetContents> m_styleSheet; RawPtrWillBeMember<StyleSheetContents> m_styleSheet;
// For the inspector // For the inspector
......
...@@ -50,9 +50,9 @@ static void recordSelectorStats(const CSSParserContext& context, const CSSSelect ...@@ -50,9 +50,9 @@ static void recordSelectorStats(const CSSParserContext& context, const CSSSelect
} }
} }
void CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParserContext& context, const AtomicString& defaultNamespace, StyleSheetContents* styleSheet, CSSSelectorList& output) void CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParserContext& context, StyleSheetContents* styleSheet, CSSSelectorList& output)
{ {
CSSSelectorParser parser(context, defaultNamespace, styleSheet); CSSSelectorParser parser(context, styleSheet);
range.consumeWhitespace(); range.consumeWhitespace();
CSSSelectorList result; CSSSelectorList result;
parser.consumeComplexSelectorList(range, result); parser.consumeComplexSelectorList(range, result);
...@@ -63,9 +63,8 @@ void CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParser ...@@ -63,9 +63,8 @@ void CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParser
ASSERT(!(output.isValid() && parser.m_failedParsing)); ASSERT(!(output.isValid() && parser.m_failedParsing));
} }
CSSSelectorParser::CSSSelectorParser(const CSSParserContext& context, const AtomicString& defaultNamespace, StyleSheetContents* styleSheet) CSSSelectorParser::CSSSelectorParser(const CSSParserContext& context, StyleSheetContents* styleSheet)
: m_context(context) : m_context(context)
, m_defaultNamespace(defaultNamespace)
, m_styleSheet(styleSheet) , m_styleSheet(styleSheet)
, m_failedParsing(false) , m_failedParsing(false)
{ {
...@@ -162,7 +161,7 @@ PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeCompoundSelector(CSSPars ...@@ -162,7 +161,7 @@ PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeCompoundSelector(CSSPars
if (!compoundSelector) { if (!compoundSelector) {
if (hasNamespace) if (hasNamespace)
return CSSParserSelector::create(determineNameInNamespace(namespacePrefix, elementName)); return CSSParserSelector::create(determineNameInNamespace(namespacePrefix, elementName));
return CSSParserSelector::create(QualifiedName(nullAtom, elementName, m_defaultNamespace)); return CSSParserSelector::create(QualifiedName(nullAtom, elementName, defaultNamespace()));
} }
prependTypeSelectorIfNeeded(namespacePrefix, elementName, compoundSelector.get()); prependTypeSelectorIfNeeded(namespacePrefix, elementName, compoundSelector.get());
return compoundSelector.release(); return compoundSelector.release();
...@@ -536,20 +535,27 @@ bool CSSSelectorParser::consumeANPlusB(CSSParserTokenRange& range, std::pair<int ...@@ -536,20 +535,27 @@ bool CSSSelectorParser::consumeANPlusB(CSSParserTokenRange& range, std::pair<int
return true; return true;
} }
const AtomicString& CSSSelectorParser::defaultNamespace() const
{
if (!m_styleSheet)
return starAtom;
return m_styleSheet->defaultNamespace();
}
QualifiedName CSSSelectorParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName) QualifiedName CSSSelectorParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
{ {
if (!m_styleSheet) if (!m_styleSheet)
return QualifiedName(prefix, localName, m_defaultNamespace); return QualifiedName(prefix, localName, defaultNamespace());
return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix)); return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
} }
void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector) void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector)
{ {
if (elementName.isNull() && m_defaultNamespace == starAtom && !compoundSelector->crossesTreeScopes()) if (elementName.isNull() && defaultNamespace() == starAtom && !compoundSelector->crossesTreeScopes())
return; return;
AtomicString determinedElementName = elementName.isNull() ? starAtom : elementName; AtomicString determinedElementName = elementName.isNull() ? starAtom : elementName;
AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace; AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : defaultNamespace();
QualifiedName tag(namespacePrefix, determinedElementName, determinedNamespace); QualifiedName tag(namespacePrefix, determinedElementName, determinedNamespace);
if (compoundSelector->crossesTreeScopes()) if (compoundSelector->crossesTreeScopes())
......
...@@ -19,12 +19,12 @@ class StyleSheetContents; ...@@ -19,12 +19,12 @@ class StyleSheetContents;
class CORE_EXPORT CSSSelectorParser { class CORE_EXPORT CSSSelectorParser {
STACK_ALLOCATED(); STACK_ALLOCATED();
public: public:
static void parseSelector(CSSParserTokenRange, const CSSParserContext&, const AtomicString& defaultNamespace, StyleSheetContents*, CSSSelectorList&); static void parseSelector(CSSParserTokenRange, const CSSParserContext&, StyleSheetContents*, CSSSelectorList&);
static bool consumeANPlusB(CSSParserTokenRange&, std::pair<int, int>&); static bool consumeANPlusB(CSSParserTokenRange&, std::pair<int, int>&);
private: private:
CSSSelectorParser(const CSSParserContext&, const AtomicString& defaultNamespace, StyleSheetContents*); CSSSelectorParser(const CSSParserContext&, StyleSheetContents*);
// These will all consume trailing comments if successful // These will all consume trailing comments if successful
...@@ -48,6 +48,7 @@ private: ...@@ -48,6 +48,7 @@ private:
CSSSelector::Match consumeAttributeMatch(CSSParserTokenRange&); CSSSelector::Match consumeAttributeMatch(CSSParserTokenRange&);
CSSSelector::AttributeMatchType consumeAttributeFlags(CSSParserTokenRange&); CSSSelector::AttributeMatchType consumeAttributeFlags(CSSParserTokenRange&);
const AtomicString& defaultNamespace() const;
QualifiedName determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName); QualifiedName determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName);
void prependTypeSelectorIfNeeded(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector*); void prependTypeSelectorIfNeeded(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector*);
void rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, CSSParserSelector*, bool tagIsImplicit); void rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, CSSParserSelector*, bool tagIsImplicit);
...@@ -55,7 +56,6 @@ private: ...@@ -55,7 +56,6 @@ private:
static PassOwnPtr<CSSParserSelector> addSimpleSelectorToCompound(PassOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpleSelector); static PassOwnPtr<CSSParserSelector> addSimpleSelectorToCompound(PassOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpleSelector);
const CSSParserContext& m_context; const CSSParserContext& m_context;
AtomicString m_defaultNamespace;
RawPtrWillBeMember<StyleSheetContents> m_styleSheet; // FIXME: Should be const RawPtrWillBeMember<StyleSheetContents> m_styleSheet; // FIXME: Should be const
bool m_failedParsing; bool m_failedParsing;
......
...@@ -113,10 +113,12 @@ TEST(CSSSelectorParserTest, InvalidANPlusB) ...@@ -113,10 +113,12 @@ TEST(CSSSelectorParserTest, InvalidANPlusB)
} }
} }
TEST(CSSSelectorParserTest, ContentPseudoInCompound) TEST(CSSSelectorParserTest, ShadowDomPseudoInCompound)
{ {
const char* testCases[][2] = { const char* testCases[][2] = {
{ "::content", "*::content" }, // crbug.com/478969 { "::shadow", "*::shadow" }, // crbug.com/478969
{ ".a::shadow", ".a::shadow" },
{ "::content", "::content" },
{ ".a::content", ".a::content" }, { ".a::content", ".a::content" },
{ "::content.a", ".a::content" }, { "::content.a", ".a::content" },
{ "::content.a.b", ".b.a::content" }, { "::content.a.b", ".b.a::content" },
...@@ -128,7 +130,7 @@ TEST(CSSSelectorParserTest, ContentPseudoInCompound) ...@@ -128,7 +130,7 @@ TEST(CSSSelectorParserTest, ContentPseudoInCompound)
CSSTokenizer::Scope scope(testCases[i][0]); CSSTokenizer::Scope scope(testCases[i][0]);
CSSParserTokenRange range = scope.tokenRange(); CSSParserTokenRange range = scope.tokenRange();
CSSSelectorList list; CSSSelectorList list;
CSSSelectorParser::parseSelector(range, CSSParserContext(HTMLStandardMode, nullptr), nullAtom, nullptr, list); CSSSelectorParser::parseSelector(range, CSSParserContext(HTMLStandardMode, nullptr), nullptr, list);
EXPECT_STREQ(testCases[i][1], list.selectorsText().ascii().data()); EXPECT_STREQ(testCases[i][1], list.selectorsText().ascii().data());
} }
} }
......
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