8933640c2f911a3e2ecca983d5e7fb762fdb46cc
[vuplus_webkit] / Source / WebCore / css / SelectorChecker.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "SelectorChecker.h"
30
31 #include "CSSSelector.h"
32 #include "CSSSelectorList.h"
33 #include "Document.h"
34 #include "FocusController.h"
35 #include "Frame.h"
36 #include "HTMLFrameElementBase.h"
37 #include "HTMLInputElement.h"
38 #include "HTMLNames.h"
39 #include "HTMLProgressElement.h"
40 #include "InspectorInstrumentation.h"
41 #include "NodeRenderStyle.h"
42 #include "Page.h"
43 #include "PageGroup.h"
44 #include "RenderObject.h"
45 #include "RenderScrollbar.h"
46 #include "RenderStyle.h"
47 #include "ScrollableArea.h"
48 #include "ScrollbarTheme.h"
49 #include "StyledElement.h"
50 #include "Text.h"
51
52 #if USE(PLATFORM_STRATEGIES)
53 #include "PlatformStrategies.h"
54 #include "VisitedLinkStrategy.h"
55 #endif
56
57 #if ENABLE(SVG)
58 #include "SVGNames.h"
59 #include "XLinkNames.h"
60 #endif
61
62 #if PLATFORM(QT)
63 //FIXME: Remove this Qt specific code from a platform neutral file.
64 #include <qwebhistoryinterface.h>
65 #endif
66
67 namespace WebCore {
68     
69 using namespace HTMLNames;
70
71 SelectorChecker::SelectorChecker(Document* document, bool strictParsing)
72     : m_document(document)
73     , m_strictParsing(strictParsing)
74     , m_documentIsHTML(document->isHTMLDocument())
75     , m_isCollectingRulesOnly(false)
76     , m_pseudoStyle(NOPSEUDO)
77     , m_hasUnknownPseudoElements(false)
78     , m_isMatchingVisitedPseudoClass(false)
79 {
80 }
81
82 static inline void collectElementIdentifierHashes(const Element* element, Vector<unsigned, 4>& identifierHashes)
83 {
84     identifierHashes.append(element->localName().impl()->existingHash());
85     if (element->hasID())
86         identifierHashes.append(element->idForStyleResolution().impl()->existingHash());
87     const StyledElement* styledElement = element->isStyledElement() ? static_cast<const StyledElement*>(element) : 0;
88     if (styledElement && styledElement->hasClass()) {
89         const SpaceSplitString& classNames = styledElement->classNames();
90         size_t count = classNames.size();
91         for (size_t i = 0; i < count; ++i)
92             identifierHashes.append(classNames[i].impl()->existingHash());
93     }
94 }
95
96 void SelectorChecker::pushParentStackFrame(Element* parent)
97 {
98     ASSERT(m_ancestorIdentifierFilter);
99     ASSERT(m_parentStack.isEmpty() || m_parentStack.last().element == parent->parentOrHostElement());
100     ASSERT(!m_parentStack.isEmpty() || !parent->parentOrHostElement());
101     m_parentStack.append(ParentStackFrame(parent));
102     ParentStackFrame& parentFrame = m_parentStack.last();
103     // Mix tags, class names and ids into some sort of weird bouillabaisse.
104     // The filter is used for fast rejection of child and descendant selectors.
105     collectElementIdentifierHashes(parent, parentFrame.identifierHashes);
106     size_t count = parentFrame.identifierHashes.size();
107     for (size_t i = 0; i < count; ++i)
108         m_ancestorIdentifierFilter->add(parentFrame.identifierHashes[i]);
109 }
110
111 void SelectorChecker::popParentStackFrame()
112 {
113     ASSERT(!m_parentStack.isEmpty());
114     ASSERT(m_ancestorIdentifierFilter);
115     const ParentStackFrame& parentFrame = m_parentStack.last();
116     size_t count = parentFrame.identifierHashes.size();
117     for (size_t i = 0; i < count; ++i)
118         m_ancestorIdentifierFilter->remove(parentFrame.identifierHashes[i]);
119     m_parentStack.removeLast();
120     if (m_parentStack.isEmpty()) {
121         ASSERT(m_ancestorIdentifierFilter->likelyEmpty());
122         m_ancestorIdentifierFilter.clear();
123     }
124 }
125
126 void SelectorChecker::pushParent(Element* parent)
127 {
128     if (m_parentStack.isEmpty()) {
129         ASSERT(!m_ancestorIdentifierFilter);
130         m_ancestorIdentifierFilter = adoptPtr(new BloomFilter<bloomFilterKeyBits>);
131         // If the element is not the root itself, build the stack starting from the root.
132         if (parent->parentOrHostNode()) {
133             Vector<Element*, 30> ancestors;
134             for (Element* ancestor = parent; ancestor; ancestor = ancestor->parentOrHostElement())
135                 ancestors.append(ancestor);
136             int count = ancestors.size();
137             for (int n = count - 1; n >= 0; --n)
138                 pushParentStackFrame(ancestors[n]);
139             return;
140         }
141     } else if (!parent->parentOrHostElement()) {
142         // We are not always invoked consistently. For example, script execution can cause us to enter
143         // style recalc in the middle of tree building. Reset the stack if we see a new root element.
144         ASSERT(m_ancestorIdentifierFilter);
145         m_ancestorIdentifierFilter->clear();
146         m_parentStack.resize(0);
147     } else {
148         ASSERT(m_ancestorIdentifierFilter);
149         // We may get invoked for some random elements in some wacky cases during style resolve.
150         // Pause maintaining the stack in this case.
151         if (m_parentStack.last().element != parent->parentOrHostElement())
152             return;
153     }
154     pushParentStackFrame(parent);
155 }
156
157 void SelectorChecker::popParent(Element* parent)
158 {
159     if (m_parentStack.isEmpty() || m_parentStack.last().element != parent)
160         return;
161     popParentStackFrame();
162 }
163
164 static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector* selector, unsigned* hash, const unsigned* end)
165 {
166     if ((selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class) && !selector->value().isEmpty())
167         (*hash++) = selector->value().impl()->existingHash();
168     if (hash == end)
169         return;
170     const AtomicString& localName = selector->tag().localName();
171     if (localName != starAtom)
172         (*hash++) = localName.impl()->existingHash();
173 }
174
175 void SelectorChecker::collectIdentifierHashes(const CSSSelector* selector, unsigned* identifierHashes, unsigned maximumIdentifierCount)
176 {
177     unsigned* hash = identifierHashes;
178     unsigned* end = identifierHashes + maximumIdentifierCount;
179     CSSSelector::Relation relation = selector->relation();
180     
181     // Skip the topmost selector. It is handled quickly by the rule hashes.    
182     bool skipOverSubselectors = true;
183     for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) {
184         // Only collect identifiers that match ancestors.
185         switch (relation) {
186         case CSSSelector::SubSelector:
187             if (!skipOverSubselectors)
188                 collectDescendantSelectorIdentifierHashes(selector, hash, end);
189             break;
190         case CSSSelector::DirectAdjacent:
191         case CSSSelector::IndirectAdjacent:
192         case CSSSelector::ShadowDescendant:
193             skipOverSubselectors = true;
194             break;
195         case CSSSelector::Descendant:
196         case CSSSelector::Child:
197             skipOverSubselectors = false;
198             collectDescendantSelectorIdentifierHashes(selector, hash, end);
199             break;
200         }
201         if (hash == end)
202             return;
203         relation = selector->relation();
204     }
205     *hash = 0;
206 }
207
208 static inline const AtomicString* linkAttribute(Node* node)
209 {
210     if (!node->isLink())
211         return 0;
212     
213     ASSERT(node->isElementNode());
214     Element* element = static_cast<Element*>(node);
215     if (element->isHTMLElement())
216         return &element->fastGetAttribute(hrefAttr);
217     
218 #if ENABLE(SVG)
219     if (element->isSVGElement())
220         return &element->fastGetAttribute(XLinkNames::hrefAttr);
221 #endif
222     
223     return 0;
224 }
225
226 EInsideLink SelectorChecker::determineLinkStateSlowCase(Element* element) const
227 {
228     ASSERT(element->isLink());
229     
230     const AtomicString* attr = linkAttribute(element);
231     if (!attr || attr->isNull())
232         return NotInsideLink;
233     
234 #if PLATFORM(QT)
235     //FIXME: Remove this Qt specific code from a platform neutral file.
236     Vector<UChar, 512> url;
237     visitedURL(m_document->baseURL(), *attr, url);
238     if (url.isEmpty())
239         return InsideUnvisitedLink;
240     
241     // If the Qt4.4 interface for the history is used, we will have to fallback
242     // to the old global history.
243     QWebHistoryInterface* iface = QWebHistoryInterface::defaultInterface();
244     if (iface)
245         return iface->historyContains(QString(reinterpret_cast<QChar*>(url.data()), url.size())) ? InsideVisitedLink : InsideUnvisitedLink;
246     
247     LinkHash hash = visitedLinkHash(url.data(), url.size());
248     if (!hash)
249         return InsideUnvisitedLink;
250 #else
251     LinkHash hash = visitedLinkHash(m_document->baseURL(), *attr);
252     if (!hash)
253         return InsideUnvisitedLink;
254 #endif
255     
256     Frame* frame = m_document->frame();
257     if (!frame)
258         return InsideUnvisitedLink;
259     
260     Page* page = frame->page();
261     if (!page)
262         return InsideUnvisitedLink;
263     
264     m_linksCheckedForVisitedState.add(hash);
265     
266 #if USE(PLATFORM_STRATEGIES)
267     return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash) ? InsideVisitedLink : InsideUnvisitedLink;
268 #else
269     return page->group().isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink;
270 #endif
271 }
272
273 bool SelectorChecker::checkSelector(CSSSelector* sel, Element* element, bool isFastCheckableSelector) const
274 {
275     PseudoId dynamicPseudo = NOPSEUDO;
276     if (isFastCheckableSelector && !element->isSVGElement()) {
277         // fastCheckSelector assumes class and id match for the top selector.
278         if (sel->m_match == CSSSelector::Class) {
279             if (!(element->hasClass() && static_cast<StyledElement*>(element)->classNames().contains(sel->value())))
280                 return false;
281         } else if (sel->m_match == CSSSelector::Id) {
282             if (!(element->hasID() && element->idForStyleResolution() == sel->value()))
283                 return false;
284         }
285         return fastCheckSelector(sel, element);
286     }
287     return checkSelector(sel, element, dynamicPseudo, false, false) == SelectorMatches;
288 }
289
290 namespace {
291     
292 inline bool selectorTagMatches(const Element* element, const CSSSelector* selector)
293 {
294     if (!selector->hasTag())
295         return true;
296     const AtomicString& localName = selector->tag().localName();
297     if (localName != starAtom && localName != element->localName())
298         return false;
299     const AtomicString& namespaceURI = selector->tag().namespaceURI();
300     return namespaceURI == starAtom || namespaceURI == element->namespaceURI();
301 }
302
303 template <bool checkValue(const Element*, AtomicStringImpl*)>
304 inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement)
305 {
306     AtomicStringImpl* value = selector->value().impl();
307     for (; element; element = element->parentElement()) {
308         if (checkValue(element, value) && selectorTagMatches(element, selector)) {
309             if (selector->relation() == CSSSelector::Descendant)
310                 topChildOrSubselector = 0;
311             else if (!topChildOrSubselector) {
312                 ASSERT(selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector);
313                 topChildOrSubselector = selector;
314                 topChildOrSubselectorMatchElement = element;
315             }
316             if (selector->relation() != CSSSelector::SubSelector)
317                 element = element->parentElement();
318             selector = selector->tagHistory();
319             return true;
320         }
321         if (topChildOrSubselector) {
322             // Child or subselector check failed.
323             // If the match element is null, topChildOrSubselector was also the very topmost selector and had to match 
324             // the original element we were checking.
325             if (!topChildOrSubselectorMatchElement)
326                 return false;
327             // There may be other matches down the ancestor chain.
328             // Rewind to the topmost child or subselector and the element it matched, continue checking ancestors.
329             selector = topChildOrSubselector;
330             element = topChildOrSubselectorMatchElement->parentElement();
331             topChildOrSubselector = 0;
332             return true;
333         }
334     }
335     return false;
336 }
337
338 inline bool checkClassValue(const Element* element, AtomicStringImpl* value) 
339 {
340     return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(value);
341 }
342
343 inline bool checkIDValue(const Element* element, AtomicStringImpl* value) 
344 {
345     return element->hasID() && element->idForStyleResolution().impl() == value;
346 }
347
348 inline bool checkTagValue(const Element*, AtomicStringImpl*)
349 {
350     return true;
351 }
352     
353 }
354
355 bool SelectorChecker::fastCheckSelector(const CSSSelector* selector, const Element* element)
356 {
357     ASSERT(isFastCheckableSelector(selector));
358     
359     // The top selector requires tag check only as rule hashes have already handled id and class matches.
360     if (!selectorTagMatches(element, selector))
361         return false;
362     
363     const CSSSelector* topChildOrSubselector = 0;
364     const Element* topChildOrSubselectorMatchElement = 0;
365     if (selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector)
366         topChildOrSubselector = selector;
367     
368     if (selector->relation() != CSSSelector::SubSelector)
369         element = element->parentElement();
370     
371     selector = selector->tagHistory();
372     
373     // We know this compound selector has descendant, child and subselector combinators only and all components are simple.
374     while (selector) {
375         switch (selector->m_match) {
376         case CSSSelector::Class:
377             if (!fastCheckSingleSelector<checkClassValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
378                 return false;
379             break;
380         case CSSSelector::Id:
381             if (!fastCheckSingleSelector<checkIDValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
382                 return false;
383             break;
384         case CSSSelector::None:
385             if (!fastCheckSingleSelector<checkTagValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
386                 return false;
387             break;
388         default:
389             ASSERT_NOT_REACHED();
390         }
391     }
392     return true;
393 }
394
395 bool SelectorChecker::isFastCheckableSelector(const CSSSelector* selector)
396 {
397     for (; selector; selector = selector->tagHistory()) {
398         if (selector->relation() != CSSSelector::Descendant && selector->relation() != CSSSelector::Child && selector->relation() != CSSSelector::SubSelector)
399             return false;
400         if (selector->m_match != CSSSelector::None && selector->m_match != CSSSelector::Id && selector->m_match != CSSSelector::Class)
401             return false;
402     }
403     return true;
404 }
405
406 // Recursive check of selectors and combinators
407 // It can return 3 different values:
408 // * SelectorMatches         - the selector matches the element e
409 // * SelectorFailsLocally    - the selector fails for the element e
410 // * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e
411 SelectorChecker::SelectorMatch SelectorChecker::checkSelector(CSSSelector* sel, Element* e, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const
412 {
413 #if ENABLE(SVG)
414     // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
415     // because its contents are not part of the formal document structure.
416     if (e->isSVGShadowRoot())
417         return SelectorFailsCompletely;
418 #endif
419     
420     // first selector has to match
421     if (!checkOneSelector(sel, e, dynamicPseudo, isSubSelector, encounteredLink, elementStyle, elementParentStyle))
422         return SelectorFailsLocally;
423     
424     // The rest of the selectors has to match
425     CSSSelector::Relation relation = sel->relation();
426     
427     // Prepare next sel
428     sel = sel->tagHistory();
429     if (!sel)
430         return SelectorMatches;
431     
432     if (relation != CSSSelector::SubSelector)
433         // Bail-out if this selector is irrelevant for the pseudoStyle
434         if (m_pseudoStyle != NOPSEUDO && m_pseudoStyle != dynamicPseudo)
435             return SelectorFailsCompletely;
436     
437     // Check for nested links.
438     if (m_isMatchingVisitedPseudoClass && !isSubSelector) {
439         RenderStyle* currentStyle = elementStyle ? elementStyle : e->renderStyle();
440         if (currentStyle && currentStyle->insideLink() && e->isLink()) {
441             if (encounteredLink)
442                 m_isMatchingVisitedPseudoClass = false; // This link is not relevant to the style being resolved, so disable matching.
443             else
444                 encounteredLink = true;
445         }
446     }
447     
448     switch (relation) {
449     case CSSSelector::Descendant:
450         while (true) {
451             ContainerNode* n = e->parentNode();
452             if (!n || !n->isElementNode())
453                 return SelectorFailsCompletely;
454             e = static_cast<Element*>(n);
455             SelectorMatch match = checkSelector(sel, e, dynamicPseudo, false, encounteredLink);
456             if (match != SelectorFailsLocally)
457                 return match;
458         }
459         break;
460     case CSSSelector::Child: 
461         {
462             ContainerNode* n = e->parentNode();
463             if (!n || !n->isElementNode())
464                 return SelectorFailsCompletely;
465             e = static_cast<Element*>(n);
466             return checkSelector(sel, e, dynamicPseudo, false, encounteredLink);
467         }
468     case CSSSelector::DirectAdjacent:
469         {
470             if (!m_isCollectingRulesOnly) {
471                 RenderStyle* currentStyle = elementStyle ? elementStyle : e->renderStyle();
472                 if (currentStyle)
473                     currentStyle->setAffectedByDirectAdjacentRules();
474             }
475             Node* n = e->previousSibling();
476             while (n && !n->isElementNode())
477                 n = n->previousSibling();
478             if (!n)
479                 return SelectorFailsLocally;
480             e = static_cast<Element*>(n);
481             m_isMatchingVisitedPseudoClass = false;
482             return checkSelector(sel, e, dynamicPseudo, false, encounteredLink);
483         }
484     case CSSSelector::IndirectAdjacent:
485         if (!m_isCollectingRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) {
486             RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
487             if (parentStyle)
488                 parentStyle->setChildrenAffectedByForwardPositionalRules();
489         }
490         while (true) {
491             Node* n = e->previousSibling();
492             while (n && !n->isElementNode())
493                 n = n->previousSibling();
494             if (!n)
495                 return SelectorFailsLocally;
496             e = static_cast<Element*>(n);
497             m_isMatchingVisitedPseudoClass = false;
498             SelectorMatch match = checkSelector(sel, e, dynamicPseudo, false, encounteredLink);
499             if (match != SelectorFailsLocally)
500                 return match;
501         };
502         break;
503     case CSSSelector::SubSelector:
504         // a selector is invalid if something follows a pseudo-element
505         // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
506         // to follow the pseudo elements.
507         if ((elementStyle || m_isCollectingRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION
508              && !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && sel->m_match == CSSSelector::PseudoClass))
509             return SelectorFailsCompletely;
510         return checkSelector(sel, e, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle);
511     case CSSSelector::ShadowDescendant:
512         {
513             Node* shadowHostNode = e->shadowAncestorNode();
514             if (shadowHostNode == e || !shadowHostNode->isElementNode())
515                 return SelectorFailsCompletely;
516             e = static_cast<Element*>(shadowHostNode);
517             return checkSelector(sel, e, dynamicPseudo, false, encounteredLink);
518         }
519     }
520     
521     return SelectorFailsCompletely;
522 }
523
524 static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName)
525 {
526     set->add(qName.localName().impl());
527 }
528
529 static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet()
530 {
531     // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive
532     // Mozilla treats all other values as case-sensitive, thus so do we.
533     HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>;
534     
535     addLocalNameToSet(attrSet, accept_charsetAttr);
536     addLocalNameToSet(attrSet, acceptAttr);
537     addLocalNameToSet(attrSet, alignAttr);
538     addLocalNameToSet(attrSet, alinkAttr);
539     addLocalNameToSet(attrSet, axisAttr);
540     addLocalNameToSet(attrSet, bgcolorAttr);
541     addLocalNameToSet(attrSet, charsetAttr);
542     addLocalNameToSet(attrSet, checkedAttr);
543     addLocalNameToSet(attrSet, clearAttr);
544     addLocalNameToSet(attrSet, codetypeAttr);
545     addLocalNameToSet(attrSet, colorAttr);
546     addLocalNameToSet(attrSet, compactAttr);
547     addLocalNameToSet(attrSet, declareAttr);
548     addLocalNameToSet(attrSet, deferAttr);
549     addLocalNameToSet(attrSet, dirAttr);
550     addLocalNameToSet(attrSet, disabledAttr);
551     addLocalNameToSet(attrSet, enctypeAttr);
552     addLocalNameToSet(attrSet, faceAttr);
553     addLocalNameToSet(attrSet, frameAttr);
554     addLocalNameToSet(attrSet, hreflangAttr);
555     addLocalNameToSet(attrSet, http_equivAttr);
556     addLocalNameToSet(attrSet, langAttr);
557     addLocalNameToSet(attrSet, languageAttr);
558     addLocalNameToSet(attrSet, linkAttr);
559     addLocalNameToSet(attrSet, mediaAttr);
560     addLocalNameToSet(attrSet, methodAttr);
561     addLocalNameToSet(attrSet, multipleAttr);
562     addLocalNameToSet(attrSet, nohrefAttr);
563     addLocalNameToSet(attrSet, noresizeAttr);
564     addLocalNameToSet(attrSet, noshadeAttr);
565     addLocalNameToSet(attrSet, nowrapAttr);
566     addLocalNameToSet(attrSet, readonlyAttr);
567     addLocalNameToSet(attrSet, relAttr);
568     addLocalNameToSet(attrSet, revAttr);
569     addLocalNameToSet(attrSet, rulesAttr);
570     addLocalNameToSet(attrSet, scopeAttr);
571     addLocalNameToSet(attrSet, scrollingAttr);
572     addLocalNameToSet(attrSet, selectedAttr);
573     addLocalNameToSet(attrSet, shapeAttr);
574     addLocalNameToSet(attrSet, targetAttr);
575     addLocalNameToSet(attrSet, textAttr);
576     addLocalNameToSet(attrSet, typeAttr);
577     addLocalNameToSet(attrSet, valignAttr);
578     addLocalNameToSet(attrSet, valuetypeAttr);
579     addLocalNameToSet(attrSet, vlinkAttr);
580     
581     return attrSet;
582 }
583
584 static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr)
585 {
586     static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
587     bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom);
588     return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl());
589 }
590
591 static bool attributeQualifiedNameMatches(Attribute* attribute, const QualifiedName& selectorAttr)
592 {
593     if (selectorAttr.localName() != attribute->localName())
594         return false;
595     
596     return selectorAttr.prefix() == starAtom || selectorAttr.namespaceURI() == attribute->namespaceURI();
597 }
598
599 static bool attributeValueMatches(Attribute* attributeItem, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive)
600 {
601     const AtomicString& value = attributeItem->value();
602     if (value.isNull())
603         return false;
604     
605     switch (match) {
606     case CSSSelector::Exact:
607         if (caseSensitive ? selectorValue != value : !equalIgnoringCase(selectorValue, value))
608             return false;
609         break;
610     case CSSSelector::List:
611         {
612             // Ignore empty selectors or selectors containing spaces
613             if (selectorValue.contains(' ') || selectorValue.isEmpty())
614                 return false;
615             
616             unsigned startSearchAt = 0;
617             while (true) {
618                 size_t foundPos = value.find(selectorValue, startSearchAt, caseSensitive);
619                 if (foundPos == notFound)
620                     return false;
621                 if (!foundPos || value[foundPos - 1] == ' ') {
622                     unsigned endStr = foundPos + selectorValue.length();
623                     if (endStr == value.length() || value[endStr] == ' ')
624                         break; // We found a match.
625                 }
626                 
627                 // No match. Keep looking.
628                 startSearchAt = foundPos + 1;
629             }
630             break;
631         }
632     case CSSSelector::Contain:
633         if (!value.contains(selectorValue, caseSensitive) || selectorValue.isEmpty())
634             return false;
635         break;
636     case CSSSelector::Begin:
637         if (!value.startsWith(selectorValue, caseSensitive) || selectorValue.isEmpty())
638             return false;
639         break;
640     case CSSSelector::End:
641         if (!value.endsWith(selectorValue, caseSensitive) || selectorValue.isEmpty())
642             return false;
643         break;
644     case CSSSelector::Hyphen:
645         if (value.length() < selectorValue.length())
646             return false;
647         if (!value.startsWith(selectorValue, caseSensitive))
648             return false;
649         // It they start the same, check for exact match or following '-':
650         if (value.length() != selectorValue.length() && value[selectorValue.length()] != '-')
651             return false;
652         break;
653     case CSSSelector::PseudoClass:
654     case CSSSelector::PseudoElement:
655     default:
656         break;
657     }
658     
659     return true;
660 }
661
662 static bool anyAttributeMatches(NamedNodeMap* attributes, CSSSelector::Match match, const QualifiedName& selectorAttr, const AtomicString& selectorValue, bool caseSensitive)
663 {
664     for (size_t i = 0; i < attributes->length(); ++i) {
665         Attribute* attributeItem = attributes->attributeItem(i);
666         
667         if (!attributeQualifiedNameMatches(attributeItem, selectorAttr))
668             continue;
669         
670         if (attributeValueMatches(attributeItem, match, selectorValue, caseSensitive))
671             return true;
672     }
673     
674     return false;
675 }
676
677 bool SelectorChecker::checkOneSelector(CSSSelector* sel, Element* e, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const
678 {
679     ASSERT(e);
680     if (!e)
681         return false;
682     
683     if (!selectorTagMatches(e, sel))
684         return false;
685     
686     if (sel->hasAttribute()) {
687         if (sel->m_match == CSSSelector::Class)
688             return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value());
689         
690         if (sel->m_match == CSSSelector::Id)
691             return e->hasID() && e->idForStyleResolution() == sel->value();
692         
693         const QualifiedName& attr = sel->attribute();
694         
695         // FIXME: Handle the case were elementStyle is 0.
696         if (elementStyle && (!e->isStyledElement() || (!static_cast<StyledElement*>(e)->isMappedAttribute(attr) && attr != typeAttr && attr != readonlyAttr)))
697             elementStyle->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style.
698         
699         NamedNodeMap* attributes = e->attributes(true);
700         if (!attributes)
701             return false;
702         
703         bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr);
704         
705         if (!anyAttributeMatches(attributes, static_cast<CSSSelector::Match>(sel->m_match), attr, sel->value(), caseSensitive))
706             return false;
707     }
708     
709     if (sel->m_match == CSSSelector::PseudoClass) {
710         // Handle :not up front.
711         if (sel->pseudoType() == CSSSelector::PseudoNot) {
712             ASSERT(sel->selectorList());
713             for (CSSSelector* subSel = sel->selectorList()->first(); subSel; subSel = subSel->tagHistory()) {
714                 // :not cannot nest. I don't really know why this is a
715                 // restriction in CSS3, but it is, so let's honor it.
716                 // the parser enforces that this never occurs
717                 ASSERT(subSel->pseudoType() != CSSSelector::PseudoNot);
718                 
719                 if (!checkOneSelector(subSel, e, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle))
720                     return true;
721             }
722         } else if (dynamicPseudo != NOPSEUDO && (RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER)) {
723             // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
724             // (since there are no elements involved).
725             return checkScrollbarPseudoClass(sel, dynamicPseudo);
726         } else if (dynamicPseudo == SELECTION) {
727             if (sel->pseudoType() == CSSSelector::PseudoWindowInactive)
728                 return !m_document->page()->focusController()->isActive();
729         }
730         
731         // Normal element pseudo class checking.
732         switch (sel->pseudoType()) {
733             // Pseudo classes:
734         case CSSSelector::PseudoNot:
735             break; // Already handled up above.
736         case CSSSelector::PseudoEmpty:
737             {
738                 bool result = true;
739                 for (Node* n = e->firstChild(); n; n = n->nextSibling()) {
740                     if (n->isElementNode()) {
741                         result = false;
742                         break;
743                     }
744                     if (n->isTextNode()) {
745                         Text* textNode = static_cast<Text*>(n);
746                         if (!textNode->data().isEmpty()) {
747                             result = false;
748                             break;
749                         }
750                     }
751                 }
752                 if (!m_isCollectingRulesOnly) {
753                     if (elementStyle)
754                         elementStyle->setEmptyState(result);
755                     else if (e->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique()))
756                         e->renderStyle()->setEmptyState(result);
757                 }
758                 return result;
759             }
760         case CSSSelector::PseudoFirstChild:
761             // first-child matches the first child that is an element
762             if (e->parentNode() && e->parentNode()->isElementNode()) {
763                 bool result = false;
764                 Node* n = e->previousSibling();
765                 while (n && !n->isElementNode())
766                     n = n->previousSibling();
767                 if (!n)
768                     result = true;
769                 if (!m_isCollectingRulesOnly) {
770                     RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
771                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
772                     if (parentStyle)
773                         parentStyle->setChildrenAffectedByFirstChildRules();
774                     if (result && childStyle)
775                         childStyle->setFirstChildState();
776                 }
777                 return result;
778             }
779             break;
780         case CSSSelector::PseudoFirstOfType:
781             // first-of-type matches the first element of its type
782             if (e->parentNode() && e->parentNode()->isElementNode()) {
783                 bool result = false;
784                 const QualifiedName& type = e->tagQName();
785                 Node* n = e->previousSibling();
786                 while (n) {
787                     if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
788                         break;
789                     n = n->previousSibling();
790                 }
791                 if (!n)
792                     result = true;
793                 if (!m_isCollectingRulesOnly) {
794                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
795                     if (parentStyle)
796                         parentStyle->setChildrenAffectedByForwardPositionalRules();
797                 }
798                 return result;
799             }
800             break;
801         case CSSSelector::PseudoLastChild:
802             // last-child matches the last child that is an element
803             if (Element* parentElement = e->parentElement()) {
804                 bool result = false;
805                 if (parentElement->isFinishedParsingChildren()) {
806                     Node* n = e->nextSibling();
807                     while (n && !n->isElementNode())
808                         n = n->nextSibling();
809                     if (!n)
810                         result = true;
811                 }
812                 if (!m_isCollectingRulesOnly) {
813                     RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
814                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
815                     if (parentStyle)
816                         parentStyle->setChildrenAffectedByLastChildRules();
817                     if (result && childStyle)
818                         childStyle->setLastChildState();
819                 }
820                 return result;
821             }
822             break;
823         case CSSSelector::PseudoLastOfType:
824             // last-of-type matches the last element of its type
825             if (Element* parentElement = e->parentElement()) {
826                 if (!m_isCollectingRulesOnly) {
827                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
828                     if (parentStyle)
829                         parentStyle->setChildrenAffectedByBackwardPositionalRules();
830                 }
831                 if (!parentElement->isFinishedParsingChildren())
832                     return false;
833                 bool result = false;
834                 const QualifiedName& type = e->tagQName();
835                 Node* n = e->nextSibling();
836                 while (n) {
837                     if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
838                         break;
839                     n = n->nextSibling();
840                 }
841                 if (!n)
842                     result = true;
843                 return result;
844             }
845             break;
846         case CSSSelector::PseudoOnlyChild:
847             if (Element* parentElement = e->parentElement()) {
848                 bool firstChild = false;
849                 bool lastChild = false;
850                 
851                 Node* n = e->previousSibling();
852                 while (n && !n->isElementNode())
853                     n = n->previousSibling();
854                 if (!n)
855                     firstChild = true;
856                 if (firstChild && parentElement->isFinishedParsingChildren()) {
857                     n = e->nextSibling();
858                     while (n && !n->isElementNode())
859                         n = n->nextSibling();
860                     if (!n)
861                         lastChild = true;
862                 }
863                 if (!m_isCollectingRulesOnly) {
864                     RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
865                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
866                     if (parentStyle) {
867                         parentStyle->setChildrenAffectedByFirstChildRules();
868                         parentStyle->setChildrenAffectedByLastChildRules();
869                     }
870                     if (firstChild && childStyle)
871                         childStyle->setFirstChildState();
872                     if (lastChild && childStyle)
873                         childStyle->setLastChildState();
874                 }
875                 return firstChild && lastChild;
876             }
877             break;
878         case CSSSelector::PseudoOnlyOfType:
879             // FIXME: This selector is very slow.
880             if (Element* parentElement = e->parentElement()) {
881                 if (!m_isCollectingRulesOnly) {
882                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
883                     if (parentStyle) {
884                         parentStyle->setChildrenAffectedByForwardPositionalRules();
885                         parentStyle->setChildrenAffectedByBackwardPositionalRules();
886                     }
887                 }
888                 if (!parentElement->isFinishedParsingChildren())
889                     return false;
890                 bool firstChild = false;
891                 bool lastChild = false;
892                 const QualifiedName& type = e->tagQName();
893                 Node* n = e->previousSibling();
894                 while (n) {
895                     if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
896                         break;
897                     n = n->previousSibling();
898                 }
899                 if (!n)
900                     firstChild = true;
901                 if (firstChild) {
902                     n = e->nextSibling();
903                     while (n) {
904                         if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
905                             break;
906                         n = n->nextSibling();
907                     }
908                     if (!n)
909                         lastChild = true;
910                 }
911                 return firstChild && lastChild;
912             }
913             break;
914         case CSSSelector::PseudoNthChild:
915             if (!sel->parseNth())
916                 break;
917             if (Element* parentElement = e->parentElement()) {
918                 int count = 1;
919                 Node* n = e->previousSibling();
920                 while (n) {
921                     if (n->isElementNode()) {
922                         RenderStyle* s = n->renderStyle();
923                         unsigned index = s ? s->childIndex() : 0;
924                         if (index) {
925                             count += index;
926                             break;
927                         }
928                         count++;
929                     }
930                     n = n->previousSibling();
931                 }
932                 
933                 if (!m_isCollectingRulesOnly) {
934                     RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
935                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
936                     if (childStyle)
937                         childStyle->setChildIndex(count);
938                     if (parentStyle)
939                         parentStyle->setChildrenAffectedByForwardPositionalRules();
940                 }
941                 
942                 if (sel->matchNth(count))
943                     return true;
944             }
945             break;
946         case CSSSelector::PseudoNthOfType:
947             if (!sel->parseNth())
948                 break;
949             if (Element* parentElement = e->parentElement()) {
950                 int count = 1;
951                 const QualifiedName& type = e->tagQName();
952                 Node* n = e->previousSibling();
953                 while (n) {
954                     if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
955                         count++;
956                     n = n->previousSibling();
957                 }
958                 
959                 if (!m_isCollectingRulesOnly) {
960                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
961                     if (parentStyle)
962                         parentStyle->setChildrenAffectedByForwardPositionalRules();
963                 }
964                 
965                 if (sel->matchNth(count))
966                     return true;
967             }
968             break;
969         case CSSSelector::PseudoNthLastChild:
970             if (!sel->parseNth())
971                 break;
972             if (Element* parentElement = e->parentElement()) {
973                 if (!m_isCollectingRulesOnly) {
974                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
975                     if (parentStyle)
976                         parentStyle->setChildrenAffectedByBackwardPositionalRules();
977                 }
978                 if (!parentElement->isFinishedParsingChildren())
979                     return false;
980                 int count = 1;
981                 Node* n = e->nextSibling();
982                 while (n) {
983                     if (n->isElementNode())
984                         count++;
985                     n = n->nextSibling();
986                 }
987                 if (sel->matchNth(count))
988                     return true;
989             }
990             break;
991         case CSSSelector::PseudoNthLastOfType:
992             if (!sel->parseNth())
993                 break;
994             if (Element* parentElement = e->parentElement()) {
995                 if (!m_isCollectingRulesOnly) {
996                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
997                     if (parentStyle)
998                         parentStyle->setChildrenAffectedByBackwardPositionalRules();
999                 }
1000                 if (!parentElement->isFinishedParsingChildren())
1001                     return false;
1002                 int count = 1;
1003                 const QualifiedName& type = e->tagQName();
1004                 Node* n = e->nextSibling();
1005                 while (n) {
1006                     if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
1007                         count++;
1008                     n = n->nextSibling();
1009                 }
1010                 if (sel->matchNth(count))
1011                     return true;
1012             }
1013             break;
1014         case CSSSelector::PseudoTarget:
1015             if (e == e->document()->cssTarget())
1016                 return true;
1017             break;
1018         case CSSSelector::PseudoAny:
1019             for (CSSSelector* selector = sel->selectorList()->first(); selector; selector = CSSSelectorList::next(selector)) {
1020                 if (checkSelector(selector, e, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle) == SelectorMatches)
1021                     return true;
1022             }
1023             break;
1024         case CSSSelector::PseudoAnyLink:
1025             if (e && e->isLink())
1026                 return true;
1027             break;
1028         case CSSSelector::PseudoAutofill:
1029             if (!e || !e->isFormControlElement())
1030                 break;
1031             if (HTMLInputElement* inputElement = e->toInputElement())
1032                 return inputElement->isAutofilled();
1033             break;
1034         case CSSSelector::PseudoLink:
1035             if (e && e->isLink())
1036                 return !m_isMatchingVisitedPseudoClass;
1037             break;
1038         case CSSSelector::PseudoVisited:
1039             if (e && e->isLink())
1040                 return m_isMatchingVisitedPseudoClass || InspectorInstrumentation::forcePseudoState(e, CSSSelector::PseudoVisited);
1041             break;
1042         case CSSSelector::PseudoDrag:
1043             if (elementStyle)
1044                 elementStyle->setAffectedByDragRules(true);
1045             else if (e->renderStyle())
1046                 e->renderStyle()->setAffectedByDragRules(true);
1047             if (e->renderer() && e->renderer()->isDragging())
1048                 return true;
1049             break;
1050         case CSSSelector::PseudoFocus:
1051             if (e && ((e->focused() && e->document()->frame() && e->document()->frame()->selection()->isFocusedAndActive()) || InspectorInstrumentation::forcePseudoState(e, CSSSelector::PseudoFocus)))
1052                 return true;
1053             break;
1054         case CSSSelector::PseudoHover:
1055             // If we're in quirks mode, then hover should never match anchors with no
1056             // href and *:hover should not match anything. This is important for sites like wsj.com.
1057             if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1058                 if (elementStyle)
1059                     elementStyle->setAffectedByHoverRules(true);
1060                 else if (e->renderStyle())
1061                     e->renderStyle()->setAffectedByHoverRules(true);
1062                 if (e->hovered() || InspectorInstrumentation::forcePseudoState(e, CSSSelector::PseudoHover))
1063                     return true;
1064             }
1065             break;
1066         case CSSSelector::PseudoActive:
1067             // If we're in quirks mode, then :active should never match anchors with no
1068             // href and *:active should not match anything. 
1069             if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1070                 if (elementStyle)
1071                     elementStyle->setAffectedByActiveRules(true);
1072                 else if (e->renderStyle())
1073                     e->renderStyle()->setAffectedByActiveRules(true);
1074                 if (e->active() || InspectorInstrumentation::forcePseudoState(e, CSSSelector::PseudoActive))
1075                     return true;
1076             }
1077             break;
1078         case CSSSelector::PseudoEnabled:
1079             if (e && e->isFormControlElement())
1080                 return e->isEnabledFormControl();
1081             break;
1082         case CSSSelector::PseudoFullPageMedia:
1083             return e && e->document() && e->document()->isMediaDocument();
1084             break;
1085         case CSSSelector::PseudoDefault:
1086             return e && e->isDefaultButtonForForm();
1087         case CSSSelector::PseudoDisabled:
1088             if (e && e->isFormControlElement())
1089                 return !e->isEnabledFormControl();
1090             break;
1091         case CSSSelector::PseudoReadOnly:
1092             if (!e || !e->isFormControlElement())
1093                 return false;
1094             return e->isTextFormControl() && e->isReadOnlyFormControl();
1095         case CSSSelector::PseudoReadWrite: 
1096             if (!e || !e->isFormControlElement())
1097                 return false;
1098             return e->isTextFormControl() && !e->isReadOnlyFormControl();
1099         case CSSSelector::PseudoOptional:
1100             return e && e->isOptionalFormControl();
1101         case CSSSelector::PseudoRequired:
1102             return e && e->isRequiredFormControl();
1103         case CSSSelector::PseudoValid:
1104             if (!e)
1105                 return false;
1106             e->document()->setContainsValidityStyleRules();
1107             return e->willValidate() && e->isValidFormControlElement();
1108         case CSSSelector::PseudoInvalid:
1109             if (!e)
1110                 return false;
1111             e->document()->setContainsValidityStyleRules();
1112             return (e->willValidate() && !e->isValidFormControlElement()) || e->hasUnacceptableValue();
1113         case CSSSelector::PseudoChecked:
1114             {
1115                 if (!e || !e->isFormControlElement())
1116                     break;
1117                 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
1118                 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
1119                 // obey the CSS spec here in the test for matching the pseudo.
1120                 HTMLInputElement* inputElement = e->toInputElement();
1121                 if (inputElement && inputElement->shouldAppearChecked() && !inputElement->isIndeterminate())
1122                     return true;
1123                 break;
1124             }
1125         case CSSSelector::PseudoIndeterminate:
1126             {
1127                 if (!e || !e->isFormControlElement())
1128                     break;
1129 #if ENABLE(PROGRESS_TAG)
1130                 if (e->hasTagName(progressTag)) {
1131                     HTMLProgressElement* progress = static_cast<HTMLProgressElement*>(e);
1132                     if (progress && !progress->isDeterminate())
1133                         return true;
1134                     break;
1135                 }
1136 #endif
1137                 HTMLInputElement* inputElement = e->toInputElement();
1138                 if (inputElement && inputElement->isIndeterminate())
1139                     return true;
1140                 break;
1141             }
1142         case CSSSelector::PseudoRoot:
1143             if (e == e->document()->documentElement())
1144                 return true;
1145             break;
1146         case CSSSelector::PseudoLang:
1147             {
1148                 AtomicString value = e->computeInheritedLanguage();
1149                 const AtomicString& argument = sel->argument();
1150                 if (value.isEmpty() || !value.startsWith(argument, false))
1151                     break;
1152                 if (value.length() != argument.length() && value[argument.length()] != '-')
1153                     break;
1154                 return true;
1155             }
1156 #if ENABLE(FULLSCREEN_API)
1157         case CSSSelector::PseudoFullScreen:
1158             // While a Document is in the fullscreen state, and the document's current fullscreen 
1159             // element is an element in the document, the 'full-screen' pseudoclass applies to 
1160             // that element. Also, an <iframe>, <object> or <embed> element whose child browsing 
1161             // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied.
1162             if (e->isFrameElementBase() && static_cast<HTMLFrameElementBase*>(e)->containsFullScreenElement())
1163                 return true;
1164             if (!e->document()->webkitIsFullScreen())
1165                 return false;
1166             return e == e->document()->webkitCurrentFullScreenElement();
1167         case CSSSelector::PseudoAnimatingFullScreenTransition:
1168             if (e != e->document()->webkitCurrentFullScreenElement())
1169                 return false;
1170             return e->document()->isAnimatingFullScreen();
1171         case CSSSelector::PseudoFullScreenAncestor:
1172             return e->containsFullScreenElement();
1173         case CSSSelector::PseudoFullScreenDocument:
1174             // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies 
1175             // to all elements of that Document.
1176             if (!e->document()->webkitIsFullScreen())
1177                 return false;
1178             return true;
1179 #endif
1180         case CSSSelector::PseudoInRange:
1181             if (!e)
1182                 return false;
1183             e->document()->setContainsValidityStyleRules();
1184             return e->isInRange();
1185         case CSSSelector::PseudoOutOfRange:
1186             if (!e)
1187                 return false;
1188             e->document()->setContainsValidityStyleRules();
1189             return e->isOutOfRange();
1190         case CSSSelector::PseudoUnknown:
1191         case CSSSelector::PseudoNotParsed:
1192         default:
1193             ASSERT_NOT_REACHED();
1194             break;
1195         }
1196         return false;
1197     }
1198     if (sel->m_match == CSSSelector::PseudoElement) {
1199         if (!elementStyle && !m_isCollectingRulesOnly)
1200             return false;
1201         
1202         if (sel->isUnknownPseudoElement()) {
1203             m_hasUnknownPseudoElements = true;
1204             return e->shadowPseudoId() == sel->value();
1205         }
1206         
1207         PseudoId pseudoId = CSSSelector::pseudoId(sel->pseudoType());
1208         if (pseudoId == FIRST_LETTER) {
1209             if (Document* document = e->document())
1210                 document->setUsesFirstLetterRules(true);
1211         }
1212         if (pseudoId != NOPSEUDO)
1213             dynamicPseudo = pseudoId;
1214     }
1215     // ### add the rest of the checks...
1216     return true;
1217 }
1218
1219 bool SelectorChecker::checkScrollbarPseudoClass(CSSSelector* sel, PseudoId&) const
1220 {
1221     RenderScrollbar* scrollbar = RenderScrollbar::scrollbarForStyleResolve();
1222     ScrollbarPart part = RenderScrollbar::partForStyleResolve();
1223     
1224     // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real
1225     // pseudo class and just apply to everything.
1226     if (sel->pseudoType() == CSSSelector::PseudoWindowInactive)
1227         return !m_document->page()->focusController()->isActive();
1228     
1229     if (!scrollbar)
1230         return false;
1231     
1232     ASSERT(sel->m_match == CSSSelector::PseudoClass);
1233     switch (sel->pseudoType()) {
1234     case CSSSelector::PseudoEnabled:
1235         return scrollbar->enabled();
1236     case CSSSelector::PseudoDisabled:
1237         return !scrollbar->enabled();
1238     case CSSSelector::PseudoHover:
1239         {
1240             ScrollbarPart hoveredPart = scrollbar->hoveredPart();
1241             if (part == ScrollbarBGPart)
1242                 return hoveredPart != NoPart;
1243             if (part == TrackBGPart)
1244                 return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart;
1245             return part == hoveredPart;
1246         }
1247     case CSSSelector::PseudoActive:
1248         {
1249             ScrollbarPart pressedPart = scrollbar->pressedPart();
1250             if (part == ScrollbarBGPart)
1251                 return pressedPart != NoPart;
1252             if (part == TrackBGPart)
1253                 return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart;
1254             return part == pressedPart;
1255         }
1256     case CSSSelector::PseudoHorizontal:
1257         return scrollbar->orientation() == HorizontalScrollbar;
1258     case CSSSelector::PseudoVertical:
1259         return scrollbar->orientation() == VerticalScrollbar;
1260     case CSSSelector::PseudoDecrement:
1261         return part == BackButtonStartPart || part == BackButtonEndPart || part == BackTrackPart;
1262     case CSSSelector::PseudoIncrement:
1263         return part == ForwardButtonStartPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
1264     case CSSSelector::PseudoStart:
1265         return part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart;
1266     case CSSSelector::PseudoEnd:
1267         return part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
1268     case CSSSelector::PseudoDoubleButton: 
1269         {
1270             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1271             if (part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart)
1272                 return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth;
1273             if (part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart)
1274                 return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth;
1275             return false;
1276         } 
1277     case CSSSelector::PseudoSingleButton:
1278         {
1279             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1280             if (part == BackButtonStartPart || part == ForwardButtonEndPart || part == BackTrackPart || part == ForwardTrackPart)
1281                 return buttonsPlacement == ScrollbarButtonsSingle;
1282             return false;
1283         }
1284     case CSSSelector::PseudoNoButton:
1285         {
1286             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1287             if (part == BackTrackPart)
1288                 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd;
1289             if (part == ForwardTrackPart)
1290                 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart;
1291             return false;
1292         }
1293     case CSSSelector::PseudoCornerPresent:
1294         return scrollbar->scrollableArea()->isScrollCornerVisible();
1295     default:
1296         return false;
1297     }
1298 }
1299
1300 void SelectorChecker::allVisitedStateChanged()
1301 {
1302     if (m_linksCheckedForVisitedState.isEmpty())
1303         return;
1304     for (Node* node = m_document; node; node = node->traverseNextNode()) {
1305         if (node->isLink())
1306             node->setNeedsStyleRecalc();
1307     }
1308 }
1309
1310 void SelectorChecker::visitedStateChanged(LinkHash visitedHash)
1311 {
1312     if (!m_linksCheckedForVisitedState.contains(visitedHash))
1313         return;
1314     for (Node* node = m_document; node; node = node->traverseNextNode()) {
1315         const AtomicString* attr = linkAttribute(node);
1316         if (attr && visitedLinkHash(m_document->baseURL(), *attr) == visitedHash)
1317             node->setNeedsStyleRecalc();
1318     }
1319 }
1320
1321 }