summaryrefslogtreecommitdiffstats
path: root/WebCore/css/CSSSelector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/css/CSSSelector.cpp')
-rw-r--r--WebCore/css/CSSSelector.cpp907
1 files changed, 641 insertions, 266 deletions
diff --git a/WebCore/css/CSSSelector.cpp b/WebCore/css/CSSSelector.cpp
index 9ae9b9f..fb8f695 100644
--- a/WebCore/css/CSSSelector.cpp
+++ b/WebCore/css/CSSSelector.cpp
@@ -3,8 +3,9 @@
* 1999 Waldo Bastian (bastian@kde.org)
* 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch)
* 2001-2003 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2002, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2002, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2008 David Smith (catfish.man@gmail.com)
+ * Copyright (C) 2010 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -25,51 +26,303 @@
#include "config.h"
#include "CSSSelector.h"
-#include "wtf/Assertions.h"
+#include "CSSOMUtils.h"
#include "HTMLNames.h"
-
+#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
namespace WebCore {
-
+
using namespace HTMLNames;
-unsigned int CSSSelector::specificity()
+class CSSSelectorBag : public Noncopyable {
+public:
+ ~CSSSelectorBag()
+ {
+ ASSERT(isEmpty());
+ }
+
+ bool isEmpty() const
+ {
+ return m_stack.isEmpty();
+ }
+
+ void add(PassOwnPtr<CSSSelector> selector)
+ {
+ if (selector)
+ m_stack.append(selector.leakPtr());
+ }
+
+ PassOwnPtr<CSSSelector> takeAny()
+ {
+ ASSERT(!isEmpty());
+ OwnPtr<CSSSelector> selector = adoptPtr(m_stack.last());
+ m_stack.removeLast();
+ return selector.release();
+ }
+
+private:
+ Vector<CSSSelector*, 16> m_stack;
+};
+
+unsigned CSSSelector::specificity() const
+{
+ // make sure the result doesn't overflow
+ static const unsigned maxValueMask = 0xffffff;
+ unsigned total = 0;
+ for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) {
+ if (selector->m_isForPage)
+ return (total + selector->specificityForPage()) & maxValueMask;
+ total = (total + selector->specificityForOneSelector()) & maxValueMask;
+ }
+ return total;
+}
+
+inline unsigned CSSSelector::specificityForOneSelector() const
{
// FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function
// isn't quite correct.
- int s = (m_tag.localName() == starAtom ? 0 : 1);
+ unsigned s = (m_tag.localName() == starAtom ? 0 : 1);
switch (m_match) {
- case Id:
- s += 0x10000;
- break;
- case Exact:
- case Class:
- case Set:
- case List:
- case Hyphen:
- case PseudoClass:
- case PseudoElement:
- case Contain:
- case Begin:
- case End:
- s += 0x100;
- case None:
- break;
+ case Id:
+ s += 0x10000;
+ break;
+ case Exact:
+ case Class:
+ case Set:
+ case List:
+ case Hyphen:
+ case PseudoClass:
+ case PseudoElement:
+ case Contain:
+ case Begin:
+ case End:
+ s += 0x100;
+ case None:
+ break;
}
+ return s;
+}
- if (CSSSelector* tagHistory = this->tagHistory())
- s += tagHistory->specificity();
+unsigned CSSSelector::specificityForPage() const
+{
+ // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context
+ unsigned s = (m_tag.localName() == starAtom ? 0 : 4);
- // make sure it doesn't overflow
- return s & 0xffffff;
+ switch (pseudoType()) {
+ case PseudoFirstPage:
+ s += 2;
+ break;
+ case PseudoLeftPage:
+ case PseudoRightPage:
+ s += 1;
+ break;
+ case PseudoNotParsed:
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return s;
}
-void CSSSelector::extractPseudoType() const
+PseudoId CSSSelector::pseudoId(PseudoType type)
{
- if (m_match != PseudoClass && m_match != PseudoElement)
- return;
+ switch (type) {
+ case PseudoFirstLine:
+ return FIRST_LINE;
+ case PseudoFirstLetter:
+ return FIRST_LETTER;
+ case PseudoSelection:
+ return SELECTION;
+ case PseudoBefore:
+ return BEFORE;
+ case PseudoAfter:
+ return AFTER;
+ case PseudoFileUploadButton:
+ return FILE_UPLOAD_BUTTON;
+ case PseudoInputPlaceholder:
+ return INPUT_PLACEHOLDER;
+#if ENABLE(INPUT_SPEECH)
+ case PseudoInputSpeechButton:
+ return INPUT_SPEECH_BUTTON;
+#endif
+ case PseudoSliderThumb:
+ return SLIDER_THUMB;
+ case PseudoSearchCancelButton:
+ return SEARCH_CANCEL_BUTTON;
+ case PseudoSearchDecoration:
+ return SEARCH_DECORATION;
+ case PseudoSearchResultsDecoration:
+ return SEARCH_RESULTS_DECORATION;
+ case PseudoSearchResultsButton:
+ return SEARCH_RESULTS_BUTTON;
+ case PseudoMediaControlsPanel:
+ return MEDIA_CONTROLS_PANEL;
+ case PseudoMediaControlsMuteButton:
+ return MEDIA_CONTROLS_MUTE_BUTTON;
+ case PseudoMediaControlsPlayButton:
+ return MEDIA_CONTROLS_PLAY_BUTTON;
+ case PseudoMediaControlsTimelineContainer:
+ return MEDIA_CONTROLS_TIMELINE_CONTAINER;
+ case PseudoMediaControlsVolumeSliderContainer:
+ return MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER;
+ case PseudoMediaControlsCurrentTimeDisplay:
+ return MEDIA_CONTROLS_CURRENT_TIME_DISPLAY;
+ case PseudoMediaControlsTimeRemainingDisplay:
+ return MEDIA_CONTROLS_TIME_REMAINING_DISPLAY;
+ case PseudoMediaControlsTimeline:
+ return MEDIA_CONTROLS_TIMELINE;
+ case PseudoMediaControlsVolumeSlider:
+ return MEDIA_CONTROLS_VOLUME_SLIDER;
+ case PseudoMediaControlsVolumeSliderMuteButton:
+ return MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON;
+ case PseudoMediaControlsSeekBackButton:
+ return MEDIA_CONTROLS_SEEK_BACK_BUTTON;
+ case PseudoMediaControlsSeekForwardButton:
+ return MEDIA_CONTROLS_SEEK_FORWARD_BUTTON;
+ case PseudoMediaControlsRewindButton:
+ return MEDIA_CONTROLS_REWIND_BUTTON;
+ case PseudoMediaControlsReturnToRealtimeButton:
+ return MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON;
+ case PseudoMediaControlsToggleClosedCaptions:
+ return MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON;
+ case PseudoMediaControlsStatusDisplay:
+ return MEDIA_CONTROLS_STATUS_DISPLAY;
+ case PseudoMediaControlsFullscreenButton:
+ return MEDIA_CONTROLS_FULLSCREEN_BUTTON;
+ case PseudoScrollbar:
+ return SCROLLBAR;
+ case PseudoScrollbarButton:
+ return SCROLLBAR_BUTTON;
+ case PseudoScrollbarCorner:
+ return SCROLLBAR_CORNER;
+ case PseudoScrollbarThumb:
+ return SCROLLBAR_THUMB;
+ case PseudoScrollbarTrack:
+ return SCROLLBAR_TRACK;
+ case PseudoScrollbarTrackPiece:
+ return SCROLLBAR_TRACK_PIECE;
+ case PseudoResizer:
+ return RESIZER;
+ case PseudoInnerSpinButton:
+ return INNER_SPIN_BUTTON;
+ case PseudoOuterSpinButton:
+ return OUTER_SPIN_BUTTON;
+ case PseudoProgressBarValue:
+#if ENABLE(PROGRESS_TAG)
+ return PROGRESS_BAR_VALUE;
+#else
+ ASSERT_NOT_REACHED();
+ return NOPSEUDO;
+#endif
+
+#if ENABLE(METER_TAG)
+ case PseudoMeterHorizontalBar:
+ return METER_HORIZONTAL_BAR;
+ case PseudoMeterHorizontalOptimum:
+ return METER_HORIZONTAL_OPTIMUM;
+ case PseudoMeterHorizontalSuboptimal:
+ return METER_HORIZONTAL_SUBOPTIMAL;
+ case PseudoMeterHorizontalEvenLessGood:
+ return METER_HORIZONTAL_EVEN_LESS_GOOD;
+ case PseudoMeterVerticalBar:
+ return METER_VERTICAL_BAR;
+ case PseudoMeterVerticalOptimum:
+ return METER_VERTICAL_OPTIMUM;
+ case PseudoMeterVerticalSuboptimal:
+ return METER_VERTICAL_SUBOPTIMAL;
+ case PseudoMeterVerticalEvenLessGood:
+ return METER_VERTICAL_EVEN_LESS_GOOD;
+#else
+ case PseudoMeterHorizontalBar:
+ case PseudoMeterHorizontalOptimum:
+ case PseudoMeterHorizontalSuboptimal:
+ case PseudoMeterHorizontalEvenLessGood:
+ case PseudoMeterVerticalBar:
+ case PseudoMeterVerticalOptimum:
+ case PseudoMeterVerticalSuboptimal:
+ case PseudoMeterVerticalEvenLessGood:
+ ASSERT_NOT_REACHED();
+ return NOPSEUDO;
+#endif
+
+#if ENABLE(FULLSCREEN_API)
+ case PseudoFullScreen:
+ return FULL_SCREEN;
+ case PseudoFullScreenDocument:
+ return FULL_SCREEN_DOCUMENT;
+#endif
+
+ case PseudoInputListButton:
+#if ENABLE(DATALIST)
+ return INPUT_LIST_BUTTON;
+#endif
+ case PseudoUnknown:
+ case PseudoEmpty:
+ case PseudoFirstChild:
+ case PseudoFirstOfType:
+ case PseudoLastChild:
+ case PseudoLastOfType:
+ case PseudoOnlyChild:
+ case PseudoOnlyOfType:
+ case PseudoNthChild:
+ case PseudoNthOfType:
+ case PseudoNthLastChild:
+ case PseudoNthLastOfType:
+ case PseudoLink:
+ case PseudoVisited:
+ case PseudoAnyLink:
+ case PseudoAutofill:
+ case PseudoHover:
+ case PseudoDrag:
+ case PseudoFocus:
+ case PseudoActive:
+ case PseudoChecked:
+ case PseudoEnabled:
+ case PseudoFullPageMedia:
+ case PseudoDefault:
+ case PseudoDisabled:
+ case PseudoOptional:
+ case PseudoRequired:
+ case PseudoReadOnly:
+ case PseudoReadWrite:
+ case PseudoValid:
+ case PseudoInvalid:
+ case PseudoIndeterminate:
+ case PseudoTarget:
+ case PseudoLang:
+ case PseudoNot:
+ case PseudoRoot:
+ case PseudoScrollbarBack:
+ case PseudoScrollbarForward:
+ case PseudoWindowInactive:
+ case PseudoCornerPresent:
+ case PseudoDecrement:
+ case PseudoIncrement:
+ case PseudoHorizontal:
+ case PseudoVertical:
+ case PseudoStart:
+ case PseudoEnd:
+ case PseudoDoubleButton:
+ case PseudoSingleButton:
+ case PseudoNoButton:
+ case PseudoFirstPage:
+ case PseudoLeftPage:
+ case PseudoRightPage:
+ return NOPSEUDO;
+ case PseudoNotParsed:
+ ASSERT_NOT_REACHED();
+ return NOPSEUDO;
+ }
+ ASSERT_NOT_REACHED();
+ return NOPSEUDO;
+}
+
+static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap()
+{
DEFINE_STATIC_LOCAL(AtomicString, active, ("active"));
DEFINE_STATIC_LOCAL(AtomicString, after, ("after"));
DEFINE_STATIC_LOCAL(AtomicString, anyLink, ("-webkit-any-link"));
@@ -77,6 +330,9 @@ void CSSSelector::extractPseudoType() const
DEFINE_STATIC_LOCAL(AtomicString, before, ("before"));
DEFINE_STATIC_LOCAL(AtomicString, checked, ("checked"));
DEFINE_STATIC_LOCAL(AtomicString, fileUploadButton, ("-webkit-file-upload-button"));
+#if ENABLE(INPUT_SPEECH)
+ DEFINE_STATIC_LOCAL(AtomicString, inputSpeechButton, ("-webkit-input-speech-button"));
+#endif
DEFINE_STATIC_LOCAL(AtomicString, defaultString, ("default"));
DEFINE_STATIC_LOCAL(AtomicString, disabled, ("disabled"));
DEFINE_STATIC_LOCAL(AtomicString, readOnly, ("read-only"));
@@ -113,6 +369,7 @@ void CSSSelector::extractPseudoType() const
DEFINE_STATIC_LOCAL(AtomicString, mediaControlsPlayButton, ("-webkit-media-controls-play-button"));
DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimeline, ("-webkit-media-controls-timeline"));
DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSlider, ("-webkit-media-controls-volume-slider"));
+ DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSliderMuteButton, ("-webkit-media-controls-volume-slider-mute-button"));
DEFINE_STATIC_LOCAL(AtomicString, mediaControlsSeekBackButton, ("-webkit-media-controls-seek-back-button"));
DEFINE_STATIC_LOCAL(AtomicString, mediaControlsSeekForwardButton, ("-webkit-media-controls-seek-forward-button"));
DEFINE_STATIC_LOCAL(AtomicString, mediaControlsRewindButton, ("-webkit-media-controls-rewind-button"));
@@ -129,6 +386,21 @@ void CSSSelector::extractPseudoType() const
DEFINE_STATIC_LOCAL(AtomicString, onlyOfType, ("only-of-type"));
DEFINE_STATIC_LOCAL(AtomicString, optional, ("optional"));
DEFINE_STATIC_LOCAL(AtomicString, outerSpinButton, ("-webkit-outer-spin-button"));
+#if ENABLE(PROGRESS_TAG)
+ DEFINE_STATIC_LOCAL(AtomicString, progressBarValue, ("-webkit-progress-bar-value"));
+#endif
+
+#if ENABLE(METER_TAG)
+ DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalBar, ("-webkit-meter-horizontal-bar"));
+ DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalOptimumValue, ("-webkit-meter-horizontal-optimum-value"));
+ DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalSuboptimalValue, ("-webkit-meter-horizontal-suboptimal-value"));
+ DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalEvenLessGoodValue, ("-webkit-meter-horizontal-even-less-good-value"));
+ DEFINE_STATIC_LOCAL(AtomicString, meterVerticalBar, ("-webkit-meter-vertical-bar"));
+ DEFINE_STATIC_LOCAL(AtomicString, meterVerticalOptimumValue, ("-webkit-meter-vertical-optimum-value"));
+ DEFINE_STATIC_LOCAL(AtomicString, meterVerticalSuboptimalValue, ("-webkit-meter-vertical-suboptimal-value"));
+ DEFINE_STATIC_LOCAL(AtomicString, meterVerticalEvenLessGoodValue, ("-webkit-meter-vertical-even-less-good-value"));
+#endif
+
DEFINE_STATIC_LOCAL(AtomicString, required, ("required"));
DEFINE_STATIC_LOCAL(AtomicString, resizer, ("-webkit-resizer"));
DEFINE_STATIC_LOCAL(AtomicString, root, ("root"));
@@ -157,233 +429,277 @@ void CSSSelector::extractPseudoType() const
DEFINE_STATIC_LOCAL(AtomicString, singleButton, ("single-button"));
DEFINE_STATIC_LOCAL(AtomicString, noButton, ("no-button"));
DEFINE_STATIC_LOCAL(AtomicString, cornerPresent, ("corner-present"));
+ // Paged Media pseudo-classes
+ DEFINE_STATIC_LOCAL(AtomicString, firstPage, ("first"));
+ DEFINE_STATIC_LOCAL(AtomicString, leftPage, ("left"));
+ DEFINE_STATIC_LOCAL(AtomicString, rightPage, ("right"));
+#if ENABLE(FULLSCREEN_API)
+ DEFINE_STATIC_LOCAL(AtomicString, fullScreen, ("-webkit-full-screen"));
+ DEFINE_STATIC_LOCAL(AtomicString, fullScreenDocument, ("-webkit-full-screen-document"));
+#endif
+
+ static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0;
+ if (!nameToPseudoType) {
+ nameToPseudoType = new HashMap<AtomicStringImpl*, CSSSelector::PseudoType>;
+ nameToPseudoType->set(active.impl(), CSSSelector::PseudoActive);
+ nameToPseudoType->set(after.impl(), CSSSelector::PseudoAfter);
+ nameToPseudoType->set(anyLink.impl(), CSSSelector::PseudoAnyLink);
+ nameToPseudoType->set(autofill.impl(), CSSSelector::PseudoAutofill);
+ nameToPseudoType->set(before.impl(), CSSSelector::PseudoBefore);
+ nameToPseudoType->set(checked.impl(), CSSSelector::PseudoChecked);
+ nameToPseudoType->set(fileUploadButton.impl(), CSSSelector::PseudoFileUploadButton);
+#if ENABLE(INPUT_SPEECH)
+ nameToPseudoType->set(inputSpeechButton.impl(), CSSSelector::PseudoInputSpeechButton);
+#endif
+ nameToPseudoType->set(defaultString.impl(), CSSSelector::PseudoDefault);
+ nameToPseudoType->set(disabled.impl(), CSSSelector::PseudoDisabled);
+ nameToPseudoType->set(readOnly.impl(), CSSSelector::PseudoReadOnly);
+ nameToPseudoType->set(readWrite.impl(), CSSSelector::PseudoReadWrite);
+ nameToPseudoType->set(valid.impl(), CSSSelector::PseudoValid);
+ nameToPseudoType->set(invalid.impl(), CSSSelector::PseudoInvalid);
+ nameToPseudoType->set(drag.impl(), CSSSelector::PseudoDrag);
+ nameToPseudoType->set(dragAlias.impl(), CSSSelector::PseudoDrag);
+ nameToPseudoType->set(enabled.impl(), CSSSelector::PseudoEnabled);
+ nameToPseudoType->set(empty.impl(), CSSSelector::PseudoEmpty);
+ nameToPseudoType->set(firstChild.impl(), CSSSelector::PseudoFirstChild);
+ nameToPseudoType->set(fullPageMedia.impl(), CSSSelector::PseudoFullPageMedia);
+#if ENABLE(DATALIST)
+ nameToPseudoType->set(inputListButton.impl(), CSSSelector::PseudoInputListButton);
+#endif
+ nameToPseudoType->set(inputPlaceholder.impl(), CSSSelector::PseudoInputPlaceholder);
+ nameToPseudoType->set(lastChild.impl(), CSSSelector::PseudoLastChild);
+ nameToPseudoType->set(lastOfType.impl(), CSSSelector::PseudoLastOfType);
+ nameToPseudoType->set(onlyChild.impl(), CSSSelector::PseudoOnlyChild);
+ nameToPseudoType->set(onlyOfType.impl(), CSSSelector::PseudoOnlyOfType);
+ nameToPseudoType->set(firstLetter.impl(), CSSSelector::PseudoFirstLetter);
+ nameToPseudoType->set(firstLine.impl(), CSSSelector::PseudoFirstLine);
+ nameToPseudoType->set(firstOfType.impl(), CSSSelector::PseudoFirstOfType);
+ nameToPseudoType->set(focus.impl(), CSSSelector::PseudoFocus);
+ nameToPseudoType->set(hover.impl(), CSSSelector::PseudoHover);
+ nameToPseudoType->set(indeterminate.impl(), CSSSelector::PseudoIndeterminate);
+ nameToPseudoType->set(innerSpinButton.impl(), CSSSelector::PseudoInnerSpinButton);
+ nameToPseudoType->set(link.impl(), CSSSelector::PseudoLink);
+ nameToPseudoType->set(lang.impl(), CSSSelector::PseudoLang);
+ nameToPseudoType->set(mediaControlsPanel.impl(), CSSSelector::PseudoMediaControlsPanel);
+ nameToPseudoType->set(mediaControlsMuteButton.impl(), CSSSelector::PseudoMediaControlsMuteButton);
+ nameToPseudoType->set(mediaControlsPlayButton.impl(), CSSSelector::PseudoMediaControlsPlayButton);
+ nameToPseudoType->set(mediaControlsCurrentTimeDisplay.impl(), CSSSelector::PseudoMediaControlsCurrentTimeDisplay);
+ nameToPseudoType->set(mediaControlsTimeRemainingDisplay.impl(), CSSSelector::PseudoMediaControlsTimeRemainingDisplay);
+ nameToPseudoType->set(mediaControlsTimeline.impl(), CSSSelector::PseudoMediaControlsTimeline);
+ nameToPseudoType->set(mediaControlsVolumeSlider.impl(), CSSSelector::PseudoMediaControlsVolumeSlider);
+ nameToPseudoType->set(mediaControlsVolumeSliderMuteButton.impl(), CSSSelector::PseudoMediaControlsVolumeSliderMuteButton);
+ nameToPseudoType->set(mediaControlsSeekBackButton.impl(), CSSSelector::PseudoMediaControlsSeekBackButton);
+ nameToPseudoType->set(mediaControlsSeekForwardButton.impl(), CSSSelector::PseudoMediaControlsSeekForwardButton);
+ nameToPseudoType->set(mediaControlsRewindButton.impl(), CSSSelector::PseudoMediaControlsRewindButton);
+ nameToPseudoType->set(mediaControlsReturnToRealtimeButton.impl(), CSSSelector::PseudoMediaControlsReturnToRealtimeButton);
+ nameToPseudoType->set(mediaControlsToggleClosedCaptionsButton.impl(), CSSSelector::PseudoMediaControlsToggleClosedCaptions);
+ nameToPseudoType->set(mediaControlsStatusDisplay.impl(), CSSSelector::PseudoMediaControlsStatusDisplay);
+ nameToPseudoType->set(mediaControlsFullscreenButton.impl(), CSSSelector::PseudoMediaControlsFullscreenButton);
+ nameToPseudoType->set(mediaControlsTimelineContainer.impl(), CSSSelector::PseudoMediaControlsTimelineContainer);
+ nameToPseudoType->set(mediaControlsVolumeSliderContainer.impl(), CSSSelector::PseudoMediaControlsVolumeSliderContainer);
+ nameToPseudoType->set(notStr.impl(), CSSSelector::PseudoNot);
+ nameToPseudoType->set(nthChild.impl(), CSSSelector::PseudoNthChild);
+ nameToPseudoType->set(nthOfType.impl(), CSSSelector::PseudoNthOfType);
+ nameToPseudoType->set(nthLastChild.impl(), CSSSelector::PseudoNthLastChild);
+ nameToPseudoType->set(nthLastOfType.impl(), CSSSelector::PseudoNthLastOfType);
+ nameToPseudoType->set(outerSpinButton.impl(), CSSSelector::PseudoOuterSpinButton);
+#if ENABLE(PROGRESS_TAG)
+ nameToPseudoType->set(progressBarValue.impl(), CSSSelector::PseudoProgressBarValue);
+#endif
+#if ENABLE(METER_TAG)
+ nameToPseudoType->set(meterHorizontalBar.impl(), CSSSelector::PseudoMeterHorizontalBar);
+ nameToPseudoType->set(meterHorizontalOptimumValue.impl(), CSSSelector::PseudoMeterHorizontalOptimum);
+ nameToPseudoType->set(meterHorizontalSuboptimalValue.impl(), CSSSelector::PseudoMeterHorizontalSuboptimal);
+ nameToPseudoType->set(meterHorizontalEvenLessGoodValue.impl(), CSSSelector::PseudoMeterHorizontalEvenLessGood);
+ nameToPseudoType->set(meterVerticalBar.impl(), CSSSelector::PseudoMeterVerticalBar);
+ nameToPseudoType->set(meterVerticalOptimumValue.impl(), CSSSelector::PseudoMeterVerticalOptimum);
+ nameToPseudoType->set(meterVerticalSuboptimalValue.impl(), CSSSelector::PseudoMeterVerticalSuboptimal);
+ nameToPseudoType->set(meterVerticalEvenLessGoodValue.impl(), CSSSelector::PseudoMeterVerticalEvenLessGood);
+#endif
+ nameToPseudoType->set(root.impl(), CSSSelector::PseudoRoot);
+ nameToPseudoType->set(windowInactive.impl(), CSSSelector::PseudoWindowInactive);
+ nameToPseudoType->set(decrement.impl(), CSSSelector::PseudoDecrement);
+ nameToPseudoType->set(increment.impl(), CSSSelector::PseudoIncrement);
+ nameToPseudoType->set(start.impl(), CSSSelector::PseudoStart);
+ nameToPseudoType->set(end.impl(), CSSSelector::PseudoEnd);
+ nameToPseudoType->set(horizontal.impl(), CSSSelector::PseudoHorizontal);
+ nameToPseudoType->set(vertical.impl(), CSSSelector::PseudoVertical);
+ nameToPseudoType->set(doubleButton.impl(), CSSSelector::PseudoDoubleButton);
+ nameToPseudoType->set(singleButton.impl(), CSSSelector::PseudoSingleButton);
+ nameToPseudoType->set(noButton.impl(), CSSSelector::PseudoNoButton);
+ nameToPseudoType->set(optional.impl(), CSSSelector::PseudoOptional);
+ nameToPseudoType->set(required.impl(), CSSSelector::PseudoRequired);
+ nameToPseudoType->set(resizer.impl(), CSSSelector::PseudoResizer);
+ nameToPseudoType->set(scrollbar.impl(), CSSSelector::PseudoScrollbar);
+ nameToPseudoType->set(scrollbarButton.impl(), CSSSelector::PseudoScrollbarButton);
+ nameToPseudoType->set(scrollbarCorner.impl(), CSSSelector::PseudoScrollbarCorner);
+ nameToPseudoType->set(scrollbarThumb.impl(), CSSSelector::PseudoScrollbarThumb);
+ nameToPseudoType->set(scrollbarTrack.impl(), CSSSelector::PseudoScrollbarTrack);
+ nameToPseudoType->set(scrollbarTrackPiece.impl(), CSSSelector::PseudoScrollbarTrackPiece);
+ nameToPseudoType->set(cornerPresent.impl(), CSSSelector::PseudoCornerPresent);
+ nameToPseudoType->set(searchCancelButton.impl(), CSSSelector::PseudoSearchCancelButton);
+ nameToPseudoType->set(searchDecoration.impl(), CSSSelector::PseudoSearchDecoration);
+ nameToPseudoType->set(searchResultsDecoration.impl(), CSSSelector::PseudoSearchResultsDecoration);
+ nameToPseudoType->set(searchResultsButton.impl(), CSSSelector::PseudoSearchResultsButton);
+ nameToPseudoType->set(selection.impl(), CSSSelector::PseudoSelection);
+ nameToPseudoType->set(sliderThumb.impl(), CSSSelector::PseudoSliderThumb);
+ nameToPseudoType->set(target.impl(), CSSSelector::PseudoTarget);
+ nameToPseudoType->set(visited.impl(), CSSSelector::PseudoVisited);
+ nameToPseudoType->set(firstPage.impl(), CSSSelector::PseudoFirstPage);
+ nameToPseudoType->set(leftPage.impl(), CSSSelector::PseudoLeftPage);
+ nameToPseudoType->set(rightPage.impl(), CSSSelector::PseudoRightPage);
+#if ENABLE(FULLSCREEN_API)
+ nameToPseudoType->set(fullScreen.impl(), CSSSelector::PseudoFullScreen);
+ nameToPseudoType->set(fullScreenDocument.impl(), CSSSelector::PseudoFullScreenDocument);
+#endif
+ }
+ return nameToPseudoType;
+}
+
+CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name)
+{
+ if (name.isNull())
+ return PseudoUnknown;
+ HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseudoTypeMap();
+ HashMap<AtomicStringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoType->find(name.impl());
+ return slot == nameToPseudoType->end() ? PseudoUnknown : slot->second;
+}
+
+void CSSSelector::extractPseudoType() const
+{
+ if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass)
+ return;
+
+ m_pseudoType = parsePseudoType(m_value);
bool element = false; // pseudo-element
bool compat = false; // single colon compatbility mode
+ bool isPagePseudoClass = false; // Page pseudo-class
- m_pseudoType = PseudoUnknown;
- if (m_value == active)
- m_pseudoType = PseudoActive;
- else if (m_value == after) {
- m_pseudoType = PseudoAfter;
- element = true;
- compat = true;
- } else if (m_value == anyLink)
- m_pseudoType = PseudoAnyLink;
- else if (m_value == autofill)
- m_pseudoType = PseudoAutofill;
- else if (m_value == before) {
- m_pseudoType = PseudoBefore;
- element = true;
+ switch (m_pseudoType) {
+ case PseudoAfter:
+ case PseudoBefore:
+ case PseudoFirstLetter:
+ case PseudoFirstLine:
compat = true;
- } else if (m_value == checked)
- m_pseudoType = PseudoChecked;
- else if (m_value == fileUploadButton) {
- m_pseudoType = PseudoFileUploadButton;
- element = true;
- } else if (m_value == defaultString)
- m_pseudoType = PseudoDefault;
- else if (m_value == disabled)
- m_pseudoType = PseudoDisabled;
- else if (m_value == readOnly)
- m_pseudoType = PseudoReadOnly;
- else if (m_value == readWrite)
- m_pseudoType = PseudoReadWrite;
- else if (m_value == valid)
- m_pseudoType = PseudoValid;
- else if (m_value == invalid)
- m_pseudoType = PseudoInvalid;
- else if (m_value == drag || m_value == dragAlias)
- m_pseudoType = PseudoDrag;
- else if (m_value == enabled)
- m_pseudoType = PseudoEnabled;
- else if (m_value == empty)
- m_pseudoType = PseudoEmpty;
- else if (m_value == firstChild)
- m_pseudoType = PseudoFirstChild;
- else if (m_value == fullPageMedia)
- m_pseudoType = PseudoFullPageMedia;
- else
-#if ENABLE(DATALIST)
- if (m_value == inputListButton) {
- m_pseudoType = PseudoInputListButton;
- element = true;
- } else
+ case PseudoFileUploadButton:
+ case PseudoInputListButton:
+ case PseudoInputPlaceholder:
+#if ENABLE(INPUT_SPEECH)
+ case PseudoInputSpeechButton:
#endif
- if (m_value == inputPlaceholder) {
- m_pseudoType = PseudoInputPlaceholder;
- element = true;
- } else if (m_value == lastChild)
- m_pseudoType = PseudoLastChild;
- else if (m_value == lastOfType)
- m_pseudoType = PseudoLastOfType;
- else if (m_value == onlyChild)
- m_pseudoType = PseudoOnlyChild;
- else if (m_value == onlyOfType)
- m_pseudoType = PseudoOnlyOfType;
- else if (m_value == firstLetter) {
- m_pseudoType = PseudoFirstLetter;
- element = true;
- compat = true;
- } else if (m_value == firstLine) {
- m_pseudoType = PseudoFirstLine;
- element = true;
- compat = true;
- } else if (m_value == firstOfType)
- m_pseudoType = PseudoFirstOfType;
- else if (m_value == focus)
- m_pseudoType = PseudoFocus;
- else if (m_value == hover)
- m_pseudoType = PseudoHover;
- else if (m_value == indeterminate)
- m_pseudoType = PseudoIndeterminate;
- else if (m_value == innerSpinButton) {
- m_pseudoType = PseudoInnerSpinButton;
- element = true;
- } else if (m_value == link)
- m_pseudoType = PseudoLink;
- else if (m_value == lang)
- m_pseudoType = PseudoLang;
- else if (m_value == mediaControlsPanel) {
- m_pseudoType = PseudoMediaControlsPanel;
- element = true;
- } else if (m_value == mediaControlsMuteButton) {
- m_pseudoType = PseudoMediaControlsMuteButton;
- element = true;
- } else if (m_value == mediaControlsPlayButton) {
- m_pseudoType = PseudoMediaControlsPlayButton;
- element = true;
- } else if (m_value == mediaControlsCurrentTimeDisplay) {
- m_pseudoType = PseudoMediaControlsCurrentTimeDisplay;
- element = true;
- } else if (m_value == mediaControlsTimeRemainingDisplay) {
- m_pseudoType = PseudoMediaControlsTimeRemainingDisplay;
- element = true;
- } else if (m_value == mediaControlsTimeline) {
- m_pseudoType = PseudoMediaControlsTimeline;
- element = true;
- } else if (m_value == mediaControlsVolumeSlider) {
- m_pseudoType = PseudoMediaControlsVolumeSlider;
- element = true;
- } else if (m_value == mediaControlsSeekBackButton) {
- m_pseudoType = PseudoMediaControlsSeekBackButton;
- element = true;
- } else if (m_value == mediaControlsSeekForwardButton) {
- m_pseudoType = PseudoMediaControlsSeekForwardButton;
- element = true;
- } else if (m_value == mediaControlsRewindButton) {
- m_pseudoType = PseudoMediaControlsRewindButton;
- element = true;
- } else if (m_value == mediaControlsReturnToRealtimeButton) {
- m_pseudoType = PseudoMediaControlsReturnToRealtimeButton;
- element = true;
- } else if (m_value == mediaControlsToggleClosedCaptionsButton) {
- m_pseudoType = PseudoMediaControlsToggleClosedCaptions;
- element = true;
- } else if (m_value == mediaControlsStatusDisplay) {
- m_pseudoType = PseudoMediaControlsStatusDisplay;
- element = true;
- } else if (m_value == mediaControlsFullscreenButton) {
- m_pseudoType = PseudoMediaControlsFullscreenButton;
- element = true;
- } else if (m_value == mediaControlsTimelineContainer) {
- m_pseudoType = PseudoMediaControlsTimelineContainer;
- element = true;
- } else if (m_value == mediaControlsVolumeSliderContainer) {
- m_pseudoType = PseudoMediaControlsVolumeSliderContainer;
- element = true;
- } else if (m_value == notStr)
- m_pseudoType = PseudoNot;
- else if (m_value == nthChild)
- m_pseudoType = PseudoNthChild;
- else if (m_value == nthOfType)
- m_pseudoType = PseudoNthOfType;
- else if (m_value == nthLastChild)
- m_pseudoType = PseudoNthLastChild;
- else if (m_value == nthLastOfType)
- m_pseudoType = PseudoNthLastOfType;
- else if (m_value == outerSpinButton) {
- m_pseudoType = PseudoOuterSpinButton;
- element = true;
- } else if (m_value == root)
- m_pseudoType = PseudoRoot;
- else if (m_value == windowInactive)
- m_pseudoType = PseudoWindowInactive;
- else if (m_value == decrement)
- m_pseudoType = PseudoDecrement;
- else if (m_value == increment)
- m_pseudoType = PseudoIncrement;
- else if (m_value == start)
- m_pseudoType = PseudoStart;
- else if (m_value == end)
- m_pseudoType = PseudoEnd;
- else if (m_value == horizontal)
- m_pseudoType = PseudoHorizontal;
- else if (m_value == vertical)
- m_pseudoType = PseudoVertical;
- else if (m_value == doubleButton)
- m_pseudoType = PseudoDoubleButton;
- else if (m_value == singleButton)
- m_pseudoType = PseudoSingleButton;
- else if (m_value == noButton)
- m_pseudoType = PseudoNoButton;
- else if (m_value == optional)
- m_pseudoType = PseudoOptional;
- else if (m_value == required)
- m_pseudoType = PseudoRequired;
- else if (m_value == scrollbarCorner) {
- element = true;
- m_pseudoType = PseudoScrollbarCorner;
- } else if (m_value == resizer) {
- element = true;
- m_pseudoType = PseudoResizer;
- } else if (m_value == scrollbar) {
- element = true;
- m_pseudoType = PseudoScrollbar;
- } else if (m_value == scrollbarButton) {
- element = true;
- m_pseudoType = PseudoScrollbarButton;
- } else if (m_value == scrollbarCorner) {
- element = true;
- m_pseudoType = PseudoScrollbarCorner;
- } else if (m_value == scrollbarThumb) {
- element = true;
- m_pseudoType = PseudoScrollbarThumb;
- } else if (m_value == scrollbarTrack) {
- element = true;
- m_pseudoType = PseudoScrollbarTrack;
- } else if (m_value == scrollbarTrackPiece) {
- element = true;
- m_pseudoType = PseudoScrollbarTrackPiece;
- } else if (m_value == cornerPresent)
- m_pseudoType = PseudoCornerPresent;
- else if (m_value == searchCancelButton) {
- m_pseudoType = PseudoSearchCancelButton;
- element = true;
- } else if (m_value == searchDecoration) {
- m_pseudoType = PseudoSearchDecoration;
- element = true;
- } else if (m_value == searchResultsDecoration) {
- m_pseudoType = PseudoSearchResultsDecoration;
- element = true;
- } else if (m_value == searchResultsButton) {
- m_pseudoType = PseudoSearchResultsButton;
- element = true;
- } else if (m_value == selection) {
- m_pseudoType = PseudoSelection;
- element = true;
- } else if (m_value == sliderThumb) {
- m_pseudoType = PseudoSliderThumb;
- element = true;
- } else if (m_value == target)
- m_pseudoType = PseudoTarget;
- else if (m_value == visited)
- m_pseudoType = PseudoVisited;
+ case PseudoInnerSpinButton:
+ case PseudoMediaControlsPanel:
+ case PseudoMediaControlsMuteButton:
+ case PseudoMediaControlsPlayButton:
+ case PseudoMediaControlsCurrentTimeDisplay:
+ case PseudoMediaControlsTimeRemainingDisplay:
+ case PseudoMediaControlsTimeline:
+ case PseudoMediaControlsVolumeSlider:
+ case PseudoMediaControlsVolumeSliderMuteButton:
+ case PseudoMediaControlsSeekBackButton:
+ case PseudoMediaControlsSeekForwardButton:
+ case PseudoMediaControlsRewindButton:
+ case PseudoMediaControlsReturnToRealtimeButton:
+ case PseudoMediaControlsToggleClosedCaptions:
+ case PseudoMediaControlsStatusDisplay:
+ case PseudoMediaControlsFullscreenButton:
+ case PseudoMediaControlsTimelineContainer:
+ case PseudoMediaControlsVolumeSliderContainer:
+ case PseudoMeterHorizontalBar:
+ case PseudoMeterHorizontalOptimum:
+ case PseudoMeterHorizontalSuboptimal:
+ case PseudoMeterHorizontalEvenLessGood:
+ case PseudoMeterVerticalBar:
+ case PseudoMeterVerticalOptimum:
+ case PseudoMeterVerticalSuboptimal:
+ case PseudoMeterVerticalEvenLessGood:
+ case PseudoOuterSpinButton:
+ case PseudoProgressBarValue:
+ case PseudoResizer:
+ case PseudoScrollbar:
+ case PseudoScrollbarCorner:
+ case PseudoScrollbarButton:
+ case PseudoScrollbarThumb:
+ case PseudoScrollbarTrack:
+ case PseudoScrollbarTrackPiece:
+ case PseudoSearchCancelButton:
+ case PseudoSearchDecoration:
+ case PseudoSearchResultsDecoration:
+ case PseudoSearchResultsButton:
+ case PseudoSelection:
+ case PseudoSliderThumb:
+ element = true;
+ break;
+ case PseudoUnknown:
+ case PseudoEmpty:
+ case PseudoFirstChild:
+ case PseudoFirstOfType:
+ case PseudoLastChild:
+ case PseudoLastOfType:
+ case PseudoOnlyChild:
+ case PseudoOnlyOfType:
+ case PseudoNthChild:
+ case PseudoNthOfType:
+ case PseudoNthLastChild:
+ case PseudoNthLastOfType:
+ case PseudoLink:
+ case PseudoVisited:
+ case PseudoAnyLink:
+ case PseudoAutofill:
+ case PseudoHover:
+ case PseudoDrag:
+ case PseudoFocus:
+ case PseudoActive:
+ case PseudoChecked:
+ case PseudoEnabled:
+ case PseudoFullPageMedia:
+ case PseudoDefault:
+ case PseudoDisabled:
+ case PseudoOptional:
+ case PseudoRequired:
+ case PseudoReadOnly:
+ case PseudoReadWrite:
+ case PseudoValid:
+ case PseudoInvalid:
+ case PseudoIndeterminate:
+ case PseudoTarget:
+ case PseudoLang:
+ case PseudoNot:
+ case PseudoRoot:
+ case PseudoScrollbarBack:
+ case PseudoScrollbarForward:
+ case PseudoWindowInactive:
+ case PseudoCornerPresent:
+ case PseudoDecrement:
+ case PseudoIncrement:
+ case PseudoHorizontal:
+ case PseudoVertical:
+ case PseudoStart:
+ case PseudoEnd:
+ case PseudoDoubleButton:
+ case PseudoSingleButton:
+ case PseudoNoButton:
+ case PseudoNotParsed:
+#if ENABLE(FULLSCREEN_API)
+ case PseudoFullScreen:
+ case PseudoFullScreenDocument:
+#endif
+ break;
+ case PseudoFirstPage:
+ case PseudoLeftPage:
+ case PseudoRightPage:
+ isPagePseudoClass = true;
+ break;
+ }
- if (m_match == PseudoClass && element) {
- if (!compat)
+ bool matchPagePseudoClass = (m_match == PagePseudoClass);
+ if (matchPagePseudoClass != isPagePseudoClass)
+ m_pseudoType = PseudoUnknown;
+ else if (m_match == PseudoClass && element) {
+ if (!compat)
m_pseudoType = PseudoUnknown;
- else
+ else
m_match = PseudoElement;
} else if (m_match == PseudoElement && !element)
m_pseudoType = PseudoUnknown;
@@ -420,19 +736,22 @@ String CSSSelector::selectorText() const
if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) {
if (prefix.isNull())
str = localName;
- else
- str = prefix + "|" + localName;
+ else {
+ str = prefix.string();
+ str.append("|");
+ str.append(localName);
+ }
}
const CSSSelector* cs = this;
while (true) {
if (cs->m_match == CSSSelector::Id) {
str += "#";
- str += cs->m_value;
+ serializeIdentifier(cs->m_value, str);
} else if (cs->m_match == CSSSelector::Class) {
str += ".";
- str += cs->m_value;
- } else if (cs->m_match == CSSSelector::PseudoClass) {
+ serializeIdentifier(cs->m_value, str);
+ } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) {
str += ":";
str += cs->m_value;
if (cs->pseudoType() == PseudoNot) {
@@ -453,8 +772,10 @@ String CSSSelector::selectorText() const
} else if (cs->hasAttribute()) {
str += "[";
const AtomicString& prefix = cs->attribute().prefix();
- if (!prefix.isNull())
- str += prefix + "|";
+ if (!prefix.isNull()) {
+ str.append(prefix);
+ str.append("|");
+ }
str += cs->attribute().localName();
switch (cs->m_match) {
case CSSSelector::Exact:
@@ -483,9 +804,8 @@ String CSSSelector::selectorText() const
break;
}
if (cs->m_match != CSSSelector::Set) {
- str += "\"";
- str += cs->m_value;
- str += "\"]";
+ serializeString(cs->m_value, str);
+ str += "]";
}
}
if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory())
@@ -563,10 +883,35 @@ bool CSSSelector::matchNth(int count)
return m_data.m_rareData->matchNth(count);
}
+bool CSSSelector::isSimple() const
+{
+ if (simpleSelector() || tagHistory() || matchesPseudoElement())
+ return false;
+
+ int numConditions = 0;
+
+ // hasTag() cannot be be used here because namespace may not be nullAtom.
+ // Example:
+ // @namespace "http://www.w3.org/2000/svg";
+ // svg:not(:root) { ...
+ if (m_tag != starAtom)
+ numConditions++;
+
+ if (m_match == Id || m_match == Class || m_match == PseudoClass)
+ numConditions++;
+
+ if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName())
+ numConditions++;
+
+ // numConditions is 0 for a universal selector.
+ // numConditions is 1 for other simple selectors.
+ return numConditions <= 1;
+}
+
// a helper function for parsing nth-arguments
bool CSSSelector::RareData::parseNth()
-{
- const String& argument = m_argument;
+{
+ String argument = m_argument.lower();
if (argument.isEmpty())
return false;
@@ -580,8 +925,8 @@ bool CSSSelector::RareData::parseNth()
m_a = 2;
m_b = 0;
} else {
- int n = argument.find('n');
- if (n != -1) {
+ size_t n = argument.find('n');
+ if (n != notFound) {
if (argument[0] == '-') {
if (n == 1)
m_a = -1; // -n == -1n
@@ -592,12 +937,13 @@ bool CSSSelector::RareData::parseNth()
else
m_a = argument.substring(0, n).toInt();
- int p = argument.find('+', n);
- if (p != -1)
+ size_t p = argument.find('+', n);
+ if (p != notFound)
m_b = argument.substring(p + 1, argument.length() - p - 1).toInt();
else {
p = argument.find('-', n);
- m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt();
+ if (p != notFound)
+ m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt();
}
} else
m_b = argument.toInt();
@@ -620,5 +966,34 @@ bool CSSSelector::RareData::matchNth(int count)
return (m_b - count) % (-m_a) == 0;
}
}
-
+
+inline void CSSSelector::releaseOwnedSelectorsToBag(CSSSelectorBag& bag)
+{
+ if (m_hasRareData) {
+ ASSERT(m_data.m_rareData);
+ bag.add(m_data.m_rareData->m_tagHistory.release());
+ bag.add(m_data.m_rareData->m_simpleSelector.release());
+ delete m_data.m_rareData;
+ // Clear the pointer so that a destructor of this selector will not
+ // traverse this chain.
+ m_data.m_rareData = 0;
+ } else {
+ bag.add(adoptPtr(m_data.m_tagHistory));
+ // Clear the pointer for the same reason.
+ m_data.m_tagHistory = 0;
+ }
+}
+
+void CSSSelector::deleteReachableSelectors()
+{
+ // Traverse the chain of selectors and delete each iteratively.
+ CSSSelectorBag selectorsToBeDeleted;
+ releaseOwnedSelectorsToBag(selectorsToBeDeleted);
+ while (!selectorsToBeDeleted.isEmpty()) {
+ OwnPtr<CSSSelector> selector(selectorsToBeDeleted.takeAny());
+ ASSERT(selector);
+ selector->releaseOwnedSelectorsToBag(selectorsToBeDeleted);
+ }
+}
+
} // namespace WebCore