diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/css/SelectorCheckerTestFunctions.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/css/SelectorCheckerTestFunctions.h')
-rw-r--r-- | Source/WebCore/css/SelectorCheckerTestFunctions.h | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/Source/WebCore/css/SelectorCheckerTestFunctions.h b/Source/WebCore/css/SelectorCheckerTestFunctions.h new file mode 100644 index 000000000..db62a8b21 --- /dev/null +++ b/Source/WebCore/css/SelectorCheckerTestFunctions.h @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2014-2016 Apple Inc. All rights reserved. + * Copyright (C) 2014 Dhi Aurrahman <diorahman@rockybars.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "FocusController.h" +#include "HTMLInputElement.h" +#include "HTMLOptionElement.h" +#include "RenderScrollbar.h" +#include "ScrollableArea.h" +#include "ScrollbarTheme.h" +#include <wtf/Compiler.h> + +#if ENABLE(VIDEO_TRACK) +#include "WebVTTElement.h" +#endif + +namespace WebCore { + +ALWAYS_INLINE bool isAutofilled(const Element& element) +{ + return is<HTMLInputElement>(element) && downcast<HTMLInputElement>(element).isAutoFilled(); +} + +ALWAYS_INLINE bool matchesDefaultPseudoClass(const Element& element) +{ + return element.matchesDefaultPseudoClass(); +} + +// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled +ALWAYS_INLINE bool matchesDisabledPseudoClass(const Element& element) +{ + return is<HTMLElement>(element) && downcast<HTMLElement>(element).isActuallyDisabled(); +} + +// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled +ALWAYS_INLINE bool matchesEnabledPseudoClass(const Element& element) +{ + return is<HTMLElement>(element) && downcast<HTMLElement>(element).canBeActuallyDisabled() && !element.isDisabledFormControl(); +} + +ALWAYS_INLINE bool isDefinedElement(const Element& element) +{ + return !element.isUndefinedCustomElement(); +} + +ALWAYS_INLINE bool isMediaDocument(const Element& element) +{ + return element.document().isMediaDocument(); +} + +ALWAYS_INLINE bool isChecked(const Element& element) +{ + // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that + // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just + // obey the CSS spec here in the test for matching the pseudo. + if (is<HTMLInputElement>(element)) { + auto& inputElement = downcast<HTMLInputElement>(element); + return inputElement.shouldAppearChecked() && !inputElement.shouldAppearIndeterminate(); + } + if (is<HTMLOptionElement>(element)) + return const_cast<HTMLOptionElement&>(downcast<HTMLOptionElement>(element)).selected(); + + return false; +} + +ALWAYS_INLINE bool isInRange(const Element& element) +{ + return element.isInRange(); +} + +ALWAYS_INLINE bool isOutOfRange(const Element& element) +{ + return element.isOutOfRange(); +} + +ALWAYS_INLINE bool isInvalid(const Element& element) +{ + return element.matchesInvalidPseudoClass(); +} + +ALWAYS_INLINE bool isOptionalFormControl(const Element& element) +{ + return element.isOptionalFormControl(); +} + +ALWAYS_INLINE bool isRequiredFormControl(const Element& element) +{ + return element.isRequiredFormControl(); +} + +ALWAYS_INLINE bool isValid(const Element& element) +{ + return element.matchesValidPseudoClass(); +} + +ALWAYS_INLINE bool isWindowInactive(const Element& element) +{ + auto* page = element.document().page(); + if (!page) + return false; + return !page->focusController().isActive(); +} + +ALWAYS_INLINE bool containslanguageSubtagMatchingRange(StringView language, StringView range, unsigned languageLength, unsigned& position) +{ + unsigned languageSubtagsStartIndex = position; + unsigned languageSubtagsEndIndex = languageLength; + bool isAsteriskRange = range == "*"; + do { + if (languageSubtagsStartIndex > 0) + languageSubtagsStartIndex += 1; + + languageSubtagsEndIndex = std::min<unsigned>(language.find('-', languageSubtagsStartIndex), languageLength); + + if (languageSubtagsStartIndex > languageSubtagsEndIndex) + return false; + + StringView languageSubtag = language.substring(languageSubtagsStartIndex, languageSubtagsEndIndex - languageSubtagsStartIndex); + bool isEqual = equalIgnoringASCIICase(range, languageSubtag); + if (!isAsteriskRange) { + if ((!isEqual && !languageSubtagsStartIndex) || (languageSubtag.length() == 1 && languageSubtagsStartIndex > 0)) + return false; + } + languageSubtagsStartIndex = languageSubtagsEndIndex; + if (isEqual || isAsteriskRange) { + position = languageSubtagsStartIndex; + return true; + } + + } while (languageSubtagsStartIndex < languageLength); + return false; +} + +ALWAYS_INLINE bool matchesLangPseudoClass(const Element& element, const Vector<AtomicString>& argumentList) +{ + AtomicString language; +#if ENABLE(VIDEO_TRACK) + if (is<WebVTTElement>(element)) + language = downcast<WebVTTElement>(element).language(); + else +#endif + language = element.computeInheritedLanguage(); + + if (language.isEmpty()) + return false; + + // Implement basic and extended filterings of given language tags + // as specified in www.ietf.org/rfc/rfc4647.txt. + StringView languageStringView = language.string(); + unsigned languageLength = language.length(); + for (const AtomicString& range : argumentList) { + if (range.isEmpty()) + continue; + + if (range == "*") + return true; + + StringView rangeStringView = range.string(); + if (equalIgnoringASCIICase(languageStringView, rangeStringView) && !languageStringView.contains('-')) + return true; + + unsigned rangeLength = rangeStringView.length(); + unsigned rangeSubtagsStartIndex = 0; + unsigned rangeSubtagsEndIndex = rangeLength; + unsigned lastMatchedLanguageSubtagIndex = 0; + + bool matchedRange = true; + do { + if (rangeSubtagsStartIndex > 0) + rangeSubtagsStartIndex += 1; + if (rangeSubtagsStartIndex > languageLength) + return false; + rangeSubtagsEndIndex = std::min<unsigned>(rangeStringView.find('-', rangeSubtagsStartIndex), rangeLength); + StringView rangeSubtag = rangeStringView.substring(rangeSubtagsStartIndex, rangeSubtagsEndIndex - rangeSubtagsStartIndex); + if (!containslanguageSubtagMatchingRange(languageStringView, rangeSubtag, languageLength, lastMatchedLanguageSubtagIndex)) { + matchedRange = false; + break; + } + rangeSubtagsStartIndex = rangeSubtagsEndIndex; + } while (rangeSubtagsStartIndex < rangeLength); + if (matchedRange) + return true; + } + return false; +} + +ALWAYS_INLINE bool matchesReadOnlyPseudoClass(const Element& element) +{ + return !element.matchesReadWritePseudoClass(); +} + +ALWAYS_INLINE bool matchesReadWritePseudoClass(const Element& element) +{ + return element.matchesReadWritePseudoClass(); +} + +ALWAYS_INLINE bool matchesIndeterminatePseudoClass(const Element& element) +{ + return element.matchesIndeterminatePseudoClass(); +} + +ALWAYS_INLINE bool scrollbarMatchesEnabledPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbar && context.scrollbar->enabled(); +} + +ALWAYS_INLINE bool scrollbarMatchesDisabledPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbar && !context.scrollbar->enabled(); +} + +ALWAYS_INLINE bool scrollbarMatchesHoverPseudoClass(const SelectorChecker::CheckingContext& context) +{ + if (!context.scrollbar) + return false; + ScrollbarPart hoveredPart = context.scrollbar->hoveredPart(); + if (context.scrollbarPart == ScrollbarBGPart) + return hoveredPart != NoPart; + if (context.scrollbarPart == TrackBGPart) + return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart; + return context.scrollbarPart == hoveredPart; +} + +ALWAYS_INLINE bool scrollbarMatchesActivePseudoClass(const SelectorChecker::CheckingContext& context) +{ + if (!context.scrollbar) + return false; + ScrollbarPart pressedPart = context.scrollbar->pressedPart(); + if (context.scrollbarPart == ScrollbarBGPart) + return pressedPart != NoPart; + if (context.scrollbarPart == TrackBGPart) + return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart; + return context.scrollbarPart == pressedPart; +} + +ALWAYS_INLINE bool scrollbarMatchesHorizontalPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbar && context.scrollbar->orientation() == HorizontalScrollbar; +} + +ALWAYS_INLINE bool scrollbarMatchesVerticalPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbar && context.scrollbar->orientation() == VerticalScrollbar; +} + +ALWAYS_INLINE bool scrollbarMatchesDecrementPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == BackTrackPart; +} + +ALWAYS_INLINE bool scrollbarMatchesIncrementPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart; +} + +ALWAYS_INLINE bool scrollbarMatchesStartPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == BackTrackPart; +} + +ALWAYS_INLINE bool scrollbarMatchesEndPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart; +} + +ALWAYS_INLINE bool scrollbarMatchesDoubleButtonPseudoClass(const SelectorChecker::CheckingContext& context) +{ + if (!context.scrollbar) + return false; + ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme().buttonsPlacement(); + if (context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == BackTrackPart) + return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth; + if (context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart) + return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth; + return false; +} + +ALWAYS_INLINE bool scrollbarMatchesSingleButtonPseudoClass(const SelectorChecker::CheckingContext& context) +{ + if (!context.scrollbar) + return false; + ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme().buttonsPlacement(); + if (context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == BackTrackPart || context.scrollbarPart == ForwardTrackPart) + return buttonsPlacement == ScrollbarButtonsSingle; + return false; +} + +ALWAYS_INLINE bool scrollbarMatchesNoButtonPseudoClass(const SelectorChecker::CheckingContext& context) +{ + if (!context.scrollbar) + return false; + ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme().buttonsPlacement(); + if (context.scrollbarPart == BackTrackPart) + return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd; + if (context.scrollbarPart == ForwardTrackPart) + return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart; + return false; +} + +ALWAYS_INLINE bool scrollbarMatchesCornerPresentPseudoClass(const SelectorChecker::CheckingContext& context) +{ + return context.scrollbar && context.scrollbar->scrollableArea().isScrollCornerVisible(); +} + +#if ENABLE(FULLSCREEN_API) +ALWAYS_INLINE bool matchesFullScreenPseudoClass(const Element& element) +{ + // While a Document is in the fullscreen state, and the document's current fullscreen + // element is an element in the document, the 'full-screen' pseudoclass applies to + // that element. Also, an <iframe>, <object> or <embed> element whose child browsing + // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied. + if (element.isFrameElementBase() && element.containsFullScreenElement()) + return true; + if (!element.document().webkitIsFullScreen()) + return false; + return &element == element.document().webkitCurrentFullScreenElement(); +} + +ALWAYS_INLINE bool matchesFullScreenAnimatingFullScreenTransitionPseudoClass(const Element& element) +{ + if (&element != element.document().webkitCurrentFullScreenElement()) + return false; + return element.document().isAnimatingFullScreen(); +} + +ALWAYS_INLINE bool matchesFullScreenAncestorPseudoClass(const Element& element) +{ + return element.containsFullScreenElement(); +} + +ALWAYS_INLINE bool matchesFullScreenDocumentPseudoClass(const Element& element) +{ + // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies + // to all elements of that Document. + if (!element.document().webkitIsFullScreen()) + return false; + return true; +} +#endif + +#if ENABLE(VIDEO_TRACK) +ALWAYS_INLINE bool matchesFutureCuePseudoClass(const Element& element) +{ + return is<WebVTTElement>(element) && !downcast<WebVTTElement>(element).isPastNode(); +} + +ALWAYS_INLINE bool matchesPastCuePseudoClass(const Element& element) +{ + return is<WebVTTElement>(element) && downcast<WebVTTElement>(element).isPastNode(); +} +#endif + +} // namespace WebCore |