2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
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.
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.
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.
27 #include "CSSStyleSelector.h"
29 #include "Attribute.h"
30 #include "CSSBorderImageValue.h"
31 #include "CSSCursorImageValue.h"
32 #include "CSSFontFaceRule.h"
33 #include "CSSImportRule.h"
34 #include "CSSMediaRule.h"
35 #include "CSSPageRule.h"
36 #include "CSSParser.h"
37 #include "CSSPrimitiveValueMappings.h"
38 #include "CSSPropertyNames.h"
39 #include "CSSReflectValue.h"
40 #include "CSSRuleList.h"
41 #include "CSSSelector.h"
42 #include "CSSSelectorList.h"
43 #include "CSSStyleRule.h"
44 #include "CSSStyleSheet.h"
45 #include "CSSTimingFunctionValue.h"
46 #include "CSSValueList.h"
47 #include "CachedImage.h"
49 #include "FocusController.h"
50 #include "FontFamilyValue.h"
51 #include "FontValue.h"
53 #include "FrameView.h"
54 #include "HTMLDocument.h"
55 #include "HTMLElement.h"
56 #include "HTMLInputElement.h"
57 #include "HTMLNames.h"
58 #include "HTMLTextAreaElement.h"
59 #include "KeyframeList.h"
61 #include "Matrix3DTransformOperation.h"
62 #include "MatrixTransformOperation.h"
63 #include "MediaList.h"
64 #include "MediaQueryEvaluator.h"
65 #include "NodeRenderStyle.h"
67 #include "PageGroup.h"
69 #include "PerspectiveTransformOperation.h"
71 #include "RenderScrollbar.h"
72 #include "RenderScrollbarTheme.h"
73 #include "RenderStyleConstants.h"
74 #include "RenderTheme.h"
75 #include "RotateTransformOperation.h"
76 #include "ScaleTransformOperation.h"
77 #include "SelectionController.h"
79 #include "ShadowValue.h"
80 #include "SkewTransformOperation.h"
81 #include "StyleCachedImage.h"
82 #include "StylePendingImage.h"
83 #include "StyleGeneratedImage.h"
84 #include "StyleSheetList.h"
86 #include "TransformationMatrix.h"
87 #include "TranslateTransformOperation.h"
88 #include "UserAgentStyleSheets.h"
89 #include "WebKitCSSKeyframeRule.h"
90 #include "WebKitCSSKeyframesRule.h"
91 #include "WebKitCSSTransformValue.h"
93 #include <wtf/StdLibExtras.h>
94 #include <wtf/Vector.h>
96 #if USE(PLATFORM_STRATEGIES)
97 #include "PlatformStrategies.h"
98 #include "VisitedLinkStrategy.h"
101 #if ENABLE(DASHBOARD_SUPPORT)
102 #include "DashboardRegion.h"
106 #include "XLinkNames.h"
107 #include "SVGNames.h"
111 #include "WMLNames.h"
115 #include <qwebhistoryinterface.h>
122 using namespace HTMLNames;
124 #define HANDLE_INHERIT(prop, Prop) \
126 m_style->set##Prop(m_parentStyle->prop()); \
130 #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
131 HANDLE_INHERIT(prop, Prop) \
133 m_style->set##Prop(RenderStyle::initial##Prop()); \
137 #define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \
138 HANDLE_INHERIT(prop, Prop) \
140 m_style->set##Prop(RenderStyle::initial##Value());\
144 #define HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(prop, Prop) \
145 HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
146 if (primitiveValue) \
147 m_style->set##Prop(*primitiveValue);
149 #define HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(prop, Prop, Value) \
150 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \
151 if (primitiveValue) \
152 m_style->set##Prop(*primitiveValue);
154 #define HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(layerType, LayerType, prop, Prop) \
156 FillLayer* currChild = m_style->access##LayerType##Layers(); \
157 FillLayer* prevChild = 0; \
158 const FillLayer* currParent = m_parentStyle->layerType##Layers(); \
159 while (currParent && currParent->is##Prop##Set()) { \
161 /* Need to make a new layer.*/ \
162 currChild = new FillLayer(LayerType##FillLayer); \
163 prevChild->setNext(currChild); \
165 currChild->set##Prop(currParent->prop()); \
166 prevChild = currChild; \
167 currChild = prevChild->next(); \
168 currParent = currParent->next(); \
171 while (currChild) { \
172 /* Reset any remaining layers to not have the property set. */ \
173 currChild->clear##Prop(); \
174 currChild = currChild->next(); \
176 } else if (isInitial) { \
177 FillLayer* currChild = m_style->access##LayerType##Layers(); \
178 currChild->set##Prop(FillLayer::initialFill##Prop(LayerType##FillLayer)); \
179 for (currChild = currChild->next(); currChild; currChild = currChild->next()) \
180 currChild->clear##Prop(); \
183 #define HANDLE_FILL_LAYER_VALUE(layerType, LayerType, prop, Prop, value) { \
184 HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(layerType, LayerType, prop, Prop) \
185 if (isInherit || isInitial) \
187 FillLayer* currChild = m_style->access##LayerType##Layers(); \
188 FillLayer* prevChild = 0; \
189 if (value->isValueList()) { \
190 /* Walk each value and put it into a layer, creating new layers as needed. */ \
191 CSSValueList* valueList = static_cast<CSSValueList*>(value); \
192 for (unsigned int i = 0; i < valueList->length(); i++) { \
194 /* Need to make a new layer to hold this value */ \
195 currChild = new FillLayer(LayerType##FillLayer); \
196 prevChild->setNext(currChild); \
198 mapFill##Prop(property, currChild, valueList->itemWithoutBoundsCheck(i)); \
199 prevChild = currChild; \
200 currChild = currChild->next(); \
203 mapFill##Prop(property, currChild, value); \
204 currChild = currChild->next(); \
206 while (currChild) { \
207 /* Reset all remaining layers to not have the property set. */ \
208 currChild->clear##Prop(); \
209 currChild = currChild->next(); \
212 #define HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \
213 HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(background, Background, prop, Prop)
215 #define HANDLE_BACKGROUND_VALUE(prop, Prop, value) \
216 HANDLE_FILL_LAYER_VALUE(background, Background, prop, Prop, value)
218 #define HANDLE_MASK_INHERIT_AND_INITIAL(prop, Prop) \
219 HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(mask, Mask, prop, Prop)
221 #define HANDLE_MASK_VALUE(prop, Prop, value) \
222 HANDLE_FILL_LAYER_VALUE(mask, Mask, prop, Prop, value)
224 #define HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \
226 AnimationList* list = m_style->accessAnimations(); \
227 const AnimationList* parentList = m_parentStyle->animations(); \
228 size_t i = 0, parentSize = parentList ? parentList->size() : 0; \
229 for ( ; i < parentSize && parentList->animation(i)->is##Prop##Set(); ++i) { \
230 if (list->size() <= i) \
231 list->append(Animation::create()); \
232 list->animation(i)->set##Prop(parentList->animation(i)->prop()); \
235 /* Reset any remaining animations to not have the property set. */ \
236 for ( ; i < list->size(); ++i) \
237 list->animation(i)->clear##Prop(); \
238 } else if (isInitial) { \
239 AnimationList* list = m_style->accessAnimations(); \
240 if (list->isEmpty()) \
241 list->append(Animation::create()); \
242 list->animation(0)->set##Prop(Animation::initialAnimation##Prop()); \
243 for (size_t i = 1; i < list->size(); ++i) \
244 list->animation(0)->clear##Prop(); \
247 #define HANDLE_ANIMATION_VALUE(prop, Prop, value) { \
248 HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \
249 if (isInherit || isInitial) \
251 AnimationList* list = m_style->accessAnimations(); \
252 size_t childIndex = 0; \
253 if (value->isValueList()) { \
254 /* Walk each value and put it into an animation, creating new animations as needed. */ \
255 CSSValueList* valueList = static_cast<CSSValueList*>(value); \
256 for (unsigned int i = 0; i < valueList->length(); i++) { \
257 if (childIndex <= list->size()) \
258 list->append(Animation::create()); \
259 mapAnimation##Prop(list->animation(childIndex), valueList->itemWithoutBoundsCheck(i)); \
263 if (list->isEmpty()) \
264 list->append(Animation::create()); \
265 mapAnimation##Prop(list->animation(childIndex), value); \
268 for ( ; childIndex < list->size(); ++childIndex) { \
269 /* Reset all remaining animations to not have the property set. */ \
270 list->animation(childIndex)->clear##Prop(); \
274 #define HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \
276 AnimationList* list = m_style->accessTransitions(); \
277 const AnimationList* parentList = m_parentStyle->transitions(); \
278 size_t i = 0, parentSize = parentList ? parentList->size() : 0; \
279 for ( ; i < parentSize && parentList->animation(i)->is##Prop##Set(); ++i) { \
280 if (list->size() <= i) \
281 list->append(Animation::create()); \
282 list->animation(i)->set##Prop(parentList->animation(i)->prop()); \
285 /* Reset any remaining transitions to not have the property set. */ \
286 for ( ; i < list->size(); ++i) \
287 list->animation(i)->clear##Prop(); \
288 } else if (isInitial) { \
289 AnimationList* list = m_style->accessTransitions(); \
290 if (list->isEmpty()) \
291 list->append(Animation::create()); \
292 list->animation(0)->set##Prop(Animation::initialAnimation##Prop()); \
293 for (size_t i = 1; i < list->size(); ++i) \
294 list->animation(0)->clear##Prop(); \
297 #define HANDLE_TRANSITION_VALUE(prop, Prop, value) { \
298 HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \
299 if (isInherit || isInitial) \
301 AnimationList* list = m_style->accessTransitions(); \
302 size_t childIndex = 0; \
303 if (value->isValueList()) { \
304 /* Walk each value and put it into a transition, creating new animations as needed. */ \
305 CSSValueList* valueList = static_cast<CSSValueList*>(value); \
306 for (unsigned int i = 0; i < valueList->length(); i++) { \
307 if (childIndex <= list->size()) \
308 list->append(Animation::create()); \
309 mapAnimation##Prop(list->animation(childIndex), valueList->itemWithoutBoundsCheck(i)); \
313 if (list->isEmpty()) \
314 list->append(Animation::create()); \
315 mapAnimation##Prop(list->animation(childIndex), value); \
318 for ( ; childIndex < list->size(); ++childIndex) { \
319 /* Reset all remaining transitions to not have the property set. */ \
320 list->animation(childIndex)->clear##Prop(); \
324 #define HANDLE_INHERIT_COND(propID, prop, Prop) \
325 if (id == propID) { \
326 m_style->set##Prop(m_parentStyle->prop()); \
330 #define HANDLE_INHERIT_COND_WITH_BACKUP(propID, prop, propAlt, Prop) \
331 if (id == propID) { \
332 if (m_parentStyle->prop().isValid()) \
333 m_style->set##Prop(m_parentStyle->prop()); \
335 m_style->set##Prop(m_parentStyle->propAlt()); \
339 #define HANDLE_INITIAL_COND(propID, Prop) \
340 if (id == propID) { \
341 m_style->set##Prop(RenderStyle::initial##Prop()); \
345 #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \
346 if (id == propID) { \
347 m_style->set##Prop(RenderStyle::initial##Value()); \
351 class CSSRuleData : public Noncopyable {
353 CSSRuleData(unsigned pos, CSSStyleRule* r, CSSSelector* sel, CSSRuleData* prev = 0)
367 unsigned position() { return m_position; }
368 CSSStyleRule* rule() { return m_rule; }
369 CSSSelector* selector() { return m_selector; }
370 CSSRuleData* next() { return m_next; }
374 CSSStyleRule* m_rule;
375 CSSSelector* m_selector;
379 class CSSRuleDataList : public Noncopyable {
381 CSSRuleDataList(unsigned pos, CSSStyleRule* rule, CSSSelector* sel)
382 : m_first(new CSSRuleData(pos, rule, sel))
399 CSSRuleData* first() { return m_first; }
400 CSSRuleData* last() { return m_last; }
402 void append(unsigned pos, CSSStyleRule* rule, CSSSelector* sel) { m_last = new CSSRuleData(pos, rule, sel, m_last); }
405 CSSRuleData* m_first;
409 class CSSRuleSet : public Noncopyable {
414 typedef HashMap<AtomicStringImpl*, CSSRuleDataList*> AtomRuleMap;
416 void addRulesFromSheet(CSSStyleSheet*, const MediaQueryEvaluator&, CSSStyleSelector* = 0);
418 void addStyleRule(CSSStyleRule* item);
419 void addRule(CSSStyleRule* rule, CSSSelector* sel);
420 void addPageRule(CSSStyleRule* rule, CSSSelector* sel);
421 void addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
422 CSSStyleRule* rule, CSSSelector* sel);
424 CSSRuleDataList* getIDRules(AtomicStringImpl* key) { return m_idRules.get(key); }
425 CSSRuleDataList* getClassRules(AtomicStringImpl* key) { return m_classRules.get(key); }
426 CSSRuleDataList* getTagRules(AtomicStringImpl* key) { return m_tagRules.get(key); }
427 CSSRuleDataList* getPseudoRules(AtomicStringImpl* key) { return m_pseudoRules.get(key); }
428 CSSRuleDataList* getUniversalRules() { return m_universalRules.get(); }
429 CSSRuleDataList* getPageRules() { return m_pageRules.get(); }
432 AtomRuleMap m_idRules;
433 AtomRuleMap m_classRules;
434 AtomRuleMap m_tagRules;
435 AtomRuleMap m_pseudoRules;
436 OwnPtr<CSSRuleDataList> m_universalRules;
437 OwnPtr<CSSRuleDataList> m_pageRules;
438 unsigned m_ruleCount;
439 unsigned m_pageRuleCount;
442 static CSSRuleSet* defaultStyle;
443 static CSSRuleSet* defaultQuirksStyle;
444 static CSSRuleSet* defaultPrintStyle;
445 static CSSRuleSet* defaultViewSourceStyle;
446 static CSSStyleSheet* simpleDefaultStyleSheet;
448 RenderStyle* CSSStyleSelector::s_styleNotYetAvailable;
450 static void loadFullDefaultStyle();
451 #if ENABLE(FULLSCREEN_API)
452 static void loadFullScreenRulesIfNeeded(Document*);
454 static void loadSimpleDefaultStyle();
455 // FIXME: It would be nice to use some mechanism that guarantees this is in sync with the real UA stylesheet.
456 static const char* simpleUserAgentStyleSheet = "html,body,div{display:block}body{margin:8px}div:focus,span:focus{outline:auto 5px -webkit-focus-ring-color}a:-webkit-any-link{color:-webkit-link;text-decoration:underline}a:-webkit-any-link:active{color:-webkit-activelink}";
458 static bool elementCanUseSimpleDefaultStyle(Element* e)
460 return e->hasTagName(htmlTag) || e->hasTagName(bodyTag) || e->hasTagName(divTag) || e->hasTagName(spanTag) || e->hasTagName(brTag) || e->hasTagName(aTag);
463 static const MediaQueryEvaluator& screenEval()
465 DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticScreenEval, ("screen"));
466 return staticScreenEval;
469 static const MediaQueryEvaluator& printEval()
471 DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticPrintEval, ("print"));
472 return staticPrintEval;
475 CSSStyleSelector::CSSStyleSelector(Document* document, StyleSheetList* styleSheets, CSSStyleSheet* mappedElementSheet,
476 CSSStyleSheet* pageUserSheet, const Vector<RefPtr<CSSStyleSheet> >* pageGroupUserSheets,
477 bool strictParsing, bool matchAuthorAndUserStyles)
478 : m_backgroundData(BackgroundFillLayer)
479 , m_checker(document, strictParsing)
482 , m_elementLinkState(NotInsideLink)
483 , m_fontSelector(CSSFontSelector::create(document))
485 m_matchAuthorAndUserStyles = matchAuthorAndUserStyles;
487 Element* root = document->documentElement();
490 if (!root || elementCanUseSimpleDefaultStyle(root))
491 loadSimpleDefaultStyle();
493 loadFullDefaultStyle();
494 #if ENABLE(FULLSCREEN_API)
495 loadFullScreenRulesIfNeeded(document);
500 // construct document root element default style. this is needed
501 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
502 // This is here instead of constructor, because when constructor is run,
503 // document doesn't have documentElement
504 // NOTE: this assumes that element that gets passed to styleForElement -call
505 // is always from the document that owns the style selector
506 FrameView* view = document->view();
508 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType()));
510 m_medium = adoptPtr(new MediaQueryEvaluator("all"));
513 m_rootDefaultStyle = styleForElement(root, 0, false, true); // don't ref, because the RenderStyle is allocated from global heap
515 if (m_rootDefaultStyle && view)
516 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle.get()));
518 m_authorStyle = adoptPtr(new CSSRuleSet);
520 // FIXME: This sucks! The user sheet is reparsed every time!
521 OwnPtr<CSSRuleSet> tempUserStyle = adoptPtr(new CSSRuleSet);
523 tempUserStyle->addRulesFromSheet(pageUserSheet, *m_medium, this);
524 if (pageGroupUserSheets) {
525 unsigned length = pageGroupUserSheets->size();
526 for (unsigned i = 0; i < length; i++) {
527 if (pageGroupUserSheets->at(i)->isUserStyleSheet())
528 tempUserStyle->addRulesFromSheet(pageGroupUserSheets->at(i).get(), *m_medium, this);
530 m_authorStyle->addRulesFromSheet(pageGroupUserSheets->at(i).get(), *m_medium, this);
534 if (tempUserStyle->m_ruleCount > 0 || tempUserStyle->m_pageRuleCount > 0)
535 m_userStyle = tempUserStyle.release();
537 // Add rules from elements like SVG's <font-face>
538 if (mappedElementSheet)
539 m_authorStyle->addRulesFromSheet(mappedElementSheet, *m_medium, this);
541 // add stylesheets from document
542 unsigned length = styleSheets->length();
543 for (unsigned i = 0; i < length; i++) {
544 StyleSheet* sheet = styleSheets->item(i);
545 if (sheet->isCSSStyleSheet() && !sheet->disabled())
546 m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(sheet), *m_medium, this);
549 if (document->renderer() && document->renderer()->style())
550 document->renderer()->style()->font().update(fontSelector());
553 // This is a simplified style setting function for keyframe styles
554 void CSSStyleSelector::addKeyframeStyle(PassRefPtr<WebKitCSSKeyframesRule> rule)
556 AtomicString s(rule->name());
557 m_keyframesRuleMap.add(s.impl(), rule);
560 CSSStyleSelector::~CSSStyleSelector()
562 m_fontSelector->clearDocument();
563 deleteAllValues(m_viewportDependentMediaQueryResults);
566 static CSSStyleSheet* parseUASheet(const String& str)
568 CSSStyleSheet* sheet = CSSStyleSheet::create().releaseRef(); // leak the sheet on purpose
569 sheet->parseString(str);
573 static CSSStyleSheet* parseUASheet(const char* characters, unsigned size)
575 return parseUASheet(String(characters, size));
578 static void loadFullDefaultStyle()
580 if (simpleDefaultStyleSheet) {
581 ASSERT(defaultStyle);
583 simpleDefaultStyleSheet->deref();
584 defaultStyle = new CSSRuleSet;
585 simpleDefaultStyleSheet = 0;
587 ASSERT(!defaultStyle);
588 defaultStyle = new CSSRuleSet;
589 defaultPrintStyle = new CSSRuleSet;
590 defaultQuirksStyle = new CSSRuleSet;
593 // Strict-mode rules.
594 String defaultRules = String(htmlUserAgentStyleSheet, sizeof(htmlUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraDefaultStyleSheet();
595 CSSStyleSheet* defaultSheet = parseUASheet(defaultRules);
596 defaultStyle->addRulesFromSheet(defaultSheet, screenEval());
597 defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval());
599 // Quirks-mode rules.
600 String quirksRules = String(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraQuirksStyleSheet();
601 CSSStyleSheet* quirksSheet = parseUASheet(quirksRules);
602 defaultQuirksStyle->addRulesFromSheet(quirksSheet, screenEval());
605 #if ENABLE(FULLSCREEN_API)
606 static void loadFullScreenRulesIfNeeded(Document* document)
608 if (!document->webkitIsFullScreen())
610 // Full-screen rules.
611 String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraDefaultStyleSheet();
612 CSSStyleSheet* fullscreenSheet = parseUASheet(fullscreenRules);
613 defaultStyle->addRulesFromSheet(fullscreenSheet, screenEval());
614 defaultQuirksStyle->addRulesFromSheet(fullscreenSheet, screenEval());
618 static void loadSimpleDefaultStyle()
620 ASSERT(!defaultStyle);
621 ASSERT(!simpleDefaultStyleSheet);
623 defaultStyle = new CSSRuleSet;
624 defaultPrintStyle = new CSSRuleSet;
625 defaultQuirksStyle = new CSSRuleSet;
627 simpleDefaultStyleSheet = parseUASheet(simpleUserAgentStyleSheet, strlen(simpleUserAgentStyleSheet));
628 defaultStyle->addRulesFromSheet(simpleDefaultStyleSheet, screenEval());
630 // No need to initialize quirks sheet yet as there are no quirk rules for elements allowed in simple default style.
633 static void loadViewSourceStyle()
635 ASSERT(!defaultViewSourceStyle);
636 defaultViewSourceStyle = new CSSRuleSet;
637 defaultViewSourceStyle->addRulesFromSheet(parseUASheet(sourceUserAgentStyleSheet, sizeof(sourceUserAgentStyleSheet)), screenEval());
640 void CSSStyleSelector::addMatchedDeclaration(CSSMutableStyleDeclaration* decl)
642 m_matchedDecls.append(decl);
645 void CSSStyleSelector::matchRules(CSSRuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules)
647 m_matchedRules.clear();
649 if (!rules || !m_element)
652 // We need to collect the rules for id, class, tag, and everything else into a buffer and
653 // then sort the buffer.
654 if (m_element->hasID())
655 matchRulesForList(rules->getIDRules(m_element->idForStyleResolution().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
656 if (m_element->hasClass()) {
657 ASSERT(m_styledElement);
658 const SpaceSplitString& classNames = m_styledElement->classNames();
659 size_t size = classNames.size();
660 for (size_t i = 0; i < size; ++i)
661 matchRulesForList(rules->getClassRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
663 if (!m_element->shadowPseudoId().isEmpty()) {
664 ASSERT(m_styledElement);
665 matchRulesForList(rules->getPseudoRules(m_element->shadowPseudoId().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
667 matchRulesForList(rules->getTagRules(m_element->localName().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
668 matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules);
670 // If we didn't match any rules, we're done.
671 if (m_matchedRules.isEmpty())
674 // Sort the set of matched rules.
675 sortMatchedRules(0, m_matchedRules.size());
677 // Now transfer the set of matched rules over to our list of decls.
678 if (!m_checker.m_collectRulesOnly) {
679 for (unsigned i = 0; i < m_matchedRules.size(); i++)
680 addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());
682 for (unsigned i = 0; i < m_matchedRules.size(); i++) {
684 m_ruleList = CSSRuleList::create();
685 m_ruleList->append(m_matchedRules[i]->rule());
690 void CSSStyleSelector::matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules)
695 for (CSSRuleData* d = rules->first(); d; d = d->next()) {
696 CSSStyleRule* rule = d->rule();
697 if (m_checker.m_sameOriginOnly && !m_checker.m_document->securityOrigin()->canRequest(rule->baseURL()))
699 if (checkSelector(d->selector())) {
700 // If the rule has no properties to apply, then ignore it in the non-debug mode.
701 CSSMutableStyleDeclaration* decl = rule->declaration();
702 if (!decl || (!decl->length() && !includeEmptyRules))
705 // If we're matching normal rules, set a pseudo bit if
706 // we really just matched a pseudo-element.
707 if (m_dynamicPseudo != NOPSEUDO && m_checker.m_pseudoStyle == NOPSEUDO) {
708 if (m_checker.m_collectRulesOnly)
710 if (m_dynamicPseudo < FIRST_INTERNAL_PSEUDOID)
711 m_style->setHasPseudoStyle(m_dynamicPseudo);
713 // Update our first/last rule indices in the matched rules array.
714 lastRuleIndex = m_matchedDecls.size() + m_matchedRules.size();
715 if (firstRuleIndex == -1)
716 firstRuleIndex = lastRuleIndex;
718 // Add this rule to our list of matched rules.
725 static bool operator >(CSSRuleData& r1, CSSRuleData& r2)
727 int spec1 = r1.selector()->specificity();
728 int spec2 = r2.selector()->specificity();
729 return (spec1 == spec2) ? r1.position() > r2.position() : spec1 > spec2;
732 static bool operator <=(CSSRuleData& r1, CSSRuleData& r2)
737 void CSSStyleSelector::sortMatchedRules(unsigned start, unsigned end)
739 if (start >= end || (end - start == 1))
740 return; // Sanity check.
742 if (end - start <= 6) {
743 // Apply a bubble sort for smaller lists.
744 for (unsigned i = end - 1; i > start; i--) {
746 for (unsigned j = start; j < i; j++) {
747 CSSRuleData* elt = m_matchedRules[j];
748 CSSRuleData* elt2 = m_matchedRules[j + 1];
751 m_matchedRules[j] = elt2;
752 m_matchedRules[j + 1] = elt;
761 // Perform a merge sort for larger lists.
762 unsigned mid = (start + end) / 2;
763 sortMatchedRules(start, mid);
764 sortMatchedRules(mid, end);
766 CSSRuleData* elt = m_matchedRules[mid - 1];
767 CSSRuleData* elt2 = m_matchedRules[mid];
769 // Handle the fast common case (of equal specificity). The list may already
770 // be completely sorted.
774 // We have to merge sort. Ensure our merge buffer is big enough to hold
776 Vector<CSSRuleData*> rulesMergeBuffer;
777 rulesMergeBuffer.reserveInitialCapacity(end - start);
782 elt = m_matchedRules[i1];
783 elt2 = m_matchedRules[i2];
785 while (i1 < mid || i2 < end) {
786 if (i1 < mid && (i2 == end || *elt <= *elt2)) {
787 rulesMergeBuffer.append(elt);
789 elt = m_matchedRules[i1];
791 rulesMergeBuffer.append(elt2);
793 elt2 = m_matchedRules[i2];
797 for (unsigned i = start; i < end; i++)
798 m_matchedRules[i] = rulesMergeBuffer[i - start];
801 inline EInsideLink CSSStyleSelector::SelectorChecker::determineLinkState(Element* element) const
803 if (!element || !element->isLink())
804 return NotInsideLink;
805 return determineLinkStateSlowCase(element);
808 inline void CSSStyleSelector::initElement(Element* e)
810 if (m_element != e) {
812 m_styledElement = m_element && m_element->isStyledElement() ? static_cast<StyledElement*>(m_element) : 0;
813 m_elementLinkState = m_checker.determineLinkState(m_element);
814 if (e && e == e->document()->documentElement()) {
815 e->document()->setDirectionSetOnDocumentElement(false);
816 e->document()->setWritingModeSetOnDocumentElement(false);
821 inline void CSSStyleSelector::initForStyleResolve(Element* e, RenderStyle* parentStyle, PseudoId pseudoID)
823 m_checker.m_pseudoStyle = pseudoID;
825 m_parentNode = e ? e->parentNode() : 0;
828 if (!m_parentNode && e && e->isSVGElement() && e->isShadowRoot())
829 m_parentNode = e->shadowHost();
833 m_parentStyle = parentStyle;
835 m_parentStyle = m_parentNode ? m_parentNode->renderStyle() : 0;
837 Node* docElement = e ? e->document()->documentElement() : 0;
838 RenderStyle* docStyle = m_checker.m_document->renderStyle();
839 m_rootElementStyle = docElement && e != docElement ? docElement->renderStyle() : docStyle;
843 m_matchedDecls.clear();
845 m_pendingImageProperties.clear();
852 static inline const AtomicString* linkAttribute(Node* node)
857 ASSERT(node->isElementNode());
858 Element* element = static_cast<Element*>(node);
859 if (element->isHTMLElement())
860 return &element->fastGetAttribute(hrefAttr);
863 if (element->isWMLElement()) {
864 // <anchor> elements don't have href attributes, but we still want to
865 // appear as link, so linkAttribute() has to return a non-null value!
866 if (element->hasTagName(WMLNames::anchorTag))
869 return &element->fastGetAttribute(hrefAttr);
874 if (element->isSVGElement())
875 return &element->fastGetAttribute(XLinkNames::hrefAttr);
881 CSSStyleSelector::SelectorChecker::SelectorChecker(Document* document, bool strictParsing)
882 : m_document(document)
883 , m_strictParsing(strictParsing)
884 , m_collectRulesOnly(false)
885 , m_sameOriginOnly(false)
886 , m_pseudoStyle(NOPSEUDO)
887 , m_documentIsHTML(document->isHTMLDocument())
888 , m_matchVisitedPseudoClass(false)
892 EInsideLink CSSStyleSelector::SelectorChecker::determineLinkStateSlowCase(Element* element) const
894 ASSERT(element->isLink());
896 const AtomicString* attr = linkAttribute(element);
897 if (!attr || attr->isNull())
898 return NotInsideLink;
901 Vector<UChar, 512> url;
902 visitedURL(m_document->baseURL(), *attr, url);
904 return InsideUnvisitedLink;
906 // If the Qt4.4 interface for the history is used, we will have to fallback
907 // to the old global history.
908 QWebHistoryInterface* iface = QWebHistoryInterface::defaultInterface();
910 return iface->historyContains(QString(reinterpret_cast<QChar*>(url.data()), url.size())) ? InsideVisitedLink : InsideUnvisitedLink;
912 LinkHash hash = visitedLinkHash(url.data(), url.size());
914 return InsideUnvisitedLink;
916 LinkHash hash = visitedLinkHash(m_document->baseURL(), *attr);
918 return InsideUnvisitedLink;
921 Frame* frame = m_document->frame();
923 return InsideUnvisitedLink;
925 Page* page = frame->page();
927 return InsideUnvisitedLink;
929 m_linksCheckedForVisitedState.add(hash);
931 #if USE(PLATFORM_STRATEGIES)
932 return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash) ? InsideVisitedLink : InsideUnvisitedLink;
934 return page->group().isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink;
938 bool CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* element) const
940 PseudoId dynamicPseudo = NOPSEUDO;
941 return checkSelector(sel, element, 0, dynamicPseudo, false, false) == SelectorMatches;
944 static const unsigned cStyleSearchThreshold = 10;
946 Node* CSSStyleSelector::locateCousinList(Element* parent, unsigned depth) const
948 if (parent && parent->isStyledElement()) {
949 StyledElement* p = static_cast<StyledElement*>(parent);
950 if (!p->inlineStyleDecl() && !p->hasID()) {
951 Node* r = p->previousSibling();
952 unsigned subcount = 0;
953 RenderStyle* st = p->renderStyle();
955 if (r->renderStyle() == st)
956 return r->lastChild();
957 if (subcount++ == cStyleSearchThreshold)
959 r = r->previousSibling();
961 if (!r && depth < cStyleSearchThreshold)
962 r = locateCousinList(parent->parentElement(), depth + 1);
964 if (r->renderStyle() == st)
965 return r->lastChild();
966 if (subcount++ == cStyleSearchThreshold)
968 r = r->previousSibling();
975 bool CSSStyleSelector::canShareStyleWithElement(Node* n) const
977 if (n->isStyledElement()) {
978 StyledElement* s = static_cast<StyledElement*>(n);
979 RenderStyle* style = s->renderStyle();
980 if (style && !style->unique() &&
981 (s->tagQName() == m_element->tagQName()) && !s->hasID() &&
982 (s->hasClass() == m_element->hasClass()) && !s->inlineStyleDecl() &&
983 (s->hasMappedAttributes() == m_styledElement->hasMappedAttributes()) &&
984 (s->isLink() == m_element->isLink()) &&
985 !style->affectedByAttributeSelectors() &&
986 (s->hovered() == m_element->hovered()) &&
987 (s->active() == m_element->active()) &&
988 (s->focused() == m_element->focused()) &&
989 (s != s->document()->cssTarget() && m_element != m_element->document()->cssTarget()) &&
990 (s->fastGetAttribute(typeAttr) == m_element->fastGetAttribute(typeAttr)) &&
991 (s->fastGetAttribute(XMLNames::langAttr) == m_element->fastGetAttribute(XMLNames::langAttr)) &&
992 (s->fastGetAttribute(langAttr) == m_element->fastGetAttribute(langAttr)) &&
993 (s->fastGetAttribute(readonlyAttr) == m_element->fastGetAttribute(readonlyAttr)) &&
994 (s->fastGetAttribute(cellpaddingAttr) == m_element->fastGetAttribute(cellpaddingAttr))) {
995 bool isControl = s->isFormControlElement();
996 if (isControl != m_element->isFormControlElement())
999 InputElement* thisInputElement = toInputElement(s);
1000 InputElement* otherInputElement = toInputElement(m_element);
1001 if (thisInputElement && otherInputElement) {
1002 if ((thisInputElement->isAutofilled() != otherInputElement->isAutofilled()) ||
1003 (thisInputElement->isChecked() != otherInputElement->isChecked()) ||
1004 (thisInputElement->isIndeterminate() != otherInputElement->isIndeterminate()))
1009 if (s->isEnabledFormControl() != m_element->isEnabledFormControl())
1012 if (s->isDefaultButtonForForm() != m_element->isDefaultButtonForForm())
1015 if (!m_element->document()->containsValidityStyleRules())
1018 bool willValidate = s->willValidate();
1019 if (willValidate != m_element->willValidate())
1022 if (willValidate && (s->isValidFormControlElement() != m_element->isValidFormControlElement()))
1025 if (s->isInRange() != m_element->isInRange())
1028 if (s->isOutOfRange() != m_element->isOutOfRange())
1032 if (style->transitions() || style->animations())
1035 #if USE(ACCELERATED_COMPOSITING)
1036 // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
1037 // See comments in RenderObject::setStyle().
1038 if (s->hasTagName(iframeTag) || s->hasTagName(embedTag) || s->hasTagName(objectTag) || s->hasTagName(appletTag))
1042 bool classesMatch = true;
1043 if (s->hasClass()) {
1044 const AtomicString& class1 = m_element->fastGetAttribute(classAttr);
1045 const AtomicString& class2 = s->fastGetAttribute(classAttr);
1046 classesMatch = (class1 == class2);
1050 bool mappedAttrsMatch = true;
1051 if (s->hasMappedAttributes())
1052 mappedAttrsMatch = s->attributeMap()->mappedMapsEquivalent(m_styledElement->attributeMap());
1053 if (mappedAttrsMatch) {
1055 if (m_elementLinkState != style->insideLink())
1066 ALWAYS_INLINE RenderStyle* CSSStyleSelector::locateSharedStyle() const
1068 if (m_styledElement && !m_styledElement->inlineStyleDecl() && !m_styledElement->hasID() && !m_styledElement->document()->usesSiblingRules()) {
1069 // Check previous siblings.
1072 for (n = m_element->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
1074 if (canShareStyleWithElement(n))
1075 return n->renderStyle();
1076 if (count++ == cStyleSearchThreshold)
1078 for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
1081 n = locateCousinList(m_element->parentElement());
1083 if (canShareStyleWithElement(n))
1084 return n->renderStyle();
1085 if (count++ == cStyleSearchThreshold)
1087 for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
1093 void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule)
1095 // First we match rules from the user agent sheet.
1096 CSSRuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
1097 ? defaultPrintStyle : defaultStyle;
1098 matchRules(userAgentStyleSheet, firstUARule, lastUARule, false);
1100 // In quirks mode, we match rules from the quirks user agent sheet.
1101 if (!m_checker.m_strictParsing)
1102 matchRules(defaultQuirksStyle, firstUARule, lastUARule, false);
1104 // If we're in view source mode, then we match rules from the view source style sheet.
1105 if (m_checker.m_document->frame() && m_checker.m_document->frame()->inViewSourceMode()) {
1106 if (!defaultViewSourceStyle)
1107 loadViewSourceStyle();
1108 matchRules(defaultViewSourceStyle, firstUARule, lastUARule, false);
1112 PassRefPtr<RenderStyle> CSSStyleSelector::styleForDocument(Document* document)
1114 Frame* frame = document->frame();
1116 RefPtr<RenderStyle> documentStyle = RenderStyle::create();
1117 documentStyle->setDisplay(BLOCK);
1118 documentStyle->setVisuallyOrdered(document->visuallyOrdered());
1119 documentStyle->setZoom(frame ? frame->pageZoomFactor() : 1);
1120 documentStyle->setPageScaleTransform(frame ? frame->pageScaleFactor() : 1);
1122 Element* docElement = document->documentElement();
1123 RenderObject* docElementRenderer = docElement ? docElement->renderer() : 0;
1124 if (docElementRenderer) {
1125 // Use the direction and writing-mode of the body to set the
1126 // viewport's direction and writing-mode unless the property is set on the document element.
1127 // If there is no body, then use the document element.
1128 RenderObject* bodyRenderer = document->body() ? document->body()->renderer() : 0;
1129 if (bodyRenderer && !document->writingModeSetOnDocumentElement())
1130 documentStyle->setWritingMode(bodyRenderer->style()->writingMode());
1132 documentStyle->setWritingMode(docElementRenderer->style()->writingMode());
1133 if (bodyRenderer && !document->directionSetOnDocumentElement())
1134 documentStyle->setDirection(bodyRenderer->style()->direction());
1136 documentStyle->setDirection(docElementRenderer->style()->direction());
1139 FontDescription fontDescription;
1140 fontDescription.setUsePrinterFont(document->printing());
1141 if (Settings* settings = document->settings()) {
1142 fontDescription.setRenderingMode(settings->fontRenderingMode());
1143 if (document->printing() && !settings->shouldPrintBackgrounds())
1144 documentStyle->setForceBackgroundsToWhite(true);
1145 const AtomicString& stdfont = settings->standardFontFamily();
1146 if (!stdfont.isEmpty()) {
1147 fontDescription.firstFamily().setFamily(stdfont);
1148 fontDescription.firstFamily().appendFamily(0);
1150 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
1151 int size = CSSStyleSelector::fontSizeForKeyword(document, CSSValueMedium, false);
1152 fontDescription.setSpecifiedSize(size);
1153 bool useSVGZoomRules = document->isSVGDocument();
1154 fontDescription.setComputedSize(CSSStyleSelector::getComputedSizeFromSpecifiedSize(document, documentStyle.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules));
1157 documentStyle->setFontDescription(fontDescription);
1158 documentStyle->font().update(0);
1160 return documentStyle.release();
1163 // If resolveForRootDefault is true, style based on user agent style sheet only. This is used in media queries, where
1164 // relative units are interpreted according to document root element style, styled only with UA stylesheet
1166 PassRefPtr<RenderStyle> CSSStyleSelector::styleForElement(Element* e, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault, bool matchVisitedPseudoClass)
1168 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
1169 // will vanish if a style recalc happens during loading.
1170 if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) {
1171 if (!s_styleNotYetAvailable) {
1172 s_styleNotYetAvailable = RenderStyle::create().releaseRef();
1173 s_styleNotYetAvailable->ref();
1174 s_styleNotYetAvailable->setDisplay(NONE);
1175 s_styleNotYetAvailable->font().update(m_fontSelector);
1177 s_styleNotYetAvailable->ref();
1178 e->document()->setHasNodesWithPlaceholderStyle();
1179 return s_styleNotYetAvailable;
1184 RenderStyle* sharedStyle = locateSharedStyle();
1188 initForStyleResolve(e, defaultParent);
1190 // Compute our style allowing :visited to match first.
1191 RefPtr<RenderStyle> visitedStyle;
1192 if (!matchVisitedPseudoClass && m_parentStyle && (m_parentStyle->insideLink() || e->isLink()) && e->document()->usesLinkRules()) {
1193 // Fetch our parent style.
1194 RenderStyle* parentStyle = m_parentStyle;
1196 // Use the parent's visited style if one exists.
1197 RenderStyle* parentVisitedStyle = m_parentStyle->getCachedPseudoStyle(VISITED_LINK);
1198 if (parentVisitedStyle)
1199 parentStyle = parentVisitedStyle;
1201 visitedStyle = styleForElement(e, parentStyle, false, false, true);
1203 if (m_elementLinkState == InsideUnvisitedLink)
1204 visitedStyle = 0; // We made the style to avoid timing attacks. Just throw it away now that we did that, since we don't need it.
1206 visitedStyle->setStyleType(VISITED_LINK);
1208 initForStyleResolve(e, defaultParent);
1211 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass;
1213 m_style = RenderStyle::create();
1216 m_style->inheritFrom(m_parentStyle);
1218 m_parentStyle = style();
1221 m_style->setIsLink(true);
1222 m_style->setInsideLink(m_elementLinkState);
1225 if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(e)) {
1226 loadFullDefaultStyle();
1227 #if ENABLE(FULLSCREEN_API)
1228 loadFullScreenRulesIfNeeded(e->document());
1233 static bool loadedSVGUserAgentSheet;
1234 if (e->isSVGElement() && !loadedSVGUserAgentSheet) {
1236 loadedSVGUserAgentSheet = true;
1237 CSSStyleSheet* svgSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet));
1238 defaultStyle->addRulesFromSheet(svgSheet, screenEval());
1239 defaultPrintStyle->addRulesFromSheet(svgSheet, printEval());
1244 static bool loadedMathMLUserAgentSheet;
1245 if (e->isMathMLElement() && !loadedMathMLUserAgentSheet) {
1247 loadedMathMLUserAgentSheet = true;
1248 CSSStyleSheet* mathMLSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet));
1249 defaultStyle->addRulesFromSheet(mathMLSheet, screenEval());
1250 defaultPrintStyle->addRulesFromSheet(mathMLSheet, printEval());
1255 static bool loadedWMLUserAgentSheet;
1256 if (e->isWMLElement() && !loadedWMLUserAgentSheet) {
1258 loadedWMLUserAgentSheet = true;
1259 CSSStyleSheet* wmlSheet = parseUASheet(wmlUserAgentStyleSheet, sizeof(wmlUserAgentStyleSheet));
1260 defaultStyle->addRulesFromSheet(wmlSheet, screenEval());
1261 defaultPrintStyle->addRulesFromSheet(wmlSheet, printEval());
1266 static bool loadedMediaStyleSheet;
1267 if (!loadedMediaStyleSheet && (e->hasTagName(videoTag) || e->hasTagName(audioTag))) {
1268 loadedMediaStyleSheet = true;
1269 String mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::themeForPage(e->document()->page())->extraMediaControlsStyleSheet();
1270 CSSStyleSheet* mediaControlsSheet = parseUASheet(mediaRules);
1271 defaultStyle->addRulesFromSheet(mediaControlsSheet, screenEval());
1272 defaultPrintStyle->addRulesFromSheet(mediaControlsSheet, printEval());
1276 int firstUARule = -1, lastUARule = -1;
1277 int firstUserRule = -1, lastUserRule = -1;
1278 int firstAuthorRule = -1, lastAuthorRule = -1;
1279 matchUARules(firstUARule, lastUARule);
1281 if (!resolveForRootDefault) {
1282 // 4. Now we check user sheet rules.
1283 if (m_matchAuthorAndUserStyles)
1284 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, false);
1286 // 5. Now check author rules, beginning first with presentational attributes
1287 // mapped from HTML.
1288 if (m_styledElement) {
1289 // Ask if the HTML element has mapped attributes.
1290 if (m_styledElement->hasMappedAttributes()) {
1291 // Walk our attribute list and add in each decl.
1292 const NamedNodeMap* map = m_styledElement->attributeMap();
1293 for (unsigned i = 0; i < map->length(); i++) {
1294 Attribute* attr = map->attributeItem(i);
1295 if (attr->isMappedAttribute() && attr->decl()) {
1296 lastAuthorRule = m_matchedDecls.size();
1297 if (firstAuthorRule == -1)
1298 firstAuthorRule = lastAuthorRule;
1299 addMatchedDeclaration(attr->decl());
1304 // Now we check additional mapped declarations.
1305 // Tables and table cells share an additional mapped rule that must be applied
1306 // after all attributes, since their mapped style depends on the values of multiple attributes.
1307 if (m_styledElement->canHaveAdditionalAttributeStyleDecls()) {
1308 m_additionalAttributeStyleDecls.clear();
1309 m_styledElement->additionalAttributeStyleDecls(m_additionalAttributeStyleDecls);
1310 if (!m_additionalAttributeStyleDecls.isEmpty()) {
1311 unsigned additionalDeclsSize = m_additionalAttributeStyleDecls.size();
1312 if (firstAuthorRule == -1)
1313 firstAuthorRule = m_matchedDecls.size();
1314 lastAuthorRule = m_matchedDecls.size() + additionalDeclsSize - 1;
1315 for (unsigned i = 0; i < additionalDeclsSize; i++)
1316 addMatchedDeclaration(m_additionalAttributeStyleDecls[i]);
1321 // 6. Check the rules in author sheets next.
1322 if (m_matchAuthorAndUserStyles)
1323 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, false);
1325 // 7. Now check our inline style attribute.
1326 if (m_matchAuthorAndUserStyles && m_styledElement) {
1327 CSSMutableStyleDeclaration* inlineDecl = m_styledElement->inlineStyleDecl();
1329 lastAuthorRule = m_matchedDecls.size();
1330 if (firstAuthorRule == -1)
1331 firstAuthorRule = lastAuthorRule;
1332 addMatchedDeclaration(inlineDecl);
1337 // Reset the value back before applying properties, so that -webkit-link knows what color to use.
1338 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass;
1340 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
1341 // high-priority properties first, i.e., those properties that other properties depend on.
1342 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
1343 // and (4) normal important.
1344 m_lineHeightValue = 0;
1345 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
1346 if (!resolveForRootDefault) {
1347 applyDeclarations<true>(true, firstAuthorRule, lastAuthorRule);
1348 applyDeclarations<true>(true, firstUserRule, lastUserRule);
1350 applyDeclarations<true>(true, firstUARule, lastUARule);
1352 // If our font got dirtied, go ahead and update it now.
1356 // Line-height is set when we are sure we decided on the font-size
1357 if (m_lineHeightValue)
1358 applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
1360 // Now do the normal priority UA properties.
1361 applyDeclarations<false>(false, firstUARule, lastUARule);
1363 // Cache our border and background so that we can examine them later.
1364 cacheBorderAndBackground();
1366 // Now do the author and user normal priority properties and all the !important properties.
1367 if (!resolveForRootDefault) {
1368 applyDeclarations<false>(false, lastUARule + 1, m_matchedDecls.size() - 1);
1369 applyDeclarations<false>(true, firstAuthorRule, lastAuthorRule);
1370 applyDeclarations<false>(true, firstUserRule, lastUserRule);
1372 applyDeclarations<false>(true, firstUARule, lastUARule);
1374 ASSERT(!m_fontDirty);
1375 // If our font got dirtied by one of the non-essential font props,
1376 // go ahead and update it a second time.
1380 // Clean up our style object's display and text decorations (among other fixups).
1381 adjustRenderStyle(style(), m_parentStyle, e);
1383 // Start loading images referenced by this style.
1384 loadPendingImages();
1386 // If we have first-letter pseudo style, do not share this style
1387 if (m_style->hasPseudoStyle(FIRST_LETTER))
1388 m_style->setUnique();
1391 // Copy any pseudo bits that the visited style has to the primary style so that
1392 // pseudo element styles will continue to work for pseudo elements inside :visited
1394 for (unsigned pseudo = FIRST_PUBLIC_PSEUDOID; pseudo < FIRST_INTERNAL_PSEUDOID; ++pseudo) {
1395 if (visitedStyle->hasPseudoStyle(static_cast<PseudoId>(pseudo)))
1396 m_style->setHasPseudoStyle(static_cast<PseudoId>(pseudo));
1399 // Add the visited style off the main style.
1400 m_style->addCachedPseudoStyle(visitedStyle.release());
1403 if (!matchVisitedPseudoClass)
1404 initElement(0); // Clear out for the next resolve.
1406 // Now return the style.
1407 return m_style.release();
1410 PassRefPtr<RenderStyle> CSSStyleSelector::styleForKeyframe(const RenderStyle* elementStyle, const WebKitCSSKeyframeRule* keyframeRule, KeyframeValue& keyframe)
1412 if (keyframeRule->style())
1413 addMatchedDeclaration(keyframeRule->style());
1418 m_style = RenderStyle::clone(elementStyle);
1420 m_lineHeightValue = 0;
1422 // We don't need to bother with !important. Since there is only ever one
1423 // decl, there's nothing to override. So just add the first properties.
1424 if (keyframeRule->style())
1425 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
1427 // If our font got dirtied, go ahead and update it now.
1431 // Line-height is set when we are sure we decided on the font-size
1432 if (m_lineHeightValue)
1433 applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
1435 // Now do rest of the properties.
1436 if (keyframeRule->style())
1437 applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1);
1439 // If our font got dirtied by one of the non-essential font props,
1440 // go ahead and update it a second time.
1444 // Start loading images referenced by this style.
1445 loadPendingImages();
1447 // Add all the animating properties to the keyframe.
1448 if (keyframeRule->style()) {
1449 CSSMutableStyleDeclaration::const_iterator end = keyframeRule->style()->end();
1450 for (CSSMutableStyleDeclaration::const_iterator it = keyframeRule->style()->begin(); it != end; ++it) {
1451 int property = (*it).id();
1452 // Timing-function within keyframes is special, because it is not animated; it just
1453 // describes the timing function between this keyframe and the next.
1454 if (property != CSSPropertyWebkitAnimationTimingFunction)
1455 keyframe.addProperty(property);
1459 return m_style.release();
1462 void CSSStyleSelector::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list)
1466 // Get the keyframesRule for this name
1467 if (!e || list.animationName().isEmpty())
1470 m_keyframesRuleMap.checkConsistency();
1472 if (!m_keyframesRuleMap.contains(list.animationName().impl()))
1475 const WebKitCSSKeyframesRule* rule = m_keyframesRuleMap.find(list.animationName().impl()).get()->second.get();
1477 // Construct and populate the style for each keyframe
1478 for (unsigned i = 0; i < rule->length(); ++i) {
1479 // Apply the declaration to the style. This is a simplified version of the logic in styleForElement
1481 initForStyleResolve(e);
1483 const WebKitCSSKeyframeRule* keyframeRule = rule->item(i);
1485 KeyframeValue keyframe(0, 0);
1486 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule, keyframe));
1488 // Add this keyframe style to all the indicated key times
1490 keyframeRule->getKeys(keys);
1491 for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) {
1492 keyframe.setKey(keys[keyIndex]);
1493 list.insert(keyframe);
1497 // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe)
1498 int initialListSize = list.size();
1499 if (initialListSize > 0 && list[0].key() != 0) {
1500 RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create();
1501 keyframeRule->setKeyText("0%");
1502 KeyframeValue keyframe(0, 0);
1503 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe));
1504 list.insert(keyframe);
1507 // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe)
1508 if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) {
1509 RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create();
1510 keyframeRule->setKeyText("100%");
1511 KeyframeValue keyframe(1, 0);
1512 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe));
1513 list.insert(keyframe);
1517 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForElement(PseudoId pseudo, Element* e, RenderStyle* parentStyle, bool matchVisitedPseudoClass)
1524 // Compute our :visited style first, so that we know whether or not we'll need to create a normal style just to hang it
1526 RefPtr<RenderStyle> visitedStyle;
1527 if (!matchVisitedPseudoClass && parentStyle && parentStyle->insideLink()) {
1528 // Fetch our parent style with :visited in effect.
1529 RenderStyle* parentVisitedStyle = parentStyle->getCachedPseudoStyle(VISITED_LINK);
1530 visitedStyle = pseudoStyleForElement(pseudo, e, parentVisitedStyle ? parentVisitedStyle : parentStyle, true);
1532 if (m_elementLinkState == InsideUnvisitedLink)
1533 visitedStyle = 0; // We made the style to avoid timing attacks. Just throw it away now that we did that.
1535 visitedStyle->setStyleType(VISITED_LINK);
1539 initForStyleResolve(e, parentStyle, pseudo);
1540 m_style = RenderStyle::create();
1542 m_style->inheritFrom(parentStyle);
1544 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass;
1546 // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
1549 // Check UA, user and author rules.
1550 int firstUARule = -1, lastUARule = -1, firstUserRule = -1, lastUserRule = -1, firstAuthorRule = -1, lastAuthorRule = -1;
1551 matchUARules(firstUARule, lastUARule);
1553 if (m_matchAuthorAndUserStyles) {
1554 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, false);
1555 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, false);
1558 if (m_matchedDecls.isEmpty() && !visitedStyle)
1561 m_style->setStyleType(pseudo);
1563 m_lineHeightValue = 0;
1565 // Reset the value back before applying properties, so that -webkit-link knows what color to use.
1566 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass;
1568 // High-priority properties.
1569 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
1570 applyDeclarations<true>(true, firstAuthorRule, lastAuthorRule);
1571 applyDeclarations<true>(true, firstUserRule, lastUserRule);
1572 applyDeclarations<true>(true, firstUARule, lastUARule);
1574 // If our font got dirtied, go ahead and update it now.
1578 // Line-height is set when we are sure we decided on the font-size
1579 if (m_lineHeightValue)
1580 applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
1582 // Now do the normal priority properties.
1583 applyDeclarations<false>(false, firstUARule, lastUARule);
1585 // Cache our border and background so that we can examine them later.
1586 cacheBorderAndBackground();
1588 applyDeclarations<false>(false, lastUARule + 1, m_matchedDecls.size() - 1);
1589 applyDeclarations<false>(true, firstAuthorRule, lastAuthorRule);
1590 applyDeclarations<false>(true, firstUserRule, lastUserRule);
1591 applyDeclarations<false>(true, firstUARule, lastUARule);
1593 // If our font got dirtied by one of the non-essential font props,
1594 // go ahead and update it a second time.
1598 // Clean up our style object's display and text decorations (among other fixups).
1599 adjustRenderStyle(style(), parentStyle, 0);
1601 // Start loading images referenced by this style.
1602 loadPendingImages();
1604 // Hang our visited style off m_style.
1606 m_style->addCachedPseudoStyle(visitedStyle.release());
1608 // Now return the style.
1609 return m_style.release();
1612 PassRefPtr<RenderStyle> CSSStyleSelector::styleForPage(int pageIndex)
1614 initForStyleResolve(m_checker.m_document->documentElement()); // m_rootElementStyle will be set to the document style.
1616 m_style = RenderStyle::create();
1617 m_style->inheritFrom(m_rootElementStyle);
1619 const bool isLeft = isLeftPage(pageIndex);
1620 const bool isFirst = isFirstPage(pageIndex);
1621 const String page = pageName(pageIndex);
1622 matchPageRules(defaultPrintStyle, isLeft, isFirst, page);
1623 matchPageRules(m_userStyle.get(), isLeft, isFirst, page);
1624 matchPageRules(m_authorStyle.get(), isLeft, isFirst, page);
1625 m_lineHeightValue = 0;
1626 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
1628 // If our font got dirtied, go ahead and update it now.
1632 // Line-height is set when we are sure we decided on the font-size
1633 if (m_lineHeightValue)
1634 applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
1636 applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1);
1638 // Start loading images referenced by this style.
1639 loadPendingImages();
1641 // Now return the style.
1642 return m_style.release();
1645 #if ENABLE(DATAGRID)
1647 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForDataGridColumn(DataGridColumn*, RenderStyle*)
1653 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForDataGridColumnHeader(DataGridColumn*, RenderStyle*)
1661 static void addIntrinsicMargins(RenderStyle* style)
1663 // Intrinsic margin value.
1664 const int intrinsicMargin = 2 * style->effectiveZoom();
1666 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
1667 // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame.
1668 if (style->width().isIntrinsicOrAuto()) {
1669 if (style->marginLeft().quirk())
1670 style->setMarginLeft(Length(intrinsicMargin, Fixed));
1671 if (style->marginRight().quirk())
1672 style->setMarginRight(Length(intrinsicMargin, Fixed));
1675 if (style->height().isAuto()) {
1676 if (style->marginTop().quirk())
1677 style->setMarginTop(Length(intrinsicMargin, Fixed));
1678 if (style->marginBottom().quirk())
1679 style->setMarginBottom(Length(intrinsicMargin, Fixed));
1683 void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, RenderStyle* parentStyle, Element *e)
1685 // Cache our original display.
1686 style->setOriginalDisplay(style->display());
1688 if (style->display() != NONE) {
1689 // If we have a <td> that specifies a float property, in quirks mode we just drop the float
1691 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
1692 // these tags to retain their display types.
1693 if (!m_checker.m_strictParsing && e) {
1694 if (e->hasTagName(tdTag)) {
1695 style->setDisplay(TABLE_CELL);
1696 style->setFloating(FNONE);
1698 else if (e->hasTagName(tableTag))
1699 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
1702 if (e && (e->hasTagName(tdTag) || e->hasTagName(thTag))) {
1703 if (style->whiteSpace() == KHTML_NOWRAP) {
1704 // Figure out if we are really nowrapping or if we should just
1705 // use normal instead. If the width of the cell is fixed, then
1706 // we don't actually use NOWRAP.
1707 if (style->width().isFixed())
1708 style->setWhiteSpace(NORMAL);
1710 style->setWhiteSpace(NOWRAP);
1714 // Tables never support the -webkit-* values for text-align and will reset back to the default.
1715 if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT))
1716 style->setTextAlign(TAAUTO);
1718 // Frames and framesets never honor position:relative or position:absolute. This is necessary to
1719 // fix a crash where a site tries to position these objects. They also never honor display.
1720 if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) {
1721 style->setPosition(StaticPosition);
1722 style->setDisplay(BLOCK);
1725 // Table headers with a text-align of auto will change the text-align to center.
1726 if (e && e->hasTagName(thTag) && style->textAlign() == TAAUTO)
1727 style->setTextAlign(CENTER);
1729 if (e && e->hasTagName(legendTag))
1730 style->setDisplay(BLOCK);
1732 // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to
1733 // position or float an inline, compact, or run-in. Cache the original display, since it
1734 // may be needed for positioned elements that have to compute their static normal flow
1735 // positions. We also force inline-level roots to be block-level.
1736 if (style->display() != BLOCK && style->display() != TABLE && style->display() != BOX &&
1737 (style->position() == AbsolutePosition || style->position() == FixedPosition || style->floating() != FNONE ||
1738 (e && e->document()->documentElement() == e))) {
1739 if (style->display() == INLINE_TABLE)
1740 style->setDisplay(TABLE);
1741 else if (style->display() == INLINE_BOX)
1742 style->setDisplay(BOX);
1743 else if (style->display() == LIST_ITEM) {
1744 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk,
1745 // but only in quirks mode.
1746 if (!m_checker.m_strictParsing && style->floating() != FNONE)
1747 style->setDisplay(BLOCK);
1750 style->setDisplay(BLOCK);
1753 // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely
1754 // clear how that should work.
1755 if (style->display() == INLINE && style->styleType() == NOPSEUDO && parentStyle && style->writingMode() != parentStyle->writingMode())
1756 style->setDisplay(INLINE_BLOCK);
1758 // After performing the display mutation, check table rows. We do not honor position:relative on
1759 // table rows or cells. This has been established in CSS2.1 (and caused a crash in containingBlock()
1761 if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP ||
1762 style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_CELL) &&
1763 style->position() == RelativePosition)
1764 style->setPosition(StaticPosition);
1766 // writing-mode does not apply to table row groups, table column groups, table rows, and table columns.
1767 // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though.
1768 if (style->display() == TABLE_COLUMN || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_FOOTER_GROUP
1769 || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_ROW_GROUP
1770 || style->display() == TABLE_CELL)
1771 style->setWritingMode(parentStyle->writingMode());
1773 // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting
1774 // of block-flow to anything other than TopToBottomWritingMode.
1775 // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support.
1776 if (style->writingMode() != TopToBottomWritingMode && (style->display() == BOX || style->display() == INLINE_BOX))
1777 style->setWritingMode(TopToBottomWritingMode);
1780 // Make sure our z-index value is only applied if the object is positioned.
1781 if (style->position() == StaticPosition)
1782 style->setHasAutoZIndex();
1784 // Auto z-index becomes 0 for the root element and transparent objects. This prevents
1785 // cases where objects that should be blended as a single unit end up with a non-transparent
1786 // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections.
1787 if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) || style->opacity() < 1.0f ||
1788 style->hasTransformRelatedProperty() || style->hasMask() || style->boxReflect()))
1789 style->setZIndex(0);
1792 if (e && (e->hasTagName(WMLNames::insertedLegendTag)
1793 || e->hasTagName(WMLNames::inputTag))
1794 && style->width().isAuto())
1795 style->setWidth(Length(Intrinsic));
1798 // Textarea considers overflow visible as auto.
1799 if (e && e->hasTagName(textareaTag)) {
1800 style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX());
1801 style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY());
1804 // Finally update our text decorations in effect, but don't allow text-decoration to percolate through
1805 // tables, inline blocks, inline tables, or run-ins.
1806 if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
1807 || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX)
1808 style->setTextDecorationsInEffect(style->textDecoration());
1810 style->addToTextDecorationsInEffect(style->textDecoration());
1812 // If either overflow value is not visible, change to auto.
1813 if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE)
1814 style->setOverflowY(OMARQUEE);
1815 else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE)
1816 style->setOverflowX(OMARQUEE);
1817 else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE)
1818 style->setOverflowX(OAUTO);
1819 else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE)
1820 style->setOverflowY(OAUTO);
1822 // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
1823 // FIXME: Eventually table sections will support auto and scroll.
1824 if (style->display() == TABLE || style->display() == INLINE_TABLE ||
1825 style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
1826 if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN)
1827 style->setOverflowX(OVISIBLE);
1828 if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN)
1829 style->setOverflowY(OVISIBLE);
1832 // Menulists should have visible overflow
1833 if (style->appearance() == MenulistPart) {
1834 style->setOverflowX(OVISIBLE);
1835 style->setOverflowY(OVISIBLE);
1838 // Cull out any useless layers and also repeat patterns into additional layers.
1839 style->adjustBackgroundLayers();
1840 style->adjustMaskLayers();
1842 // Do the same for animations and transitions.
1843 style->adjustAnimations();
1844 style->adjustTransitions();
1846 // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will
1847 // alter fonts and heights/widths.
1848 if (e && e->isFormControlElement() && style->fontSize() >= 11) {
1849 // Don't apply intrinsic margins to image buttons. The designer knows how big the images are,
1850 // so we have to treat all image buttons as though they were explicitly sized.
1851 if (!e->hasTagName(inputTag) || !static_cast<HTMLInputElement*>(e)->isImageButton())
1852 addIntrinsicMargins(style);
1855 // Let the theme also have a crack at adjusting the style.
1856 if (style->hasAppearance())
1857 RenderTheme::defaultTheme()->adjustStyle(this, style, e, m_hasUAAppearance, m_borderData, m_backgroundData, m_backgroundColor);
1860 if (e && e->isSVGElement()) {
1861 // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty
1862 if (style->overflowY() == OSCROLL)
1863 style->setOverflowY(OHIDDEN);
1864 else if (style->overflowY() == OAUTO)
1865 style->setOverflowY(OVISIBLE);
1867 if (style->overflowX() == OSCROLL)
1868 style->setOverflowX(OHIDDEN);
1869 else if (style->overflowX() == OAUTO)
1870 style->setOverflowX(OVISIBLE);
1872 // Only the root <svg> element in an SVG document fragment tree honors css position
1873 if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement()))
1874 style->setPosition(RenderStyle::initialPosition());
1879 void CSSStyleSelector::updateFont()
1881 checkForTextSizeAdjust();
1882 checkForGenericFamilyChange(style(), m_parentStyle);
1883 checkForZoomChange(style(), m_parentStyle);
1884 m_style->font().update(m_fontSelector);
1885 m_fontDirty = false;
1888 void CSSStyleSelector::cacheBorderAndBackground()
1890 m_hasUAAppearance = m_style->hasAppearance();
1891 if (m_hasUAAppearance) {
1892 m_borderData = m_style->border();
1893 m_backgroundData = *m_style->backgroundLayers();
1894 m_backgroundColor = m_style->backgroundColor();
1898 PassRefPtr<CSSRuleList> CSSStyleSelector::styleRulesForElement(Element* e, bool authorOnly, bool includeEmptyRules, CSSRuleFilter filter)
1900 return pseudoStyleRulesForElement(e, NOPSEUDO, authorOnly, includeEmptyRules, filter);
1903 PassRefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, bool authorOnly, bool includeEmptyRules, CSSRuleFilter filter)
1905 if (!e || !e->document()->haveStylesheetsLoaded())
1908 m_checker.m_collectRulesOnly = true;
1911 initForStyleResolve(e, 0, pseudoId);
1914 int firstUARule = -1, lastUARule = -1;
1915 // First we match rules from the user agent sheet.
1916 matchUARules(firstUARule, lastUARule);
1918 // Now we check user sheet rules.
1919 if (m_matchAuthorAndUserStyles) {
1920 int firstUserRule = -1, lastUserRule = -1;
1921 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, includeEmptyRules);
1925 if (m_matchAuthorAndUserStyles) {
1926 m_checker.m_sameOriginOnly = (filter == SameOriginCSSRulesOnly);
1928 // Check the rules in author sheets.
1929 int firstAuthorRule = -1, lastAuthorRule = -1;
1930 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, includeEmptyRules);
1932 m_checker.m_sameOriginOnly = false;
1935 m_checker.m_collectRulesOnly = false;
1937 return m_ruleList.release();
1940 bool CSSStyleSelector::checkSelector(CSSSelector* sel)
1942 m_dynamicPseudo = NOPSEUDO;
1944 // Check the selector
1945 SelectorMatch match = m_checker.checkSelector(sel, m_element, &m_selectorAttrs, m_dynamicPseudo, false, false, style(), m_parentNode ? m_parentNode->renderStyle() : 0);
1946 if (match != SelectorMatches)
1949 if (m_checker.m_pseudoStyle != NOPSEUDO && m_checker.m_pseudoStyle != m_dynamicPseudo)
1955 // Recursive check of selectors and combinators
1956 // It can return 3 different values:
1957 // * SelectorMatches - the selector matches the element e
1958 // * SelectorFailsLocally - the selector fails for the element e
1959 // * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e
1960 CSSStyleSelector::SelectorMatch CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const
1963 // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
1964 // because its contents are not part of the formal document structure.
1965 if (e->isSVGElement() && e->isShadowRoot())
1966 return SelectorFailsCompletely;
1969 // first selector has to match
1970 if (!checkOneSelector(sel, e, selectorAttrs, dynamicPseudo, isSubSelector, elementStyle, elementParentStyle))
1971 return SelectorFailsLocally;
1973 // The rest of the selectors has to match
1974 CSSSelector::Relation relation = sel->relation();
1977 sel = sel->tagHistory();
1979 return SelectorMatches;
1981 if (relation != CSSSelector::SubSelector)
1982 // Bail-out if this selector is irrelevant for the pseudoStyle
1983 if (m_pseudoStyle != NOPSEUDO && m_pseudoStyle != dynamicPseudo)
1984 return SelectorFailsCompletely;
1986 // Check for nested links.
1987 if (m_matchVisitedPseudoClass && !isSubSelector) {
1988 RenderStyle* currentStyle = elementStyle ? elementStyle : e->renderStyle();
1989 if (currentStyle && currentStyle->insideLink() && e->isLink()) {
1990 if (encounteredLink)
1991 m_matchVisitedPseudoClass = false; // This link is not relevant to the style being resolved, so disable matching.
1993 encounteredLink = true;
1998 case CSSSelector::Descendant:
2000 ContainerNode* n = e->parentNode();
2001 if (!n || !n->isElementNode())
2002 return SelectorFailsCompletely;
2003 e = static_cast<Element*>(n);
2004 SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2005 if (match != SelectorFailsLocally)
2009 case CSSSelector::Child:
2011 ContainerNode* n = e->parentNode();
2012 if (!n || !n->isElementNode())
2013 return SelectorFailsCompletely;
2014 e = static_cast<Element*>(n);
2015 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2017 case CSSSelector::DirectAdjacent:
2019 if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) {
2020 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
2022 parentStyle->setChildrenAffectedByDirectAdjacentRules();
2024 Node* n = e->previousSibling();
2025 while (n && !n->isElementNode())
2026 n = n->previousSibling();
2028 return SelectorFailsLocally;
2029 e = static_cast<Element*>(n);
2030 m_matchVisitedPseudoClass = false;
2031 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2033 case CSSSelector::IndirectAdjacent:
2034 if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) {
2035 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
2037 parentStyle->setChildrenAffectedByForwardPositionalRules();
2040 Node* n = e->previousSibling();
2041 while (n && !n->isElementNode())
2042 n = n->previousSibling();
2044 return SelectorFailsLocally;
2045 e = static_cast<Element*>(n);
2046 m_matchVisitedPseudoClass = false;
2047 SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2048 if (match != SelectorFailsLocally)
2052 case CSSSelector::SubSelector:
2053 // a selector is invalid if something follows a pseudo-element
2054 // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
2055 // to follow the pseudo elements.
2056 if ((elementStyle || m_collectRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION &&
2057 !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && sel->m_match == CSSSelector::PseudoClass))
2058 return SelectorFailsCompletely;
2059 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle);
2060 case CSSSelector::ShadowDescendant:
2062 Node* shadowHostNode = e->shadowAncestorNode();
2063 if (shadowHostNode == e || !shadowHostNode->isElementNode())
2064 return SelectorFailsCompletely;
2065 e = static_cast<Element*>(shadowHostNode);
2066 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2070 return SelectorFailsCompletely;
2073 static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName)
2075 set->add(qName.localName().impl());
2078 static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet()
2080 // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive
2081 // Mozilla treats all other values as case-sensitive, thus so do we.
2082 HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>;
2084 addLocalNameToSet(attrSet, accept_charsetAttr);
2085 addLocalNameToSet(attrSet, acceptAttr);
2086 addLocalNameToSet(attrSet, alignAttr);
2087 addLocalNameToSet(attrSet, alinkAttr);
2088 addLocalNameToSet(attrSet, axisAttr);
2089 addLocalNameToSet(attrSet, bgcolorAttr);
2090 addLocalNameToSet(attrSet, charsetAttr);
2091 addLocalNameToSet(attrSet, checkedAttr);
2092 addLocalNameToSet(attrSet, clearAttr);
2093 addLocalNameToSet(attrSet, codetypeAttr);
2094 addLocalNameToSet(attrSet, colorAttr);
2095 addLocalNameToSet(attrSet, compactAttr);
2096 addLocalNameToSet(attrSet, declareAttr);
2097 addLocalNameToSet(attrSet, deferAttr);
2098 addLocalNameToSet(attrSet, dirAttr);
2099 addLocalNameToSet(attrSet, disabledAttr);
2100 addLocalNameToSet(attrSet, enctypeAttr);
2101 addLocalNameToSet(attrSet, faceAttr);
2102 addLocalNameToSet(attrSet, frameAttr);
2103 addLocalNameToSet(attrSet, hreflangAttr);
2104 addLocalNameToSet(attrSet, http_equivAttr);
2105 addLocalNameToSet(attrSet, langAttr);
2106 addLocalNameToSet(attrSet, languageAttr);
2107 addLocalNameToSet(attrSet, linkAttr);
2108 addLocalNameToSet(attrSet, mediaAttr);
2109 addLocalNameToSet(attrSet, methodAttr);
2110 addLocalNameToSet(attrSet, multipleAttr);
2111 addLocalNameToSet(attrSet, nohrefAttr);
2112 addLocalNameToSet(attrSet, noresizeAttr);
2113 addLocalNameToSet(attrSet, noshadeAttr);
2114 addLocalNameToSet(attrSet, nowrapAttr);
2115 addLocalNameToSet(attrSet, readonlyAttr);
2116 addLocalNameToSet(attrSet, relAttr);
2117 addLocalNameToSet(attrSet, revAttr);
2118 addLocalNameToSet(attrSet, rulesAttr);
2119 addLocalNameToSet(attrSet, scopeAttr);
2120 addLocalNameToSet(attrSet, scrollingAttr);
2121 addLocalNameToSet(attrSet, selectedAttr);
2122 addLocalNameToSet(attrSet, shapeAttr);
2123 addLocalNameToSet(attrSet, targetAttr);
2124 addLocalNameToSet(attrSet, textAttr);
2125 addLocalNameToSet(attrSet, typeAttr);
2126 addLocalNameToSet(attrSet, valignAttr);
2127 addLocalNameToSet(attrSet, valuetypeAttr);
2128 addLocalNameToSet(attrSet, vlinkAttr);
2133 static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr)
2135 static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
2136 bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom);
2137 return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl());
2140 bool CSSStyleSelector::SelectorChecker::checkOneSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const
2146 if (sel->hasTag()) {
2147 const AtomicString& selLocalName = sel->m_tag.localName();
2148 if (selLocalName != starAtom && selLocalName != e->localName())
2150 const AtomicString& selNS = sel->m_tag.namespaceURI();
2151 if (selNS != starAtom && selNS != e->namespaceURI())
2155 if (sel->hasAttribute()) {
2156 if (sel->m_match == CSSSelector::Class)
2157 return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->m_value);
2159 if (sel->m_match == CSSSelector::Id)
2160 return e->hasID() && e->idForStyleResolution() == sel->m_value;
2162 const QualifiedName& attr = sel->attribute();
2164 // FIXME: Handle the case were elementStyle is 0.
2165 if (elementStyle && (!e->isStyledElement() || (!static_cast<StyledElement*>(e)->isMappedAttribute(attr) && attr != typeAttr && attr != readonlyAttr))) {
2166 elementStyle->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style.
2168 selectorAttrs->add(attr.localName().impl());
2171 const AtomicString& value = e->getAttribute(attr);
2173 return false; // attribute is not set
2175 bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr);
2177 switch (sel->m_match) {
2178 case CSSSelector::Exact:
2179 if (caseSensitive ? sel->m_value != value : !equalIgnoringCase(sel->m_value, value))
2182 case CSSSelector::List:
2184 // Ignore empty selectors or selectors containing spaces
2185 if (sel->m_value.contains(' ') || sel->m_value.isEmpty())
2188 unsigned startSearchAt = 0;
2190 size_t foundPos = value.find(sel->m_value, startSearchAt, caseSensitive);
2191 if (foundPos == notFound)
2193 if (foundPos == 0 || value[foundPos - 1] == ' ') {
2194 unsigned endStr = foundPos + sel->m_value.length();
2195 if (endStr == value.length() || value[endStr] == ' ')
2196 break; // We found a match.
2199 // No match. Keep looking.
2200 startSearchAt = foundPos + 1;
2204 case CSSSelector::Contain:
2205 if (!value.contains(sel->m_value, caseSensitive) || sel->m_value.isEmpty())
2208 case CSSSelector::Begin:
2209 if (!value.startsWith(sel->m_value, caseSensitive) || sel->m_value.isEmpty())
2212 case CSSSelector::End:
2213 if (!value.endsWith(sel->m_value, caseSensitive) || sel->m_value.isEmpty())
2216 case CSSSelector::Hyphen:
2217 if (value.length() < sel->m_value.length())
2219 if (!value.startsWith(sel->m_value, caseSensitive))
2221 // It they start the same, check for exact match or following '-':
2222 if (value.length() != sel->m_value.length() && value[sel->m_value.length()] != '-')
2225 case CSSSelector::PseudoClass:
2226 case CSSSelector::PseudoElement:
2232 if (sel->m_match == CSSSelector::PseudoClass) {
2233 // Handle :not up front.
2234 if (sel->pseudoType() == CSSSelector::PseudoNot) {
2235 // check the simple selector
2236 for (CSSSelector* subSel = sel->simpleSelector(); subSel; subSel = subSel->tagHistory()) {
2237 // :not cannot nest. I don't really know why this is a
2238 // restriction in CSS3, but it is, so let's honor it.
2239 // the parser enforces that this never occurs
2240 ASSERT(!subSel->simpleSelector());
2242 if (!checkOneSelector(subSel, e, selectorAttrs, dynamicPseudo, true, elementStyle, elementParentStyle))
2245 } else if (dynamicPseudo != NOPSEUDO && (RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER)) {
2246 // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
2247 // (since there are no elements involved).
2248 return checkScrollbarPseudoClass(sel, dynamicPseudo);
2249 } else if (dynamicPseudo == SELECTION) {
2250 if (sel->pseudoType() == CSSSelector::PseudoWindowInactive)
2251 return !m_document->page()->focusController()->isActive();
2254 // Normal element pseudo class checking.
2255 switch (sel->pseudoType()) {
2257 case CSSSelector::PseudoNot:
2258 break; // Already handled up above.
2259 case CSSSelector::PseudoEmpty: {
2261 for (Node* n = e->firstChild(); n; n = n->nextSibling()) {
2262 if (n->isElementNode()) {
2265 } else if (n->isTextNode()) {
2266 Text* textNode = static_cast<Text*>(n);
2267 if (!textNode->data().isEmpty()) {
2273 if (!m_collectRulesOnly) {
2275 elementStyle->setEmptyState(result);
2276 else if (e->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique()))
2277 e->renderStyle()->setEmptyState(result);
2281 case CSSSelector::PseudoFirstChild: {
2282 // first-child matches the first child that is an element
2283 if (e->parentNode() && e->parentNode()->isElementNode()) {
2284 bool result = false;
2285 Node* n = e->previousSibling();
2286 while (n && !n->isElementNode())
2287 n = n->previousSibling();
2290 if (!m_collectRulesOnly) {
2291 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
2292 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
2294 parentStyle->setChildrenAffectedByFirstChildRules();
2295 if (result && childStyle)
2296 childStyle->setFirstChildState();
2302 case CSSSelector::PseudoFirstOfType: {
2303 // first-of-type matches the first element of its type
2304 if (e->parentNode() && e->parentNode()->isElementNode()) {
2305 bool result = false;
2306 const QualifiedName& type = e->tagQName();
2307 Node* n = e->previousSibling();
2309 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2311 n = n->previousSibling();
2315 if (!m_collectRulesOnly) {
2316 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
2318 parentStyle->setChildrenAffectedByForwardPositionalRules();
2324 case CSSSelector::PseudoLastChild: {
2325 // last-child matches the last child that is an element
2326 if (Element* parentElement = e->parentElement()) {
2327 bool result = false;
2328 if (parentElement->isFinishedParsingChildren()) {
2329 Node* n = e->nextSibling();
2330 while (n && !n->isElementNode())
2331 n = n->nextSibling();
2335 if (!m_collectRulesOnly) {
2336 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
2337 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2339 parentStyle->setChildrenAffectedByLastChildRules();
2340 if (result && childStyle)
2341 childStyle->setLastChildState();
2347 case CSSSelector::PseudoLastOfType: {
2348 // last-of-type matches the last element of its type
2349 if (Element* parentElement = e->parentElement()) {
2350 if (!m_collectRulesOnly) {
2351 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2353 parentStyle->setChildrenAffectedByBackwardPositionalRules();
2355 if (!parentElement->isFinishedParsingChildren())
2357 bool result = false;
2358 const QualifiedName& type = e->tagQName();
2359 Node* n = e->nextSibling();
2361 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2363 n = n->nextSibling();
2371 case CSSSelector::PseudoOnlyChild: {
2372 if (Element* parentElement = e->parentElement()) {
2373 bool firstChild = false;
2374 bool lastChild = false;
2376 Node* n = e->previousSibling();
2377 while (n && !n->isElementNode())
2378 n = n->previousSibling();
2381 if (firstChild && parentElement->isFinishedParsingChildren()) {
2382 n = e->nextSibling();
2383 while (n && !n->isElementNode())
2384 n = n->nextSibling();
2388 if (!m_collectRulesOnly) {
2389 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
2390 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2392 parentStyle->setChildrenAffectedByFirstChildRules();
2393 parentStyle->setChildrenAffectedByLastChildRules();
2395 if (firstChild && childStyle)
2396 childStyle->setFirstChildState();
2397 if (lastChild && childStyle)
2398 childStyle->setLastChildState();
2400 return firstChild && lastChild;
2404 case CSSSelector::PseudoOnlyOfType: {
2405 // FIXME: This selector is very slow.
2406 if (Element* parentElement = e->parentElement()) {
2407 if (!m_collectRulesOnly) {
2408 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2410 parentStyle->setChildrenAffectedByForwardPositionalRules();
2411 parentStyle->setChildrenAffectedByBackwardPositionalRules();
2414 if (!parentElement->isFinishedParsingChildren())
2416 bool firstChild = false;
2417 bool lastChild = false;
2418 const QualifiedName& type = e->tagQName();
2419 Node* n = e->previousSibling();
2421 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2423 n = n->previousSibling();
2428 n = e->nextSibling();
2430 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2432 n = n->nextSibling();
2437 return firstChild && lastChild;
2441 case CSSSelector::PseudoNthChild: {
2442 if (!sel->parseNth())
2444 if (Element* parentElement = e->parentElement()) {
2446 Node* n = e->previousSibling();
2448 if (n->isElementNode()) {
2449 RenderStyle* s = n->renderStyle();
2450 unsigned index = s ? s->childIndex() : 0;
2457 n = n->previousSibling();
2460 if (!m_collectRulesOnly) {
2461 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
2462 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2464 childStyle->setChildIndex(count);
2466 parentStyle->setChildrenAffectedByForwardPositionalRules();
2469 if (sel->matchNth(count))
2474 case CSSSelector::PseudoNthOfType: {
2475 if (!sel->parseNth())
2477 if (Element* parentElement = e->parentElement()) {
2479 const QualifiedName& type = e->tagQName();
2480 Node* n = e->previousSibling();
2482 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2484 n = n->previousSibling();
2487 if (!m_collectRulesOnly) {
2488 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2490 parentStyle->setChildrenAffectedByForwardPositionalRules();
2493 if (sel->matchNth(count))
2498 case CSSSelector::PseudoNthLastChild: {
2499 if (!sel->parseNth())
2501 if (Element* parentElement = e->parentElement()) {
2502 if (!m_collectRulesOnly) {
2503 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2505 parentStyle->setChildrenAffectedByBackwardPositionalRules();
2507 if (!parentElement->isFinishedParsingChildren())
2510 Node* n = e->nextSibling();
2512 if (n->isElementNode())
2514 n = n->nextSibling();
2516 if (sel->matchNth(count))
2521 case CSSSelector::PseudoNthLastOfType: {
2522 if (!sel->parseNth())
2524 if (Element* parentElement = e->parentElement()) {
2525 if (!m_collectRulesOnly) {
2526 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2528 parentStyle->setChildrenAffectedByBackwardPositionalRules();
2530 if (!parentElement->isFinishedParsingChildren())
2533 const QualifiedName& type = e->tagQName();
2534 Node* n = e->nextSibling();
2536 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2538 n = n->nextSibling();
2540 if (sel->matchNth(count))
2545 case CSSSelector::PseudoTarget:
2546 if (e == e->document()->cssTarget())
2549 case CSSSelector::PseudoAnyLink:
2550 if (e && e->isLink())
2553 case CSSSelector::PseudoAutofill: {
2554 if (!e || !e->isFormControlElement())
2556 if (InputElement* inputElement = toInputElement(e))
2557 return inputElement->isAutofilled();
2560 case CSSSelector::PseudoLink:
2561 if (e && e->isLink())
2562 return !m_matchVisitedPseudoClass;
2564 case CSSSelector::PseudoVisited:
2565 if (e && e->isLink())
2566 return m_matchVisitedPseudoClass;
2568 case CSSSelector::PseudoDrag: {
2570 elementStyle->setAffectedByDragRules(true);
2571 else if (e->renderStyle())
2572 e->renderStyle()->setAffectedByDragRules(true);
2573 if (e->renderer() && e->renderer()->isDragging())
2577 case CSSSelector::PseudoFocus:
2578 if (e && e->focused() && e->document()->frame() && e->document()->frame()->selection()->isFocusedAndActive())
2581 case CSSSelector::PseudoHover: {
2582 // If we're in quirks mode, then hover should never match anchors with no
2583 // href and *:hover should not match anything. This is important for sites like wsj.com.
2584 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
2586 elementStyle->setAffectedByHoverRules(true);
2587 else if (e->renderStyle())
2588 e->renderStyle()->setAffectedByHoverRules(true);
2594 case CSSSelector::PseudoActive:
2595 // If we're in quirks mode, then :active should never match anchors with no
2596 // href and *:active should not match anything.
2597 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
2599 elementStyle->setAffectedByActiveRules(true);
2600 else if (e->renderStyle())
2601 e->renderStyle()->setAffectedByActiveRules(true);
2606 case CSSSelector::PseudoEnabled:
2607 if (e && e->isFormControlElement())
2608 return e->isEnabledFormControl();
2610 case CSSSelector::PseudoFullPageMedia:
2611 return e && e->document() && e->document()->isMediaDocument();
2613 case CSSSelector::PseudoDefault:
2614 return e && e->isDefaultButtonForForm();
2615 case CSSSelector::PseudoDisabled:
2616 if (e && e->isFormControlElement())
2617 return !e->isEnabledFormControl();
2619 case CSSSelector::PseudoReadOnly: {
2620 if (!e || !e->isFormControlElement())
2622 return e->isTextFormControl() && e->isReadOnlyFormControl();
2624 case CSSSelector::PseudoReadWrite: {
2625 if (!e || !e->isFormControlElement())
2627 return e->isTextFormControl() && !e->isReadOnlyFormControl();
2629 case CSSSelector::PseudoOptional:
2630 return e && e->isOptionalFormControl();
2631 case CSSSelector::PseudoRequired:
2632 return e && e->isRequiredFormControl();
2633 case CSSSelector::PseudoValid: {
2636 e->document()->setContainsValidityStyleRules();
2637 return e->willValidate() && e->isValidFormControlElement();
2638 } case CSSSelector::PseudoInvalid: {
2641 e->document()->setContainsValidityStyleRules();
2642 return (e->willValidate() && !e->isValidFormControlElement()) || e->hasUnacceptableValue();
2643 } case CSSSelector::PseudoChecked: {
2644 if (!e || !e->isFormControlElement())
2646 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
2647 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
2648 // obey the CSS spec here in the test for matching the pseudo.
2649 InputElement* inputElement = toInputElement(e);
2650 if (inputElement && inputElement->isChecked() && !inputElement->isIndeterminate())
2654 case CSSSelector::PseudoIndeterminate: {
2655 if (!e || !e->isFormControlElement())
2657 InputElement* inputElement = toInputElement(e);
2658 if (inputElement && inputElement->isIndeterminate())
2662 case CSSSelector::PseudoRoot:
2663 if (e == e->document()->documentElement())
2666 case CSSSelector::PseudoLang: {
2667 AtomicString value = e->computeInheritedLanguage();
2668 const AtomicString& argument = sel->argument();
2669 if (value.isEmpty() || !value.startsWith(argument, false))
2671 if (value.length() != argument.length() && value[argument.length()] != '-')
2675 #if ENABLE(FULLSCREEN_API)
2676 case CSSSelector::PseudoFullScreen:
2677 // While a Document is in the fullscreen state, and the document's current fullscreen
2678 // element is an element in the document, the 'full-screen' pseudoclass applies to
2679 // that element. Also, an <iframe>, <object> or <embed> element whose child browsing
2680 // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied.
2681 if (!e->document()->webkitIsFullScreen())
2683 if (e != e->document()->webkitCurrentFullScreenElement())
2686 case CSSSelector::PseudoFullScreenDocument:
2687 // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies
2688 // to all elements of that Document.
2689 if (!e->document()->webkitIsFullScreen())
2693 case CSSSelector::PseudoInRange:
2696 e->document()->setContainsValidityStyleRules();
2697 return e->isInRange();
2698 case CSSSelector::PseudoOutOfRange:
2701 e->document()->setContainsValidityStyleRules();
2702 return e->isOutOfRange();
2703 case CSSSelector::PseudoUnknown:
2704 case CSSSelector::PseudoNotParsed:
2706 ASSERT_NOT_REACHED();
2711 if (sel->m_match == CSSSelector::PseudoElement) {
2712 if (!elementStyle && !m_collectRulesOnly)
2715 PseudoId pseudoId = CSSSelector::pseudoId(sel->pseudoType());
2716 if (pseudoId == FIRST_LETTER) {
2717 if (Document* document = e->document())
2718 document->setUsesFirstLetterRules(true);
2720 if (pseudoId != NOPSEUDO)
2721 dynamicPseudo = pseudoId;
2723 // ### add the rest of the checks...
2727 bool CSSStyleSelector::SelectorChecker::checkScrollbarPseudoClass(CSSSelector* sel, PseudoId&) const
2729 RenderScrollbar* scrollbar = RenderScrollbar::scrollbarForStyleResolve();
2730 ScrollbarPart part = RenderScrollbar::partForStyleResolve();
2732 // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real
2733 // pseudo class and just apply to everything.
2734 if (sel->pseudoType() == CSSSelector::PseudoWindowInactive)
2735 return !m_document->page()->focusController()->isActive();
2740 ASSERT(sel->m_match == CSSSelector::PseudoClass);
2741 switch (sel->pseudoType()) {
2742 case CSSSelector::PseudoEnabled:
2743 return scrollbar->enabled();
2744 case CSSSelector::PseudoDisabled:
2745 return !scrollbar->enabled();
2746 case CSSSelector::PseudoHover: {
2747 ScrollbarPart hoveredPart = scrollbar->hoveredPart();
2748 if (part == ScrollbarBGPart)
2749 return hoveredPart != NoPart;
2750 if (part == TrackBGPart)
2751 return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart;
2752 return part == hoveredPart;
2754 case CSSSelector::PseudoActive: {
2755 ScrollbarPart pressedPart = scrollbar->pressedPart();
2756 if (part == ScrollbarBGPart)
2757 return pressedPart != NoPart;
2758 if (part == TrackBGPart)
2759 return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart;
2760 return part == pressedPart;
2762 case CSSSelector::PseudoHorizontal:
2763 return scrollbar->orientation() == HorizontalScrollbar;
2764 case CSSSelector::PseudoVertical:
2765 return scrollbar->orientation() == VerticalScrollbar;
2766 case CSSSelector::PseudoDecrement:
2767 return part == BackButtonStartPart || part == BackButtonEndPart || part == BackTrackPart;
2768 case CSSSelector::PseudoIncrement:
2769 return part == ForwardButtonStartPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
2770 case CSSSelector::PseudoStart:
2771 return part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart;
2772 case CSSSelector::PseudoEnd:
2773 return part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
2774 case CSSSelector::PseudoDoubleButton: {
2775 ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
2776 if (part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart)
2777 return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth;
2778 if (part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart)
2779 return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth;
2782 case CSSSelector::PseudoSingleButton: {
2783 ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
2784 if (part == BackButtonStartPart || part == ForwardButtonEndPart || part == BackTrackPart || part == ForwardTrackPart)
2785 return buttonsPlacement == ScrollbarButtonsSingle;
2788 case CSSSelector::PseudoNoButton: {
2789 ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
2790 if (part == BackTrackPart)
2791 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd;
2792 if (part == ForwardTrackPart)
2793 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart;
2796 case CSSSelector::PseudoCornerPresent:
2797 return scrollbar->client()->scrollbarCornerPresent();
2803 // -----------------------------------------------------------------
2805 CSSRuleSet::CSSRuleSet()
2807 , m_pageRuleCount(0)
2811 CSSRuleSet::~CSSRuleSet()
2813 deleteAllValues(m_idRules);
2814 deleteAllValues(m_classRules);
2815 deleteAllValues(m_tagRules);
2819 void CSSRuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
2820 CSSStyleRule* rule, CSSSelector* sel)
2823 CSSRuleDataList* rules = map.get(key);
2825 rules = new CSSRuleDataList(m_ruleCount++, rule, sel);
2826 map.set(key, rules);
2828 rules->append(m_ruleCount++, rule, sel);
2831 void CSSRuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel)
2833 if (sel->m_match == CSSSelector::Id) {
2834 addToRuleSet(sel->m_value.impl(), m_idRules, rule, sel);
2837 if (sel->m_match == CSSSelector::Class) {
2838 addToRuleSet(sel->m_value.impl(), m_classRules, rule, sel);
2842 if (sel->isUnknownPseudoElement()) {
2843 addToRuleSet(sel->m_value.impl(), m_pseudoRules, rule, sel);
2847 const AtomicString& localName = sel->m_tag.localName();
2848 if (localName != starAtom) {
2849 addToRuleSet(localName.impl(), m_tagRules, rule, sel);
2853 // Just put it in the universal rule set.
2854 if (!m_universalRules)
2855 m_universalRules = adoptPtr(new CSSRuleDataList(m_ruleCount++, rule, sel));
2857 m_universalRules->append(m_ruleCount++, rule, sel);
2860 void CSSRuleSet::addPageRule(CSSStyleRule* rule, CSSSelector* sel)
2863 m_pageRules = adoptPtr(new CSSRuleDataList(m_pageRuleCount++, rule, sel));
2865 m_pageRules->append(m_pageRuleCount++, rule, sel);
2868 void CSSRuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector)
2873 // No media implies "all", but if a media list exists it must
2874 // contain our current medium
2875 if (sheet->media() && !medium.eval(sheet->media(), styleSelector))
2876 return; // the style sheet doesn't apply
2878 int len = sheet->length();
2880 for (int i = 0; i < len; i++) {
2881 StyleBase* item = sheet->item(i);
2882 if (item->isStyleRule())
2883 addStyleRule(static_cast<CSSStyleRule*>(item));
2884 else if (item->isImportRule()) {
2885 CSSImportRule* import = static_cast<CSSImportRule*>(item);
2886 if (!import->media() || medium.eval(import->media(), styleSelector))
2887 addRulesFromSheet(import->styleSheet(), medium, styleSelector);
2889 else if (item->isMediaRule()) {
2890 CSSMediaRule* r = static_cast<CSSMediaRule*>(item);
2891 CSSRuleList* rules = r->cssRules();
2893 if ((!r->media() || medium.eval(r->media(), styleSelector)) && rules) {
2894 // Traverse child elements of the @media rule.
2895 for (unsigned j = 0; j < rules->length(); j++) {
2896 CSSRule *childItem = rules->item(j);
2897 if (childItem->isStyleRule()) {
2898 // It is a StyleRule, so append it to our list
2899 addStyleRule(static_cast<CSSStyleRule*>(childItem));
2900 } else if (childItem->isFontFaceRule() && styleSelector) {
2901 // Add this font face to our set.
2902 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(childItem);
2903 styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
2904 } else if (childItem->isKeyframesRule() && styleSelector) {
2905 // Add this keyframe rule to our set.
2906 styleSelector->addKeyframeStyle(static_cast<WebKitCSSKeyframesRule*>(childItem));
2910 } else if (item->isFontFaceRule() && styleSelector) {
2911 // Add this font face to our set.
2912 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item);
2913 styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
2914 } else if (item->isKeyframesRule())
2915 styleSelector->addKeyframeStyle(static_cast<WebKitCSSKeyframesRule*>(item));
2919 void CSSRuleSet::addStyleRule(CSSStyleRule* rule)
2921 if (rule->isPageRule()) {
2922 CSSPageRule* pageRule = static_cast<CSSPageRule*>(rule);
2923 addPageRule(pageRule, pageRule->selectorList().first());
2925 for (CSSSelector* s = rule->selectorList().first(); s; s = CSSSelectorList::next(s))
2930 // -------------------------------------------------------------------------------------
2931 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
2933 static Length convertToLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1, bool *ok = 0)
2935 // This function is tolerant of a null style value. The only place style is used is in
2936 // length measurements, like 'ems' and 'px'. And in those cases style is only used
2937 // when the units are EMS or EXS. So we will just fail in those cases.
2939 if (!primitiveValue) {
2943 int type = primitiveValue->primitiveType();
2945 if (!style && (type == CSSPrimitiveValue::CSS_EMS || type == CSSPrimitiveValue::CSS_EXS || type == CSSPrimitiveValue::CSS_REMS)) {
2948 } else if (CSSPrimitiveValue::isUnitTypeLength(type))
2949 l = Length(primitiveValue->computeLengthIntForLength(style, rootStyle, multiplier), Fixed);
2950 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2951 l = Length(primitiveValue->getDoubleValue(), Percent);
2952 else if (type == CSSPrimitiveValue::CSS_NUMBER)
2953 l = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
2960 template <bool applyFirst>
2961 void CSSStyleSelector::applyDeclarations(bool isImportant, int startIndex, int endIndex)
2963 if (startIndex == -1)
2966 for (int i = startIndex; i <= endIndex; i++) {
2967 CSSMutableStyleDeclaration* decl = m_matchedDecls[i];
2968 CSSMutableStyleDeclaration::const_iterator end = decl->end();
2969 for (CSSMutableStyleDeclaration::const_iterator it = decl->begin(); it != end; ++it) {
2970 const CSSProperty& current = *it;
2971 if (isImportant == current.isImportant()) {
2972 int property = current.id();
2975 COMPILE_ASSERT(firstCSSProperty == CSSPropertyColor, CSS_color_is_first_property);
2976 COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyColor + 13, CSS_zoom_is_end_of_first_prop_range);
2977 COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyZoom + 1, CSS_line_height_is_after_zoom);
2979 // give special priority to font-xxx, color properties, etc
2980 if (property <= CSSPropertyLineHeight) {
2981 // we apply line-height later
2982 if (property == CSSPropertyLineHeight)
2983 m_lineHeightValue = current.value();
2985 applyProperty(current.id(), current.value());
2988 if (property > CSSPropertyLineHeight)
2989 applyProperty(current.id(), current.value());
2996 void CSSStyleSelector::matchPageRules(CSSRuleSet* rules, bool isLeftPage, bool isFirstPage, const String& pageName)
2998 m_matchedRules.clear();
3003 matchPageRulesForList(rules->getPageRules(), isLeftPage, isFirstPage, pageName);
3005 // If we didn't match any rules, we're done.
3006 if (m_matchedRules.isEmpty())
3009 // Sort the set of matched rules.
3010 sortMatchedRules(0, m_matchedRules.size());
3012 // Now transfer the set of matched rules over to our list of decls.
3013 for (unsigned i = 0; i < m_matchedRules.size(); i++)
3014 addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());
3017 void CSSStyleSelector::matchPageRulesForList(CSSRuleDataList* rules, bool isLeftPage, bool isFirstPage, const String& pageName)
3022 for (CSSRuleData* d = rules->first(); d; d = d->next()) {
3023 CSSStyleRule* rule = d->rule();
3024 const AtomicString& selectorLocalName = d->selector()->m_tag.localName();
3025 if (selectorLocalName != starAtom && selectorLocalName != pageName)
3027 CSSSelector::PseudoType pseudoType = d->selector()->pseudoType();
3028 if ((pseudoType == CSSSelector::PseudoLeftPage && !isLeftPage)
3029 || (pseudoType == CSSSelector::PseudoRightPage && isLeftPage)
3030 || (pseudoType == CSSSelector::PseudoFirstPage && !isFirstPage))
3033 // If the rule has no properties to apply, then ignore it.
3034 CSSMutableStyleDeclaration* decl = rule->declaration();
3035 if (!decl || !decl->length())
3038 // Add this rule to our list of matched rules.
3043 bool CSSStyleSelector::isLeftPage(int pageIndex) const
3045 bool isFirstPageLeft = false;
3046 if (!m_rootElementStyle->isLeftToRightDirection())
3047 isFirstPageLeft = true;
3049 return (pageIndex + (isFirstPageLeft ? 1 : 0)) % 2;
3052 bool CSSStyleSelector::isFirstPage(int pageIndex) const
3054 // FIXME: In case of forced left/right page, page at index 1 (not 0) can be the first page.
3055 return (!pageIndex);
3058 String CSSStyleSelector::pageName(int /* pageIndex */) const
3060 // FIXME: Implement page index to page name mapping.
3064 static void applyCounterList(RenderStyle* style, CSSValueList* list, bool isReset)
3066 CounterDirectiveMap& map = style->accessCounterDirectives();
3067 typedef CounterDirectiveMap::iterator Iterator;
3069 Iterator end = map.end();
3070 for (Iterator it = map.begin(); it != end; ++it)
3072 it->second.m_reset = false;
3074 it->second.m_increment = false;
3076 int length = list ? list->length() : 0;
3077 for (int i = 0; i < length; ++i) {
3078 CSSValue* currValue = list->itemWithoutBoundsCheck(i);
3079 if (!currValue->isPrimitiveValue())
3082 Pair* pair = static_cast<CSSPrimitiveValue*>(currValue)->getPairValue();
3083 if (!pair || !pair->first() || !pair->second())
3086 AtomicString identifier = static_cast<CSSPrimitiveValue*>(pair->first())->getStringValue();
3087 // FIXME: What about overflow?
3088 int value = static_cast<CSSPrimitiveValue*>(pair->second())->getIntValue();
3089 CounterDirectives& directives = map.add(identifier.impl(), CounterDirectives()).first->second;
3091 directives.m_reset = true;
3092 directives.m_resetValue = value;
3094 if (directives.m_increment)
3095 directives.m_incrementValue += value;
3097 directives.m_increment = true;
3098 directives.m_incrementValue = value;
3104 void CSSStyleSelector::applyPropertyToStyle(int id, CSSValue *value, RenderStyle* style)
3107 initForStyleResolve(0, style);
3110 applyProperty(id, value);
3113 inline bool isValidVisitedLinkProperty(int id)
3115 switch(static_cast<CSSPropertyID>(id)) {
3116 case CSSPropertyBackgroundColor:
3117 case CSSPropertyBorderLeftColor:
3118 case CSSPropertyBorderRightColor:
3119 case CSSPropertyBorderTopColor:
3120 case CSSPropertyBorderBottomColor:
3121 case CSSPropertyColor:
3122 case CSSPropertyOutlineColor:
3123 case CSSPropertyWebkitColumnRuleColor:
3124 case CSSPropertyWebkitTextEmphasisColor:
3125 case CSSPropertyWebkitTextFillColor:
3126 case CSSPropertyWebkitTextStrokeColor:
3127 // Also allow shorthands so that inherit/initial still work.
3128 case CSSPropertyBackground:
3129 case CSSPropertyBorderLeft:
3130 case CSSPropertyBorderRight:
3131 case CSSPropertyBorderTop:
3132 case CSSPropertyBorderBottom:
3133 case CSSPropertyOutline:
3134 case CSSPropertyWebkitColumnRule:
3136 case CSSPropertyFill:
3137 case CSSPropertyStroke:
3147 void CSSStyleSelector::applyProperty(int id, CSSValue *value)
3149 CSSPrimitiveValue* primitiveValue = 0;
3150 if (value->isPrimitiveValue())
3151 primitiveValue = static_cast<CSSPrimitiveValue*>(value);
3153 float zoomFactor = m_style->effectiveZoom();
3155 // SVG handles zooming in a different way compared to CSS. The whole document is scaled instead
3156 // of each individual length value in the render style / tree. CSSPrimitiveValue::computeLength*()
3157 // multiplies each resolved length with the zoom multiplier - so for SVG we need to disable that.
3158 // Though all CSS values that can be applied to outermost <svg> elements (width/height/border/padding...)
3159 // need to respect the scaling. RenderBox (the parent class of RenderSVGRoot) grabs values like
3160 // width/height/border/padding/... from the RenderStyle -> for SVG these values would never scale,
3161 // if we'd pass a 1.0 zoom factor everyhwere. So we only pass a zoom factor of 1.0 for specific
3162 // properties that are NOT allowed to scale within a zoomed SVG document (letter/word-spacing/font-size).
3163 bool useSVGZoomRules = m_element && m_element->isSVGElement();
3168 unsigned short valueType = value->cssValueType();
3170 bool isInherit = m_parentNode && valueType == CSSValue::CSS_INHERIT;
3171 bool isInitial = valueType == CSSValue::CSS_INITIAL || (!m_parentNode && valueType == CSSValue::CSS_INHERIT);
3173 id = CSSProperty::resolveDirectionAwareProperty(id, m_style->direction(), m_style->writingMode());
3175 if (m_checker.m_matchVisitedPseudoClass && !isValidVisitedLinkProperty(id)) {
3176 // Limit the properties that can be applied to only the ones honored by :visited.
3180 // What follows is a list that maps the CSS properties into their corresponding front-end
3181 // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and
3182 // are only hit when mapping "inherit" or "initial" into front-end values.
3183 CSSPropertyID property = static_cast<CSSPropertyID>(id);
3185 // ident only properties
3186 case CSSPropertyBackgroundAttachment:
3187 HANDLE_BACKGROUND_VALUE(attachment, Attachment, value)
3189 case CSSPropertyBackgroundClip:
3190 case CSSPropertyWebkitBackgroundClip:
3191 HANDLE_BACKGROUND_VALUE(clip, Clip, value)
3193 case CSSPropertyWebkitBackgroundComposite:
3194 HANDLE_BACKGROUND_VALUE(composite, Composite, value)
3196 case CSSPropertyBackgroundOrigin:
3197 case CSSPropertyWebkitBackgroundOrigin:
3198 HANDLE_BACKGROUND_VALUE(origin, Origin, value)
3200 case CSSPropertyBackgroundSize:
3201 case CSSPropertyWebkitBackgroundSize:
3202 HANDLE_BACKGROUND_VALUE(size, Size, value)
3204 case CSSPropertyWebkitMaskAttachment:
3205 HANDLE_MASK_VALUE(attachment, Attachment, value)
3207 case CSSPropertyWebkitMaskClip:
3208 HANDLE_MASK_VALUE(clip, Clip, value)
3210 case CSSPropertyWebkitMaskComposite:
3211 HANDLE_MASK_VALUE(composite, Composite, value)
3213 case CSSPropertyWebkitMaskOrigin:
3214 HANDLE_MASK_VALUE(origin, Origin, value)
3216 case CSSPropertyWebkitMaskSize:
3217 HANDLE_MASK_VALUE(size, Size, value)
3219 case CSSPropertyBorderCollapse:
3220 HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse)
3221 if (!primitiveValue)
3223 switch (primitiveValue->getIdent()) {
3224 case CSSValueCollapse:
3225 m_style->setBorderCollapse(true);
3227 case CSSValueSeparate:
3228 m_style->setBorderCollapse(false);
3234 case CSSPropertyBorderTopStyle:
3235 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(borderTopStyle, BorderTopStyle, BorderStyle)
3237 case CSSPropertyBorderRightStyle:
3238 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(borderRightStyle, BorderRightStyle, BorderStyle)
3240 case CSSPropertyBorderBottomStyle:
3241 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(borderBottomStyle, BorderBottomStyle, BorderStyle)
3243 case CSSPropertyBorderLeftStyle:
3244 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(borderLeftStyle, BorderLeftStyle, BorderStyle)
3246 case CSSPropertyOutlineStyle:
3247 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle)
3248 if (primitiveValue) {
3249 if (primitiveValue->getIdent() == CSSValueAuto)
3250 m_style->setOutlineStyle(DOTTED, true);
3252 m_style->setOutlineStyle(*primitiveValue);
3255 case CSSPropertyCaptionSide:
3256 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(captionSide, CaptionSide)
3258 case CSSPropertyClear:
3259 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(clear, Clear)
3261 case CSSPropertyDirection:
3262 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(direction, Direction)
3263 if (!isInherit && !isInitial && m_element && m_element == m_element->document()->documentElement())
3264 m_element->document()->setDirectionSetOnDocumentElement(true);
3266 case CSSPropertyDisplay:
3267 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(display, Display)
3269 if (primitiveValue) {
3270 if (primitiveValue->getIdent() == CSSValueWapMarquee) {
3271 // Initialize WAP Marquee style
3272 m_style->setOverflowX(OMARQUEE);
3273 m_style->setOverflowY(OMARQUEE);
3274 m_style->setWhiteSpace(NOWRAP);
3275 m_style->setMarqueeDirection(MLEFT);
3276 m_style->setMarqueeSpeed(85); // Normal speed
3277 m_style->setMarqueeLoopCount(1);
3278 m_style->setMarqueeBehavior(MSCROLL);
3281 m_style->setDisplay(m_parentStyle->display());
3283 m_style->setDisplay(*primitiveValue);
3285 m_style->setDisplay(*primitiveValue);
3289 case CSSPropertyEmptyCells:
3290 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(emptyCells, EmptyCells)
3292 case CSSPropertyFloat:
3293 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(floating, Floating)
3295 case CSSPropertyFontStyle:
3297 FontDescription fontDescription = m_style->fontDescription();
3299 fontDescription.setItalic(m_parentStyle->fontDescription().italic());
3301 fontDescription.setItalic(false);
3303 if (!primitiveValue)
3305 switch (primitiveValue->getIdent()) {
3306 case CSSValueOblique:
3307 // FIXME: oblique is the same as italic for the moment...
3308 case CSSValueItalic:
3309 fontDescription.setItalic(true);
3311 case CSSValueNormal:
3312 fontDescription.setItalic(false);
3318 if (m_style->setFontDescription(fontDescription))
3323 case CSSPropertyFontVariant:
3325 FontDescription fontDescription = m_style->fontDescription();
3327 fontDescription.setSmallCaps(m_parentStyle->fontDescription().smallCaps());
3329 fontDescription.setSmallCaps(false);
3331 if (!primitiveValue)
3333 int id = primitiveValue->getIdent();
3334 if (id == CSSValueNormal)
3335 fontDescription.setSmallCaps(false);
3336 else if (id == CSSValueSmallCaps)
3337 fontDescription.setSmallCaps(true);
3341 if (m_style->setFontDescription(fontDescription))
3346 case CSSPropertyFontWeight:
3348 FontDescription fontDescription = m_style->fontDescription();
3350 fontDescription.setWeight(m_parentStyle->fontDescription().weight());
3352 fontDescription.setWeight(FontWeightNormal);
3354 if (!primitiveValue)
3356 if (primitiveValue->getIdent()) {
3357 switch (primitiveValue->getIdent()) {
3358 case CSSValueBolder:
3359 fontDescription.setWeight(fontDescription.bolderWeight());
3361 case CSSValueLighter:
3362 fontDescription.setWeight(fontDescription.lighterWeight());
3366 fontDescription.setWeight(FontWeightBold);
3368 case CSSValueNormal:
3370 fontDescription.setWeight(FontWeightNormal);
3373 fontDescription.setWeight(FontWeight900);
3376 fontDescription.setWeight(FontWeight800);
3379 fontDescription.setWeight(FontWeight600);
3382 fontDescription.setWeight(FontWeight500);
3385 fontDescription.setWeight(FontWeight300);
3388 fontDescription.setWeight(FontWeight200);
3391 fontDescription.setWeight(FontWeight100);
3397 ASSERT_NOT_REACHED();
3399 if (m_style->setFontDescription(fontDescription))
3404 case CSSPropertyListStylePosition:
3405 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(listStylePosition, ListStylePosition)
3407 case CSSPropertyListStyleType:
3408 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(listStyleType, ListStyleType)
3410 case CSSPropertyOverflow:
3413 m_style->setOverflowX(m_parentStyle->overflowX());
3414 m_style->setOverflowY(m_parentStyle->overflowY());
3419 m_style->setOverflowX(RenderStyle::initialOverflowX());
3420 m_style->setOverflowY(RenderStyle::initialOverflowY());
3424 EOverflow o = *primitiveValue;
3426 m_style->setOverflowX(o);
3427 m_style->setOverflowY(o);
3431 case CSSPropertyOverflowX:
3432 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(overflowX, OverflowX)
3434 case CSSPropertyOverflowY:
3435 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(overflowY, OverflowY)
3437 case CSSPropertyPageBreakBefore:
3438 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak)
3440 case CSSPropertyPageBreakAfter:
3441 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak)
3443 case CSSPropertyPageBreakInside: {
3444 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak)
3445 if (!primitiveValue)
3447 EPageBreak pageBreak = *primitiveValue;
3448 if (pageBreak != PBALWAYS)
3449 m_style->setPageBreakInside(pageBreak);
3453 case CSSPropertyPosition:
3454 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(position, Position)
3456 case CSSPropertyTableLayout: {
3457 HANDLE_INHERIT_AND_INITIAL(tableLayout, TableLayout)
3459 ETableLayout l = *primitiveValue;
3461 l = RenderStyle::initialTableLayout();
3463 m_style->setTableLayout(l);
3467 case CSSPropertyUnicodeBidi:
3468 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(unicodeBidi, UnicodeBidi)
3470 case CSSPropertyTextTransform:
3471 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textTransform, TextTransform)
3473 case CSSPropertyVisibility:
3474 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(visibility, Visibility)
3476 case CSSPropertyWhiteSpace:
3477 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(whiteSpace, WhiteSpace)
3480 case CSSPropertyBackgroundPosition:
3481 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(xPosition, XPosition);
3482 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(yPosition, YPosition);
3484 case CSSPropertyBackgroundPositionX: {
3485 HANDLE_BACKGROUND_VALUE(xPosition, XPosition, value)
3488 case CSSPropertyBackgroundPositionY: {
3489 HANDLE_BACKGROUND_VALUE(yPosition, YPosition, value)
3492 case CSSPropertyWebkitMaskPosition:
3493 HANDLE_MASK_INHERIT_AND_INITIAL(xPosition, XPosition);
3494 HANDLE_MASK_INHERIT_AND_INITIAL(yPosition, YPosition);
3496 case CSSPropertyWebkitMaskPositionX: {
3497 HANDLE_MASK_VALUE(xPosition, XPosition, value)
3500 case CSSPropertyWebkitMaskPositionY: {
3501 HANDLE_MASK_VALUE(yPosition, YPosition, value)
3504 case CSSPropertyBackgroundRepeat:
3505 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(repeatX, RepeatX);
3506 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(repeatY, RepeatY);
3508 case CSSPropertyBackgroundRepeatX:
3509 HANDLE_BACKGROUND_VALUE(repeatX, RepeatX, value)
3511 case CSSPropertyBackgroundRepeatY:
3512 HANDLE_BACKGROUND_VALUE(repeatY, RepeatY, value)
3514 case CSSPropertyWebkitMaskRepeat:
3515 HANDLE_MASK_INHERIT_AND_INITIAL(repeatX, RepeatX);
3516 HANDLE_MASK_INHERIT_AND_INITIAL(repeatY, RepeatY);
3518 case CSSPropertyWebkitMaskRepeatX:
3519 HANDLE_MASK_VALUE(repeatX, RepeatX, value)
3521 case CSSPropertyWebkitMaskRepeatY:
3522 HANDLE_MASK_VALUE(repeatY, RepeatY, value)
3524 case CSSPropertyBorderSpacing: {
3526 m_style->setHorizontalBorderSpacing(m_parentStyle->horizontalBorderSpacing());
3527 m_style->setVerticalBorderSpacing(m_parentStyle->verticalBorderSpacing());
3529 else if (isInitial) {
3530 m_style->setHorizontalBorderSpacing(0);
3531 m_style->setVerticalBorderSpacing(0);
3535 case CSSPropertyWebkitBorderHorizontalSpacing: {
3536 HANDLE_INHERIT_AND_INITIAL(horizontalBorderSpacing, HorizontalBorderSpacing)
3537 if (!primitiveValue)
3539 short spacing = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor);
3540 m_style->setHorizontalBorderSpacing(spacing);
3543 case CSSPropertyWebkitBorderVerticalSpacing: {
3544 HANDLE_INHERIT_AND_INITIAL(verticalBorderSpacing, VerticalBorderSpacing)
3545 if (!primitiveValue)
3547 short spacing = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor);
3548 m_style->setVerticalBorderSpacing(spacing);
3551 case CSSPropertyCursor:
3553 m_style->setCursor(m_parentStyle->cursor());
3554 m_style->setCursorList(m_parentStyle->cursors());
3557 m_style->clearCursorList();
3559 m_style->setCursor(RenderStyle::initialCursor());
3562 if (value->isValueList()) {
3563 CSSValueList* list = static_cast<CSSValueList*>(value);
3564 int len = list->length();
3565 m_style->setCursor(CURSOR_AUTO);
3566 for (int i = 0; i < len; i++) {
3567 CSSValue* item = list->itemWithoutBoundsCheck(i);
3568 if (!item->isPrimitiveValue())
3570 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
3571 int type = primitiveValue->primitiveType();
3572 if (type == CSSPrimitiveValue::CSS_URI) {
3573 if (primitiveValue->isCursorImageValue()) {
3574 CSSCursorImageValue* image = static_cast<CSSCursorImageValue*>(primitiveValue);
3575 if (image->updateIfSVGCursorIsUsed(m_element)) // Elements with SVG cursors are not allowed to share style.
3576 m_style->setUnique();
3577 m_style->addCursor(cachedOrPendingFromValue(CSSPropertyCursor, image), image->hotSpot());
3579 } else if (type == CSSPrimitiveValue::CSS_IDENT)
3580 m_style->setCursor(*primitiveValue);
3582 } else if (primitiveValue) {
3583 int type = primitiveValue->primitiveType();
3584 if (type == CSSPrimitiveValue::CSS_IDENT && m_style->cursor() != ECursor(*primitiveValue))
3585 m_style->setCursor(*primitiveValue);
3588 // colors || inherit
3589 case CSSPropertyColor:
3590 // If the 'currentColor' keyword is set on the 'color' property itself,
3591 // it is treated as 'color:inherit' at parse time
3592 if (primitiveValue && primitiveValue->getIdent() == CSSValueCurrentcolor)
3594 case CSSPropertyBackgroundColor:
3595 case CSSPropertyBorderTopColor:
3596 case CSSPropertyBorderRightColor:
3597 case CSSPropertyBorderBottomColor:
3598 case CSSPropertyBorderLeftColor:
3599 case CSSPropertyOutlineColor:
3600 case CSSPropertyWebkitColumnRuleColor:
3601 case CSSPropertyWebkitTextStrokeColor:
3602 case CSSPropertyWebkitTextEmphasisColor:
3603 case CSSPropertyWebkitTextFillColor: {
3606 HANDLE_INHERIT_COND(CSSPropertyBackgroundColor, backgroundColor, BackgroundColor)
3607 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderTopColor, borderTopColor, color, BorderTopColor)
3608 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderBottomColor, borderBottomColor, color, BorderBottomColor)
3609 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderRightColor, borderRightColor, color, BorderRightColor)
3610 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderLeftColor, borderLeftColor, color, BorderLeftColor)
3611 HANDLE_INHERIT_COND(CSSPropertyColor, color, Color)
3612 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyOutlineColor, outlineColor, color, OutlineColor)
3613 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitColumnRuleColor, columnRuleColor, color, ColumnRuleColor)
3614 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitTextStrokeColor, textStrokeColor, color, TextStrokeColor)
3615 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitTextEmphasisColor, textEmphasisColor, color, TextEmphasisColor)
3616 HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitTextFillColor, textFillColor, color, TextFillColor)
3620 // The border/outline colors will just map to the invalid color |col| above. This will have the
3621 // effect of forcing the use of the currentColor when it comes time to draw the borders (and of
3622 // not painting the background since the color won't be valid).
3623 if (id == CSSPropertyColor)
3624 col = RenderStyle::initialColor();
3626 if (!primitiveValue)
3628 col = getColorFromPrimitiveValue(primitiveValue);
3632 case CSSPropertyBackgroundColor:
3633 m_style->setBackgroundColor(col);
3635 case CSSPropertyBorderTopColor:
3636 m_style->setBorderTopColor(col);
3638 case CSSPropertyBorderRightColor:
3639 m_style->setBorderRightColor(col);
3641 case CSSPropertyBorderBottomColor:
3642 m_style->setBorderBottomColor(col);
3644 case CSSPropertyBorderLeftColor:
3645 m_style->setBorderLeftColor(col);
3647 case CSSPropertyColor:
3648 m_style->setColor(col);
3650 case CSSPropertyOutlineColor:
3651 m_style->setOutlineColor(col);
3653 case CSSPropertyWebkitColumnRuleColor:
3654 m_style->setColumnRuleColor(col);
3656 case CSSPropertyWebkitTextStrokeColor:
3657 m_style->setTextStrokeColor(col);
3659 case CSSPropertyWebkitTextEmphasisColor:
3660 m_style->setTextEmphasisColor(col);
3662 case CSSPropertyWebkitTextFillColor:
3663 m_style->setTextFillColor(col);
3671 case CSSPropertyBackgroundImage:
3672 HANDLE_BACKGROUND_VALUE(image, Image, value)
3674 case CSSPropertyWebkitMaskImage:
3675 HANDLE_MASK_VALUE(image, Image, value)
3677 case CSSPropertyListStyleImage:
3679 HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage)
3680 m_style->setListStyleImage(styleImage(CSSPropertyListStyleImage, value));
3685 case CSSPropertyBorderTopWidth:
3686 case CSSPropertyBorderRightWidth:
3687 case CSSPropertyBorderBottomWidth:
3688 case CSSPropertyBorderLeftWidth:
3689 case CSSPropertyOutlineWidth:
3690 case CSSPropertyWebkitColumnRuleWidth:
3693 HANDLE_INHERIT_COND(CSSPropertyBorderTopWidth, borderTopWidth, BorderTopWidth)
3694 HANDLE_INHERIT_COND(CSSPropertyBorderRightWidth, borderRightWidth, BorderRightWidth)
3695 HANDLE_INHERIT_COND(CSSPropertyBorderBottomWidth, borderBottomWidth, BorderBottomWidth)
3696 HANDLE_INHERIT_COND(CSSPropertyBorderLeftWidth, borderLeftWidth, BorderLeftWidth)
3697 HANDLE_INHERIT_COND(CSSPropertyOutlineWidth, outlineWidth, OutlineWidth)
3698 HANDLE_INHERIT_COND(CSSPropertyWebkitColumnRuleWidth, columnRuleWidth, ColumnRuleWidth)
3701 else if (isInitial) {
3702 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderTopWidth, BorderTopWidth, BorderWidth)
3703 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderRightWidth, BorderRightWidth, BorderWidth)
3704 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderBottomWidth, BorderBottomWidth, BorderWidth)
3705 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderLeftWidth, BorderLeftWidth, BorderWidth)
3706 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyOutlineWidth, OutlineWidth, BorderWidth)
3707 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitColumnRuleWidth, ColumnRuleWidth, BorderWidth)
3711 if (!primitiveValue)
3714 switch (primitiveValue->getIdent()) {
3718 case CSSValueMedium:
3724 case CSSValueInvalid:
3725 width = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor);
3731 if (width < 0) return;
3733 case CSSPropertyBorderTopWidth:
3734 m_style->setBorderTopWidth(width);
3736 case CSSPropertyBorderRightWidth:
3737 m_style->setBorderRightWidth(width);
3739 case CSSPropertyBorderBottomWidth:
3740 m_style->setBorderBottomWidth(width);
3742 case CSSPropertyBorderLeftWidth:
3743 m_style->setBorderLeftWidth(width);
3745 case CSSPropertyOutlineWidth:
3746 m_style->setOutlineWidth(width);
3748 case CSSPropertyWebkitColumnRuleWidth:
3749 m_style->setColumnRuleWidth(width);
3757 case CSSPropertyWebkitFontSmoothing: {
3758 FontDescription fontDescription = m_style->fontDescription();
3760 fontDescription.setFontSmoothing(m_parentStyle->fontDescription().fontSmoothing());
3762 fontDescription.setFontSmoothing(AutoSmoothing);
3764 if (!primitiveValue)
3766 int id = primitiveValue->getIdent();
3767 FontSmoothingMode smoothing;
3770 smoothing = AutoSmoothing;
3773 smoothing = NoSmoothing;
3775 case CSSValueAntialiased:
3776 smoothing = Antialiased;
3778 case CSSValueSubpixelAntialiased:
3779 smoothing = SubpixelAntialiased;
3782 ASSERT_NOT_REACHED();
3783 smoothing = AutoSmoothing;
3785 fontDescription.setFontSmoothing(smoothing);
3787 if (m_style->setFontDescription(fontDescription))
3792 case CSSPropertyLetterSpacing:
3793 case CSSPropertyWordSpacing: