Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / RuleSet.cpp
index d1b2c10..7e048b8 100644 (file)
@@ -40,6 +40,7 @@
 #include "core/css/StyleRuleImport.h"
 #include "core/css/StyleSheetContents.h"
 #include "core/html/track/TextTrackCue.h"
+#include "platform/TraceEvent.h"
 #include "platform/weborigin/SecurityOrigin.h"
 
 namespace WebCore {
@@ -48,20 +49,21 @@ using namespace HTMLNames;
 
 // -----------------------------------------------------------------
 
-static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector* selector)
+static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector& selector)
 {
-    ASSERT(selector);
-    if (selector->m_match == CSSSelector::Tag) {
-        const AtomicString& selectorNamespace = selector->tagQName().namespaceURI();
+    if (selector.m_match == CSSSelector::Tag) {
+        const AtomicString& selectorNamespace = selector.tagQName().namespaceURI();
         if (selectorNamespace != starAtom && selectorNamespace != xhtmlNamespaceURI)
             return false;
-        if (selector->relation() == CSSSelector::SubSelector)
-            return isSelectorMatchingHTMLBasedOnRuleHash(selector->tagHistory());
+        if (selector.relation() == CSSSelector::SubSelector) {
+            ASSERT(selector.tagHistory());
+            return isSelectorMatchingHTMLBasedOnRuleHash(*selector.tagHistory());
+        }
         return true;
     }
     if (SelectorChecker::isCommonPseudoClassSelector(selector))
         return true;
-    return selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class;
+    return selector.m_match == CSSSelector::Id || selector.m_match == CSSSelector::Class;
 }
 
 static inline bool selectorListContainsUncommonAttributeSelector(const CSSSelector* selector)
@@ -69,7 +71,7 @@ static inline bool selectorListContainsUncommonAttributeSelector(const CSSSelect
     const CSSSelectorList* selectorList = selector->selectorList();
     if (!selectorList)
         return false;
-    for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
+    for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) {
         for (const CSSSelector* component = selector; component; component = component->tagHistory()) {
             if (component->isAttributeSelector())
                 return true;
@@ -84,34 +86,33 @@ static inline bool isCommonAttributeSelectorAttribute(const QualifiedName& attri
     return attribute == typeAttr || attribute == readonlyAttr;
 }
 
-static inline bool containsUncommonAttributeSelector(const CSSSelector* selector)
+static inline bool containsUncommonAttributeSelector(const CSSSelector& selector)
 {
-    for (; selector; selector = selector->tagHistory()) {
+    const CSSSelector* current = &selector;
+    for (; current; current = current->tagHistory()) {
         // Allow certain common attributes (used in the default style) in the selectors that match the current element.
-        if (selector->isAttributeSelector() && !isCommonAttributeSelectorAttribute(selector->attribute()))
+        if (current->isAttributeSelector() && !isCommonAttributeSelectorAttribute(current->attribute()))
             return true;
-        if (selectorListContainsUncommonAttributeSelector(selector))
+        if (selectorListContainsUncommonAttributeSelector(current))
             return true;
-        if (selector->relation() != CSSSelector::SubSelector) {
-            selector = selector->tagHistory();
+        if (current->relation() != CSSSelector::SubSelector) {
+            current = current->tagHistory();
             break;
         }
     }
 
-    for (; selector; selector = selector->tagHistory()) {
-        if (selector->isAttributeSelector())
+    for (; current; current = current->tagHistory()) {
+        if (current->isAttributeSelector())
             return true;
-        if (selectorListContainsUncommonAttributeSelector(selector))
+        if (selectorListContainsUncommonAttributeSelector(current))
             return true;
     }
     return false;
 }
 
-static inline PropertyWhitelistType determinePropertyWhitelistType(const AddRuleFlags addRuleFlags, const CSSSelector* selector)
+static inline PropertyWhitelistType determinePropertyWhitelistType(const AddRuleFlags addRuleFlags, const CSSSelector& selector)
 {
-    if (addRuleFlags & RuleIsInRegionRule)
-        return PropertyWhitelistRegion;
-    for (const CSSSelector* component = selector; component; component = component->tagHistory()) {
+    for (const CSSSelector* component = &selector; component; component = component->tagHistory()) {
         if (component->pseudoType() == CSSSelector::PseudoCue || (component->m_match == CSSSelector::PseudoElement && component->value() == TextTrackCue::cueShadowPseudoId()))
             return PropertyWhitelistCue;
     }
@@ -194,8 +195,8 @@ RuleData::RuleData(StyleRule* rule, unsigned selectorIndex, unsigned position, A
     , m_isLastInArray(false)
     , m_position(position)
     , m_hasFastCheckableSelector((addRuleFlags & RuleCanUseFastCheckSelector) && SelectorCheckerFastPath::canUse(selector()))
-    , m_specificity(selector()->specificity())
-    , m_hasMultipartSelector(!!selector()->tagHistory())
+    , m_specificity(selector().specificity())
+    , m_hasMultipartSelector(!!selector().tagHistory())
     , m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector()))
     , m_containsUncommonAttributeSelector(WebCore::containsUncommonAttributeSelector(selector()))
     , m_linkMatchType(SelectorChecker::determineLinkMatchType(selector()))
@@ -207,36 +208,74 @@ RuleData::RuleData(StyleRule* rule, unsigned selectorIndex, unsigned position, A
     SelectorFilter::collectIdentifierHashes(selector(), m_descendantSelectorIdentifierHashes, maximumIdentifierCount);
 }
 
-void RuleSet::addToRuleSet(StringImpl* key, PendingRuleMap& map, const RuleData& ruleData)
+void RuleSet::addToRuleSet(const AtomicString& key, PendingRuleMap& map, const RuleData& ruleData)
 {
-    if (!key)
-        return;
-    OwnPtr<LinkedStack<RuleData> >& rules = map.add(key, nullptr).iterator->value;
+    OwnPtr<LinkedStack<RuleData> >& rules = map.add(key, nullptr).storedValue->value;
     if (!rules)
         rules = adoptPtr(new LinkedStack<RuleData>);
     rules->push(ruleData);
 }
 
-bool RuleSet::findBestRuleSetAndAdd(const CSSSelector* component, RuleData& ruleData)
+static void extractValuesforSelector(const CSSSelector* selector, AtomicString& id, AtomicString& className, AtomicString& customPseudoElementName, AtomicString& tagName)
+{
+    switch (selector->m_match) {
+    case CSSSelector::Id:
+        id = selector->value();
+        break;
+    case CSSSelector::Class:
+        className = selector->value();
+        break;
+    case CSSSelector::Tag:
+        if (selector->tagQName().localName() != starAtom)
+            tagName = selector->tagQName().localName();
+        break;
+    }
+    if (selector->isCustomPseudoElement())
+        customPseudoElementName = selector->value();
+}
+
+bool RuleSet::findBestRuleSetAndAdd(const CSSSelector& component, RuleData& ruleData)
 {
-    if (component->m_match == CSSSelector::Id) {
-        addToRuleSet(component->value().impl(), ensurePendingRules()->idRules, ruleData);
+    AtomicString id;
+    AtomicString className;
+    AtomicString customPseudoElementName;
+    AtomicString tagName;
+
+#ifndef NDEBUG
+    m_allRules.append(ruleData);
+#endif
+
+    const CSSSelector* it = &component;
+    for (; it->relation() == CSSSelector::SubSelector; it = it->tagHistory()) {
+        extractValuesforSelector(it, id, className, customPseudoElementName, tagName);
+    }
+    extractValuesforSelector(it, id, className, customPseudoElementName, tagName);
+
+    // Prefer rule sets in order of most likely to apply infrequently.
+    if (!id.isEmpty()) {
+        addToRuleSet(id, ensurePendingRules()->idRules, ruleData);
         return true;
     }
-    if (component->m_match == CSSSelector::Class) {
-        addToRuleSet(component->value().impl(), ensurePendingRules()->classRules, ruleData);
+    if (!className.isEmpty()) {
+        addToRuleSet(className, ensurePendingRules()->classRules, ruleData);
         return true;
     }
-    if (component->isCustomPseudoElement()) {
-        addToRuleSet(component->value().impl(), ensurePendingRules()->shadowPseudoElementRules, ruleData);
+    if (!customPseudoElementName.isEmpty()) {
+        // Custom pseudos come before ids and classes in the order of tagHistory, and have a relation of
+        // ShadowPseudo between them. Therefore we should never be a situation where extractValuesforSelector
+        // finsd id and className in addition to custom pseudo.
+        ASSERT(id.isEmpty() && className.isEmpty());
+        addToRuleSet(customPseudoElementName, ensurePendingRules()->shadowPseudoElementRules, ruleData);
         return true;
     }
-    if (component->pseudoType() == CSSSelector::PseudoCue) {
+
+    if (component.pseudoType() == CSSSelector::PseudoCue) {
         m_cuePseudoRules.append(ruleData);
         return true;
     }
+
     if (SelectorChecker::isCommonPseudoClassSelector(component)) {
-        switch (component->pseudoType()) {
+        switch (component.pseudoType()) {
         case CSSSelector::PseudoLink:
         case CSSSelector::PseudoVisited:
         case CSSSelector::PseudoAnyLink:
@@ -251,18 +290,11 @@ bool RuleSet::findBestRuleSetAndAdd(const CSSSelector* component, RuleData& rule
         }
     }
 
-    if (component->m_match == CSSSelector::Tag) {
-        if (component->tagQName().localName() != starAtom) {
-            // If this is part of a subselector chain, recurse ahead to find a narrower set (ID/class.)
-            if (component->relation() == CSSSelector::SubSelector
-                && (component->tagHistory()->m_match == CSSSelector::Class || component->tagHistory()->m_match == CSSSelector::Id || SelectorChecker::isCommonPseudoClassSelector(component->tagHistory()))
-                && findBestRuleSetAndAdd(component->tagHistory(), ruleData))
-                return true;
-
-            addToRuleSet(component->tagQName().localName().impl(), ensurePendingRules()->tagRules, ruleData);
-            return true;
-        }
+    if (!tagName.isEmpty()) {
+        addToRuleSet(tagName, ensurePendingRules()->tagRules, ruleData);
+        return true;
     }
+
     return false;
 }
 
@@ -301,31 +333,6 @@ void RuleSet::addKeyframesRule(StyleRuleKeyframes* rule)
     m_keyframesRules.append(rule);
 }
 
-void RuleSet::addRegionRule(StyleRuleRegion* regionRule, bool hasDocumentSecurityOrigin)
-{
-    ensurePendingRules(); // So that m_regionSelectorsAndRuleSets.shrinkToFit() gets called.
-    OwnPtr<RuleSet> regionRuleSet = RuleSet::create();
-    // The region rule set should take into account the position inside the parent rule set.
-    // Otherwise, the rules inside region block might be incorrectly positioned before other similar rules from
-    // the stylesheet that contains the region block.
-    regionRuleSet->m_ruleCount = m_ruleCount;
-
-    // Collect the region rules into a rule set
-    // FIXME: Should this add other types of rules? (i.e. use addChildRules() directly?)
-    const Vector<RefPtr<StyleRuleBase> >& childRules = regionRule->childRules();
-    AddRuleFlags addRuleFlags = hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState;
-    addRuleFlags = static_cast<AddRuleFlags>(addRuleFlags | RuleIsInRegionRule | RuleCanUseFastCheckSelector);
-    for (unsigned i = 0; i < childRules.size(); ++i) {
-        StyleRuleBase* regionStylingRule = childRules[i].get();
-        if (regionStylingRule->isStyleRule())
-            regionRuleSet->addStyleRule(toStyleRule(regionStylingRule), addRuleFlags);
-    }
-    // Update the "global" rule count so that proper order is maintained
-    m_ruleCount = regionRuleSet->m_ruleCount;
-
-    m_regionSelectorsAndRuleSets.append(RuleSetSelectorPair(regionRule->selectorList().first(), regionRuleSet.release()));
-}
-
 void RuleSet::addChildRules(const Vector<RefPtr<StyleRuleBase> >& rules, const MediaQueryEvaluator& medium, AddRuleFlags addRuleFlags)
 {
     for (unsigned i = 0; i < rules.size(); ++i) {
@@ -354,8 +361,6 @@ void RuleSet::addChildRules(const Vector<RefPtr<StyleRuleBase> >& rules, const M
             addFontFaceRule(toStyleRuleFontFace(rule));
         } else if (rule->isKeyframesRule()) {
             addKeyframesRule(toStyleRuleKeyframes(rule));
-        } else if (rule->isRegionRule()) {
-            addRegionRule(toStyleRuleRegion(rule), addRuleFlags & RuleHasDocumentSecurityOrigin);
         } else if (rule->isViewportRule()) {
             addViewportRule(toStyleRuleViewport(rule));
         } else if (rule->isSupportsRule() && toStyleRuleSupports(rule)->conditionIsSupported()) {
@@ -366,6 +371,8 @@ void RuleSet::addChildRules(const Vector<RefPtr<StyleRuleBase> >& rules, const M
 
 void RuleSet::addRulesFromSheet(StyleSheetContents* sheet, const MediaQueryEvaluator& medium, AddRuleFlags addRuleFlags)
 {
+    TRACE_EVENT0("webkit", "RuleSet::addRulesFromSheet");
+
     ASSERT(sheet);
 
     addRuleFlags = static_cast<AddRuleFlags>(addRuleFlags | RuleCanUseFastCheckSelector);
@@ -390,7 +397,7 @@ void RuleSet::compactPendingRules(PendingRuleMap& pendingMap, CompactRuleMap& co
     PendingRuleMap::iterator end = pendingMap.end();
     for (PendingRuleMap::iterator it = pendingMap.begin(); it != end; ++it) {
         OwnPtr<LinkedStack<RuleData> > pendingRules = it->value.release();
-        CompactRuleMap::iterator compactRules = compactMap.add(it->key, nullptr).iterator;
+        CompactRuleMap::ValueType* compactRules = compactMap.add(it->key, nullptr).storedValue;
 
         TerminatedArrayBuilder<RuleData> builder(compactRules->value.release());
         builder.grow(pendingRules->size());
@@ -423,4 +430,13 @@ void RuleSet::compactRules()
     m_shadowDistributedRules.shrinkToFit();
 }
 
+#ifndef NDEBUG
+
+void RuleSet::show()
+{
+    for (Vector<RuleData>::const_iterator it = m_allRules.begin(); it != m_allRules.end(); ++it)
+        it->selector().show();
+}
+#endif
+
 } // namespace WebCore