Changeset 96517 in webkit
- Timestamp:
- Oct 3, 2011, 10:40:18 AM (14 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r96515 r96517 1 2011-09-30 Antti Koivisto <antti@apple.com> 2 3 Add exact match attribute selectors to the fast path 4 https://bugs.webkit.org/show_bug.cgi?id=69159 5 6 Reviewed by Sam Weinig. 7 8 Attribute selectors are increasingly common and we have them in our default style sheet too. 9 [foo] and [foo="bar"] type selectors can be resolved quickly and easily in the fast path. 10 11 - Implement fast path checking for simple attribute selectors. 12 - Get rid of the ill-defined CSSSelector::hasAttribute(), inline CSSSelector::attribute() 13 14 This is ~20% progression in styleForElement() performance loading the full HTML5 spec (~0.8s). 15 16 * css/CSSSelector.cpp: 17 (WebCore::CSSSelector::selectorText): 18 * css/CSSSelector.h: 19 (WebCore::CSSSelector::hasTag): 20 (WebCore::CSSSelector::attribute): 21 (WebCore::CSSSelector::isAttributeSelector): 22 * css/CSSSelectorList.cpp: 23 (WebCore::SelectorNeedsNamespaceResolutionFunctor::operator()): 24 * css/CSSStyleSelector.cpp: 25 (WebCore::CSSStyleSelector::checkSelector): 26 * css/SelectorChecker.cpp: 27 (WebCore::SelectorChecker::fastCheckRightmostSelector): 28 (WebCore::SelectorChecker::fastCheckSelector): 29 (WebCore::isFastCheckableMatch): 30 (WebCore::isFastCheckableRightmostSelector): 31 (WebCore::SelectorChecker::isFastCheckableSelector): 32 (WebCore::SelectorChecker::checkSelector): 33 (WebCore::htmlAttributeHasCaseInsensitiveValue): 34 (WebCore::anyAttributeMatches): 35 (WebCore::SelectorChecker::checkOneSelector): 36 * css/SelectorChecker.h: 37 (WebCore::SelectorChecker::attributeNameMatches): 38 (WebCore::SelectorChecker::checkExactAttribute): 39 (WebCore::SelectorChecker::fastCheckRightmostAttributeSelector): 40 1 41 2011-10-03 Mike Reed <reed@google.com> 2 42 -
trunk/Source/WebCore/css/CSSSelector.cpp
r90971 r96517 581 581 str += "::"; 582 582 str += cs->value(); 583 } else if (cs-> hasAttribute()) {583 } else if (cs->isAttributeSelector()) { 584 584 str += "["; 585 585 const AtomicString& prefix = cs->attribute().prefix(); … … 641 641 } 642 642 643 const QualifiedName& CSSSelector::attribute() const644 {645 switch (m_match) {646 case Id:647 return idAttr;648 case Class:649 return classAttr;650 default:651 return m_hasRareData ? m_data.m_rareData->m_attribute : anyQName();652 }653 }654 655 643 void CSSSelector::setAttribute(const QualifiedName& value) 656 644 { -
trunk/Source/WebCore/css/CSSSelector.h
r96393 r96517 221 221 222 222 bool hasTag() const { return m_tag != anyQName(); } 223 bool hasAttribute() const { return m_match == Id || m_match == Class || (m_hasRareData && m_data.m_rareData->m_attribute != anyQName()); }224 223 225 224 const QualifiedName& tag() const { return m_tag; } … … 298 297 QualifiedName m_tag; 299 298 }; 299 300 inline const QualifiedName& CSSSelector::attribute() const 301 { 302 ASSERT(isAttributeSelector()); 303 ASSERT(m_hasRareData); 304 return m_data.m_rareData->m_attribute; 305 } 300 306 301 307 inline bool CSSSelector::matchesPseudoElement() const … … 331 337 inline bool CSSSelector::isAttributeSelector() const 332 338 { 333 if (!hasAttribute())334 return false;335 339 return m_match == CSSSelector::Exact 336 340 || m_match == CSSSelector::Set -
trunk/Source/WebCore/css/CSSSelectorList.cpp
r95901 r96517 143 143 if (selector->hasTag() && selector->tag().prefix() != nullAtom && selector->tag().prefix() != starAtom) 144 144 return true; 145 if (selector-> hasAttribute() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)145 if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom) 146 146 return true; 147 147 return false; -
trunk/Source/WebCore/css/CSSStyleSelector.cpp
r96433 r96517 1828 1828 return true; 1829 1829 } else if (!SelectorChecker::tagMatches(m_element, ruleData.selector())) 1830 return false; 1831 if (!SelectorChecker::fastCheckRightmostAttributeSelector(m_element, ruleData.selector())) 1830 1832 return false; 1831 1833 return m_checker.fastCheckSelector(ruleData.selector(), m_element); -
trunk/Source/WebCore/css/SelectorChecker.cpp
r96393 r96517 64 64 65 65 using namespace HTMLNames; 66 67 static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr); 66 68 67 69 SelectorChecker::SelectorChecker(Document* document, bool strictParsing) … … 262 264 namespace { 263 265 264 template <bool checkValue(const Element*, AtomicStringImpl* )>266 template <bool checkValue(const Element*, AtomicStringImpl*, const QualifiedName&), bool initAttributeName> 265 267 inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement) 266 268 { 267 269 AtomicStringImpl* value = selector->value().impl(); 270 const QualifiedName& attribute = initAttributeName ? selector->attribute() : anyQName(); 268 271 for (; element; element = element->parentElement()) { 269 if (checkValue(element, value ) && SelectorChecker::tagMatches(element, selector)) {272 if (checkValue(element, value, attribute) && SelectorChecker::tagMatches(element, selector)) { 270 273 if (selector->relation() == CSSSelector::Descendant) 271 274 topChildOrSubselector = 0; … … 297 300 } 298 301 299 inline bool checkClassValue(const Element* element, AtomicStringImpl* value )302 inline bool checkClassValue(const Element* element, AtomicStringImpl* value, const QualifiedName&) 300 303 { 301 304 return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(value); 302 305 } 303 306 304 inline bool checkIDValue(const Element* element, AtomicStringImpl* value )307 inline bool checkIDValue(const Element* element, AtomicStringImpl* value, const QualifiedName&) 305 308 { 306 309 return element->hasID() && element->idForStyleResolution().impl() == value; 307 310 } 308 311 309 inline bool checkTagValue(const Element*, AtomicStringImpl*) 312 inline bool checkExactAttributeValue(const Element* element, AtomicStringImpl* value, const QualifiedName& attributeName) 313 { 314 return SelectorChecker::checkExactAttribute(element, attributeName, value); 315 } 316 317 inline bool checkTagValue(const Element*, AtomicStringImpl*, const QualifiedName&) 310 318 { 311 319 return true; … … 324 332 return true; 325 333 case CSSSelector::Class: 326 return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(selector->value());334 return checkClassValue(element, selector->value().impl(), anyQName()); 327 335 case CSSSelector::Id: 328 return element->hasID() && element->idForStyleResolution() == selector->value(); 336 return checkIDValue(element, selector->value().impl(), anyQName()); 337 case CSSSelector::Exact: 338 case CSSSelector::Set: 339 return checkExactAttributeValue(element, selector->value().impl(), selector->attribute()); 329 340 case CSSSelector::PseudoClass: 330 341 return commonPseudoClassSelectorMatches(element, selector); … … 353 364 switch (selector->m_match) { 354 365 case CSSSelector::Class: 355 if (!fastCheckSingleSelector<checkClassValue >(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))366 if (!fastCheckSingleSelector<checkClassValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) 356 367 return false; 357 368 break; 358 369 case CSSSelector::Id: 359 if (!fastCheckSingleSelector<checkIDValue >(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))370 if (!fastCheckSingleSelector<checkIDValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) 360 371 return false; 361 372 break; 362 373 case CSSSelector::None: 363 if (!fastCheckSingleSelector<checkTagValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) 374 if (!fastCheckSingleSelector<checkTagValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) 375 return false; 376 break; 377 case CSSSelector::Set: 378 case CSSSelector::Exact: 379 if (!fastCheckSingleSelector<checkExactAttributeValue, true>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) 364 380 return false; 365 381 break; … … 376 392 } 377 393 378 static inline bool isFastCheckableMatch(CSSSelector::Match match) 379 { 380 return match == CSSSelector::None || match == CSSSelector::Id || match == CSSSelector::Class; 394 static inline bool isFastCheckableMatch(const CSSSelector* selector) 395 { 396 if (selector->m_match == CSSSelector::Set) 397 return true; 398 if (selector->m_match == CSSSelector::Exact) 399 return !htmlAttributeHasCaseInsensitiveValue(selector->attribute()); 400 return selector->m_match == CSSSelector::None || selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class; 381 401 } 382 402 … … 385 405 if (!isFastCheckableRelation(selector->relation())) 386 406 return false; 387 return isFastCheckableMatch(s tatic_cast<CSSSelector::Match>(selector->m_match)) || SelectorChecker::isCommonPseudoClassSelector(selector);407 return isFastCheckableMatch(selector) || SelectorChecker::isCommonPseudoClassSelector(selector); 388 408 } 389 409 … … 395 415 if (!isFastCheckableRelation(selector->relation())) 396 416 return false; 397 if (!isFastCheckableMatch(s tatic_cast<CSSSelector::Match>(selector->m_match)))417 if (!isFastCheckableMatch(selector)) 398 418 return false; 399 419 } … … 579 599 } 580 600 581 staticbool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr)601 bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr) 582 602 { 583 603 static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet(); 584 604 bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom); 585 605 return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl()); 586 }587 588 static bool attributeQualifiedNameMatches(Attribute* attribute, const QualifiedName& selectorAttr)589 {590 if (selectorAttr.localName() != attribute->localName())591 return false;592 593 return selectorAttr.prefix() == starAtom || selectorAttr.namespaceURI() == attribute->namespaceURI();594 606 } 595 607 … … 662 674 Attribute* attributeItem = attributes->attributeItem(i); 663 675 664 if (! attributeQualifiedNameMatches(attributeItem, selectorAttr))676 if (!SelectorChecker::attributeNameMatches(attributeItem, selectorAttr)) 665 677 continue; 666 678 … … 678 690 return false; 679 691 680 if (sel-> hasAttribute()) {681 if (sel->m_match == CSSSelector::Class)682 return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value());683 684 if (sel->m_match == CSSSelector::Id)685 return e->hasID() && e->idForStyleResolution() == sel->value();686 692 if (sel->m_match == CSSSelector::Class) 693 return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value()); 694 695 if (sel->m_match == CSSSelector::Id) 696 return e->hasID() && e->idForStyleResolution() == sel->value(); 697 698 if (sel->isAttributeSelector()) { 687 699 const QualifiedName& attr = sel->attribute(); 688 700 -
trunk/Source/WebCore/css/SelectorChecker.h
r95966 r96517 29 29 #define SelectorChecker_h 30 30 31 #include "Attribute.h" 31 32 #include "CSSSelector.h" 32 33 #include "Element.h" … … 84 85 85 86 static bool tagMatches(const Element*, const CSSSelector*); 87 static bool attributeNameMatches(const Attribute*, const QualifiedName&); 86 88 static bool isCommonPseudoClassSelector(const CSSSelector*); 87 89 bool commonPseudoClassSelectorMatches(const Element*, const CSSSelector*) const; 88 90 bool linkMatchesVisitedPseudoClass(const Element*) const; 89 91 bool matchesFocusPseudoClass(const Element*) const; 92 static bool fastCheckRightmostAttributeSelector(const Element*, const CSSSelector*); 93 static bool checkExactAttribute(const Element*, const QualifiedName& selectorAttributeName, const AtomicStringImpl* value); 90 94 91 95 private: … … 175 179 return namespaceURI == starAtom || namespaceURI == element->namespaceURI(); 176 180 } 181 182 inline bool SelectorChecker::attributeNameMatches(const Attribute* attribute, const QualifiedName& selectorAttributeName) 183 { 184 if (selectorAttributeName.localName() != attribute->localName()) 185 return false; 186 return selectorAttributeName.prefix() == starAtom || selectorAttributeName.namespaceURI() == attribute->namespaceURI(); 187 } 188 189 inline bool SelectorChecker::checkExactAttribute(const Element* element, const QualifiedName& selectorAttributeName, const AtomicStringImpl* value) 190 { 191 NamedNodeMap* attributeMap = element->attributeMap(); 192 if (!attributeMap) 193 return false; 194 unsigned size = attributeMap->length(); 195 for (unsigned i = 0; i < size; ++i) { 196 Attribute* attribute = attributeMap->attributeItem(i); 197 if (attributeNameMatches(attribute, selectorAttributeName) && (!value || attribute->value().impl() == value)) 198 return true; 199 } 200 return false; 201 } 202 203 inline bool SelectorChecker::fastCheckRightmostAttributeSelector(const Element* element, const CSSSelector* selector) 204 { 205 if (selector->m_match == CSSSelector::Exact || selector->m_match == CSSSelector::Set) 206 return checkExactAttribute(element, selector->attribute(), selector->value().impl()); 207 ASSERT(!selector->isAttributeSelector()); 208 return true; 209 } 177 210 178 211 }
Note:
See TracChangeset
for help on using the changeset viewer.