Title: [229090] trunk/Source/WebCore
Revision
229090
Author
[email protected]
Date
2018-02-28 07:50:00 -0800 (Wed, 28 Feb 2018)

Log Message

Filter attribute selectors with selector filter
https://bugs.webkit.org/show_bug.cgi?id=183200

Reviewed by Zalan Bujtas.

Currently selector filtering is done based on tags, classes and ids. We should include attributes too.

This patch adds filtering based on attribute name (but not content).

* css/SelectorFilter.cpp:
(WebCore::isExcludedAttribute):

    Ignore id, class and style attributes. First two are already handled and the last is common but is rarely
    used in selectors.

(WebCore::collectElementIdentifierHashes):

    Collect attributes.
    Remove the unnecessary StyledElement casting.

(WebCore::collectSimpleSelectorHash):

    Collect attribute selectors.

(WebCore::chooseSelectorHashesForFilter):

    Pick attributes with high priority for the filter as it is likely a good signal.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (229089 => 229090)


--- trunk/Source/WebCore/ChangeLog	2018-02-28 08:45:26 UTC (rev 229089)
+++ trunk/Source/WebCore/ChangeLog	2018-02-28 15:50:00 UTC (rev 229090)
@@ -1,3 +1,33 @@
+2018-02-28  Antti Koivisto  <[email protected]>
+
+        Filter attribute selectors with selector filter
+        https://bugs.webkit.org/show_bug.cgi?id=183200
+
+        Reviewed by Zalan Bujtas.
+
+        Currently selector filtering is done based on tags, classes and ids. We should include attributes too.
+
+        This patch adds filtering based on attribute name (but not content).
+
+        * css/SelectorFilter.cpp:
+        (WebCore::isExcludedAttribute):
+
+            Ignore id, class and style attributes. First two are already handled and the last is common but is rarely
+            used in selectors.
+
+        (WebCore::collectElementIdentifierHashes):
+
+            Collect attributes.
+            Remove the unnecessary StyledElement casting.
+
+        (WebCore::collectSimpleSelectorHash):
+
+            Collect attribute selectors.
+
+        (WebCore::chooseSelectorHashesForFilter):
+
+            Pick attributes with high priority for the filter as it is likely a good signal.
+
 2018-02-27  Sergio Villar Senin  <[email protected]>
 
         [WebVR] Convert VRPlatformDisplayInfo into a class

Modified: trunk/Source/WebCore/css/SelectorFilter.cpp (229089 => 229090)


