Have is<>(T*) function do a null check on the pointer argument
[WebKit-https.git] / Source / WebCore / css / SelectorCheckerTestFunctions.h
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef SelectorCheckerTestFunctions_h
27 #define SelectorCheckerTestFunctions_h
28
29 #include "FocusController.h"
30 #include "HTMLInputElement.h"
31 #include "HTMLOptionElement.h"
32 #include "RenderScrollbar.h"
33 #include "ScrollableArea.h"
34 #include "ScrollbarTheme.h"
35 #include <wtf/Compiler.h>
36
37 #if ENABLE(VIDEO_TRACK)
38 #include "WebVTTElement.h"
39 #endif
40
41 namespace WebCore {
42
43 ALWAYS_INLINE bool isAutofilled(const Element* element)
44 {
45     if (is<HTMLFormControlElement>(*element)) {
46         if (const HTMLInputElement* inputElement = element->toInputElement())
47             return inputElement->isAutofilled();
48     }
49     return false;
50 }
51
52 ALWAYS_INLINE bool isDefaultButtonForForm(const Element* element)
53 {
54     return element->isDefaultButtonForForm();
55 }
56
57 ALWAYS_INLINE bool isDisabled(const Element* element)
58 {
59     return (is<HTMLFormControlElement>(*element) || is<HTMLOptionElement>(*element) || is<HTMLOptGroupElement>(*element))
60         && element->isDisabledFormControl();
61 }
62
63 ALWAYS_INLINE bool isEnabled(const Element* element)
64 {
65     return (is<HTMLFormControlElement>(*element) || is<HTMLOptionElement>(*element) || is<HTMLOptGroupElement>(*element))
66         && !element->isDisabledFormControl();
67 }
68
69 ALWAYS_INLINE bool isMediaDocument(Element* element)
70 {
71     return element->document().isMediaDocument();
72 }
73
74 ALWAYS_INLINE bool isChecked(Element* element)
75 {
76     // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
77     // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
78     // obey the CSS spec here in the test for matching the pseudo.
79     const HTMLInputElement* inputElement = element->toInputElement();
80     if (inputElement && inputElement->shouldAppearChecked() && !inputElement->shouldAppearIndeterminate())
81         return true;
82     if (is<HTMLOptionElement>(*element) && downcast<HTMLOptionElement>(*element).selected())
83         return true;
84     return false;
85 }
86
87 ALWAYS_INLINE bool isInRange(Element* element)
88 {
89     element->document().setContainsValidityStyleRules();
90     return element->isInRange();
91 }
92
93 ALWAYS_INLINE bool isOutOfRange(Element* element)
94 {
95     element->document().setContainsValidityStyleRules();
96     return element->isOutOfRange();
97 }
98
99 ALWAYS_INLINE bool isInvalid(const Element* element)
100 {
101     element->document().setContainsValidityStyleRules();
102     return element->willValidate() && !element->isValidFormControlElement();
103 }
104
105 ALWAYS_INLINE bool isOptionalFormControl(const Element* element)
106 {
107     return element->isOptionalFormControl();
108 }
109
110 ALWAYS_INLINE bool isRequiredFormControl(const Element* element)
111 {
112     return element->isRequiredFormControl();
113 }
114
115 ALWAYS_INLINE bool isValid(const Element* element)
116 {
117     element->document().setContainsValidityStyleRules();
118     return element->willValidate() && element->isValidFormControlElement();
119 }
120
121 ALWAYS_INLINE bool isWindowInactive(const Element* element)
122 {
123     return !element->document().page()->focusController().isActive();
124 }
125     
126 inline bool matchesLangPseudoClass(const Element* element, AtomicStringImpl* filter)
127 {
128     AtomicString value;
129 #if ENABLE(VIDEO_TRACK)
130     if (is<WebVTTElement>(*element))
131         value = downcast<WebVTTElement>(*element).language();
132     else
133 #endif
134         value = element->computeInheritedLanguage();
135
136     if (value.isNull())
137         return false;
138
139     if (value.impl() == filter)
140         return true;
141
142     if (value.impl()->startsWith(filter, false)) {
143         if (value.length() == filter->length())
144             return true;
145         return value[filter->length()] == '-';
146     }
147     return false;
148 }
149
150 ALWAYS_INLINE bool matchesReadOnlyPseudoClass(const Element* element)
151 {
152     return !element->matchesReadWritePseudoClass();
153 }
154
155 ALWAYS_INLINE bool matchesReadWritePseudoClass(const Element* element)
156 {
157     return element->matchesReadWritePseudoClass();
158 }
159
160 ALWAYS_INLINE bool shouldAppearIndeterminate(const Element* element)
161 {
162     return element->shouldAppearIndeterminate();
163 }
164
165 ALWAYS_INLINE bool scrollbarMatchesEnabledPseudoClass(const SelectorChecker::CheckingContext& context)
166 {
167     return context.scrollbar && context.scrollbar->enabled();
168 }
169
170 ALWAYS_INLINE bool scrollbarMatchesDisabledPseudoClass(const SelectorChecker::CheckingContext& context)
171 {
172     return context.scrollbar && !context.scrollbar->enabled();
173 }
174
175 ALWAYS_INLINE bool scrollbarMatchesHoverPseudoClass(const SelectorChecker::CheckingContext& context)
176 {
177     if (!context.scrollbar)
178         return false;
179     ScrollbarPart hoveredPart = context.scrollbar->hoveredPart();
180     if (context.scrollbarPart == ScrollbarBGPart)
181         return hoveredPart != NoPart;
182     if (context.scrollbarPart == TrackBGPart)
183         return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart;
184     return context.scrollbarPart == hoveredPart;
185 }
186
187 ALWAYS_INLINE bool scrollbarMatchesActivePseudoClass(const SelectorChecker::CheckingContext& context)
188 {
189     if (!context.scrollbar)
190         return false;
191     ScrollbarPart pressedPart = context.scrollbar->pressedPart();
192     if (context.scrollbarPart == ScrollbarBGPart)
193         return pressedPart != NoPart;
194     if (context.scrollbarPart == TrackBGPart)
195         return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart;
196     return context.scrollbarPart == pressedPart;
197 }
198
199 ALWAYS_INLINE bool scrollbarMatchesHorizontalPseudoClass(const SelectorChecker::CheckingContext& context)
200 {
201     return context.scrollbar && context.scrollbar->orientation() == HorizontalScrollbar;
202 }
203
204 ALWAYS_INLINE bool scrollbarMatchesVerticalPseudoClass(const SelectorChecker::CheckingContext& context)
205 {
206     return context.scrollbar && context.scrollbar->orientation() == VerticalScrollbar;
207 }
208
209 ALWAYS_INLINE bool scrollbarMatchesDecrementPseudoClass(const SelectorChecker::CheckingContext& context)
210 {
211     return context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == BackTrackPart;
212 }
213
214 ALWAYS_INLINE bool scrollbarMatchesIncrementPseudoClass(const SelectorChecker::CheckingContext& context)
215 {
216     return context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart;
217 }
218
219 ALWAYS_INLINE bool scrollbarMatchesStartPseudoClass(const SelectorChecker::CheckingContext& context)
220 {
221     return context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == BackTrackPart;
222 }
223
224 ALWAYS_INLINE bool scrollbarMatchesEndPseudoClass(const SelectorChecker::CheckingContext& context)
225 {
226     return context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart;
227 }
228
229 ALWAYS_INLINE bool scrollbarMatchesDoubleButtonPseudoClass(const SelectorChecker::CheckingContext& context)
230 {
231     if (!context.scrollbar)
232         return false;
233     ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme()->buttonsPlacement();
234     if (context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == BackTrackPart)
235         return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth;
236     if (context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart)
237         return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth;
238     return false;
239 }
240
241 ALWAYS_INLINE bool scrollbarMatchesSingleButtonPseudoClass(const SelectorChecker::CheckingContext& context)
242 {
243     if (!context.scrollbar)
244         return false;
245     ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme()->buttonsPlacement();
246     if (context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == BackTrackPart || context.scrollbarPart == ForwardTrackPart)
247         return buttonsPlacement == ScrollbarButtonsSingle;
248     return false;
249 }
250
251 ALWAYS_INLINE bool scrollbarMatchesNoButtonPseudoClass(const SelectorChecker::CheckingContext& context)
252 {
253     if (!context.scrollbar)
254         return false;
255     ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme()->buttonsPlacement();
256     if (context.scrollbarPart == BackTrackPart)
257         return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd;
258     if (context.scrollbarPart == ForwardTrackPart)
259         return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart;
260     return false;
261 }
262
263 ALWAYS_INLINE bool scrollbarMatchesCornerPresentPseudoClass(const SelectorChecker::CheckingContext& context)
264 {
265     return context.scrollbar && context.scrollbar->scrollableArea()->isScrollCornerVisible();
266 }
267
268 #if ENABLE(FULLSCREEN_API)
269 ALWAYS_INLINE bool matchesFullScreenPseudoClass(const Element* element)
270 {
271     // While a Document is in the fullscreen state, and the document's current fullscreen
272     // element is an element in the document, the 'full-screen' pseudoclass applies to
273     // that element. Also, an <iframe>, <object> or <embed> element whose child browsing
274     // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied.
275     if (element->isFrameElementBase() && element->containsFullScreenElement())
276         return true;
277     if (!element->document().webkitIsFullScreen())
278         return false;
279     return element == element->document().webkitCurrentFullScreenElement();
280 }
281
282 ALWAYS_INLINE bool matchesFullScreenAnimatingFullScreenTransitionPseudoClass(const Element* element)
283 {
284     if (element != element->document().webkitCurrentFullScreenElement())
285         return false;
286     return element->document().isAnimatingFullScreen();
287 }
288
289 ALWAYS_INLINE bool matchesFullScreenAncestorPseudoClass(const Element* element)
290 {
291     return element->containsFullScreenElement();
292 }
293
294 ALWAYS_INLINE bool matchesFullScreenDocumentPseudoClass(const Element* element)
295 {
296     // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies
297     // to all elements of that Document.
298     if (!element->document().webkitIsFullScreen())
299         return false;
300     return true;
301 }
302 #endif
303
304 #if ENABLE(VIDEO_TRACK)
305 ALWAYS_INLINE bool matchesFutureCuePseudoClass(const Element* element)
306 {
307     return is<WebVTTElement>(*element) && !downcast<WebVTTElement>(*element).isPastNode();
308 }
309
310 ALWAYS_INLINE bool matchesPastCuePseudoClass(const Element* element)
311 {
312     return is<WebVTTElement>(*element) && downcast<WebVTTElement>(*element).isPastNode();
313 }
314 #endif
315
316 } // namespace WebCore
317
318 #endif // SelectorCheckerTestFunctions_h