Apply a zoom property when resolution is changed
[framework/web/webkit-efl.git] / 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 "FrameSelection.h"
37 #include "HTMLAnchorElement.h"
38 #include "HTMLFrameElementBase.h"
39 #include "HTMLInputElement.h"
40 #include "HTMLNames.h"
41 #include "HTMLOptionElement.h"
42 #include "HTMLProgressElement.h"
43 #include "HTMLStyleElement.h"
44 #include "InspectorInstrumentation.h"
45 #include "NodeRenderStyle.h"
46 #include "Page.h"
47 #include "PageGroup.h"
48 #include "RenderObject.h"
49 #include "RenderScrollbar.h"
50 #include "RenderStyle.h"
51 #include "ScrollableArea.h"
52 #include "ScrollbarTheme.h"
53 #include "StyledElement.h"
54 #include "Text.h"
55 #include "XLinkNames.h"
56
57 #if USE(PLATFORM_STRATEGIES)
58 #include "PlatformStrategies.h"
59 #include "VisitedLinkStrategy.h"
60 #endif
61
62 namespace WebCore {
63
64 using namespace HTMLNames;
65
66 static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr);
67
68 SelectorChecker::SelectorChecker(Document* document, bool strictParsing)
69     : m_document(document)
70     , m_strictParsing(strictParsing)
71     , m_documentIsHTML(document->isHTMLDocument())
72     , m_mode(ResolvingStyle)
73     , m_pseudoStyle(NOPSEUDO)
74     , m_hasUnknownPseudoElements(false)
75 {
76 }
77
78 // Salt to separate otherwise identical string hashes so a class-selector like .article won't match <article> elements.
79 enum { TagNameSalt = 13, IdAttributeSalt = 17, ClassAttributeSalt = 19 };
80
81 static inline void collectElementIdentifierHashes(const Element* element, Vector<unsigned, 4>& identifierHashes)
82 {
83     identifierHashes.append(element->localName().impl()->existingHash() * TagNameSalt);
84     if (element->hasID())
85         identifierHashes.append(element->idForStyleResolution().impl()->existingHash() * IdAttributeSalt);
86     const StyledElement* styledElement = element->isStyledElement() ? static_cast<const StyledElement*>(element) : 0;
87     if (styledElement && styledElement->hasClass()) {
88         const SpaceSplitString& classNames = styledElement->classNames();
89         size_t count = classNames.size();
90         for (size_t i = 0; i < count; ++i)
91             identifierHashes.append(classNames[i].impl()->existingHash() * ClassAttributeSalt);
92     }
93 }
94
95 void SelectorChecker::pushParentStackFrame(Element* parent)
96 {
97     ASSERT(m_ancestorIdentifierFilter);
98     ASSERT(m_parentStack.isEmpty() || m_parentStack.last().element == parent->parentOrHostElement());
99     ASSERT(!m_parentStack.isEmpty() || !parent->parentOrHostElement());
100     m_parentStack.append(ParentStackFrame(parent));
101     ParentStackFrame& parentFrame = m_parentStack.last();
102     // Mix tags, class names and ids into some sort of weird bouillabaisse.
103     // The filter is used for fast rejection of child and descendant selectors.
104     collectElementIdentifierHashes(parent, parentFrame.identifierHashes);
105     size_t count = parentFrame.identifierHashes.size();
106     for (size_t i = 0; i < count; ++i)
107         m_ancestorIdentifierFilter->add(parentFrame.identifierHashes[i]);
108 }
109
110 void SelectorChecker::popParentStackFrame()
111 {
112     ASSERT(!m_parentStack.isEmpty());
113     ASSERT(m_ancestorIdentifierFilter);
114     const ParentStackFrame& parentFrame = m_parentStack.last();
115     size_t count = parentFrame.identifierHashes.size();
116     for (size_t i = 0; i < count; ++i)
117         m_ancestorIdentifierFilter->remove(parentFrame.identifierHashes[i]);
118     m_parentStack.removeLast();
119     if (m_parentStack.isEmpty()) {
120         ASSERT(m_ancestorIdentifierFilter->likelyEmpty());
121         m_ancestorIdentifierFilter.clear();
122     }
123 }
124
125 void SelectorChecker::setupParentStack(Element* parent)
126 {
127     ASSERT(m_parentStack.isEmpty() == !m_ancestorIdentifierFilter);
128     // Kill whatever we stored before.
129     m_parentStack.shrink(0);
130     m_ancestorIdentifierFilter = adoptPtr(new BloomFilter<bloomFilterKeyBits>);
131     // Fast version if parent is a root element:
132     if (!parent->parentOrHostNode()) {
133         pushParentStackFrame(parent);
134         return;
135     }
136     // Otherwise climb up the tree.
137     Vector<Element*, 30> ancestors;
138     for (Element* ancestor = parent; ancestor; ancestor = ancestor->parentOrHostElement())
139         ancestors.append(ancestor);
140     for (size_t n = ancestors.size(); n; --n)
141         pushParentStackFrame(ancestors[n - 1]);
142 }
143
144 void SelectorChecker::pushParent(Element* parent)
145 {
146     ASSERT(m_ancestorIdentifierFilter);
147     // We may get invoked for some random elements in some wacky cases during style resolve.
148     // Pause maintaining the stack in this case.
149     if (m_parentStack.last().element != parent->parentOrHostElement())
150         return;
151     pushParentStackFrame(parent);
152 }
153
154 static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector* selector, unsigned*& hash, const unsigned* end)
155 {
156     switch (selector->m_match) {
157     case CSSSelector::Id:
158         if (!selector->value().isEmpty())
159             (*hash++) = selector->value().impl()->existingHash() * IdAttributeSalt;
160         break;
161     case CSSSelector::Class:
162         if (!selector->value().isEmpty())
163             (*hash++) = selector->value().impl()->existingHash() * ClassAttributeSalt;
164         break;
165     default:
166         break;
167     }
168     if (hash == end)
169         return;
170     const AtomicString& localName = selector->tag().localName();
171     if (localName != starAtom)
172         (*hash++) = localName.impl()->existingHash() * TagNameSalt;
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     if (element->isSVGElement())
218         return &element->getAttribute(XLinkNames::hrefAttr);
219
220     return 0;
221 }
222
223 EInsideLink SelectorChecker::determineLinkStateSlowCase(Element* element) const
224 {
225     ASSERT(element->isLink());
226
227     const AtomicString* attribute = linkAttribute(element);
228     if (!attribute || attribute->isNull())
229         return NotInsideLink;
230
231     // An empty href refers to the document itself which is always visited. It is useful to check this explicitly so
232     // that visited links can be tested in platform independent manner, without explicit support in the test harness.
233     if (attribute->isEmpty())
234         return InsideVisitedLink;
235     
236     LinkHash hash;
237     if (element->hasTagName(aTag)) 
238         hash = static_cast<HTMLAnchorElement*>(element)->visitedLinkHash();
239     else
240         hash = visitedLinkHash(m_document->baseURL(), *attribute);
241
242     if (!hash)
243         return InsideUnvisitedLink;
244
245     Frame* frame = m_document->frame();
246     if (!frame)
247         return InsideUnvisitedLink;
248
249     Page* page = frame->page();
250     if (!page)
251         return InsideUnvisitedLink;
252
253     m_linksCheckedForVisitedState.add(hash);
254
255 #if USE(PLATFORM_STRATEGIES)
256     return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash, m_document->baseURL(), *attribute) ? InsideVisitedLink : InsideUnvisitedLink;
257 #else
258     return page->group().isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink;
259 #endif
260 }
261
262 bool SelectorChecker::checkSelector(CSSSelector* sel, Element* element, bool isFastCheckableSelector) const
263 {
264     if (isFastCheckableSelector && !element->isSVGElement()) {
265         if (!fastCheckRightmostSelector(sel, element, VisitedMatchDisabled))
266             return false;
267         return fastCheckSelector(sel, element);
268     }
269
270     PseudoId dynamicPseudo = NOPSEUDO;
271     return checkSelector(SelectorCheckingContext(sel, element, SelectorChecker::VisitedMatchDisabled), dynamicPseudo) == SelectorMatches;
272 }
273
274 namespace {
275
276 template <bool checkValue(const Element*, AtomicStringImpl*, const QualifiedName&), bool initAttributeName>
277 inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement)
278 {
279     AtomicStringImpl* value = selector->value().impl();
280     const QualifiedName& attribute = initAttributeName ? selector->attribute() : anyQName();
281     for (; element; element = element->parentElement()) {
282         if (checkValue(element, value, attribute) && SelectorChecker::tagMatches(element, selector)) {
283             if (selector->relation() == CSSSelector::Descendant)
284                 topChildOrSubselector = 0;
285             else if (!topChildOrSubselector) {
286                 ASSERT(selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector);
287                 topChildOrSubselector = selector;
288                 topChildOrSubselectorMatchElement = element;
289             }
290             if (selector->relation() != CSSSelector::SubSelector)
291                 element = element->parentElement();
292             selector = selector->tagHistory();
293             return true;
294         }
295         if (topChildOrSubselector) {
296             // Child or subselector check failed.
297             // If the match element is null, topChildOrSubselector was also the very topmost selector and had to match
298             // the original element we were checking.
299             if (!topChildOrSubselectorMatchElement)
300                 return false;
301             // There may be other matches down the ancestor chain.
302             // Rewind to the topmost child or subselector and the element it matched, continue checking ancestors.
303             selector = topChildOrSubselector;
304             element = topChildOrSubselectorMatchElement->parentElement();
305             topChildOrSubselector = 0;
306             return true;
307         }
308     }
309     return false;
310 }
311
312 inline bool checkClassValue(const Element* element, AtomicStringImpl* value, const QualifiedName&)
313 {
314     return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(value);
315 }
316
317 inline bool checkIDValue(const Element* element, AtomicStringImpl* value, const QualifiedName&)
318 {
319     return element->hasID() && element->idForStyleResolution().impl() == value;
320 }
321
322 inline bool checkExactAttributeValue(const Element* element, AtomicStringImpl* value, const QualifiedName& attributeName)
323 {
324     return SelectorChecker::checkExactAttribute(element, attributeName, value);
325 }
326
327 inline bool checkTagValue(const Element*, AtomicStringImpl*, const QualifiedName&)
328 {
329     return true;
330 }
331
332 }
333
334 inline bool SelectorChecker::fastCheckRightmostSelector(const CSSSelector* selector, const Element* element, VisitedMatchType visitedMatchType) const
335 {
336     ASSERT(isFastCheckableSelector(selector));
337
338     if (!SelectorChecker::tagMatches(element, selector))
339         return false;
340     switch (selector->m_match) {
341     case CSSSelector::None:
342         return true;
343     case CSSSelector::Class:
344         return checkClassValue(element, selector->value().impl(), anyQName());
345     case CSSSelector::Id:
346         return checkIDValue(element, selector->value().impl(), anyQName());
347     case CSSSelector::Exact:
348     case CSSSelector::Set:
349         return checkExactAttributeValue(element, selector->value().impl(), selector->attribute());
350     case CSSSelector::PseudoClass:
351         return commonPseudoClassSelectorMatches(element, selector, visitedMatchType);
352     default:
353         ASSERT_NOT_REACHED();
354     }
355     return false;
356 }
357
358 bool SelectorChecker::fastCheckSelector(const CSSSelector* selector, const Element* element) const
359 {
360     ASSERT(fastCheckRightmostSelector(selector, element, VisitedMatchEnabled));
361
362     const CSSSelector* topChildOrSubselector = 0;
363     const Element* topChildOrSubselectorMatchElement = 0;
364     if (selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector)
365         topChildOrSubselector = selector;
366
367     if (selector->relation() != CSSSelector::SubSelector)
368         element = element->parentElement();
369
370     selector = selector->tagHistory();
371
372     // We know this compound selector has descendant, child and subselector combinators only and all components are simple.
373     while (selector) {
374         switch (selector->m_match) {
375         case CSSSelector::Class:
376             if (!fastCheckSingleSelector<checkClassValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
377                 return false;
378             break;
379         case CSSSelector::Id:
380             if (!fastCheckSingleSelector<checkIDValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
381                 return false;
382             break;
383         case CSSSelector::None:
384             if (!fastCheckSingleSelector<checkTagValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
385                 return false;
386             break;
387         case CSSSelector::Set:
388         case CSSSelector::Exact:
389             if (!fastCheckSingleSelector<checkExactAttributeValue, true>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
390                 return false;
391             break;
392         default:
393             ASSERT_NOT_REACHED();
394         }
395     }
396     return true;
397 }
398
399 static inline bool isFastCheckableRelation(CSSSelector::Relation relation)
400 {
401     return relation == CSSSelector::Descendant || relation == CSSSelector::Child || relation == CSSSelector::SubSelector;
402 }
403
404 static inline bool isFastCheckableMatch(const CSSSelector* selector)
405 {
406     if (selector->m_match == CSSSelector::Set) {
407         // Style attribute is generated lazily but the fast path doesn't trigger it.
408         // Disallow them here rather than making the fast path more branchy.
409         return selector->attribute() != styleAttr;
410     }
411     if (selector->m_match == CSSSelector::Exact)
412         return selector->attribute() != styleAttr && !htmlAttributeHasCaseInsensitiveValue(selector->attribute());
413     return selector->m_match == CSSSelector::None || selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class;
414 }
415
416 static inline bool isFastCheckableRightmostSelector(const CSSSelector* selector)
417 {
418     if (!isFastCheckableRelation(selector->relation()))
419         return false;
420     return isFastCheckableMatch(selector) || SelectorChecker::isCommonPseudoClassSelector(selector);
421 }
422
423 bool SelectorChecker::isFastCheckableSelector(const CSSSelector* selector)
424 {
425     if (!isFastCheckableRightmostSelector(selector))
426         return false;
427     for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) {
428         if (!isFastCheckableRelation(selector->relation()))
429             return false;
430         if (!isFastCheckableMatch(selector))
431             return false;
432     }
433     return true;
434 }
435
436 // Recursive check of selectors and combinators
437 // It can return 4 different values:
438 // * SelectorMatches          - the selector matches the element e
439 // * SelectorFailsLocally     - the selector fails for the element e
440 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
441 // * SelectorFailsCompletely  - the selector fails for e and any sibling or ancestor of e
442 SelectorChecker::SelectorMatch SelectorChecker::checkSelector(const SelectorCheckingContext& context, PseudoId& dynamicPseudo) const
443 {
444     // first selector has to match
445     if (!checkOneSelector(context, dynamicPseudo))
446         return SelectorFailsLocally;
447
448     // The rest of the selectors has to match
449     CSSSelector::Relation relation = context.selector->relation();
450
451     // Prepare next selector
452     CSSSelector* historySelector = context.selector->tagHistory();
453     if (!historySelector)
454         return SelectorMatches;
455
456     SelectorCheckingContext nextContext(context);
457     nextContext.selector = historySelector;
458
459     if (relation != CSSSelector::SubSelector) {
460         // Abort if the next selector would exceed the scope.
461         if (context.element == context.scope)
462             return SelectorFailsCompletely;
463
464         // Bail-out if this selector is irrelevant for the pseudoStyle
465         if (m_pseudoStyle != NOPSEUDO && m_pseudoStyle != dynamicPseudo)
466             return SelectorFailsCompletely;
467
468         // Disable :visited matching when we see the first link or try to match anything else than an ancestors.
469         if (!context.isSubSelector && (context.element->isLink() || (relation != CSSSelector::Descendant && relation != CSSSelector::Child)))
470             nextContext.visitedMatchType = VisitedMatchDisabled;
471     }
472
473     switch (relation) {
474     case CSSSelector::Descendant:
475         nextContext.element = context.element->parentElement();
476         nextContext.isSubSelector = false;
477         nextContext.elementStyle = 0;
478         nextContext.elementParentStyle = 0;
479         for (; nextContext.element; nextContext.element = nextContext.element->parentElement()) {
480             SelectorMatch match = checkSelector(nextContext, dynamicPseudo);
481             if (match == SelectorMatches || match == SelectorFailsCompletely)
482                 return match;
483             if (nextContext.element == nextContext.scope)
484                 return SelectorFailsCompletely;
485         }
486         return SelectorFailsCompletely;
487
488     case CSSSelector::Child:
489         nextContext.element = context.element->parentElement();
490         if (!nextContext.element)
491             return SelectorFailsCompletely;
492         nextContext.isSubSelector = false;
493         nextContext.elementStyle = 0;
494         nextContext.elementParentStyle = 0;
495         return checkSelector(nextContext, dynamicPseudo);
496
497     case CSSSelector::DirectAdjacent:
498         if (m_mode == ResolvingStyle && context.element->parentElement()) {
499             RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : context.element->parentNode()->renderStyle();
500             if (parentStyle)
501                 parentStyle->setChildrenAffectedByDirectAdjacentRules();
502         }
503         nextContext.element = context.element->previousElementSibling();
504         if (!nextContext.element)
505             return SelectorFailsAllSiblings;
506         nextContext.isSubSelector = false;
507         nextContext.elementStyle = 0;
508         nextContext.elementParentStyle = 0;
509         return checkSelector(nextContext, dynamicPseudo);
510
511     case CSSSelector::IndirectAdjacent:
512         if (m_mode == ResolvingStyle && context.element->parentElement()) {
513             RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : context.element->parentNode()->renderStyle();
514             if (parentStyle)
515                 parentStyle->setChildrenAffectedByForwardPositionalRules();
516         }
517         nextContext.element = context.element->previousElementSibling();
518         nextContext.isSubSelector = false;
519         nextContext.elementStyle = 0;
520         nextContext.elementParentStyle = 0;
521         for (; nextContext.element; nextContext.element = nextContext.element->previousElementSibling()) {
522             SelectorMatch match = checkSelector(nextContext, dynamicPseudo);
523             if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely)
524                 return match;
525         };
526         return SelectorFailsAllSiblings;
527
528     case CSSSelector::SubSelector:
529         // a selector is invalid if something follows a pseudo-element
530         // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
531         // to follow the pseudo elements.
532         if ((context.elementStyle || m_mode == CollectingRules || m_mode == QueryingRules) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION
533              && !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && nextContext.selector->m_match == CSSSelector::PseudoClass))
534             return SelectorFailsCompletely;
535         nextContext.isSubSelector = true;
536         return checkSelector(nextContext, dynamicPseudo);
537
538     case CSSSelector::ShadowDescendant:
539         {
540             // If we're in the same tree-scope as the scoping element, then following a shadow descendant combinator would escape that and thus the scope.
541             if (context.scope && context.scope->treeScope() == context.element->treeScope())
542                 return SelectorFailsCompletely;
543             Element* shadowHostNode = context.element->shadowHost();
544             if (!shadowHostNode)
545                 return SelectorFailsCompletely;
546             nextContext.element = shadowHostNode;
547             nextContext.isSubSelector = false;
548             nextContext.elementStyle = 0;
549             nextContext.elementParentStyle = 0;
550             return checkSelector(nextContext, dynamicPseudo);
551         }
552     }
553
554     ASSERT_NOT_REACHED();
555     return SelectorFailsCompletely;
556 }
557
558 static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName)
559 {
560     set->add(qName.localName().impl());
561 }
562
563 static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet()
564 {
565     // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive
566     // Mozilla treats all other values as case-sensitive, thus so do we.
567     HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>;
568
569     addLocalNameToSet(attrSet, accept_charsetAttr);
570     addLocalNameToSet(attrSet, acceptAttr);
571     addLocalNameToSet(attrSet, alignAttr);
572     addLocalNameToSet(attrSet, alinkAttr);
573     addLocalNameToSet(attrSet, axisAttr);
574     addLocalNameToSet(attrSet, bgcolorAttr);
575     addLocalNameToSet(attrSet, charsetAttr);
576     addLocalNameToSet(attrSet, checkedAttr);
577     addLocalNameToSet(attrSet, clearAttr);
578     addLocalNameToSet(attrSet, codetypeAttr);
579     addLocalNameToSet(attrSet, colorAttr);
580     addLocalNameToSet(attrSet, compactAttr);
581     addLocalNameToSet(attrSet, declareAttr);
582     addLocalNameToSet(attrSet, deferAttr);
583     addLocalNameToSet(attrSet, dirAttr);
584     addLocalNameToSet(attrSet, disabledAttr);
585     addLocalNameToSet(attrSet, enctypeAttr);
586     addLocalNameToSet(attrSet, faceAttr);
587     addLocalNameToSet(attrSet, frameAttr);
588     addLocalNameToSet(attrSet, hreflangAttr);
589     addLocalNameToSet(attrSet, http_equivAttr);
590     addLocalNameToSet(attrSet, langAttr);
591     addLocalNameToSet(attrSet, languageAttr);
592     addLocalNameToSet(attrSet, linkAttr);
593     addLocalNameToSet(attrSet, mediaAttr);
594     addLocalNameToSet(attrSet, methodAttr);
595     addLocalNameToSet(attrSet, multipleAttr);
596     addLocalNameToSet(attrSet, nohrefAttr);
597     addLocalNameToSet(attrSet, noresizeAttr);
598     addLocalNameToSet(attrSet, noshadeAttr);
599     addLocalNameToSet(attrSet, nowrapAttr);
600     addLocalNameToSet(attrSet, readonlyAttr);
601     addLocalNameToSet(attrSet, relAttr);
602     addLocalNameToSet(attrSet, revAttr);
603     addLocalNameToSet(attrSet, rulesAttr);
604     addLocalNameToSet(attrSet, scopeAttr);
605     addLocalNameToSet(attrSet, scrollingAttr);
606     addLocalNameToSet(attrSet, selectedAttr);
607     addLocalNameToSet(attrSet, shapeAttr);
608     addLocalNameToSet(attrSet, targetAttr);
609     addLocalNameToSet(attrSet, textAttr);
610     addLocalNameToSet(attrSet, typeAttr);
611     addLocalNameToSet(attrSet, valignAttr);
612     addLocalNameToSet(attrSet, valuetypeAttr);
613     addLocalNameToSet(attrSet, vlinkAttr);
614
615     return attrSet;
616 }
617
618 bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr)
619 {
620     static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
621     bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom);
622     return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl());
623 }
624
625 static bool attributeValueMatches(const Attribute* attributeItem, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive)
626 {
627     const AtomicString& value = attributeItem->value();
628     if (value.isNull())
629         return false;
630
631     switch (match) {
632     case CSSSelector::Exact:
633         if (caseSensitive ? selectorValue != value : !equalIgnoringCase(selectorValue, value))
634             return false;
635         break;
636     case CSSSelector::List:
637         {
638             // Ignore empty selectors or selectors containing spaces
639             if (selectorValue.contains(' ') || selectorValue.isEmpty())
640                 return false;
641
642             unsigned startSearchAt = 0;
643             while (true) {
644                 size_t foundPos = value.find(selectorValue, startSearchAt, caseSensitive);
645                 if (foundPos == notFound)
646                     return false;
647                 if (!foundPos || value[foundPos - 1] == ' ') {
648                     unsigned endStr = foundPos + selectorValue.length();
649                     if (endStr == value.length() || value[endStr] == ' ')
650                         break; // We found a match.
651                 }
652
653                 // No match. Keep looking.
654                 startSearchAt = foundPos + 1;
655             }
656             break;
657         }
658     case CSSSelector::Contain:
659         if (!value.contains(selectorValue, caseSensitive) || selectorValue.isEmpty())
660             return false;
661         break;
662     case CSSSelector::Begin:
663         if (!value.startsWith(selectorValue, caseSensitive) || selectorValue.isEmpty())
664             return false;
665         break;
666     case CSSSelector::End:
667         if (!value.endsWith(selectorValue, caseSensitive) || selectorValue.isEmpty())
668             return false;
669         break;
670     case CSSSelector::Hyphen:
671         if (value.length() < selectorValue.length())
672             return false;
673         if (!value.startsWith(selectorValue, caseSensitive))
674             return false;
675         // It they start the same, check for exact match or following '-':
676         if (value.length() != selectorValue.length() && value[selectorValue.length()] != '-')
677             return false;
678         break;
679     case CSSSelector::PseudoClass:
680     case CSSSelector::PseudoElement:
681     default:
682         break;
683     }
684
685     return true;
686 }
687
688 static bool anyAttributeMatches(Element* element, CSSSelector::Match match, const QualifiedName& selectorAttr, const AtomicString& selectorValue, bool caseSensitive)
689 {
690     ASSERT(element->hasAttributesWithoutUpdate());
691     for (size_t i = 0; i < element->attributeCount(); ++i) {
692         const Attribute* attributeItem = element->attributeItem(i);
693
694         if (!SelectorChecker::attributeNameMatches(attributeItem, selectorAttr))
695             continue;
696
697         if (attributeValueMatches(attributeItem, match, selectorValue, caseSensitive))
698             return true;
699     }
700
701     return false;
702 }
703
704 bool SelectorChecker::checkOneSelector(const SelectorCheckingContext& context, PseudoId& dynamicPseudo) const
705 {
706     Element* const & element = context.element;
707     CSSSelector* const & selector = context.selector;
708     ASSERT(element);
709     ASSERT(selector);
710
711     if (!SelectorChecker::tagMatches(element, selector))
712         return false;
713
714     if (selector->m_match == CSSSelector::Class)
715         return element->hasClass() && static_cast<StyledElement*>(element)->classNames().contains(selector->value());
716
717     if (selector->m_match == CSSSelector::Id)
718         return element->hasID() && element->idForStyleResolution() == selector->value();
719
720     if (selector->isAttributeSelector()) {
721         const QualifiedName& attr = selector->attribute();
722
723         if (!element->hasAttributes())
724             return false;
725
726         bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr);
727
728         if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(selector->m_match), attr, selector->value(), caseSensitive))
729             return false;
730     }
731
732     if (selector->m_match == CSSSelector::PseudoClass) {
733         // Handle :not up front.
734         if (selector->pseudoType() == CSSSelector::PseudoNot) {
735             CSSSelectorList* selectorList = selector->selectorList();
736
737             // FIXME: We probably should fix the parser and make it never produce :not rules with missing selector list.
738             if (!selectorList)
739                 return false;
740
741             SelectorCheckingContext subContext(context);
742             subContext.isSubSelector = true;
743             for (subContext.selector = selectorList->first(); subContext.selector; subContext.selector = subContext.selector->tagHistory()) {
744                 // :not cannot nest. I don't really know why this is a
745                 // restriction in CSS3, but it is, so let's honor it.
746                 // the parser enforces that this never occurs
747                 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot);
748                 // We select between :visited and :link when applying. We don't know which one applied (or not) yet.
749                 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.visitedMatchType == VisitedMatchEnabled))
750                     return true;
751                 if (!checkOneSelector(subContext, dynamicPseudo))
752                     return true;
753             }
754         } else if (dynamicPseudo != NOPSEUDO && (RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER)) {
755             // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
756             // (since there are no elements involved).
757             return checkScrollbarPseudoClass(selector, dynamicPseudo);
758         } else if (dynamicPseudo == SELECTION) {
759             if (selector->pseudoType() == CSSSelector::PseudoWindowInactive)
760                 return !m_document->page()->focusController()->isActive();
761         }
762
763         // Normal element pseudo class checking.
764         switch (selector->pseudoType()) {
765             // Pseudo classes:
766         case CSSSelector::PseudoNot:
767             break; // Already handled up above.
768         case CSSSelector::PseudoEmpty:
769             {
770                 bool result = true;
771                 for (Node* n = element->firstChild(); n; n = n->nextSibling()) {
772                     if (n->isElementNode()) {
773                         result = false;
774                         break;
775                     }
776                     if (n->isTextNode()) {
777                         Text* textNode = toText(n);
778                         if (!textNode->data().isEmpty()) {
779                             result = false;
780                             break;
781                         }
782                     }
783                 }
784                 if (m_mode == ResolvingStyle) {
785                     if (context.elementStyle)
786                         context.elementStyle->setEmptyState(result);
787                     else if (element->renderStyle() && (element->document()->usesSiblingRules() || element->renderStyle()->unique()))
788                         element->renderStyle()->setEmptyState(result);
789                 }
790                 return result;
791             }
792         case CSSSelector::PseudoFirstChild:
793             // first-child matches the first child that is an element
794             if (element->parentElement()) {
795                 bool result = false;
796                 if (!element->previousElementSibling())
797                     result = true;
798                 if (m_mode == ResolvingStyle) {
799                     RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
800                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : element->parentNode()->renderStyle();
801                     if (parentStyle)
802                         parentStyle->setChildrenAffectedByFirstChildRules();
803                     if (result && childStyle)
804                         childStyle->setFirstChildState();
805                 }
806                 return result;
807             }
808             break;
809         case CSSSelector::PseudoFirstOfType:
810             // first-of-type matches the first element of its type
811             if (element->parentElement()) {
812                 bool result = true;
813                 const QualifiedName& type = element->tagQName();
814                 for (const Element* sibling = element->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {
815                     if (sibling->hasTagName(type)) {
816                         result = false;
817                         break;
818                     }
819                 }
820                 if (m_mode == ResolvingStyle) {
821                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : element->parentNode()->renderStyle();
822                     if (parentStyle)
823                         parentStyle->setChildrenAffectedByForwardPositionalRules();
824                 }
825                 return result;
826             }
827             break;
828         case CSSSelector::PseudoLastChild:
829             // last-child matches the last child that is an element
830             if (Element* parentElement = element->parentElement()) {
831                 bool result = parentElement->isFinishedParsingChildren() && !element->nextElementSibling();
832                 if (m_mode == ResolvingStyle) {
833                     RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
834                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
835                     if (parentStyle)
836                         parentStyle->setChildrenAffectedByLastChildRules();
837                     if (result && childStyle)
838                         childStyle->setLastChildState();
839                 }
840                 return result;
841             }
842             break;
843         case CSSSelector::PseudoLastOfType:
844             // last-of-type matches the last element of its type
845             if (Element* parentElement = element->parentElement()) {
846                 if (m_mode == ResolvingStyle) {
847                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
848                     if (parentStyle)
849                         parentStyle->setChildrenAffectedByBackwardPositionalRules();
850                 }
851                 if (!parentElement->isFinishedParsingChildren())
852                     return false;
853                 const QualifiedName& type = element->tagQName();
854                 for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
855                     if (sibling->hasTagName(type))
856                         return false;
857                 }
858                 return true;
859             }
860             break;
861         case CSSSelector::PseudoOnlyChild:
862             if (Element* parentElement = element->parentElement()) {
863                 bool firstChild = !element->previousElementSibling();
864                 bool onlyChild = firstChild && parentElement->isFinishedParsingChildren() && !element->nextElementSibling();
865
866                 if (m_mode == ResolvingStyle) {
867                     RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
868                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
869                     if (parentStyle) {
870                         parentStyle->setChildrenAffectedByFirstChildRules();
871                         parentStyle->setChildrenAffectedByLastChildRules();
872                     }
873                     if (firstChild && childStyle)
874                         childStyle->setFirstChildState();
875                     if (onlyChild && childStyle)
876                         childStyle->setLastChildState();
877                 }
878                 return onlyChild;
879             }
880             break;
881         case CSSSelector::PseudoOnlyOfType:
882             // FIXME: This selector is very slow.
883             if (Element* parentElement = element->parentElement()) {
884                 if (m_mode == ResolvingStyle) {
885                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
886                     if (parentStyle) {
887                         parentStyle->setChildrenAffectedByForwardPositionalRules();
888                         parentStyle->setChildrenAffectedByBackwardPositionalRules();
889                     }
890                 }
891                 if (!parentElement->isFinishedParsingChildren())
892                     return false;
893                 const QualifiedName& type = element->tagQName();
894                 for (const Element* sibling = element->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {
895                     if (sibling->hasTagName(type))
896                         return false;
897                 }
898                 for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
899                     if (sibling->hasTagName(type))
900                         return false;
901                 }
902                 return true;
903             }
904             break;
905         case CSSSelector::PseudoNthChild:
906             if (!selector->parseNth())
907                 break;
908             if (Element* parentElement = element->parentElement()) {
909                 int count = 1;
910                 for (const Element* sibling = element->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {
911                     RenderStyle* s = sibling->renderStyle();
912                     unsigned index = s ? s->childIndex() : 0;
913                     if (index) {
914                         count += index;
915                         break;
916                     }
917                     count++;
918                 }
919
920                 if (m_mode == ResolvingStyle) {
921                     RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
922                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
923                     if (childStyle)
924                         childStyle->setChildIndex(count);
925                     if (parentStyle)
926                         parentStyle->setChildrenAffectedByForwardPositionalRules();
927                 }
928
929                 if (selector->matchNth(count))
930                     return true;
931             }
932             break;
933         case CSSSelector::PseudoNthOfType:
934             if (!selector->parseNth())
935                 break;
936             if (Element* parentElement = element->parentElement()) {
937                 int count = 1;
938                 const QualifiedName& type = element->tagQName();
939                 for (const Element* sibling = element->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {
940                     if (sibling->hasTagName(type))
941                         ++count;
942                 }
943                 if (m_mode == ResolvingStyle) {
944                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
945                     if (parentStyle)
946                         parentStyle->setChildrenAffectedByForwardPositionalRules();
947                 }
948
949                 if (selector->matchNth(count))
950                     return true;
951             }
952             break;
953         case CSSSelector::PseudoNthLastChild:
954             if (!selector->parseNth())
955                 break;
956             if (Element* parentElement = element->parentElement()) {
957                 if (m_mode == ResolvingStyle) {
958                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
959                     if (parentStyle)
960                         parentStyle->setChildrenAffectedByBackwardPositionalRules();
961                 }
962                 if (!parentElement->isFinishedParsingChildren())
963                     return false;
964                 int count = 1;
965                 for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling())
966                     ++count;
967                 if (selector->matchNth(count))
968                     return true;
969             }
970             break;
971         case CSSSelector::PseudoNthLastOfType:
972             if (!selector->parseNth())
973                 break;
974             if (Element* parentElement = element->parentElement()) {
975                 if (m_mode == ResolvingStyle) {
976                     RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
977                     if (parentStyle)
978                         parentStyle->setChildrenAffectedByBackwardPositionalRules();
979                 }
980                 if (!parentElement->isFinishedParsingChildren())
981                     return false;
982                 int count = 1;
983                 const QualifiedName& type = element->tagQName();
984                 for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
985                     if (sibling->hasTagName(type))
986                         ++count;
987                 }
988                 if (selector->matchNth(count))
989                     return true;
990             }
991             break;
992         case CSSSelector::PseudoTarget:
993             if (element == element->document()->cssTarget())
994                 return true;
995             break;
996         case CSSSelector::PseudoAny:
997             {
998                 SelectorCheckingContext subContext(context);
999                 subContext.isSubSelector = true;
1000                 for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
1001                     if (checkSelector(subContext, dynamicPseudo) == SelectorMatches)
1002                         return true;
1003                 }
1004             }
1005             break;
1006         case CSSSelector::PseudoAutofill:
1007             if (!element || !element->isFormControlElement())
1008                 break;
1009             if (HTMLInputElement* inputElement = element->toInputElement())
1010                 return inputElement->isAutofilled();
1011             break;
1012         case CSSSelector::PseudoAnyLink:
1013         case CSSSelector::PseudoLink:
1014             // :visited and :link matches are separated later when applying the style. Here both classes match all links...
1015             return element->isLink();
1016         case CSSSelector::PseudoVisited:
1017             // ...except if :visited matching is disabled for ancestor/sibling matching.
1018             return element->isLink() && context.visitedMatchType == VisitedMatchEnabled;
1019         case CSSSelector::PseudoDrag:
1020             if (context.elementStyle)
1021                 context.elementStyle->setAffectedByDragRules(true);
1022             else if (element->renderStyle())
1023                 element->renderStyle()->setAffectedByDragRules(true);
1024             if (element->renderer() && element->renderer()->isDragging())
1025                 return true;
1026             break;
1027         case CSSSelector::PseudoFocus:
1028             return matchesFocusPseudoClass(element);
1029         case CSSSelector::PseudoHover:
1030             // If we're in quirks mode, then hover should never match anchors with no
1031             // href and *:hover should not match anything. This is important for sites like wsj.com.
1032             if (m_strictParsing || context.isSubSelector || (selector->hasTag() && !element->hasTagName(aTag)) || element->isLink()) {
1033                 if (context.elementStyle)
1034                     context.elementStyle->setAffectedByHoverRules(true);
1035                 else if (element->renderStyle())
1036                     element->renderStyle()->setAffectedByHoverRules(true);
1037                 if (element->hovered() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoHover))
1038                     return true;
1039             }
1040             break;
1041         case CSSSelector::PseudoActive:
1042             // If we're in quirks mode, then :active should never match anchors with no
1043             // href and *:active should not match anything.
1044             if (m_strictParsing || context.isSubSelector || (selector->hasTag() && !element->hasTagName(aTag)) || element->isLink()) {
1045                 if (context.elementStyle)
1046                     context.elementStyle->setAffectedByActiveRules(true);
1047                 else if (element->renderStyle())
1048                     element->renderStyle()->setAffectedByActiveRules(true);
1049                 if (element->active() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoActive))
1050                     return true;
1051             }
1052             break;
1053         case CSSSelector::PseudoEnabled:
1054             if (element && (element->isFormControlElement() || element->hasTagName(optionTag) || element->hasTagName(optgroupTag)))
1055                 return element->isEnabledFormControl();
1056             break;
1057         case CSSSelector::PseudoFullPageMedia:
1058             return element && element->document() && element->document()->isMediaDocument();
1059             break;
1060         case CSSSelector::PseudoDefault:
1061             return element && element->isDefaultButtonForForm();
1062         case CSSSelector::PseudoDisabled:
1063             if (element && (element->isFormControlElement() || element->hasTagName(optionTag) || element->hasTagName(optgroupTag)))
1064                 return !element->isEnabledFormControl();
1065             break;
1066         case CSSSelector::PseudoReadOnly:
1067             if (!element || !element->isFormControlElement())
1068                 return false;
1069             return element->isTextFormControl() && element->isReadOnlyFormControl();
1070         case CSSSelector::PseudoReadWrite:
1071             if (!element || !element->isFormControlElement())
1072                 return false;
1073             return element->isTextFormControl() && !element->isReadOnlyFormControl();
1074         case CSSSelector::PseudoOptional:
1075             return element && element->isOptionalFormControl();
1076         case CSSSelector::PseudoRequired:
1077             return element && element->isRequiredFormControl();
1078         case CSSSelector::PseudoValid:
1079             if (!element)
1080                 return false;
1081             element->document()->setContainsValidityStyleRules();
1082             return element->willValidate() && element->isValidFormControlElement();
1083         case CSSSelector::PseudoInvalid:
1084             if (!element)
1085                 return false;
1086             element->document()->setContainsValidityStyleRules();
1087             return element->willValidate() && !element->isValidFormControlElement();
1088         case CSSSelector::PseudoChecked:
1089             {
1090                 if (!element)
1091                     break;
1092                 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
1093                 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
1094                 // obey the CSS spec here in the test for matching the pseudo.
1095                 HTMLInputElement* inputElement = element->toInputElement();
1096                 if (inputElement && inputElement->shouldAppearChecked() && !inputElement->isIndeterminate())
1097                     return true;
1098                 if (element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected())
1099                     return true;
1100                 break;
1101             }
1102         case CSSSelector::PseudoIndeterminate:
1103             {
1104                 if (!element)
1105                     break;
1106 #if ENABLE(PROGRESS_ELEMENT)
1107                 if (element->hasTagName(progressTag)) {
1108                     HTMLProgressElement* progress = static_cast<HTMLProgressElement*>(element);
1109                     if (progress && !progress->isDeterminate())
1110                         return true;
1111                     break;
1112                 }
1113 #endif
1114                 HTMLInputElement* inputElement = element->toInputElement();
1115                 if (inputElement && inputElement->isIndeterminate())
1116                     return true;
1117                 break;
1118             }
1119         case CSSSelector::PseudoScope:
1120             if (context.scope)
1121                 return element == context.scope;
1122             // If there is no scope, :scope should behave as :root -> fall through
1123         case CSSSelector::PseudoRoot:
1124             if (element == element->document()->documentElement())
1125                 return true;
1126             break;
1127         case CSSSelector::PseudoLang:
1128             {
1129                 AtomicString value = element->computeInheritedLanguage();
1130                 const AtomicString& argument = selector->argument();
1131                 if (value.isEmpty() || !value.startsWith(argument, false))
1132                     break;
1133                 if (value.length() != argument.length() && value[argument.length()] != '-')
1134                     break;
1135                 return true;
1136             }
1137 #if ENABLE(FULLSCREEN_API)
1138         case CSSSelector::PseudoFullScreen:
1139             // While a Document is in the fullscreen state, and the document's current fullscreen
1140             // element is an element in the document, the 'full-screen' pseudoclass applies to
1141             // that element. Also, an <iframe>, <object> or <embed> element whose child browsing
1142             // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied.
1143             if (element->isFrameElementBase() && static_cast<HTMLFrameElementBase*>(element)->containsFullScreenElement())
1144                 return true;
1145             if (!element->document()->webkitIsFullScreen())
1146                 return false;
1147             return element == element->document()->webkitCurrentFullScreenElement();
1148         case CSSSelector::PseudoAnimatingFullScreenTransition:
1149             if (element != element->document()->webkitCurrentFullScreenElement())
1150                 return false;
1151             return element->document()->isAnimatingFullScreen();
1152         case CSSSelector::PseudoFullScreenAncestor:
1153             return element->containsFullScreenElement();
1154         case CSSSelector::PseudoFullScreenDocument:
1155             // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies
1156             // to all elements of that Document.
1157             if (!element->document()->webkitIsFullScreen())
1158                 return false;
1159             return true;
1160 #endif
1161         case CSSSelector::PseudoInRange:
1162             if (!element)
1163                 return false;
1164             element->document()->setContainsValidityStyleRules();
1165             return element->isInRange();
1166         case CSSSelector::PseudoOutOfRange:
1167             if (!element)
1168                 return false;
1169             element->document()->setContainsValidityStyleRules();
1170             return element->isOutOfRange();
1171         case CSSSelector::PseudoUnknown:
1172         case CSSSelector::PseudoNotParsed:
1173         default:
1174             ASSERT_NOT_REACHED();
1175             break;
1176         }
1177         return false;
1178     }
1179     if (selector->m_match == CSSSelector::PseudoElement) {
1180         if (selector->isUnknownPseudoElement()) {
1181             m_hasUnknownPseudoElements = true;
1182             return element->shadowPseudoId() == selector->value();
1183         }
1184
1185         if ((!context.elementStyle && m_mode == ResolvingStyle) || m_mode == QueryingRules)
1186             return false;
1187
1188         PseudoId pseudoId = CSSSelector::pseudoId(selector->pseudoType());
1189         if (pseudoId == FIRST_LETTER) {
1190             if (Document* document = element->document())
1191                 document->setUsesFirstLetterRules(true);
1192         }
1193         if (pseudoId != NOPSEUDO)
1194             dynamicPseudo = pseudoId;
1195     }
1196     // ### add the rest of the checks...
1197     return true;
1198 }
1199
1200 bool SelectorChecker::checkScrollbarPseudoClass(CSSSelector* sel, PseudoId&) const
1201 {
1202     RenderScrollbar* scrollbar = RenderScrollbar::scrollbarForStyleResolve();
1203     ScrollbarPart part = RenderScrollbar::partForStyleResolve();
1204
1205     // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real
1206     // pseudo class and just apply to everything.
1207     if (sel->pseudoType() == CSSSelector::PseudoWindowInactive)
1208         return !m_document->page()->focusController()->isActive();
1209
1210     if (!scrollbar)
1211         return false;
1212
1213     ASSERT(sel->m_match == CSSSelector::PseudoClass);
1214     switch (sel->pseudoType()) {
1215     case CSSSelector::PseudoEnabled:
1216         return scrollbar->enabled();
1217     case CSSSelector::PseudoDisabled:
1218         return !scrollbar->enabled();
1219     case CSSSelector::PseudoHover:
1220         {
1221             ScrollbarPart hoveredPart = scrollbar->hoveredPart();
1222             if (part == ScrollbarBGPart)
1223                 return hoveredPart != NoPart;
1224             if (part == TrackBGPart)
1225                 return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart;
1226             return part == hoveredPart;
1227         }
1228     case CSSSelector::PseudoActive:
1229         {
1230             ScrollbarPart pressedPart = scrollbar->pressedPart();
1231             if (part == ScrollbarBGPart)
1232                 return pressedPart != NoPart;
1233             if (part == TrackBGPart)
1234                 return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart;
1235             return part == pressedPart;
1236         }
1237     case CSSSelector::PseudoHorizontal:
1238         return scrollbar->orientation() == HorizontalScrollbar;
1239     case CSSSelector::PseudoVertical:
1240         return scrollbar->orientation() == VerticalScrollbar;
1241     case CSSSelector::PseudoDecrement:
1242         return part == BackButtonStartPart || part == BackButtonEndPart || part == BackTrackPart;
1243     case CSSSelector::PseudoIncrement:
1244         return part == ForwardButtonStartPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
1245     case CSSSelector::PseudoStart:
1246         return part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart;
1247     case CSSSelector::PseudoEnd:
1248         return part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
1249     case CSSSelector::PseudoDoubleButton:
1250         {
1251             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1252             if (part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart)
1253                 return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth;
1254             if (part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart)
1255                 return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth;
1256             return false;
1257         }
1258     case CSSSelector::PseudoSingleButton:
1259         {
1260             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1261             if (part == BackButtonStartPart || part == ForwardButtonEndPart || part == BackTrackPart || part == ForwardTrackPart)
1262                 return buttonsPlacement == ScrollbarButtonsSingle;
1263             return false;
1264         }
1265     case CSSSelector::PseudoNoButton:
1266         {
1267             ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
1268             if (part == BackTrackPart)
1269                 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd;
1270             if (part == ForwardTrackPart)
1271                 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart;
1272             return false;
1273         }
1274     case CSSSelector::PseudoCornerPresent:
1275         return scrollbar->scrollableArea()->isScrollCornerVisible();
1276     default:
1277         return false;
1278     }
1279 }
1280
1281 void SelectorChecker::allVisitedStateChanged()
1282 {
1283     if (m_linksCheckedForVisitedState.isEmpty())
1284         return;
1285     for (Node* node = m_document; node; node = node->traverseNextNode()) {
1286         if (node->isLink())
1287             node->setNeedsStyleRecalc();
1288     }
1289 }
1290
1291 void SelectorChecker::visitedStateChanged(LinkHash visitedHash)
1292 {
1293     if (!m_linksCheckedForVisitedState.contains(visitedHash))
1294         return;
1295     for (Node* node = m_document; node; node = node->traverseNextNode()) {
1296         LinkHash hash = 0;
1297         if (node->hasTagName(aTag))
1298             hash = static_cast<HTMLAnchorElement*>(node)->visitedLinkHash();
1299         else if (const AtomicString* attr = linkAttribute(node))
1300             hash = visitedLinkHash(m_document->baseURL(), *attr);
1301         if (hash == visitedHash)
1302             node->setNeedsStyleRecalc();
1303     }
1304 }
1305
1306 bool SelectorChecker::commonPseudoClassSelectorMatches(const Element* element, const CSSSelector* selector, VisitedMatchType visitedMatchType) const
1307 {
1308     ASSERT(isCommonPseudoClassSelector(selector));
1309     switch (selector->pseudoType()) {
1310     case CSSSelector::PseudoLink:
1311     case CSSSelector::PseudoAnyLink:
1312         return element->isLink();
1313     case CSSSelector::PseudoVisited:
1314         return element->isLink() && visitedMatchType == VisitedMatchEnabled;
1315     case CSSSelector::PseudoFocus:
1316         return matchesFocusPseudoClass(element);
1317     default:
1318         ASSERT_NOT_REACHED();
1319     }
1320     return true;
1321 }
1322
1323 unsigned SelectorChecker::determineLinkMatchType(const CSSSelector* selector)
1324 {
1325     unsigned linkMatchType = MatchAll;
1326
1327     // Statically determine if this selector will match a link in visited, unvisited or any state, or never.
1328     // :visited never matches other elements than the innermost link element.
1329     for (; selector; selector = selector->tagHistory()) {
1330         switch (selector->pseudoType()) {
1331         case CSSSelector::PseudoNot:
1332             {
1333                 // :not(:visited) is equivalent to :link. Parser enforces that :not can't nest.
1334                 CSSSelectorList* selectorList = selector->selectorList();
1335                 if (!selectorList)
1336                     break;
1337
1338                 for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = subSelector->tagHistory()) {
1339                     CSSSelector::PseudoType subType = subSelector->pseudoType();
1340                     if (subType == CSSSelector::PseudoVisited)
1341                         linkMatchType &= ~SelectorChecker::MatchVisited;
1342                     else if (subType == CSSSelector::PseudoLink)
1343                         linkMatchType &= ~SelectorChecker::MatchLink;
1344                 }
1345             }
1346             break;
1347         case CSSSelector::PseudoLink:
1348             linkMatchType &= ~SelectorChecker::MatchVisited;
1349             break;
1350         case CSSSelector::PseudoVisited:
1351             linkMatchType &= ~SelectorChecker::MatchLink;
1352             break;
1353         default:
1354             // We don't support :link and :visited inside :-webkit-any.
1355             break;
1356         }
1357         CSSSelector::Relation relation = selector->relation();
1358         if (relation == CSSSelector::SubSelector)
1359             continue;
1360         if (relation != CSSSelector::Descendant && relation != CSSSelector::Child)
1361             return linkMatchType;
1362         if (linkMatchType != MatchAll)
1363             return linkMatchType;
1364     }
1365     return linkMatchType;
1366 }
1367
1368 bool SelectorChecker::isFrameFocused(const Element* element)
1369 {
1370     return element->document()->frame() && element->document()->frame()->selection()->isFocusedAndActive();
1371 }
1372
1373 bool SelectorChecker::determineSelectorScopes(const CSSSelectorList& selectorList, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes)
1374 {
1375     for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
1376         CSSSelector* scopeSelector = 0;
1377         // This picks the widest scope, not the narrowest, to minimize the number of found scopes.
1378         for (CSSSelector* current = selector; current; current = current->tagHistory()) {
1379             // Prefer ids over classes.
1380             if (current->m_match == CSSSelector::Id)
1381                 scopeSelector = current;
1382             else if (current->m_match == CSSSelector::Class && (!scopeSelector || scopeSelector->m_match != CSSSelector::Id))
1383                 scopeSelector = current;
1384             CSSSelector::Relation relation = current->relation();
1385             if (relation != CSSSelector::Descendant && relation != CSSSelector::Child && relation != CSSSelector::SubSelector)
1386                 break;
1387         }
1388         if (!scopeSelector)
1389             return false;
1390         ASSERT(scopeSelector->m_match == CSSSelector::Class || scopeSelector->m_match == CSSSelector::Id);
1391         if (scopeSelector->m_match == CSSSelector::Id)
1392             idScopes.add(scopeSelector->value().impl());
1393         else
1394             classScopes.add(scopeSelector->value().impl());
1395     }
1396     return true;
1397 }
1398
1399 }