--- trunk/Source/WebCore/css/SelectorFilter.cpp	2018-02-28 08:45:26 UTC (rev 229089)
+++ trunk/Source/WebCore/css/SelectorFilter.cpp	2018-02-28 15:50:00 UTC (rev 229090)
@@ -36,23 +36,37 @@
 namespace WebCore {
 
 // Salt to separate otherwise identical string hashes so a class-selector like .article won't match <article> elements.
-enum { TagNameSalt = 13, IdAttributeSalt = 17, ClassAttributeSalt = 19 };
+enum { TagNameSalt = 13, IdSalt = 17, ClassSalt = 19, AttributeSalt = 23 };
 
-static inline void collectElementIdentifierHashes(const Element* element, Vector<unsigned, 4>& identifierHashes)
+static bool isExcludedAttribute(const AtomicString& name)
 {
-    AtomicString tagLowercaseLocalName = element->localName().convertToASCIILowercase();
+    return name == HTMLNames::classAttr->localName() || name == HTMLNames::idAttr->localName() || name == HTMLNames::styleAttr->localName();
+}
+
+static inline void collectElementIdentifierHashes(const Element& element, Vector<unsigned, 4>& identifierHashes)
+{
+    AtomicString tagLowercaseLocalName = element.localName().convertToASCIILowercase();
     identifierHashes.append(tagLowercaseLocalName.impl()->existingHash() * TagNameSalt);
 
-    auto& id = element->idForStyleResolution();
+    auto& id = element.idForStyleResolution();
     if (!id.isNull())
-        identifierHashes.append(id.impl()->existingHash() * IdAttributeSalt);
-    const StyledElement* styledElement = element->isStyledElement() ? static_cast<const StyledElement*>(element) : 0;
-    if (styledElement && styledElement->hasClass()) {
-        const SpaceSplitString& classNames = styledElement->classNames();
+        identifierHashes.append(id.impl()->existingHash() * IdSalt);
+
+    if (element.hasClass()) {
+        const SpaceSplitString& classNames = element.classNames();
         size_t count = classNames.size();
         for (size_t i = 0; i < count; ++i)
-            identifierHashes.append(classNames[i].impl()->existingHash() * ClassAttributeSalt);
+            identifierHashes.append(classNames[i].impl()->existingHash() * ClassSalt);
     }
+    
+    if (element.hasAttributesWithoutUpdate()) {
+        for (auto& attribute : element.attributesIterator()) {
+            auto attributeName = element.isHTMLElement() ? attribute.localName() : attribute.localName().convertToASCIILowercase();
+            if (isExcludedAttribute(attributeName))
+                continue;
+            identifierHashes.append(attributeName.impl()->existingHash() * AttributeSalt);
+        }
+    }
 }
 
 bool SelectorFilter::parentStackIsConsistent(const ContainerNode* parentNode) const
@@ -80,7 +94,7 @@
     ParentStackFrame& parentFrame = m_parentStack.last();
     // Mix tags, class names and ids into some sort of weird bouillabaisse.
     // The filter is used for fast rejection of child and descendant selectors.
-    collectElementIdentifierHashes(parent, parentFrame.identifierHashes);
+    collectElementIdentifierHashes(*parent, parentFrame.identifierHashes);
     size_t count = parentFrame.identifierHashes.size();
     for (size_t i = 0; i < count; ++i)
         m_ancestorIdentifierFilter.add(parentFrame.identifierHashes[i]);
@@ -123,6 +137,7 @@
     HashVector ids;
     HashVector classes;
     HashVector tags;
+    HashVector attributes;
 };
 
 static inline void collectSimpleSelectorHash(CollectedSelectorHashes& collectedHashes, const CSSSelector& selector)
@@ -130,11 +145,11 @@
     switch (selector.match()) {
     case CSSSelector::Id:
         if (!selector.value().isEmpty())
-            collectedHashes.ids.append(selector.value().impl()->existingHash() * IdAttributeSalt);
+            collectedHashes.ids.append(selector.value().impl()->existingHash() * IdSalt);
         break;
     case CSSSelector::Class:
         if (!selector.value().isEmpty())
-            collectedHashes.classes.append(selector.value().impl()->existingHash() * ClassAttributeSalt);
+            collectedHashes.classes.append(selector.value().impl()->existingHash() * ClassSalt);
         break;
     case CSSSelector::Tag: {
         auto& tagLowercaseLocalName = selector.tagLowercaseLocalName();
@@ -142,6 +157,18 @@
             collectedHashes.tags.append(tagLowercaseLocalName.impl()->existingHash() * TagNameSalt);
         break;
     }
+    case CSSSelector::Exact:
+    case CSSSelector::Set:
+    case CSSSelector::List:
+    case CSSSelector::Hyphen:
+    case CSSSelector::Contain:
+    case CSSSelector::Begin:
+    case CSSSelector::End: {
+        auto attributeName = selector.attributeCanonicalLocalName().convertToASCIILowercase();
+        if (!isExcludedAttribute(attributeName))
+            collectedHashes.attributes.append(attributeName.impl()->existingHash() * AttributeSalt);
+        break;
+    }
     default:
         break;
     }
@@ -204,6 +231,8 @@
     // There is a limited number of slots. Prefer more specific selector types.
     if (copyHashes(collectedSelectorHashes.ids))
         return resultHashes;
+    if (copyHashes(collectedSelectorHashes.attributes))
+        return resultHashes;
     if (copyHashes(collectedSelectorHashes.classes))
         return resultHashes;
     if (copyHashes(collectedSelectorHashes.tags))
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to