|
1 /* |
|
2 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) |
|
3 * 1999 Waldo Bastian (bastian@kde.org) |
|
4 * 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch) |
|
5 * 2001-2003 Dirk Mueller (mueller@kde.org) |
|
6 * Copyright (C) 2002, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. |
|
7 * Copyright (C) 2008 David Smith (catfish.man@gmail.com) |
|
8 * Copyright (C) 2010 Google Inc. All rights reserved. |
|
9 * |
|
10 * This library is free software; you can redistribute it and/or |
|
11 * modify it under the terms of the GNU Library General Public |
|
12 * License as published by the Free Software Foundation; either |
|
13 * version 2 of the License, or (at your option) any later version. |
|
14 * |
|
15 * This library is distributed in the hope that it will be useful, |
|
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
18 * Library General Public License for more details. |
|
19 * |
|
20 * You should have received a copy of the GNU Library General Public License |
|
21 * along with this library; see the file COPYING.LIB. If not, write to |
|
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
23 * Boston, MA 02110-1301, USA. |
|
24 */ |
|
25 |
|
26 #include "config.h" |
|
27 #include "CSSSelector.h" |
|
28 |
|
29 #include "CSSOMUtils.h" |
|
30 #include "HTMLNames.h" |
|
31 #include <wtf/Assertions.h> |
|
32 #include <wtf/HashMap.h> |
|
33 #include <wtf/StdLibExtras.h> |
|
34 #include <wtf/Vector.h> |
|
35 |
|
36 namespace WebCore { |
|
37 |
|
38 using namespace HTMLNames; |
|
39 |
|
40 // A helper class to hold CSSSelectors. |
|
41 class CSSSelectorBag : public Noncopyable { |
|
42 public: |
|
43 ~CSSSelectorBag() |
|
44 { |
|
45 deleteAllValues(m_stack); |
|
46 } |
|
47 |
|
48 bool isEmpty() const |
|
49 { |
|
50 return m_stack.isEmpty(); |
|
51 } |
|
52 |
|
53 void append(PassOwnPtr<CSSSelector> selector) |
|
54 { |
|
55 if (selector) |
|
56 m_stack.append(selector.leakPtr()); |
|
57 } |
|
58 |
|
59 PassOwnPtr<CSSSelector> takeAny() |
|
60 { |
|
61 ASSERT(!isEmpty()); |
|
62 OwnPtr<CSSSelector> selector = adoptPtr(m_stack.last()); |
|
63 m_stack.removeLast(); |
|
64 return selector.release(); |
|
65 } |
|
66 |
|
67 private: |
|
68 Vector<CSSSelector*, 16> m_stack; |
|
69 }; |
|
70 |
|
71 CSSSelector::~CSSSelector() |
|
72 { |
|
73 // We should avoid a recursive destructor call, which causes stack overflow |
|
74 // if CSS Selectors are deeply nested. |
|
75 |
|
76 // Early exit if we have already processed the children of this selector. |
|
77 if (m_hasRareData) { |
|
78 if (!m_data.m_rareData) |
|
79 return; |
|
80 } else if (!m_data.m_tagHistory) |
|
81 return; |
|
82 |
|
83 CSSSelectorBag selectorsToBeDeleted; |
|
84 if (m_hasRareData) { |
|
85 selectorsToBeDeleted.append(m_data.m_rareData->m_tagHistory.release()); |
|
86 selectorsToBeDeleted.append(m_data.m_rareData->m_simpleSelector.release()); |
|
87 delete m_data.m_rareData; |
|
88 } else |
|
89 selectorsToBeDeleted.append(adoptPtr(m_data.m_tagHistory)); |
|
90 |
|
91 // Traverse the tree of CSSSelector and delete each CSSSelector iteratively. |
|
92 while (!selectorsToBeDeleted.isEmpty()) { |
|
93 OwnPtr<CSSSelector> selector(selectorsToBeDeleted.takeAny()); |
|
94 ASSERT(selector); |
|
95 if (selector->m_hasRareData) { |
|
96 ASSERT(selector->m_data.m_rareData); |
|
97 selectorsToBeDeleted.append(selector->m_data.m_rareData->m_tagHistory.release()); |
|
98 selectorsToBeDeleted.append(selector->m_data.m_rareData->m_simpleSelector.release()); |
|
99 delete selector->m_data.m_rareData; |
|
100 // Clear the pointer so that a destructor of the selector, which is |
|
101 // about to be called, can know the children are already processed. |
|
102 selector->m_data.m_rareData = 0; |
|
103 } else { |
|
104 selectorsToBeDeleted.append(adoptPtr(selector->m_data.m_tagHistory)); |
|
105 // Clear the pointer for the same reason. |
|
106 selector->m_data.m_tagHistory = 0; |
|
107 } |
|
108 } |
|
109 } |
|
110 |
|
111 unsigned int CSSSelector::specificity() |
|
112 { |
|
113 if (m_isForPage) |
|
114 return specificityForPage(); |
|
115 |
|
116 // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function |
|
117 // isn't quite correct. |
|
118 int s = (m_tag.localName() == starAtom ? 0 : 1); |
|
119 switch (m_match) { |
|
120 case Id: |
|
121 s += 0x10000; |
|
122 break; |
|
123 case Exact: |
|
124 case Class: |
|
125 case Set: |
|
126 case List: |
|
127 case Hyphen: |
|
128 case PseudoClass: |
|
129 case PseudoElement: |
|
130 case Contain: |
|
131 case Begin: |
|
132 case End: |
|
133 s += 0x100; |
|
134 case None: |
|
135 break; |
|
136 } |
|
137 |
|
138 // FIXME: Avoid recursive calls to prevent possible stack overflow. |
|
139 if (CSSSelector* tagHistory = this->tagHistory()) |
|
140 s += tagHistory->specificity(); |
|
141 |
|
142 // make sure it doesn't overflow |
|
143 return s & 0xffffff; |
|
144 } |
|
145 |
|
146 unsigned CSSSelector::specificityForPage() |
|
147 { |
|
148 // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context |
|
149 unsigned s = (m_tag.localName() == starAtom ? 0 : 4); |
|
150 |
|
151 switch (pseudoType()) { |
|
152 case PseudoFirstPage: |
|
153 s += 2; |
|
154 break; |
|
155 case PseudoLeftPage: |
|
156 case PseudoRightPage: |
|
157 s += 1; |
|
158 break; |
|
159 case PseudoNotParsed: |
|
160 break; |
|
161 default: |
|
162 ASSERT_NOT_REACHED(); |
|
163 } |
|
164 return s; |
|
165 } |
|
166 |
|
167 PseudoId CSSSelector::pseudoId(PseudoType type) |
|
168 { |
|
169 switch (type) { |
|
170 case PseudoFirstLine: |
|
171 return FIRST_LINE; |
|
172 case PseudoFirstLetter: |
|
173 return FIRST_LETTER; |
|
174 case PseudoSelection: |
|
175 return SELECTION; |
|
176 case PseudoBefore: |
|
177 return BEFORE; |
|
178 case PseudoAfter: |
|
179 return AFTER; |
|
180 case PseudoFileUploadButton: |
|
181 return FILE_UPLOAD_BUTTON; |
|
182 case PseudoInputPlaceholder: |
|
183 return INPUT_PLACEHOLDER; |
|
184 #if ENABLE(INPUT_SPEECH) |
|
185 case PseudoInputSpeechButton: |
|
186 return INPUT_SPEECH_BUTTON; |
|
187 #endif |
|
188 case PseudoSliderThumb: |
|
189 return SLIDER_THUMB; |
|
190 case PseudoSearchCancelButton: |
|
191 return SEARCH_CANCEL_BUTTON; |
|
192 case PseudoSearchDecoration: |
|
193 return SEARCH_DECORATION; |
|
194 case PseudoSearchResultsDecoration: |
|
195 return SEARCH_RESULTS_DECORATION; |
|
196 case PseudoSearchResultsButton: |
|
197 return SEARCH_RESULTS_BUTTON; |
|
198 case PseudoMediaControlsPanel: |
|
199 return MEDIA_CONTROLS_PANEL; |
|
200 case PseudoMediaControlsMuteButton: |
|
201 return MEDIA_CONTROLS_MUTE_BUTTON; |
|
202 case PseudoMediaControlsPlayButton: |
|
203 return MEDIA_CONTROLS_PLAY_BUTTON; |
|
204 case PseudoMediaControlsTimelineContainer: |
|
205 return MEDIA_CONTROLS_TIMELINE_CONTAINER; |
|
206 case PseudoMediaControlsVolumeSliderContainer: |
|
207 return MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER; |
|
208 case PseudoMediaControlsCurrentTimeDisplay: |
|
209 return MEDIA_CONTROLS_CURRENT_TIME_DISPLAY; |
|
210 case PseudoMediaControlsTimeRemainingDisplay: |
|
211 return MEDIA_CONTROLS_TIME_REMAINING_DISPLAY; |
|
212 case PseudoMediaControlsTimeline: |
|
213 return MEDIA_CONTROLS_TIMELINE; |
|
214 case PseudoMediaControlsVolumeSlider: |
|
215 return MEDIA_CONTROLS_VOLUME_SLIDER; |
|
216 case PseudoMediaControlsVolumeSliderMuteButton: |
|
217 return MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON; |
|
218 case PseudoMediaControlsSeekBackButton: |
|
219 return MEDIA_CONTROLS_SEEK_BACK_BUTTON; |
|
220 case PseudoMediaControlsSeekForwardButton: |
|
221 return MEDIA_CONTROLS_SEEK_FORWARD_BUTTON; |
|
222 case PseudoMediaControlsRewindButton: |
|
223 return MEDIA_CONTROLS_REWIND_BUTTON; |
|
224 case PseudoMediaControlsReturnToRealtimeButton: |
|
225 return MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON; |
|
226 case PseudoMediaControlsToggleClosedCaptions: |
|
227 return MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON; |
|
228 case PseudoMediaControlsStatusDisplay: |
|
229 return MEDIA_CONTROLS_STATUS_DISPLAY; |
|
230 case PseudoMediaControlsFullscreenButton: |
|
231 return MEDIA_CONTROLS_FULLSCREEN_BUTTON; |
|
232 case PseudoScrollbar: |
|
233 return SCROLLBAR; |
|
234 case PseudoScrollbarButton: |
|
235 return SCROLLBAR_BUTTON; |
|
236 case PseudoScrollbarCorner: |
|
237 return SCROLLBAR_CORNER; |
|
238 case PseudoScrollbarThumb: |
|
239 return SCROLLBAR_THUMB; |
|
240 case PseudoScrollbarTrack: |
|
241 return SCROLLBAR_TRACK; |
|
242 case PseudoScrollbarTrackPiece: |
|
243 return SCROLLBAR_TRACK_PIECE; |
|
244 case PseudoResizer: |
|
245 return RESIZER; |
|
246 case PseudoInnerSpinButton: |
|
247 return INNER_SPIN_BUTTON; |
|
248 case PseudoOuterSpinButton: |
|
249 return OUTER_SPIN_BUTTON; |
|
250 case PseudoProgressBarValue: |
|
251 #if ENABLE(PROGRESS_TAG) |
|
252 return PROGRESS_BAR_VALUE; |
|
253 #else |
|
254 ASSERT_NOT_REACHED(); |
|
255 return NOPSEUDO; |
|
256 #endif |
|
257 |
|
258 #if ENABLE(METER_TAG) |
|
259 case PseudoMeterHorizontalBar: |
|
260 return METER_HORIZONTAL_BAR; |
|
261 case PseudoMeterHorizontalOptimum: |
|
262 return METER_HORIZONTAL_OPTIMUM; |
|
263 case PseudoMeterHorizontalSuboptimal: |
|
264 return METER_HORIZONTAL_SUBOPTIMAL; |
|
265 case PseudoMeterHorizontalEvenLessGood: |
|
266 return METER_HORIZONTAL_EVEN_LESS_GOOD; |
|
267 case PseudoMeterVerticalBar: |
|
268 return METER_VERTICAL_BAR; |
|
269 case PseudoMeterVerticalOptimum: |
|
270 return METER_VERTICAL_OPTIMUM; |
|
271 case PseudoMeterVerticalSuboptimal: |
|
272 return METER_VERTICAL_SUBOPTIMAL; |
|
273 case PseudoMeterVerticalEvenLessGood: |
|
274 return METER_VERTICAL_EVEN_LESS_GOOD; |
|
275 #else |
|
276 case PseudoMeterHorizontalBar: |
|
277 case PseudoMeterHorizontalOptimum: |
|
278 case PseudoMeterHorizontalSuboptimal: |
|
279 case PseudoMeterHorizontalEvenLessGood: |
|
280 case PseudoMeterVerticalBar: |
|
281 case PseudoMeterVerticalOptimum: |
|
282 case PseudoMeterVerticalSuboptimal: |
|
283 case PseudoMeterVerticalEvenLessGood: |
|
284 ASSERT_NOT_REACHED(); |
|
285 return NOPSEUDO; |
|
286 #endif |
|
287 |
|
288 case PseudoInputListButton: |
|
289 #if ENABLE(DATALIST) |
|
290 return INPUT_LIST_BUTTON; |
|
291 #endif |
|
292 case PseudoUnknown: |
|
293 case PseudoEmpty: |
|
294 case PseudoFirstChild: |
|
295 case PseudoFirstOfType: |
|
296 case PseudoLastChild: |
|
297 case PseudoLastOfType: |
|
298 case PseudoOnlyChild: |
|
299 case PseudoOnlyOfType: |
|
300 case PseudoNthChild: |
|
301 case PseudoNthOfType: |
|
302 case PseudoNthLastChild: |
|
303 case PseudoNthLastOfType: |
|
304 case PseudoLink: |
|
305 case PseudoVisited: |
|
306 case PseudoAnyLink: |
|
307 case PseudoAutofill: |
|
308 case PseudoHover: |
|
309 case PseudoDrag: |
|
310 case PseudoFocus: |
|
311 case PseudoActive: |
|
312 case PseudoChecked: |
|
313 case PseudoEnabled: |
|
314 case PseudoFullPageMedia: |
|
315 case PseudoDefault: |
|
316 case PseudoDisabled: |
|
317 case PseudoOptional: |
|
318 case PseudoRequired: |
|
319 case PseudoReadOnly: |
|
320 case PseudoReadWrite: |
|
321 case PseudoValid: |
|
322 case PseudoInvalid: |
|
323 case PseudoIndeterminate: |
|
324 case PseudoTarget: |
|
325 case PseudoLang: |
|
326 case PseudoNot: |
|
327 case PseudoRoot: |
|
328 case PseudoScrollbarBack: |
|
329 case PseudoScrollbarForward: |
|
330 case PseudoWindowInactive: |
|
331 case PseudoCornerPresent: |
|
332 case PseudoDecrement: |
|
333 case PseudoIncrement: |
|
334 case PseudoHorizontal: |
|
335 case PseudoVertical: |
|
336 case PseudoStart: |
|
337 case PseudoEnd: |
|
338 case PseudoDoubleButton: |
|
339 case PseudoSingleButton: |
|
340 case PseudoNoButton: |
|
341 case PseudoFirstPage: |
|
342 case PseudoLeftPage: |
|
343 case PseudoRightPage: |
|
344 return NOPSEUDO; |
|
345 case PseudoNotParsed: |
|
346 ASSERT_NOT_REACHED(); |
|
347 return NOPSEUDO; |
|
348 } |
|
349 |
|
350 ASSERT_NOT_REACHED(); |
|
351 return NOPSEUDO; |
|
352 } |
|
353 |
|
354 static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap() |
|
355 { |
|
356 DEFINE_STATIC_LOCAL(AtomicString, active, ("active")); |
|
357 DEFINE_STATIC_LOCAL(AtomicString, after, ("after")); |
|
358 DEFINE_STATIC_LOCAL(AtomicString, anyLink, ("-webkit-any-link")); |
|
359 DEFINE_STATIC_LOCAL(AtomicString, autofill, ("-webkit-autofill")); |
|
360 DEFINE_STATIC_LOCAL(AtomicString, before, ("before")); |
|
361 DEFINE_STATIC_LOCAL(AtomicString, checked, ("checked")); |
|
362 DEFINE_STATIC_LOCAL(AtomicString, fileUploadButton, ("-webkit-file-upload-button")); |
|
363 #if ENABLE(INPUT_SPEECH) |
|
364 DEFINE_STATIC_LOCAL(AtomicString, inputSpeechButton, ("-webkit-input-speech-button")); |
|
365 #endif |
|
366 DEFINE_STATIC_LOCAL(AtomicString, defaultString, ("default")); |
|
367 DEFINE_STATIC_LOCAL(AtomicString, disabled, ("disabled")); |
|
368 DEFINE_STATIC_LOCAL(AtomicString, readOnly, ("read-only")); |
|
369 DEFINE_STATIC_LOCAL(AtomicString, readWrite, ("read-write")); |
|
370 DEFINE_STATIC_LOCAL(AtomicString, valid, ("valid")); |
|
371 DEFINE_STATIC_LOCAL(AtomicString, invalid, ("invalid")); |
|
372 DEFINE_STATIC_LOCAL(AtomicString, drag, ("-webkit-drag")); |
|
373 DEFINE_STATIC_LOCAL(AtomicString, dragAlias, ("-khtml-drag")); // was documented with this name in Apple documentation, so keep an alia |
|
374 DEFINE_STATIC_LOCAL(AtomicString, empty, ("empty")); |
|
375 DEFINE_STATIC_LOCAL(AtomicString, enabled, ("enabled")); |
|
376 DEFINE_STATIC_LOCAL(AtomicString, firstChild, ("first-child")); |
|
377 DEFINE_STATIC_LOCAL(AtomicString, firstLetter, ("first-letter")); |
|
378 DEFINE_STATIC_LOCAL(AtomicString, firstLine, ("first-line")); |
|
379 DEFINE_STATIC_LOCAL(AtomicString, firstOfType, ("first-of-type")); |
|
380 DEFINE_STATIC_LOCAL(AtomicString, fullPageMedia, ("-webkit-full-page-media")); |
|
381 DEFINE_STATIC_LOCAL(AtomicString, nthChild, ("nth-child(")); |
|
382 DEFINE_STATIC_LOCAL(AtomicString, nthOfType, ("nth-of-type(")); |
|
383 DEFINE_STATIC_LOCAL(AtomicString, nthLastChild, ("nth-last-child(")); |
|
384 DEFINE_STATIC_LOCAL(AtomicString, nthLastOfType, ("nth-last-of-type(")); |
|
385 DEFINE_STATIC_LOCAL(AtomicString, focus, ("focus")); |
|
386 DEFINE_STATIC_LOCAL(AtomicString, hover, ("hover")); |
|
387 DEFINE_STATIC_LOCAL(AtomicString, indeterminate, ("indeterminate")); |
|
388 DEFINE_STATIC_LOCAL(AtomicString, innerSpinButton, ("-webkit-inner-spin-button")); |
|
389 #if ENABLE(DATALIST) |
|
390 DEFINE_STATIC_LOCAL(AtomicString, inputListButton, ("-webkit-input-list-button")); |
|
391 #endif |
|
392 DEFINE_STATIC_LOCAL(AtomicString, inputPlaceholder, ("-webkit-input-placeholder")); |
|
393 DEFINE_STATIC_LOCAL(AtomicString, lastChild, ("last-child")); |
|
394 DEFINE_STATIC_LOCAL(AtomicString, lastOfType, ("last-of-type")); |
|
395 DEFINE_STATIC_LOCAL(AtomicString, link, ("link")); |
|
396 DEFINE_STATIC_LOCAL(AtomicString, lang, ("lang(")); |
|
397 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsPanel, ("-webkit-media-controls-panel")); |
|
398 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsMuteButton, ("-webkit-media-controls-mute-button")); |
|
399 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsPlayButton, ("-webkit-media-controls-play-button")); |
|
400 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimeline, ("-webkit-media-controls-timeline")); |
|
401 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSlider, ("-webkit-media-controls-volume-slider")); |
|
402 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSliderMuteButton, ("-webkit-media-controls-volume-slider-mute-button")); |
|
403 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsSeekBackButton, ("-webkit-media-controls-seek-back-button")); |
|
404 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsSeekForwardButton, ("-webkit-media-controls-seek-forward-button")); |
|
405 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsRewindButton, ("-webkit-media-controls-rewind-button")); |
|
406 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsReturnToRealtimeButton, ("-webkit-media-controls-return-to-realtime-button")); |
|
407 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsToggleClosedCaptionsButton, ("-webkit-media-controls-toggle-closed-captions-button")); |
|
408 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsStatusDisplay, ("-webkit-media-controls-status-display")); |
|
409 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsFullscreenButton, ("-webkit-media-controls-fullscreen-button")); |
|
410 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimelineContainer, ("-webkit-media-controls-timeline-container")); |
|
411 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSliderContainer, ("-webkit-media-controls-volume-slider-container")); |
|
412 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsCurrentTimeDisplay, ("-webkit-media-controls-current-time-display")); |
|
413 DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimeRemainingDisplay, ("-webkit-media-controls-time-remaining-display")); |
|
414 DEFINE_STATIC_LOCAL(AtomicString, notStr, ("not(")); |
|
415 DEFINE_STATIC_LOCAL(AtomicString, onlyChild, ("only-child")); |
|
416 DEFINE_STATIC_LOCAL(AtomicString, onlyOfType, ("only-of-type")); |
|
417 DEFINE_STATIC_LOCAL(AtomicString, optional, ("optional")); |
|
418 DEFINE_STATIC_LOCAL(AtomicString, outerSpinButton, ("-webkit-outer-spin-button")); |
|
419 #if ENABLE(PROGRESS_TAG) |
|
420 DEFINE_STATIC_LOCAL(AtomicString, progressBarValue, ("-webkit-progress-bar-value")); |
|
421 #endif |
|
422 |
|
423 #if ENABLE(METER_TAG) |
|
424 DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalBar, ("-webkit-meter-horizontal-bar")); |
|
425 DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalOptimumValue, ("-webkit-meter-horizontal-optimum-value")); |
|
426 DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalSuboptimalValue, ("-webkit-meter-horizontal-suboptimal-value")); |
|
427 DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalEvenLessGoodValue, ("-webkit-meter-horizontal-even-less-good-value")); |
|
428 DEFINE_STATIC_LOCAL(AtomicString, meterVerticalBar, ("-webkit-meter-vertical-bar")); |
|
429 DEFINE_STATIC_LOCAL(AtomicString, meterVerticalOptimumValue, ("-webkit-meter-vertical-optimum-value")); |
|
430 DEFINE_STATIC_LOCAL(AtomicString, meterVerticalSuboptimalValue, ("-webkit-meter-vertical-suboptimal-value")); |
|
431 DEFINE_STATIC_LOCAL(AtomicString, meterVerticalEvenLessGoodValue, ("-webkit-meter-vertical-even-less-good-value")); |
|
432 #endif |
|
433 |
|
434 DEFINE_STATIC_LOCAL(AtomicString, required, ("required")); |
|
435 DEFINE_STATIC_LOCAL(AtomicString, resizer, ("-webkit-resizer")); |
|
436 DEFINE_STATIC_LOCAL(AtomicString, root, ("root")); |
|
437 DEFINE_STATIC_LOCAL(AtomicString, scrollbar, ("-webkit-scrollbar")); |
|
438 DEFINE_STATIC_LOCAL(AtomicString, scrollbarButton, ("-webkit-scrollbar-button")); |
|
439 DEFINE_STATIC_LOCAL(AtomicString, scrollbarCorner, ("-webkit-scrollbar-corner")); |
|
440 DEFINE_STATIC_LOCAL(AtomicString, scrollbarThumb, ("-webkit-scrollbar-thumb")); |
|
441 DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrack, ("-webkit-scrollbar-track")); |
|
442 DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrackPiece, ("-webkit-scrollbar-track-piece")); |
|
443 DEFINE_STATIC_LOCAL(AtomicString, searchCancelButton, ("-webkit-search-cancel-button")); |
|
444 DEFINE_STATIC_LOCAL(AtomicString, searchDecoration, ("-webkit-search-decoration")); |
|
445 DEFINE_STATIC_LOCAL(AtomicString, searchResultsDecoration, ("-webkit-search-results-decoration")); |
|
446 DEFINE_STATIC_LOCAL(AtomicString, searchResultsButton, ("-webkit-search-results-button")); |
|
447 DEFINE_STATIC_LOCAL(AtomicString, selection, ("selection")); |
|
448 DEFINE_STATIC_LOCAL(AtomicString, sliderThumb, ("-webkit-slider-thumb")); |
|
449 DEFINE_STATIC_LOCAL(AtomicString, target, ("target")); |
|
450 DEFINE_STATIC_LOCAL(AtomicString, visited, ("visited")); |
|
451 DEFINE_STATIC_LOCAL(AtomicString, windowInactive, ("window-inactive")); |
|
452 DEFINE_STATIC_LOCAL(AtomicString, decrement, ("decrement")); |
|
453 DEFINE_STATIC_LOCAL(AtomicString, increment, ("increment")); |
|
454 DEFINE_STATIC_LOCAL(AtomicString, start, ("start")); |
|
455 DEFINE_STATIC_LOCAL(AtomicString, end, ("end")); |
|
456 DEFINE_STATIC_LOCAL(AtomicString, horizontal, ("horizontal")); |
|
457 DEFINE_STATIC_LOCAL(AtomicString, vertical, ("vertical")); |
|
458 DEFINE_STATIC_LOCAL(AtomicString, doubleButton, ("double-button")); |
|
459 DEFINE_STATIC_LOCAL(AtomicString, singleButton, ("single-button")); |
|
460 DEFINE_STATIC_LOCAL(AtomicString, noButton, ("no-button")); |
|
461 DEFINE_STATIC_LOCAL(AtomicString, cornerPresent, ("corner-present")); |
|
462 // Paged Media pseudo-classes |
|
463 DEFINE_STATIC_LOCAL(AtomicString, firstPage, ("first")); |
|
464 DEFINE_STATIC_LOCAL(AtomicString, leftPage, ("left")); |
|
465 DEFINE_STATIC_LOCAL(AtomicString, rightPage, ("right")); |
|
466 |
|
467 static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0; |
|
468 if (!nameToPseudoType) { |
|
469 nameToPseudoType = new HashMap<AtomicStringImpl*, CSSSelector::PseudoType>; |
|
470 nameToPseudoType->set(active.impl(), CSSSelector::PseudoActive); |
|
471 nameToPseudoType->set(after.impl(), CSSSelector::PseudoAfter); |
|
472 nameToPseudoType->set(anyLink.impl(), CSSSelector::PseudoAnyLink); |
|
473 nameToPseudoType->set(autofill.impl(), CSSSelector::PseudoAutofill); |
|
474 nameToPseudoType->set(before.impl(), CSSSelector::PseudoBefore); |
|
475 nameToPseudoType->set(checked.impl(), CSSSelector::PseudoChecked); |
|
476 nameToPseudoType->set(fileUploadButton.impl(), CSSSelector::PseudoFileUploadButton); |
|
477 #if ENABLE(INPUT_SPEECH) |
|
478 nameToPseudoType->set(inputSpeechButton.impl(), CSSSelector::PseudoInputSpeechButton); |
|
479 #endif |
|
480 nameToPseudoType->set(defaultString.impl(), CSSSelector::PseudoDefault); |
|
481 nameToPseudoType->set(disabled.impl(), CSSSelector::PseudoDisabled); |
|
482 nameToPseudoType->set(readOnly.impl(), CSSSelector::PseudoReadOnly); |
|
483 nameToPseudoType->set(readWrite.impl(), CSSSelector::PseudoReadWrite); |
|
484 nameToPseudoType->set(valid.impl(), CSSSelector::PseudoValid); |
|
485 nameToPseudoType->set(invalid.impl(), CSSSelector::PseudoInvalid); |
|
486 nameToPseudoType->set(drag.impl(), CSSSelector::PseudoDrag); |
|
487 nameToPseudoType->set(dragAlias.impl(), CSSSelector::PseudoDrag); |
|
488 nameToPseudoType->set(enabled.impl(), CSSSelector::PseudoEnabled); |
|
489 nameToPseudoType->set(empty.impl(), CSSSelector::PseudoEmpty); |
|
490 nameToPseudoType->set(firstChild.impl(), CSSSelector::PseudoFirstChild); |
|
491 nameToPseudoType->set(fullPageMedia.impl(), CSSSelector::PseudoFullPageMedia); |
|
492 #if ENABLE(DATALIST) |
|
493 nameToPseudoType->set(inputListButton.impl(), CSSSelector::PseudoInputListButton); |
|
494 #endif |
|
495 nameToPseudoType->set(inputPlaceholder.impl(), CSSSelector::PseudoInputPlaceholder); |
|
496 nameToPseudoType->set(lastChild.impl(), CSSSelector::PseudoLastChild); |
|
497 nameToPseudoType->set(lastOfType.impl(), CSSSelector::PseudoLastOfType); |
|
498 nameToPseudoType->set(onlyChild.impl(), CSSSelector::PseudoOnlyChild); |
|
499 nameToPseudoType->set(onlyOfType.impl(), CSSSelector::PseudoOnlyOfType); |
|
500 nameToPseudoType->set(firstLetter.impl(), CSSSelector::PseudoFirstLetter); |
|
501 nameToPseudoType->set(firstLine.impl(), CSSSelector::PseudoFirstLine); |
|
502 nameToPseudoType->set(firstOfType.impl(), CSSSelector::PseudoFirstOfType); |
|
503 nameToPseudoType->set(focus.impl(), CSSSelector::PseudoFocus); |
|
504 nameToPseudoType->set(hover.impl(), CSSSelector::PseudoHover); |
|
505 nameToPseudoType->set(indeterminate.impl(), CSSSelector::PseudoIndeterminate); |
|
506 nameToPseudoType->set(innerSpinButton.impl(), CSSSelector::PseudoInnerSpinButton); |
|
507 nameToPseudoType->set(link.impl(), CSSSelector::PseudoLink); |
|
508 nameToPseudoType->set(lang.impl(), CSSSelector::PseudoLang); |
|
509 nameToPseudoType->set(mediaControlsPanel.impl(), CSSSelector::PseudoMediaControlsPanel); |
|
510 nameToPseudoType->set(mediaControlsMuteButton.impl(), CSSSelector::PseudoMediaControlsMuteButton); |
|
511 nameToPseudoType->set(mediaControlsPlayButton.impl(), CSSSelector::PseudoMediaControlsPlayButton); |
|
512 nameToPseudoType->set(mediaControlsCurrentTimeDisplay.impl(), CSSSelector::PseudoMediaControlsCurrentTimeDisplay); |
|
513 nameToPseudoType->set(mediaControlsTimeRemainingDisplay.impl(), CSSSelector::PseudoMediaControlsTimeRemainingDisplay); |
|
514 nameToPseudoType->set(mediaControlsTimeline.impl(), CSSSelector::PseudoMediaControlsTimeline); |
|
515 nameToPseudoType->set(mediaControlsVolumeSlider.impl(), CSSSelector::PseudoMediaControlsVolumeSlider); |
|
516 nameToPseudoType->set(mediaControlsVolumeSliderMuteButton.impl(), CSSSelector::PseudoMediaControlsVolumeSliderMuteButton); |
|
517 nameToPseudoType->set(mediaControlsSeekBackButton.impl(), CSSSelector::PseudoMediaControlsSeekBackButton); |
|
518 nameToPseudoType->set(mediaControlsSeekForwardButton.impl(), CSSSelector::PseudoMediaControlsSeekForwardButton); |
|
519 nameToPseudoType->set(mediaControlsRewindButton.impl(), CSSSelector::PseudoMediaControlsRewindButton); |
|
520 nameToPseudoType->set(mediaControlsReturnToRealtimeButton.impl(), CSSSelector::PseudoMediaControlsReturnToRealtimeButton); |
|
521 nameToPseudoType->set(mediaControlsToggleClosedCaptionsButton.impl(), CSSSelector::PseudoMediaControlsToggleClosedCaptions); |
|
522 nameToPseudoType->set(mediaControlsStatusDisplay.impl(), CSSSelector::PseudoMediaControlsStatusDisplay); |
|
523 nameToPseudoType->set(mediaControlsFullscreenButton.impl(), CSSSelector::PseudoMediaControlsFullscreenButton); |
|
524 nameToPseudoType->set(mediaControlsTimelineContainer.impl(), CSSSelector::PseudoMediaControlsTimelineContainer); |
|
525 nameToPseudoType->set(mediaControlsVolumeSliderContainer.impl(), CSSSelector::PseudoMediaControlsVolumeSliderContainer); |
|
526 nameToPseudoType->set(notStr.impl(), CSSSelector::PseudoNot); |
|
527 nameToPseudoType->set(nthChild.impl(), CSSSelector::PseudoNthChild); |
|
528 nameToPseudoType->set(nthOfType.impl(), CSSSelector::PseudoNthOfType); |
|
529 nameToPseudoType->set(nthLastChild.impl(), CSSSelector::PseudoNthLastChild); |
|
530 nameToPseudoType->set(nthLastOfType.impl(), CSSSelector::PseudoNthLastOfType); |
|
531 nameToPseudoType->set(outerSpinButton.impl(), CSSSelector::PseudoOuterSpinButton); |
|
532 #if ENABLE(PROGRESS_TAG) |
|
533 nameToPseudoType->set(progressBarValue.impl(), CSSSelector::PseudoProgressBarValue); |
|
534 #endif |
|
535 #if ENABLE(METER_TAG) |
|
536 nameToPseudoType->set(meterHorizontalBar.impl(), CSSSelector::PseudoMeterHorizontalBar); |
|
537 nameToPseudoType->set(meterHorizontalOptimumValue.impl(), CSSSelector::PseudoMeterHorizontalOptimum); |
|
538 nameToPseudoType->set(meterHorizontalSuboptimalValue.impl(), CSSSelector::PseudoMeterHorizontalSuboptimal); |
|
539 nameToPseudoType->set(meterHorizontalEvenLessGoodValue.impl(), CSSSelector::PseudoMeterHorizontalEvenLessGood); |
|
540 nameToPseudoType->set(meterVerticalBar.impl(), CSSSelector::PseudoMeterVerticalBar); |
|
541 nameToPseudoType->set(meterVerticalOptimumValue.impl(), CSSSelector::PseudoMeterVerticalOptimum); |
|
542 nameToPseudoType->set(meterVerticalSuboptimalValue.impl(), CSSSelector::PseudoMeterVerticalSuboptimal); |
|
543 nameToPseudoType->set(meterVerticalEvenLessGoodValue.impl(), CSSSelector::PseudoMeterVerticalEvenLessGood); |
|
544 #endif |
|
545 nameToPseudoType->set(root.impl(), CSSSelector::PseudoRoot); |
|
546 nameToPseudoType->set(windowInactive.impl(), CSSSelector::PseudoWindowInactive); |
|
547 nameToPseudoType->set(decrement.impl(), CSSSelector::PseudoDecrement); |
|
548 nameToPseudoType->set(increment.impl(), CSSSelector::PseudoIncrement); |
|
549 nameToPseudoType->set(start.impl(), CSSSelector::PseudoStart); |
|
550 nameToPseudoType->set(end.impl(), CSSSelector::PseudoEnd); |
|
551 nameToPseudoType->set(horizontal.impl(), CSSSelector::PseudoHorizontal); |
|
552 nameToPseudoType->set(vertical.impl(), CSSSelector::PseudoVertical); |
|
553 nameToPseudoType->set(doubleButton.impl(), CSSSelector::PseudoDoubleButton); |
|
554 nameToPseudoType->set(singleButton.impl(), CSSSelector::PseudoSingleButton); |
|
555 nameToPseudoType->set(noButton.impl(), CSSSelector::PseudoNoButton); |
|
556 nameToPseudoType->set(optional.impl(), CSSSelector::PseudoOptional); |
|
557 nameToPseudoType->set(required.impl(), CSSSelector::PseudoRequired); |
|
558 nameToPseudoType->set(resizer.impl(), CSSSelector::PseudoResizer); |
|
559 nameToPseudoType->set(scrollbar.impl(), CSSSelector::PseudoScrollbar); |
|
560 nameToPseudoType->set(scrollbarButton.impl(), CSSSelector::PseudoScrollbarButton); |
|
561 nameToPseudoType->set(scrollbarCorner.impl(), CSSSelector::PseudoScrollbarCorner); |
|
562 nameToPseudoType->set(scrollbarThumb.impl(), CSSSelector::PseudoScrollbarThumb); |
|
563 nameToPseudoType->set(scrollbarTrack.impl(), CSSSelector::PseudoScrollbarTrack); |
|
564 nameToPseudoType->set(scrollbarTrackPiece.impl(), CSSSelector::PseudoScrollbarTrackPiece); |
|
565 nameToPseudoType->set(cornerPresent.impl(), CSSSelector::PseudoCornerPresent); |
|
566 nameToPseudoType->set(searchCancelButton.impl(), CSSSelector::PseudoSearchCancelButton); |
|
567 nameToPseudoType->set(searchDecoration.impl(), CSSSelector::PseudoSearchDecoration); |
|
568 nameToPseudoType->set(searchResultsDecoration.impl(), CSSSelector::PseudoSearchResultsDecoration); |
|
569 nameToPseudoType->set(searchResultsButton.impl(), CSSSelector::PseudoSearchResultsButton); |
|
570 nameToPseudoType->set(selection.impl(), CSSSelector::PseudoSelection); |
|
571 nameToPseudoType->set(sliderThumb.impl(), CSSSelector::PseudoSliderThumb); |
|
572 nameToPseudoType->set(target.impl(), CSSSelector::PseudoTarget); |
|
573 nameToPseudoType->set(visited.impl(), CSSSelector::PseudoVisited); |
|
574 nameToPseudoType->set(firstPage.impl(), CSSSelector::PseudoFirstPage); |
|
575 nameToPseudoType->set(leftPage.impl(), CSSSelector::PseudoLeftPage); |
|
576 nameToPseudoType->set(rightPage.impl(), CSSSelector::PseudoRightPage); |
|
577 } |
|
578 return nameToPseudoType; |
|
579 } |
|
580 |
|
581 CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name) |
|
582 { |
|
583 if (name.isNull()) |
|
584 return PseudoUnknown; |
|
585 HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseudoTypeMap(); |
|
586 HashMap<AtomicStringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoType->find(name.impl()); |
|
587 return slot == nameToPseudoType->end() ? PseudoUnknown : slot->second; |
|
588 } |
|
589 |
|
590 void CSSSelector::extractPseudoType() const |
|
591 { |
|
592 if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass) |
|
593 return; |
|
594 |
|
595 m_pseudoType = parsePseudoType(m_value); |
|
596 |
|
597 bool element = false; // pseudo-element |
|
598 bool compat = false; // single colon compatbility mode |
|
599 bool isPagePseudoClass = false; // Page pseudo-class |
|
600 |
|
601 switch (m_pseudoType) { |
|
602 case PseudoAfter: |
|
603 case PseudoBefore: |
|
604 case PseudoFirstLetter: |
|
605 case PseudoFirstLine: |
|
606 compat = true; |
|
607 case PseudoFileUploadButton: |
|
608 case PseudoInputListButton: |
|
609 case PseudoInputPlaceholder: |
|
610 #if ENABLE(INPUT_SPEECH) |
|
611 case PseudoInputSpeechButton: |
|
612 #endif |
|
613 case PseudoInnerSpinButton: |
|
614 case PseudoMediaControlsPanel: |
|
615 case PseudoMediaControlsMuteButton: |
|
616 case PseudoMediaControlsPlayButton: |
|
617 case PseudoMediaControlsCurrentTimeDisplay: |
|
618 case PseudoMediaControlsTimeRemainingDisplay: |
|
619 case PseudoMediaControlsTimeline: |
|
620 case PseudoMediaControlsVolumeSlider: |
|
621 case PseudoMediaControlsVolumeSliderMuteButton: |
|
622 case PseudoMediaControlsSeekBackButton: |
|
623 case PseudoMediaControlsSeekForwardButton: |
|
624 case PseudoMediaControlsRewindButton: |
|
625 case PseudoMediaControlsReturnToRealtimeButton: |
|
626 case PseudoMediaControlsToggleClosedCaptions: |
|
627 case PseudoMediaControlsStatusDisplay: |
|
628 case PseudoMediaControlsFullscreenButton: |
|
629 case PseudoMediaControlsTimelineContainer: |
|
630 case PseudoMediaControlsVolumeSliderContainer: |
|
631 case PseudoMeterHorizontalBar: |
|
632 case PseudoMeterHorizontalOptimum: |
|
633 case PseudoMeterHorizontalSuboptimal: |
|
634 case PseudoMeterHorizontalEvenLessGood: |
|
635 case PseudoMeterVerticalBar: |
|
636 case PseudoMeterVerticalOptimum: |
|
637 case PseudoMeterVerticalSuboptimal: |
|
638 case PseudoMeterVerticalEvenLessGood: |
|
639 case PseudoOuterSpinButton: |
|
640 case PseudoProgressBarValue: |
|
641 case PseudoResizer: |
|
642 case PseudoScrollbar: |
|
643 case PseudoScrollbarCorner: |
|
644 case PseudoScrollbarButton: |
|
645 case PseudoScrollbarThumb: |
|
646 case PseudoScrollbarTrack: |
|
647 case PseudoScrollbarTrackPiece: |
|
648 case PseudoSearchCancelButton: |
|
649 case PseudoSearchDecoration: |
|
650 case PseudoSearchResultsDecoration: |
|
651 case PseudoSearchResultsButton: |
|
652 case PseudoSelection: |
|
653 case PseudoSliderThumb: |
|
654 element = true; |
|
655 break; |
|
656 case PseudoUnknown: |
|
657 case PseudoEmpty: |
|
658 case PseudoFirstChild: |
|
659 case PseudoFirstOfType: |
|
660 case PseudoLastChild: |
|
661 case PseudoLastOfType: |
|
662 case PseudoOnlyChild: |
|
663 case PseudoOnlyOfType: |
|
664 case PseudoNthChild: |
|
665 case PseudoNthOfType: |
|
666 case PseudoNthLastChild: |
|
667 case PseudoNthLastOfType: |
|
668 case PseudoLink: |
|
669 case PseudoVisited: |
|
670 case PseudoAnyLink: |
|
671 case PseudoAutofill: |
|
672 case PseudoHover: |
|
673 case PseudoDrag: |
|
674 case PseudoFocus: |
|
675 case PseudoActive: |
|
676 case PseudoChecked: |
|
677 case PseudoEnabled: |
|
678 case PseudoFullPageMedia: |
|
679 case PseudoDefault: |
|
680 case PseudoDisabled: |
|
681 case PseudoOptional: |
|
682 case PseudoRequired: |
|
683 case PseudoReadOnly: |
|
684 case PseudoReadWrite: |
|
685 case PseudoValid: |
|
686 case PseudoInvalid: |
|
687 case PseudoIndeterminate: |
|
688 case PseudoTarget: |
|
689 case PseudoLang: |
|
690 case PseudoNot: |
|
691 case PseudoRoot: |
|
692 case PseudoScrollbarBack: |
|
693 case PseudoScrollbarForward: |
|
694 case PseudoWindowInactive: |
|
695 case PseudoCornerPresent: |
|
696 case PseudoDecrement: |
|
697 case PseudoIncrement: |
|
698 case PseudoHorizontal: |
|
699 case PseudoVertical: |
|
700 case PseudoStart: |
|
701 case PseudoEnd: |
|
702 case PseudoDoubleButton: |
|
703 case PseudoSingleButton: |
|
704 case PseudoNoButton: |
|
705 case PseudoNotParsed: |
|
706 break; |
|
707 case PseudoFirstPage: |
|
708 case PseudoLeftPage: |
|
709 case PseudoRightPage: |
|
710 isPagePseudoClass = true; |
|
711 break; |
|
712 } |
|
713 |
|
714 bool matchPagePseudoClass = (m_match == PagePseudoClass); |
|
715 if (matchPagePseudoClass != isPagePseudoClass) |
|
716 m_pseudoType = PseudoUnknown; |
|
717 else if (m_match == PseudoClass && element) { |
|
718 if (!compat) |
|
719 m_pseudoType = PseudoUnknown; |
|
720 else |
|
721 m_match = PseudoElement; |
|
722 } else if (m_match == PseudoElement && !element) |
|
723 m_pseudoType = PseudoUnknown; |
|
724 } |
|
725 |
|
726 bool CSSSelector::operator==(const CSSSelector& other) |
|
727 { |
|
728 const CSSSelector* sel1 = this; |
|
729 const CSSSelector* sel2 = &other; |
|
730 |
|
731 while (sel1 && sel2) { |
|
732 if (sel1->m_tag != sel2->m_tag || sel1->attribute() != sel2->attribute() || |
|
733 sel1->relation() != sel2->relation() || sel1->m_match != sel2->m_match || |
|
734 sel1->m_value != sel2->m_value || |
|
735 sel1->pseudoType() != sel2->pseudoType() || |
|
736 sel1->argument() != sel2->argument()) |
|
737 return false; |
|
738 sel1 = sel1->tagHistory(); |
|
739 sel2 = sel2->tagHistory(); |
|
740 } |
|
741 |
|
742 if (sel1 || sel2) |
|
743 return false; |
|
744 |
|
745 return true; |
|
746 } |
|
747 |
|
748 String CSSSelector::selectorText() const |
|
749 { |
|
750 String str = ""; |
|
751 |
|
752 const AtomicString& prefix = m_tag.prefix(); |
|
753 const AtomicString& localName = m_tag.localName(); |
|
754 if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) { |
|
755 if (prefix.isNull()) |
|
756 str = localName; |
|
757 else |
|
758 str = prefix + "|" + localName; |
|
759 } |
|
760 |
|
761 const CSSSelector* cs = this; |
|
762 while (true) { |
|
763 if (cs->m_match == CSSSelector::Id) { |
|
764 str += "#"; |
|
765 serializeIdentifier(cs->m_value, str); |
|
766 } else if (cs->m_match == CSSSelector::Class) { |
|
767 str += "."; |
|
768 serializeIdentifier(cs->m_value, str); |
|
769 } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) { |
|
770 str += ":"; |
|
771 str += cs->m_value; |
|
772 if (cs->pseudoType() == PseudoNot) { |
|
773 if (CSSSelector* subSel = cs->simpleSelector()) |
|
774 str += subSel->selectorText(); |
|
775 str += ")"; |
|
776 } else if (cs->pseudoType() == PseudoLang |
|
777 || cs->pseudoType() == PseudoNthChild |
|
778 || cs->pseudoType() == PseudoNthLastChild |
|
779 || cs->pseudoType() == PseudoNthOfType |
|
780 || cs->pseudoType() == PseudoNthLastOfType) { |
|
781 str += cs->argument(); |
|
782 str += ")"; |
|
783 } |
|
784 } else if (cs->m_match == CSSSelector::PseudoElement) { |
|
785 str += "::"; |
|
786 str += cs->m_value; |
|
787 } else if (cs->hasAttribute()) { |
|
788 str += "["; |
|
789 const AtomicString& prefix = cs->attribute().prefix(); |
|
790 if (!prefix.isNull()) |
|
791 str += prefix + "|"; |
|
792 str += cs->attribute().localName(); |
|
793 switch (cs->m_match) { |
|
794 case CSSSelector::Exact: |
|
795 str += "="; |
|
796 break; |
|
797 case CSSSelector::Set: |
|
798 // set has no operator or value, just the attrName |
|
799 str += "]"; |
|
800 break; |
|
801 case CSSSelector::List: |
|
802 str += "~="; |
|
803 break; |
|
804 case CSSSelector::Hyphen: |
|
805 str += "|="; |
|
806 break; |
|
807 case CSSSelector::Begin: |
|
808 str += "^="; |
|
809 break; |
|
810 case CSSSelector::End: |
|
811 str += "$="; |
|
812 break; |
|
813 case CSSSelector::Contain: |
|
814 str += "*="; |
|
815 break; |
|
816 default: |
|
817 break; |
|
818 } |
|
819 if (cs->m_match != CSSSelector::Set) { |
|
820 serializeString(cs->m_value, str); |
|
821 str += "]"; |
|
822 } |
|
823 } |
|
824 if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory()) |
|
825 break; |
|
826 cs = cs->tagHistory(); |
|
827 } |
|
828 |
|
829 if (CSSSelector* tagHistory = cs->tagHistory()) { |
|
830 String tagHistoryText = tagHistory->selectorText(); |
|
831 if (cs->relation() == CSSSelector::DirectAdjacent) |
|
832 str = tagHistoryText + " + " + str; |
|
833 else if (cs->relation() == CSSSelector::IndirectAdjacent) |
|
834 str = tagHistoryText + " ~ " + str; |
|
835 else if (cs->relation() == CSSSelector::Child) |
|
836 str = tagHistoryText + " > " + str; |
|
837 else |
|
838 // Descendant |
|
839 str = tagHistoryText + " " + str; |
|
840 } |
|
841 |
|
842 return str; |
|
843 } |
|
844 |
|
845 void CSSSelector::setTagHistory(CSSSelector* tagHistory) |
|
846 { |
|
847 if (m_hasRareData) |
|
848 m_data.m_rareData->m_tagHistory.set(tagHistory); |
|
849 else |
|
850 m_data.m_tagHistory = tagHistory; |
|
851 } |
|
852 |
|
853 const QualifiedName& CSSSelector::attribute() const |
|
854 { |
|
855 switch (m_match) { |
|
856 case Id: |
|
857 return idAttr; |
|
858 case Class: |
|
859 return classAttr; |
|
860 default: |
|
861 return m_hasRareData ? m_data.m_rareData->m_attribute : anyQName(); |
|
862 } |
|
863 } |
|
864 |
|
865 void CSSSelector::setAttribute(const QualifiedName& value) |
|
866 { |
|
867 createRareData(); |
|
868 m_data.m_rareData->m_attribute = value; |
|
869 } |
|
870 |
|
871 void CSSSelector::setArgument(const AtomicString& value) |
|
872 { |
|
873 createRareData(); |
|
874 m_data.m_rareData->m_argument = value; |
|
875 } |
|
876 |
|
877 void CSSSelector::setSimpleSelector(CSSSelector* value) |
|
878 { |
|
879 createRareData(); |
|
880 m_data.m_rareData->m_simpleSelector.set(value); |
|
881 } |
|
882 |
|
883 bool CSSSelector::parseNth() |
|
884 { |
|
885 if (!m_hasRareData) |
|
886 return false; |
|
887 if (m_parsedNth) |
|
888 return true; |
|
889 m_parsedNth = m_data.m_rareData->parseNth(); |
|
890 return m_parsedNth; |
|
891 } |
|
892 |
|
893 bool CSSSelector::matchNth(int count) |
|
894 { |
|
895 ASSERT(m_hasRareData); |
|
896 return m_data.m_rareData->matchNth(count); |
|
897 } |
|
898 |
|
899 bool CSSSelector::isSimple() const |
|
900 { |
|
901 if (simpleSelector() || tagHistory() || matchesPseudoElement()) |
|
902 return false; |
|
903 |
|
904 int numConditions = 0; |
|
905 |
|
906 // hasTag() cannot be be used here because namespace may not be nullAtom. |
|
907 // Example: |
|
908 // @namespace "http://www.w3.org/2000/svg"; |
|
909 // svg:not(:root) { ... |
|
910 if (m_tag != starAtom) |
|
911 numConditions++; |
|
912 |
|
913 if (m_match == Id || m_match == Class || m_match == PseudoClass) |
|
914 numConditions++; |
|
915 |
|
916 if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName()) |
|
917 numConditions++; |
|
918 |
|
919 // numConditions is 0 for a universal selector. |
|
920 // numConditions is 1 for other simple selectors. |
|
921 return numConditions <= 1; |
|
922 } |
|
923 |
|
924 // a helper function for parsing nth-arguments |
|
925 bool CSSSelector::RareData::parseNth() |
|
926 { |
|
927 String argument = m_argument.lower(); |
|
928 |
|
929 if (argument.isEmpty()) |
|
930 return false; |
|
931 |
|
932 m_a = 0; |
|
933 m_b = 0; |
|
934 if (argument == "odd") { |
|
935 m_a = 2; |
|
936 m_b = 1; |
|
937 } else if (argument == "even") { |
|
938 m_a = 2; |
|
939 m_b = 0; |
|
940 } else { |
|
941 int n = argument.find('n'); |
|
942 if (n != -1) { |
|
943 if (argument[0] == '-') { |
|
944 if (n == 1) |
|
945 m_a = -1; // -n == -1n |
|
946 else |
|
947 m_a = argument.substring(0, n).toInt(); |
|
948 } else if (!n) |
|
949 m_a = 1; // n == 1n |
|
950 else |
|
951 m_a = argument.substring(0, n).toInt(); |
|
952 |
|
953 int p = argument.find('+', n); |
|
954 if (p != -1) |
|
955 m_b = argument.substring(p + 1, argument.length() - p - 1).toInt(); |
|
956 else { |
|
957 p = argument.find('-', n); |
|
958 if (p != -1) |
|
959 m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt(); |
|
960 } |
|
961 } else |
|
962 m_b = argument.toInt(); |
|
963 } |
|
964 return true; |
|
965 } |
|
966 |
|
967 // a helper function for checking nth-arguments |
|
968 bool CSSSelector::RareData::matchNth(int count) |
|
969 { |
|
970 if (!m_a) |
|
971 return count == m_b; |
|
972 else if (m_a > 0) { |
|
973 if (count < m_b) |
|
974 return false; |
|
975 return (count - m_b) % m_a == 0; |
|
976 } else { |
|
977 if (count > m_b) |
|
978 return false; |
|
979 return (m_b - count) % (-m_a) == 0; |
|
980 } |
|
981 } |
|
982 |
|
983 } // namespace WebCore |