1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde (at) carewolf.com) 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit (at) nickshanks.com) 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 6 * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org> 7 * Copyright (C) 2007, 2008 Eric Seidel <eric (at) webkit.org> 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Library General Public 13 * License as published by the Free Software Foundation; either 14 * version 2 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Library General Public License for more details. 20 * 21 * You should have received a copy of the GNU Library General Public License 22 * along with this library; see the file COPYING.LIB. If not, write to 23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 * Boston, MA 02110-1301, USA. 25 */ 26 27 #include "config.h" 28 #include "CSSStyleSelector.h" 29 30 #include "Attribute.h" 31 #include "ContentData.h" 32 #include "CounterContent.h" 33 #include "CursorList.h" 34 #include "CSSBorderImageValue.h" 35 #include "CSSCursorImageValue.h" 36 #include "CSSFontFaceRule.h" 37 #include "CSSImportRule.h" 38 #include "CSSLineBoxContainValue.h" 39 #include "CSSMediaRule.h" 40 #include "CSSPageRule.h" 41 #include "CSSParser.h" 42 #include "CSSPrimitiveValueMappings.h" 43 #include "CSSPropertyNames.h" 44 #include "CSSReflectValue.h" 45 #include "CSSRuleList.h" 46 #include "CSSSelector.h" 47 #include "CSSSelectorList.h" 48 #include "CSSStyleApplyProperty.h" 49 #include "CSSStyleRule.h" 50 #include "CSSStyleSheet.h" 51 #include "CSSTimingFunctionValue.h" 52 #include "CSSValueList.h" 53 #include "CachedImage.h" 54 #include "Counter.h" 55 #include "FocusController.h" 56 #include "FontFamilyValue.h" 57 #include "FontValue.h" 58 #include "Frame.h" 59 #include "FrameView.h" 60 #include "HTMLDocument.h" 61 #include "HTMLElement.h" 62 #include "HTMLInputElement.h" 63 #include "HTMLNames.h" 64 #include "HTMLTextAreaElement.h" 65 #include "KeyframeList.h" 66 #include "LinkHash.h" 67 #include "Matrix3DTransformOperation.h" 68 #include "MatrixTransformOperation.h" 69 #include "MediaList.h" 70 #include "MediaQueryEvaluator.h" 71 #include "NodeRenderStyle.h" 72 #include "Page.h" 73 #include "PageGroup.h" 74 #include "Pair.h" 75 #include "PerspectiveTransformOperation.h" 76 #include "QuotesData.h" 77 #include "Rect.h" 78 #include "RenderScrollbar.h" 79 #include "RenderScrollbarTheme.h" 80 #include "RenderStyleConstants.h" 81 #include "RenderTheme.h" 82 #include "RotateTransformOperation.h" 83 #include "ScaleTransformOperation.h" 84 #include "SelectionController.h" 85 #include "Settings.h" 86 #include "ShadowData.h" 87 #include "ShadowValue.h" 88 #include "SkewTransformOperation.h" 89 #include "StyleCachedImage.h" 90 #include "StylePendingImage.h" 91 #include "StyleGeneratedImage.h" 92 #include "StyleSheetList.h" 93 #include "Text.h" 94 #include "TransformationMatrix.h" 95 #include "TranslateTransformOperation.h" 96 #include "UserAgentStyleSheets.h" 97 #include "WebKitCSSKeyframeRule.h" 98 #include "WebKitCSSKeyframesRule.h" 99 #include "WebKitCSSTransformValue.h" 100 #include "XMLNames.h" 101 #include <wtf/StdLibExtras.h> 102 #include <wtf/Vector.h> 103 104 #if USE(PLATFORM_STRATEGIES) 105 #include "PlatformStrategies.h" 106 #include "VisitedLinkStrategy.h" 107 #endif 108 109 #if ENABLE(DASHBOARD_SUPPORT) 110 #include "DashboardRegion.h" 111 #endif 112 113 #if ENABLE(SVG) 114 #include "XLinkNames.h" 115 #include "SVGNames.h" 116 #endif 117 118 #if ENABLE(WML) 119 #include "WMLNames.h" 120 #endif 121 122 #if PLATFORM(QT) 123 #include <qwebhistoryinterface.h> 124 #endif 125 126 using namespace std; 127 128 namespace WebCore { 129 130 using namespace HTMLNames; 131 132 #define HANDLE_INHERIT(prop, Prop) \ 133 if (isInherit) { \ 134 m_style->set##Prop(m_parentStyle->prop()); \ 135 return; \ 136 } 137 138 #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ 139 HANDLE_INHERIT(prop, Prop) \ 140 if (isInitial) { \ 141 m_style->set##Prop(RenderStyle::initial##Prop()); \ 142 return; \ 143 } 144 145 #define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \ 146 HANDLE_INHERIT(prop, Prop) \ 147 if (isInitial) { \ 148 m_style->set##Prop(RenderStyle::initial##Value());\ 149 return;\ 150 } 151 152 #define HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(prop, Prop) \ 153 HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ 154 if (primitiveValue) \ 155 m_style->set##Prop(*primitiveValue); 156 157 #define HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(prop, Prop, Value) \ 158 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \ 159 if (primitiveValue) \ 160 m_style->set##Prop(*primitiveValue); 161 162 #define HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \ 163 if (isInherit) { \ 164 AnimationList* list = m_style->accessAnimations(); \ 165 const AnimationList* parentList = m_parentStyle->animations(); \ 166 size_t i = 0, parentSize = parentList ? parentList->size() : 0; \ 167 for ( ; i < parentSize && parentList->animation(i)->is##Prop##Set(); ++i) { \ 168 if (list->size() <= i) \ 169 list->append(Animation::create()); \ 170 list->animation(i)->set##Prop(parentList->animation(i)->prop()); \ 171 } \ 172 \ 173 /* Reset any remaining animations to not have the property set. */ \ 174 for ( ; i < list->size(); ++i) \ 175 list->animation(i)->clear##Prop(); \ 176 } else if (isInitial) { \ 177 AnimationList* list = m_style->accessAnimations(); \ 178 if (list->isEmpty()) \ 179 list->append(Animation::create()); \ 180 list->animation(0)->set##Prop(Animation::initialAnimation##Prop()); \ 181 for (size_t i = 1; i < list->size(); ++i) \ 182 list->animation(0)->clear##Prop(); \ 183 } 184 185 #define HANDLE_ANIMATION_VALUE(prop, Prop, value) { \ 186 HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \ 187 if (isInherit || isInitial) \ 188 return; \ 189 AnimationList* list = m_style->accessAnimations(); \ 190 size_t childIndex = 0; \ 191 if (value->isValueList()) { \ 192 /* Walk each value and put it into an animation, creating new animations as needed. */ \ 193 CSSValueList* valueList = static_cast<CSSValueList*>(value); \ 194 for (unsigned int i = 0; i < valueList->length(); i++) { \ 195 if (childIndex <= list->size()) \ 196 list->append(Animation::create()); \ 197 mapAnimation##Prop(list->animation(childIndex), valueList->itemWithoutBoundsCheck(i)); \ 198 ++childIndex; \ 199 } \ 200 } else { \ 201 if (list->isEmpty()) \ 202 list->append(Animation::create()); \ 203 mapAnimation##Prop(list->animation(childIndex), value); \ 204 childIndex = 1; \ 205 } \ 206 for ( ; childIndex < list->size(); ++childIndex) { \ 207 /* Reset all remaining animations to not have the property set. */ \ 208 list->animation(childIndex)->clear##Prop(); \ 209 } \ 210 } 211 212 #define HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \ 213 if (isInherit) { \ 214 AnimationList* list = m_style->accessTransitions(); \ 215 const AnimationList* parentList = m_parentStyle->transitions(); \ 216 size_t i = 0, parentSize = parentList ? parentList->size() : 0; \ 217 for ( ; i < parentSize && parentList->animation(i)->is##Prop##Set(); ++i) { \ 218 if (list->size() <= i) \ 219 list->append(Animation::create()); \ 220 list->animation(i)->set##Prop(parentList->animation(i)->prop()); \ 221 } \ 222 \ 223 /* Reset any remaining transitions to not have the property set. */ \ 224 for ( ; i < list->size(); ++i) \ 225 list->animation(i)->clear##Prop(); \ 226 } else if (isInitial) { \ 227 AnimationList* list = m_style->accessTransitions(); \ 228 if (list->isEmpty()) \ 229 list->append(Animation::create()); \ 230 list->animation(0)->set##Prop(Animation::initialAnimation##Prop()); \ 231 for (size_t i = 1; i < list->size(); ++i) \ 232 list->animation(0)->clear##Prop(); \ 233 } 234 235 #define HANDLE_TRANSITION_VALUE(prop, Prop, value) { \ 236 HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \ 237 if (isInherit || isInitial) \ 238 return; \ 239 AnimationList* list = m_style->accessTransitions(); \ 240 size_t childIndex = 0; \ 241 if (value->isValueList()) { \ 242 /* Walk each value and put it into a transition, creating new animations as needed. */ \ 243 CSSValueList* valueList = static_cast<CSSValueList*>(value); \ 244 for (unsigned int i = 0; i < valueList->length(); i++) { \ 245 if (childIndex <= list->size()) \ 246 list->append(Animation::create()); \ 247 mapAnimation##Prop(list->animation(childIndex), valueList->itemWithoutBoundsCheck(i)); \ 248 ++childIndex; \ 249 } \ 250 } else { \ 251 if (list->isEmpty()) \ 252 list->append(Animation::create()); \ 253 mapAnimation##Prop(list->animation(childIndex), value); \ 254 childIndex = 1; \ 255 } \ 256 for ( ; childIndex < list->size(); ++childIndex) { \ 257 /* Reset all remaining transitions to not have the property set. */ \ 258 list->animation(childIndex)->clear##Prop(); \ 259 } \ 260 } 261 262 #define HANDLE_INHERIT_COND(propID, prop, Prop) \ 263 if (id == propID) { \ 264 m_style->set##Prop(m_parentStyle->prop()); \ 265 return; \ 266 } 267 268 #define HANDLE_INHERIT_COND_WITH_BACKUP(propID, prop, propAlt, Prop) \ 269 if (id == propID) { \ 270 if (m_parentStyle->prop().isValid()) \ 271 m_style->set##Prop(m_parentStyle->prop()); \ 272 else \ 273 m_style->set##Prop(m_parentStyle->propAlt()); \ 274 return; \ 275 } 276 277 #define HANDLE_INITIAL_COND(propID, Prop) \ 278 if (id == propID) { \ 279 m_style->set##Prop(RenderStyle::initial##Prop()); \ 280 return; \ 281 } 282 283 #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \ 284 if (id == propID) { \ 285 m_style->set##Prop(RenderStyle::initial##Value()); \ 286 return; \ 287 } 288 289 class RuleData { 290 public: 291 RuleData(CSSStyleRule*, CSSSelector*, unsigned position); 292 293 unsigned position() const { return m_position; } 294 CSSStyleRule* rule() const { return m_rule; } 295 CSSSelector* selector() const { return m_selector; } 296 297 bool hasFastCheckableSelector() const { return m_hasFastCheckableSelector; } 298 bool hasMultipartSelector() const { return m_hasMultipartSelector; } 299 bool hasTopSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasTopSelectorMatchingHTMLBasedOnRuleHash; } 300 unsigned specificity() const { return m_specificity; } 301 302 // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance. 303 static const unsigned maximumIdentifierCount = 4; 304 const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; } 305 306 private: 307 void collectDescendantSelectorIdentifierHashes(); 308 void collectIdentifierHashes(const CSSSelector*, unsigned& identifierCount); 309 310 CSSStyleRule* m_rule; 311 CSSSelector* m_selector; 312 unsigned m_specificity; 313 unsigned m_position : 29; 314 bool m_hasFastCheckableSelector : 1; 315 bool m_hasMultipartSelector : 1; 316 bool m_hasTopSelectorMatchingHTMLBasedOnRuleHash : 1; 317 // Use plain array instead of a Vector to minimize memory overhead. 318 unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount]; 319 }; 320 321 class RuleSet { 322 WTF_MAKE_NONCOPYABLE(RuleSet); 323 public: 324 RuleSet(); 325 ~RuleSet(); 326 327 typedef HashMap<AtomicStringImpl*, Vector<RuleData>*> AtomRuleMap; 328 329 void addRulesFromSheet(CSSStyleSheet*, const MediaQueryEvaluator&, CSSStyleSelector* = 0); 330 331 void addStyleRule(CSSStyleRule* item); 332 void addRule(CSSStyleRule* rule, CSSSelector* sel); 333 void addPageRule(CSSStyleRule* rule, CSSSelector* sel); 334 void addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, 335 CSSStyleRule* rule, CSSSelector* sel); 336 void shrinkToFit(); 337 void disableAutoShrinkToFit() { m_autoShrinkToFitEnabled = false; } 338 339 void collectFeatures(CSSStyleSelector::Features&) const; 340 341 const Vector<RuleData>* getIDRules(AtomicStringImpl* key) const { return m_idRules.get(key); } 342 const Vector<RuleData>* getClassRules(AtomicStringImpl* key) const { return m_classRules.get(key); } 343 const Vector<RuleData>* getTagRules(AtomicStringImpl* key) const { return m_tagRules.get(key); } 344 const Vector<RuleData>* getPseudoRules(AtomicStringImpl* key) const { return m_pseudoRules.get(key); } 345 const Vector<RuleData>* getUniversalRules() const { return &m_universalRules; } 346 const Vector<RuleData>* getPageRules() const { return &m_pageRules; } 347 348 public: 349 AtomRuleMap m_idRules; 350 AtomRuleMap m_classRules; 351 AtomRuleMap m_tagRules; 352 AtomRuleMap m_pseudoRules; 353 Vector<RuleData> m_universalRules; 354 Vector<RuleData> m_pageRules; 355 unsigned m_ruleCount; 356 bool m_autoShrinkToFitEnabled; 357 }; 358 359 static RuleSet* defaultStyle; 360 static RuleSet* defaultQuirksStyle; 361 static RuleSet* defaultPrintStyle; 362 static RuleSet* defaultViewSourceStyle; 363 static CSSStyleSheet* simpleDefaultStyleSheet; 364 365 static RuleSet* siblingRulesInDefaultStyle; 366 367 RenderStyle* CSSStyleSelector::s_styleNotYetAvailable; 368 369 static void loadFullDefaultStyle(); 370 static void loadSimpleDefaultStyle(); 371 // FIXME: It would be nice to use some mechanism that guarantees this is in sync with the real UA stylesheet. 372 static const char* simpleUserAgentStyleSheet = "html,body,div{display:block}head{display:none}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}"; 373 374 static inline bool elementCanUseSimpleDefaultStyle(Element* e) 375 { 376 return e->hasTagName(htmlTag) || e->hasTagName(headTag) || e->hasTagName(bodyTag) || e->hasTagName(divTag) || e->hasTagName(spanTag) || e->hasTagName(brTag) || e->hasTagName(aTag); 377 } 378 379 static inline void collectSiblingRulesInDefaultStyle() 380 { 381 CSSStyleSelector::Features features; 382 defaultStyle->collectFeatures(features); 383 ASSERT(features.idsInRules.isEmpty()); 384 delete siblingRulesInDefaultStyle; 385 siblingRulesInDefaultStyle = features.siblingRules.leakPtr(); 386 } 387 388 static inline void assertNoSiblingRulesInDefaultStyle() 389 { 390 #ifndef NDEBUG 391 if (siblingRulesInDefaultStyle) 392 return; 393 collectSiblingRulesInDefaultStyle(); 394 ASSERT(!siblingRulesInDefaultStyle); 395 #endif 396 } 397 398 static const MediaQueryEvaluator& screenEval() 399 { 400 DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticScreenEval, ("screen")); 401 return staticScreenEval; 402 } 403 404 static const MediaQueryEvaluator& printEval() 405 { 406 DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticPrintEval, ("print")); 407 return staticPrintEval; 408 } 409 410 static CSSMutableStyleDeclaration* leftToRightDeclaration() 411 { 412 DEFINE_STATIC_LOCAL(RefPtr<CSSMutableStyleDeclaration>, leftToRightDecl, (CSSMutableStyleDeclaration::create())); 413 if (!leftToRightDecl->length()) { 414 leftToRightDecl->setProperty(CSSPropertyDirection, "ltr", false, false); 415 leftToRightDecl->setStrictParsing(false); 416 } 417 return leftToRightDecl.get(); 418 } 419 420 static CSSMutableStyleDeclaration* rightToLeftDeclaration() 421 { 422 DEFINE_STATIC_LOCAL(RefPtr<CSSMutableStyleDeclaration>, rightToLeftDecl, (CSSMutableStyleDeclaration::create())); 423 if (!rightToLeftDecl->length()) { 424 rightToLeftDecl->setProperty(CSSPropertyDirection, "rtl", false, false); 425 rightToLeftDecl->setStrictParsing(false); 426 } 427 return rightToLeftDecl.get(); 428 } 429 430 CSSStyleSelector::CSSStyleSelector(Document* document, StyleSheetList* styleSheets, CSSStyleSheet* mappedElementSheet, 431 CSSStyleSheet* pageUserSheet, const Vector<RefPtr<CSSStyleSheet> >* pageGroupUserSheets, 432 bool strictParsing, bool matchAuthorAndUserStyles) 433 : m_backgroundData(BackgroundFillLayer) 434 , m_checker(document, strictParsing) 435 , m_element(0) 436 , m_styledElement(0) 437 , m_elementLinkState(NotInsideLink) 438 , m_fontSelector(CSSFontSelector::create(document)) 439 , m_applyProperty(CSSStyleApplyProperty::sharedCSSStyleApplyProperty()) 440 { 441 m_matchAuthorAndUserStyles = matchAuthorAndUserStyles; 442 443 Element* root = document->documentElement(); 444 445 if (!defaultStyle) { 446 if (!root || elementCanUseSimpleDefaultStyle(root)) 447 loadSimpleDefaultStyle(); 448 else { 449 loadFullDefaultStyle(); 450 } 451 } 452 453 // construct document root element default style. this is needed 454 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)" 455 // This is here instead of constructor, because when constructor is run, 456 // document doesn't have documentElement 457 // NOTE: this assumes that element that gets passed to styleForElement -call 458 // is always from the document that owns the style selector 459 FrameView* view = document->view(); 460 if (view) 461 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType())); 462 else 463 m_medium = adoptPtr(new MediaQueryEvaluator("all")); 464 465 if (root) 466 m_rootDefaultStyle = styleForElement(root, 0, false, true); // don't ref, because the RenderStyle is allocated from global heap 467 468 if (m_rootDefaultStyle && view) 469 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle.get())); 470 471 m_authorStyle = adoptPtr(new RuleSet); 472 // Adding rules from multiple sheets, shrink at the end. 473 m_authorStyle->disableAutoShrinkToFit(); 474 475 // FIXME: This sucks! The user sheet is reparsed every time! 476 OwnPtr<RuleSet> tempUserStyle = adoptPtr(new RuleSet); 477 if (pageUserSheet) 478 tempUserStyle->addRulesFromSheet(pageUserSheet, *m_medium, this); 479 if (pageGroupUserSheets) { 480 unsigned length = pageGroupUserSheets->size(); 481 for (unsigned i = 0; i < length; i++) { 482 if (pageGroupUserSheets->at(i)->isUserStyleSheet()) 483 tempUserStyle->addRulesFromSheet(pageGroupUserSheets->at(i).get(), *m_medium, this); 484 else 485 m_authorStyle->addRulesFromSheet(pageGroupUserSheets->at(i).get(), *m_medium, this); 486 } 487 } 488 489 if (tempUserStyle->m_ruleCount > 0 || tempUserStyle->m_pageRules.size() > 0) 490 m_userStyle = tempUserStyle.release(); 491 492 // Add rules from elements like SVG's <font-face> 493 if (mappedElementSheet) 494 m_authorStyle->addRulesFromSheet(mappedElementSheet, *m_medium, this); 495 496 // add stylesheets from document 497 unsigned length = styleSheets->length(); 498 for (unsigned i = 0; i < length; i++) { 499 StyleSheet* sheet = styleSheets->item(i); 500 if (sheet->isCSSStyleSheet() && !sheet->disabled()) 501 m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(sheet), *m_medium, this); 502 } 503 // Collect all ids and rules using sibling selectors (:first-child and similar) 504 // in the current set of stylesheets. Style sharing code uses this information to reject 505 // sharing candidates. 506 // Usually there are no sibling rules in the default style but the MathML sheet has some. 507 if (siblingRulesInDefaultStyle) 508 siblingRulesInDefaultStyle->collectFeatures(m_features); 509 m_authorStyle->collectFeatures(m_features); 510 if (m_userStyle) 511 m_userStyle->collectFeatures(m_features); 512 513 m_authorStyle->shrinkToFit(); 514 if (m_features.siblingRules) 515 m_features.siblingRules->shrinkToFit(); 516 517 if (document->renderer() && document->renderer()->style()) 518 document->renderer()->style()->font().update(fontSelector()); 519 } 520 521 // This is a simplified style setting function for keyframe styles 522 void CSSStyleSelector::addKeyframeStyle(PassRefPtr<WebKitCSSKeyframesRule> rule) 523 { 524 AtomicString s(rule->name()); 525 m_keyframesRuleMap.add(s.impl(), rule); 526 } 527 528 CSSStyleSelector::~CSSStyleSelector() 529 { 530 m_fontSelector->clearDocument(); 531 deleteAllValues(m_viewportDependentMediaQueryResults); 532 } 533 534 CSSStyleSelector::Features::Features() 535 : usesFirstLineRules(false) 536 , usesBeforeAfterRules(false) 537 , usesLinkRules(false) 538 { 539 } 540 541 CSSStyleSelector::Features::~Features() 542 { 543 } 544 545 static CSSStyleSheet* parseUASheet(const String& str) 546 { 547 CSSStyleSheet* sheet = CSSStyleSheet::create().releaseRef(); // leak the sheet on purpose 548 sheet->parseString(str); 549 return sheet; 550 } 551 552 static CSSStyleSheet* parseUASheet(const char* characters, unsigned size) 553 { 554 return parseUASheet(String(characters, size)); 555 } 556 557 static void loadFullDefaultStyle() 558 { 559 if (simpleDefaultStyleSheet) { 560 ASSERT(defaultStyle); 561 delete defaultStyle; 562 simpleDefaultStyleSheet->deref(); 563 defaultStyle = new RuleSet; 564 simpleDefaultStyleSheet = 0; 565 } else { 566 ASSERT(!defaultStyle); 567 defaultStyle = new RuleSet; 568 defaultPrintStyle = new RuleSet; 569 defaultQuirksStyle = new RuleSet; 570 } 571 572 // Strict-mode rules. 573 String defaultRules = String(htmlUserAgentStyleSheet, sizeof(htmlUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraDefaultStyleSheet(); 574 CSSStyleSheet* defaultSheet = parseUASheet(defaultRules); 575 defaultStyle->addRulesFromSheet(defaultSheet, screenEval()); 576 defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval()); 577 578 // Quirks-mode rules. 579 String quirksRules = String(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraQuirksStyleSheet(); 580 CSSStyleSheet* quirksSheet = parseUASheet(quirksRules); 581 defaultQuirksStyle->addRulesFromSheet(quirksSheet, screenEval()); 582 } 583 584 static void loadSimpleDefaultStyle() 585 { 586 ASSERT(!defaultStyle); 587 ASSERT(!simpleDefaultStyleSheet); 588 589 defaultStyle = new RuleSet; 590 defaultPrintStyle = new RuleSet; 591 defaultQuirksStyle = new RuleSet; 592 593 simpleDefaultStyleSheet = parseUASheet(simpleUserAgentStyleSheet, strlen(simpleUserAgentStyleSheet)); 594 defaultStyle->addRulesFromSheet(simpleDefaultStyleSheet, screenEval()); 595 596 // No need to initialize quirks sheet yet as there are no quirk rules for elements allowed in simple default style. 597 } 598 599 static void loadViewSourceStyle() 600 { 601 ASSERT(!defaultViewSourceStyle); 602 defaultViewSourceStyle = new RuleSet; 603 defaultViewSourceStyle->addRulesFromSheet(parseUASheet(sourceUserAgentStyleSheet, sizeof(sourceUserAgentStyleSheet)), screenEval()); 604 } 605 606 static inline void collectElementIdentifierHashes(const Element* element, Vector<unsigned, 4>& identifierHashes) 607 { 608 identifierHashes.append(element->localName().impl()->existingHash()); 609 if (element->hasID()) 610 identifierHashes.append(element->idForStyleResolution().impl()->existingHash()); 611 const StyledElement* styledElement = element->isStyledElement() ? static_cast<const StyledElement*>(element) : 0; 612 if (styledElement && styledElement->hasClass()) { 613 const SpaceSplitString& classNames = styledElement->classNames(); 614 size_t count = classNames.size(); 615 for (size_t i = 0; i < count; ++i) 616 identifierHashes.append(classNames[i].impl()->existingHash()); 617 } 618 } 619 620 void CSSStyleSelector::pushParentStackFrame(Element* parent) 621 { 622 ASSERT(m_ancestorIdentifierFilter); 623 ASSERT(m_parentStack.isEmpty() || m_parentStack.last().element == parent->parentElement()); 624 ASSERT(!m_parentStack.isEmpty() || !parent->parentElement()); 625 m_parentStack.append(ParentStackFrame(parent)); 626 ParentStackFrame& parentFrame = m_parentStack.last(); 627 // Mix tags, class names and ids into some sort of weird bouillabaisse. 628 // The filter is used for fast rejection of child and descendant selectors. 629 collectElementIdentifierHashes(parent, parentFrame.identifierHashes); 630 size_t count = parentFrame.identifierHashes.size(); 631 for (size_t i = 0; i < count; ++i) 632 m_ancestorIdentifierFilter->add(parentFrame.identifierHashes[i]); 633 } 634 635 void CSSStyleSelector::popParentStackFrame() 636 { 637 ASSERT(!m_parentStack.isEmpty()); 638 ASSERT(m_ancestorIdentifierFilter); 639 const ParentStackFrame& parentFrame = m_parentStack.last(); 640 size_t count = parentFrame.identifierHashes.size(); 641 for (size_t i = 0; i < count; ++i) 642 m_ancestorIdentifierFilter->remove(parentFrame.identifierHashes[i]); 643 m_parentStack.removeLast(); 644 if (m_parentStack.isEmpty()) { 645 ASSERT(m_ancestorIdentifierFilter->likelyEmpty()); 646 m_ancestorIdentifierFilter.clear(); 647 } 648 } 649 650 void CSSStyleSelector::pushParent(Element* parent) 651 { 652 if (m_parentStack.isEmpty()) { 653 ASSERT(!m_ancestorIdentifierFilter); 654 m_ancestorIdentifierFilter = adoptPtr(new BloomFilter<bloomFilterKeyBits>); 655 // If the element is not the root itself, build the stack starting from the root. 656 if (parent->parentElement()) { 657 Vector<Element*, 30> ancestors; 658 for (Element* ancestor = parent; ancestor; ancestor = ancestor->parentElement()) 659 ancestors.append(ancestor); 660 int count = ancestors.size(); 661 for (int n = count - 1; n >= 0; --n) 662 pushParentStackFrame(ancestors[n]); 663 return; 664 } 665 } else if (!parent->parentElement()) { 666 // We are not always invoked consistently. For example, script execution can cause us to enter 667 // style recalc in the middle of tree building. Reset the stack if we see a new root element. 668 ASSERT(m_ancestorIdentifierFilter); 669 m_ancestorIdentifierFilter->clear(); 670 m_parentStack.resize(0); 671 } else { 672 ASSERT(m_ancestorIdentifierFilter); 673 // We may get invoked for some random elements in some wacky cases during style resolve. 674 // Pause maintaining the stack in this case. 675 if (m_parentStack.last().element != parent->parentElement()) 676 return; 677 } 678 pushParentStackFrame(parent); 679 } 680 681 void CSSStyleSelector::popParent(Element* parent) 682 { 683 if (m_parentStack.isEmpty() || m_parentStack.last().element != parent) 684 return; 685 popParentStackFrame(); 686 } 687 688 void CSSStyleSelector::addMatchedDeclaration(CSSMutableStyleDeclaration* decl) 689 { 690 m_matchedDecls.append(decl); 691 } 692 693 void CSSStyleSelector::matchRules(RuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules) 694 { 695 m_matchedRules.clear(); 696 697 if (!rules || !m_element) 698 return; 699 700 // We need to collect the rules for id, class, tag, and everything else into a buffer and 701 // then sort the buffer. 702 if (m_element->hasID()) 703 matchRulesForList(rules->getIDRules(m_element->idForStyleResolution().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); 704 if (m_element->hasClass()) { 705 ASSERT(m_styledElement); 706 const SpaceSplitString& classNames = m_styledElement->classNames(); 707 size_t size = classNames.size(); 708 for (size_t i = 0; i < size; ++i) 709 matchRulesForList(rules->getClassRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); 710 } 711 if (!m_element->shadowPseudoId().isEmpty()) { 712 ASSERT(m_styledElement); 713 matchRulesForList(rules->getPseudoRules(m_element->shadowPseudoId().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); 714 } 715 matchRulesForList(rules->getTagRules(m_element->localName().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); 716 matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules); 717 718 // If we didn't match any rules, we're done. 719 if (m_matchedRules.isEmpty()) 720 return; 721 722 // Sort the set of matched rules. 723 sortMatchedRules(); 724 725 // Now transfer the set of matched rules over to our list of decls. 726 if (!m_checker.m_collectRulesOnly) { 727 for (unsigned i = 0; i < m_matchedRules.size(); i++) 728 addMatchedDeclaration(m_matchedRules[i]->rule()->declaration()); 729 } else { 730 for (unsigned i = 0; i < m_matchedRules.size(); i++) { 731 if (!m_ruleList) 732 m_ruleList = CSSRuleList::create(); 733 m_ruleList->append(m_matchedRules[i]->rule()); 734 } 735 } 736 } 737 738 inline bool CSSStyleSelector::fastRejectSelector(const RuleData& ruleData) const 739 { 740 ASSERT(m_ancestorIdentifierFilter); 741 const unsigned* descendantSelectorIdentifierHashes = ruleData.descendantSelectorIdentifierHashes(); 742 for (unsigned n = 0; n < RuleData::maximumIdentifierCount && descendantSelectorIdentifierHashes[n]; ++n) { 743 if (!m_ancestorIdentifierFilter->mayContain(descendantSelectorIdentifierHashes[n])) 744 return true; 745 } 746 return false; 747 } 748 749 void CSSStyleSelector::matchRulesForList(const Vector<RuleData>* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules) 750 { 751 if (!rules) 752 return; 753 // In some cases we may end up looking up style for random elements in the middle of a recursive tree resolve. 754 // Ancestor identifier filter won't be up-to-date in that case and we can't use the fast path. 755 bool canUseFastReject = !m_parentStack.isEmpty() && m_parentStack.last().element == m_parentNode; 756 757 unsigned size = rules->size(); 758 for (unsigned i = 0; i < size; ++i) { 759 const RuleData& ruleData = rules->at(i); 760 if (canUseFastReject && fastRejectSelector(ruleData)) 761 continue; 762 if (checkSelector(ruleData)) { 763 // If the rule has no properties to apply, then ignore it in the non-debug mode. 764 CSSStyleRule* rule = ruleData.rule(); 765 CSSMutableStyleDeclaration* decl = rule->declaration(); 766 if (!decl || (!decl->length() && !includeEmptyRules)) 767 continue; 768 if (m_checker.m_sameOriginOnly && !m_checker.m_document->securityOrigin()->canRequest(rule->baseURL())) 769 continue; 770 // If we're matching normal rules, set a pseudo bit if 771 // we really just matched a pseudo-element. 772 if (m_dynamicPseudo != NOPSEUDO && m_checker.m_pseudoStyle == NOPSEUDO) { 773 if (m_checker.m_collectRulesOnly) 774 continue; 775 if (m_dynamicPseudo < FIRST_INTERNAL_PSEUDOID) 776 m_style->setHasPseudoStyle(m_dynamicPseudo); 777 } else { 778 // Update our first/last rule indices in the matched rules array. 779 lastRuleIndex = m_matchedDecls.size() + m_matchedRules.size(); 780 if (firstRuleIndex == -1) 781 firstRuleIndex = lastRuleIndex; 782 783 // Add this rule to our list of matched rules. 784 addMatchedRule(&ruleData); 785 } 786 } 787 } 788 } 789 790 static inline bool compareRules(const RuleData* r1, const RuleData* r2) 791 { 792 unsigned specificity1 = r1->specificity(); 793 unsigned specificity2 = r2->specificity(); 794 return (specificity1 == specificity2) ? r1->position() < r2->position() : specificity1 < specificity2; 795 } 796 797 void CSSStyleSelector::sortMatchedRules() 798 { 799 std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules); 800 } 801 802 inline EInsideLink CSSStyleSelector::SelectorChecker::determineLinkState(Element* element) const 803 { 804 if (!element || !element->isLink()) 805 return NotInsideLink; 806 return determineLinkStateSlowCase(element); 807 } 808 809 inline void CSSStyleSelector::initElement(Element* e) 810 { 811 if (m_element != e) { 812 m_element = e; 813 m_styledElement = m_element && m_element->isStyledElement() ? static_cast<StyledElement*>(m_element) : 0; 814 m_elementLinkState = m_checker.determineLinkState(m_element); 815 if (e && e == e->document()->documentElement()) { 816 e->document()->setDirectionSetOnDocumentElement(false); 817 e->document()->setWritingModeSetOnDocumentElement(false); 818 } 819 } 820 } 821 822 inline void CSSStyleSelector::initForStyleResolve(Element* e, RenderStyle* parentStyle, PseudoId pseudoID) 823 { 824 m_checker.m_pseudoStyle = pseudoID; 825 826 m_parentNode = e ? e->parentNodeForRenderingAndStyle() : 0; 827 828 if (parentStyle) 829 m_parentStyle = parentStyle; 830 else 831 m_parentStyle = m_parentNode ? m_parentNode->renderStyle() : 0; 832 833 Node* docElement = e ? e->document()->documentElement() : 0; 834 RenderStyle* docStyle = m_checker.m_document->renderStyle(); 835 m_rootElementStyle = docElement && e != docElement ? docElement->renderStyle() : docStyle; 836 837 m_style = 0; 838 839 m_matchedDecls.clear(); 840 841 m_pendingImageProperties.clear(); 842 843 m_ruleList = 0; 844 845 m_fontDirty = false; 846 } 847 848 static inline const AtomicString* linkAttribute(Node* node) 849 { 850 if (!node->isLink()) 851 return 0; 852 853 ASSERT(node->isElementNode()); 854 Element* element = static_cast<Element*>(node); 855 if (element->isHTMLElement()) 856 return &element->fastGetAttribute(hrefAttr); 857 858 #if ENABLE(WML) 859 if (element->isWMLElement()) { 860 // <anchor> elements don't have href attributes, but we still want to 861 // appear as link, so linkAttribute() has to return a non-null value! 862 if (element->hasTagName(WMLNames::anchorTag)) 863 return &emptyAtom; 864 865 return &element->fastGetAttribute(hrefAttr); 866 } 867 #endif 868 869 #if ENABLE(SVG) 870 if (element->isSVGElement()) 871 return &element->fastGetAttribute(XLinkNames::hrefAttr); 872 #endif 873 874 return 0; 875 } 876 877 CSSStyleSelector::SelectorChecker::SelectorChecker(Document* document, bool strictParsing) 878 : m_document(document) 879 , m_strictParsing(strictParsing) 880 , m_collectRulesOnly(false) 881 , m_sameOriginOnly(false) 882 , m_pseudoStyle(NOPSEUDO) 883 , m_documentIsHTML(document->isHTMLDocument()) 884 , m_matchVisitedPseudoClass(false) 885 { 886 } 887 888 EInsideLink CSSStyleSelector::SelectorChecker::determineLinkStateSlowCase(Element* element) const 889 { 890 ASSERT(element->isLink()); 891 892 const AtomicString* attr = linkAttribute(element); 893 if (!attr || attr->isNull()) 894 return NotInsideLink; 895 896 #if PLATFORM(QT) 897 Vector<UChar, 512> url; 898 visitedURL(m_document->baseURL(), *attr, url); 899 if (url.isEmpty()) 900 return InsideUnvisitedLink; 901 902 // If the Qt4.4 interface for the history is used, we will have to fallback 903 // to the old global history. 904 QWebHistoryInterface* iface = QWebHistoryInterface::defaultInterface(); 905 if (iface) 906 return iface->historyContains(QString(reinterpret_cast<QChar*>(url.data()), url.size())) ? InsideVisitedLink : InsideUnvisitedLink; 907 908 LinkHash hash = visitedLinkHash(url.data(), url.size()); 909 if (!hash) 910 return InsideUnvisitedLink; 911 #else 912 LinkHash hash = visitedLinkHash(m_document->baseURL(), *attr); 913 if (!hash) 914 return InsideUnvisitedLink; 915 #endif 916 917 Frame* frame = m_document->frame(); 918 if (!frame) 919 return InsideUnvisitedLink; 920 921 Page* page = frame->page(); 922 if (!page) 923 return InsideUnvisitedLink; 924 925 m_linksCheckedForVisitedState.add(hash); 926 927 #if USE(PLATFORM_STRATEGIES) 928 return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash) ? InsideVisitedLink : InsideUnvisitedLink; 929 #else 930 return page->group().isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink; 931 #endif 932 } 933 934 bool CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* element) const 935 { 936 PseudoId dynamicPseudo = NOPSEUDO; 937 return checkSelector(sel, element, 0, dynamicPseudo, false, false) == SelectorMatches; 938 } 939 940 static const unsigned cStyleSearchThreshold = 10; 941 static const unsigned cStyleSearchLevelThreshold = 10; 942 943 Node* CSSStyleSelector::locateCousinList(Element* parent, unsigned& visitedNodeCount) const 944 { 945 if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold) 946 return 0; 947 if (!parent || !parent->isStyledElement()) 948 return 0; 949 StyledElement* p = static_cast<StyledElement*>(parent); 950 if (p->inlineStyleDecl()) 951 return 0; 952 if (p->hasID() && m_features.idsInRules.contains(p->idForStyleResolution().impl())) 953 return 0; 954 955 RenderStyle* parentStyle = p->renderStyle(); 956 unsigned subcount = 0; 957 Node* thisCousin = p; 958 Node* currentNode = p->previousSibling(); 959 960 // Reserve the tries for this level. This effectively makes sure that the algorithm 961 // will never go deeper than cStyleSearchLevelThreshold levels into recursion. 962 visitedNodeCount += cStyleSearchThreshold; 963 while (thisCousin) { 964 while (currentNode) { 965 ++subcount; 966 if (currentNode->renderStyle() == parentStyle && currentNode->lastChild()) { 967 // Adjust for unused reserved tries. 968 visitedNodeCount -= cStyleSearchThreshold - subcount; 969 return currentNode->lastChild(); 970 } 971 if (subcount >= cStyleSearchThreshold) 972 return 0; 973 currentNode = currentNode->previousSibling(); 974 } 975 currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount); 976 thisCousin = currentNode; 977 } 978 979 return 0; 980 } 981 982 bool CSSStyleSelector::matchesSiblingRules() 983 { 984 int firstSiblingRule = -1, lastSiblingRule = -1; 985 matchRules(m_features.siblingRules.get(), firstSiblingRule, lastSiblingRule, false); 986 if (m_matchedDecls.isEmpty()) 987 return false; 988 m_matchedDecls.clear(); 989 return true; 990 } 991 992 bool CSSStyleSelector::canShareStyleWithElement(Node* node) const 993 { 994 if (!node->isStyledElement()) 995 return false; 996 997 StyledElement* element = static_cast<StyledElement*>(node); 998 RenderStyle* style = element->renderStyle(); 999 1000 if (!style) 1001 return false; 1002 if (style->unique()) 1003 return false; 1004 if (element->tagQName() != m_element->tagQName()) 1005 return false; 1006 if (element->hasClass() != m_element->hasClass()) 1007 return false; 1008 if (element->inlineStyleDecl()) 1009 return false; 1010 if (element->hasMappedAttributes() != m_styledElement->hasMappedAttributes()) 1011 return false; 1012 if (element->isLink() != m_element->isLink()) 1013 return false; 1014 if (style->affectedByAttributeSelectors()) 1015 return false; 1016 if (element->hovered() != m_element->hovered()) 1017 return false; 1018 if (element->active() != m_element->active()) 1019 return false; 1020 if (element->focused() != m_element->focused()) 1021 return false; 1022 if (element->shadowPseudoId() != m_element->shadowPseudoId()) 1023 return false; 1024 if (element == element->document()->cssTarget()) 1025 return false; 1026 if (m_element == m_element->document()->cssTarget()) 1027 return false; 1028 if (element->fastGetAttribute(typeAttr) != m_element->fastGetAttribute(typeAttr)) 1029 return false; 1030 if (element->fastGetAttribute(XMLNames::langAttr) != m_element->fastGetAttribute(XMLNames::langAttr)) 1031 return false; 1032 if (element->fastGetAttribute(langAttr) != m_element->fastGetAttribute(langAttr)) 1033 return false; 1034 if (element->fastGetAttribute(readonlyAttr) != m_element->fastGetAttribute(readonlyAttr)) 1035 return false; 1036 if (element->fastGetAttribute(cellpaddingAttr) != m_element->fastGetAttribute(cellpaddingAttr)) 1037 return false; 1038 1039 if (element->hasID() && m_features.idsInRules.contains(element->idForStyleResolution().impl())) 1040 return false; 1041 1042 bool isControl = element->isFormControlElement(); 1043 1044 if (isControl != m_element->isFormControlElement()) 1045 return false; 1046 1047 if (isControl) { 1048 InputElement* thisInputElement = element->toInputElement(); 1049 InputElement* otherInputElement = m_element->toInputElement(); 1050 1051 if (!thisInputElement || !otherInputElement) 1052 return false; 1053 1054 if (thisInputElement->isAutofilled() != otherInputElement->isAutofilled()) 1055 return false; 1056 if (thisInputElement->isChecked() != otherInputElement->isChecked()) 1057 return false; 1058 if (thisInputElement->isIndeterminate() != otherInputElement->isIndeterminate()) 1059 return false; 1060 1061 if (element->isEnabledFormControl() != m_element->isEnabledFormControl()) 1062 return false; 1063 1064 if (element->isDefaultButtonForForm() != m_element->isDefaultButtonForForm()) 1065 return false; 1066 1067 if (!m_element->document()->containsValidityStyleRules()) 1068 return false; 1069 1070 bool willValidate = element->willValidate(); 1071 1072 if (willValidate != m_element->willValidate()) 1073 return false; 1074 1075 if (willValidate && (element->isValidFormControlElement() != m_element->isValidFormControlElement())) 1076 return false; 1077 1078 if (element->isInRange() != m_element->isInRange()) 1079 return false; 1080 1081 if (element->isOutOfRange() != m_element->isOutOfRange()) 1082 return false; 1083 } 1084 1085 if (style->transitions() || style->animations()) 1086 return false; 1087 1088 #if USE(ACCELERATED_COMPOSITING) 1089 // Turn off style sharing for elements that can gain layers for reasons outside of the style system. 1090 // See comments in RenderObject::setStyle(). 1091 if (element->hasTagName(iframeTag) || element->hasTagName(frameTag) || element->hasTagName(embedTag) || element->hasTagName(objectTag) || element->hasTagName(appletTag)) 1092 return false; 1093 #endif 1094 1095 if (equalIgnoringCase(element->fastGetAttribute(dirAttr), "auto") || equalIgnoringCase(m_element->fastGetAttribute(dirAttr), "auto")) 1096 return false; 1097 1098 if (element->hasClass() && m_element->fastGetAttribute(classAttr) != element->fastGetAttribute(classAttr)) 1099 return false; 1100 1101 if (element->hasMappedAttributes() && !element->attributeMap()->mappedMapsEquivalent(m_styledElement->attributeMap())) 1102 return false; 1103 1104 if (element->isLink() && m_elementLinkState != style->insideLink()) 1105 return false; 1106 1107 return true; 1108 } 1109 1110 inline Node* CSSStyleSelector::findSiblingForStyleSharing(Node* node, unsigned& count) const 1111 { 1112 for (; node; node = node->previousSibling()) { 1113 if (!node->isElementNode()) 1114 continue; 1115 if (canShareStyleWithElement(node)) 1116 break; 1117 if (count++ == cStyleSearchThreshold) 1118 return 0; 1119 } 1120 return node; 1121 } 1122 1123 static inline bool parentStylePreventsSharing(const RenderStyle* parentStyle) 1124 { 1125 return parentStyle->childrenAffectedByPositionalRules() 1126 || parentStyle->childrenAffectedByFirstChildRules() 1127 || parentStyle->childrenAffectedByLastChildRules() 1128 || parentStyle->childrenAffectedByDirectAdjacentRules(); 1129 } 1130 1131 ALWAYS_INLINE RenderStyle* CSSStyleSelector::locateSharedStyle() 1132 { 1133 if (!m_styledElement || !m_parentStyle) 1134 return 0; 1135 // If the element has inline style it is probably unique. 1136 if (m_styledElement->inlineStyleDecl()) 1137 return 0; 1138 // Ids stop style sharing if they show up in the stylesheets. 1139 if (m_styledElement->hasID() && m_features.idsInRules.contains(m_styledElement->idForStyleResolution().impl())) 1140 return 0; 1141 if (parentStylePreventsSharing(m_parentStyle)) 1142 return 0; 1143 1144 // Check previous siblings and their cousins. 1145 unsigned count = 0; 1146 unsigned visitedNodeCount = 0; 1147 Node* shareNode = 0; 1148 Node* cousinList = m_styledElement->previousSibling(); 1149 while (cousinList) { 1150 shareNode = findSiblingForStyleSharing(cousinList, count); 1151 if (shareNode) 1152 break; 1153 cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount); 1154 } 1155 1156 // If we have exhausted all our budget or our cousins. 1157 if (!shareNode) 1158 return 0; 1159 1160 // Can't share if sibling rules apply. This is checked at the end as it should rarely fail. 1161 if (matchesSiblingRules()) 1162 return 0; 1163 // Tracking child index requires unique style for each node. This may get set by the sibling rule match above. 1164 if (parentStylePreventsSharing(m_parentStyle)) 1165 return 0; 1166 return shareNode->renderStyle(); 1167 } 1168 1169 void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule) 1170 { 1171 // First we match rules from the user agent sheet. 1172 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print") 1173 ? defaultPrintStyle : defaultStyle; 1174 matchRules(userAgentStyleSheet, firstUARule, lastUARule, false); 1175 1176 // In quirks mode, we match rules from the quirks user agent sheet. 1177 if (!m_checker.m_strictParsing) 1178 matchRules(defaultQuirksStyle, firstUARule, lastUARule, false); 1179 1180 // If document uses view source styles (in view source mode or in xml viewer mode), then we match rules from the view source style sheet. 1181 if (m_checker.m_document->usesViewSourceStyles()) { 1182 if (!defaultViewSourceStyle) 1183 loadViewSourceStyle(); 1184 matchRules(defaultViewSourceStyle, firstUARule, lastUARule, false); 1185 } 1186 } 1187 1188 PassRefPtr<RenderStyle> CSSStyleSelector::styleForDocument(Document* document) 1189 { 1190 Frame* frame = document->frame(); 1191 1192 RefPtr<RenderStyle> documentStyle = RenderStyle::create(); 1193 documentStyle->setDisplay(BLOCK); 1194 documentStyle->setVisuallyOrdered(document->visuallyOrdered()); 1195 documentStyle->setZoom(frame ? frame->pageZoomFactor() : 1); 1196 documentStyle->setPageScaleTransform(frame ? frame->pageScaleFactor() : 1); 1197 documentStyle->setUserModify(document->inDesignMode() ? READ_WRITE : READ_ONLY); 1198 1199 Element* docElement = document->documentElement(); 1200 RenderObject* docElementRenderer = docElement ? docElement->renderer() : 0; 1201 if (docElementRenderer) { 1202 // Use the direction and writing-mode of the body to set the 1203 // viewport's direction and writing-mode unless the property is set on the document element. 1204 // If there is no body, then use the document element. 1205 RenderObject* bodyRenderer = document->body() ? document->body()->renderer() : 0; 1206 if (bodyRenderer && !document->writingModeSetOnDocumentElement()) 1207 documentStyle->setWritingMode(bodyRenderer->style()->writingMode()); 1208 else 1209 documentStyle->setWritingMode(docElementRenderer->style()->writingMode()); 1210 if (bodyRenderer && !document->directionSetOnDocumentElement()) 1211 documentStyle->setDirection(bodyRenderer->style()->direction()); 1212 else 1213 documentStyle->setDirection(docElementRenderer->style()->direction()); 1214 } 1215 1216 FontDescription fontDescription; 1217 fontDescription.setUsePrinterFont(document->printing()); 1218 if (Settings* settings = document->settings()) { 1219 fontDescription.setRenderingMode(settings->fontRenderingMode()); 1220 if (document->printing() && !settings->shouldPrintBackgrounds()) 1221 documentStyle->setForceBackgroundsToWhite(true); 1222 const AtomicString& stdfont = settings->standardFontFamily(); 1223 if (!stdfont.isEmpty()) { 1224 fontDescription.firstFamily().setFamily(stdfont); 1225 fontDescription.firstFamily().appendFamily(0); 1226 } 1227 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); 1228 int size = CSSStyleSelector::fontSizeForKeyword(document, CSSValueMedium, false); 1229 fontDescription.setSpecifiedSize(size); 1230 bool useSVGZoomRules = document->isSVGDocument(); 1231 fontDescription.setComputedSize(CSSStyleSelector::getComputedSizeFromSpecifiedSize(document, documentStyle.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules)); 1232 } 1233 1234 documentStyle->setFontDescription(fontDescription); 1235 documentStyle->font().update(0); 1236 1237 return documentStyle.release(); 1238 } 1239 1240 // If resolveForRootDefault is true, style based on user agent style sheet only. This is used in media queries, where 1241 // relative units are interpreted according to document root element style, styled only with UA stylesheet 1242 1243 PassRefPtr<RenderStyle> CSSStyleSelector::styleForElement(Element* e, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault, bool matchVisitedPseudoClass) 1244 { 1245 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer 1246 // will vanish if a style recalc happens during loading. 1247 if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) { 1248 if (!s_styleNotYetAvailable) { 1249 s_styleNotYetAvailable = RenderStyle::create().releaseRef(); 1250 s_styleNotYetAvailable->ref(); 1251 s_styleNotYetAvailable->setDisplay(NONE); 1252 s_styleNotYetAvailable->font().update(m_fontSelector); 1253 } 1254 s_styleNotYetAvailable->ref(); 1255 e->document()->setHasNodesWithPlaceholderStyle(); 1256 return s_styleNotYetAvailable; 1257 } 1258 1259 initElement(e); 1260 initForStyleResolve(e, defaultParent); 1261 if (allowSharing) { 1262 RenderStyle* sharedStyle = locateSharedStyle(); 1263 if (sharedStyle) 1264 return sharedStyle; 1265 } 1266 1267 // Compute our style allowing :visited to match first. 1268 RefPtr<RenderStyle> visitedStyle; 1269 if (!matchVisitedPseudoClass && m_parentStyle && (m_parentStyle->insideLink() || e->isLink()) && e->document()->usesLinkRules()) { 1270 // Fetch our parent style. 1271 RenderStyle* parentStyle = m_parentStyle; 1272 if (!e->isLink()) { 1273 // Use the parent's visited style if one exists. 1274 RenderStyle* parentVisitedStyle = m_parentStyle->getCachedPseudoStyle(VISITED_LINK); 1275 if (parentVisitedStyle) 1276 parentStyle = parentVisitedStyle; 1277 } 1278 visitedStyle = styleForElement(e, parentStyle, false, false, true); 1279 initForStyleResolve(e, defaultParent); 1280 } 1281 1282 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass; 1283 1284 m_style = RenderStyle::create(); 1285 1286 if (m_parentStyle) 1287 m_style->inheritFrom(m_parentStyle); 1288 else { 1289 m_parentStyle = style(); 1290 // Make sure our fonts are initialized if we don't inherit them from our parent style. 1291 m_style->font().update(0); 1292 } 1293 1294 if (e->isLink()) { 1295 m_style->setIsLink(true); 1296 m_style->setInsideLink(m_elementLinkState); 1297 } 1298 1299 if (visitedStyle) { 1300 // Copy any pseudo bits that the visited style has to the primary style so that 1301 // pseudo element styles will continue to work for pseudo elements inside :visited 1302 // links. 1303 for (unsigned pseudo = FIRST_PUBLIC_PSEUDOID; pseudo < FIRST_INTERNAL_PSEUDOID; ++pseudo) { 1304 if (visitedStyle->hasPseudoStyle(static_cast<PseudoId>(pseudo))) 1305 m_style->setHasPseudoStyle(static_cast<PseudoId>(pseudo)); 1306 } 1307 if (m_elementLinkState == InsideUnvisitedLink) 1308 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. 1309 else 1310 visitedStyle->setStyleType(VISITED_LINK); 1311 } 1312 1313 if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(e)) { 1314 loadFullDefaultStyle(); 1315 assertNoSiblingRulesInDefaultStyle(); 1316 } 1317 1318 #if ENABLE(SVG) 1319 static bool loadedSVGUserAgentSheet; 1320 if (e->isSVGElement() && !loadedSVGUserAgentSheet) { 1321 // SVG rules. 1322 loadedSVGUserAgentSheet = true; 1323 CSSStyleSheet* svgSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet)); 1324 defaultStyle->addRulesFromSheet(svgSheet, screenEval()); 1325 defaultPrintStyle->addRulesFromSheet(svgSheet, printEval()); 1326 assertNoSiblingRulesInDefaultStyle(); 1327 } 1328 #endif 1329 1330 #if ENABLE(MATHML) 1331 static bool loadedMathMLUserAgentSheet; 1332 if (e->isMathMLElement() && !loadedMathMLUserAgentSheet) { 1333 // MathML rules. 1334 loadedMathMLUserAgentSheet = true; 1335 CSSStyleSheet* mathMLSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet)); 1336 defaultStyle->addRulesFromSheet(mathMLSheet, screenEval()); 1337 defaultPrintStyle->addRulesFromSheet(mathMLSheet, printEval()); 1338 // There are some sibling rules here. 1339 collectSiblingRulesInDefaultStyle(); 1340 } 1341 #endif 1342 1343 #if ENABLE(WML) 1344 static bool loadedWMLUserAgentSheet; 1345 if (e->isWMLElement() && !loadedWMLUserAgentSheet) { 1346 // WML rules. 1347 loadedWMLUserAgentSheet = true; 1348 CSSStyleSheet* wmlSheet = parseUASheet(wmlUserAgentStyleSheet, sizeof(wmlUserAgentStyleSheet)); 1349 defaultStyle->addRulesFromSheet(wmlSheet, screenEval()); 1350 defaultPrintStyle->addRulesFromSheet(wmlSheet, printEval()); 1351 assertNoSiblingRulesInDefaultStyle(); 1352 } 1353 #endif 1354 1355 #if ENABLE(VIDEO) 1356 static bool loadedMediaStyleSheet; 1357 if (!loadedMediaStyleSheet && (e->hasTagName(videoTag) || e->hasTagName(audioTag))) { 1358 loadedMediaStyleSheet = true; 1359 String mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::themeForPage(e->document()->page())->extraMediaControlsStyleSheet(); 1360 CSSStyleSheet* mediaControlsSheet = parseUASheet(mediaRules); 1361 defaultStyle->addRulesFromSheet(mediaControlsSheet, screenEval()); 1362 defaultPrintStyle->addRulesFromSheet(mediaControlsSheet, printEval()); 1363 assertNoSiblingRulesInDefaultStyle(); 1364 } 1365 #endif 1366 1367 #if ENABLE(FULLSCREEN_API) 1368 static bool loadedFullScreenStyleSheet; 1369 if (!loadedFullScreenStyleSheet && e->document()->webkitIsFullScreen()) { 1370 loadedFullScreenStyleSheet = true; 1371 String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraFullScreenStyleSheet(); 1372 CSSStyleSheet* fullscreenSheet = parseUASheet(fullscreenRules); 1373 defaultStyle->addRulesFromSheet(fullscreenSheet, screenEval()); 1374 defaultQuirksStyle->addRulesFromSheet(fullscreenSheet, screenEval()); 1375 } 1376 #endif 1377 1378 int firstUARule = -1, lastUARule = -1; 1379 int firstUserRule = -1, lastUserRule = -1; 1380 int firstAuthorRule = -1, lastAuthorRule = -1; 1381 matchUARules(firstUARule, lastUARule); 1382 1383 if (!resolveForRootDefault) { 1384 // 4. Now we check user sheet rules. 1385 if (m_matchAuthorAndUserStyles) 1386 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, false); 1387 1388 // 5. Now check author rules, beginning first with presentational attributes 1389 // mapped from HTML. 1390 if (m_styledElement) { 1391 // Ask if the HTML element has mapped attributes. 1392 if (m_styledElement->hasMappedAttributes()) { 1393 // Walk our attribute list and add in each decl. 1394 const NamedNodeMap* map = m_styledElement->attributeMap(); 1395 for (unsigned i = 0; i < map->length(); i++) { 1396 Attribute* attr = map->attributeItem(i); 1397 if (attr->isMappedAttribute() && attr->decl()) { 1398 lastAuthorRule = m_matchedDecls.size(); 1399 if (firstAuthorRule == -1) 1400 firstAuthorRule = lastAuthorRule; 1401 addMatchedDeclaration(attr->decl()); 1402 } 1403 } 1404 } 1405 1406 // Now we check additional mapped declarations. 1407 // Tables and table cells share an additional mapped rule that must be applied 1408 // after all attributes, since their mapped style depends on the values of multiple attributes. 1409 if (m_styledElement->canHaveAdditionalAttributeStyleDecls()) { 1410 m_additionalAttributeStyleDecls.clear(); 1411 m_styledElement->additionalAttributeStyleDecls(m_additionalAttributeStyleDecls); 1412 if (!m_additionalAttributeStyleDecls.isEmpty()) { 1413 unsigned additionalDeclsSize = m_additionalAttributeStyleDecls.size(); 1414 if (firstAuthorRule == -1) 1415 firstAuthorRule = m_matchedDecls.size(); 1416 lastAuthorRule = m_matchedDecls.size() + additionalDeclsSize - 1; 1417 for (unsigned i = 0; i < additionalDeclsSize; i++) 1418 addMatchedDeclaration(m_additionalAttributeStyleDecls[i]); 1419 } 1420 } 1421 if (m_styledElement->isHTMLElement()) { 1422 bool isAuto; 1423 TextDirection textDirection = toHTMLElement(m_styledElement)->directionalityIfhasDirAutoAttribute(isAuto); 1424 if (isAuto) 1425 addMatchedDeclaration(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration()); 1426 } 1427 } 1428 1429 // 6. Check the rules in author sheets next. 1430 if (m_matchAuthorAndUserStyles) 1431 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, false); 1432 1433 // 7. Now check our inline style attribute. 1434 if (m_matchAuthorAndUserStyles && m_styledElement) { 1435 CSSMutableStyleDeclaration* inlineDecl = m_styledElement->inlineStyleDecl(); 1436 if (inlineDecl) { 1437 lastAuthorRule = m_matchedDecls.size(); 1438 if (firstAuthorRule == -1) 1439 firstAuthorRule = lastAuthorRule; 1440 addMatchedDeclaration(inlineDecl); 1441 } 1442 } 1443 } 1444 1445 // Reset the value back before applying properties, so that -webkit-link knows what color to use. 1446 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass; 1447 1448 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply 1449 // high-priority properties first, i.e., those properties that other properties depend on. 1450 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important 1451 // and (4) normal important. 1452 m_lineHeightValue = 0; 1453 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1); 1454 if (!resolveForRootDefault) { 1455 applyDeclarations<true>(true, firstAuthorRule, lastAuthorRule); 1456 applyDeclarations<true>(true, firstUserRule, lastUserRule); 1457 } 1458 applyDeclarations<true>(true, firstUARule, lastUARule); 1459 1460 // If our font got dirtied, go ahead and update it now. 1461 if (m_fontDirty) 1462 updateFont(); 1463 1464 // Line-height is set when we are sure we decided on the font-size 1465 if (m_lineHeightValue) 1466 applyProperty(CSSPropertyLineHeight, m_lineHeightValue); 1467 1468 // Now do the normal priority UA properties. 1469 applyDeclarations<false>(false, firstUARule, lastUARule); 1470 1471 // Cache our border and background so that we can examine them later. 1472 cacheBorderAndBackground(); 1473 1474 // Now do the author and user normal priority properties and all the !important properties. 1475 if (!resolveForRootDefault) { 1476 applyDeclarations<false>(false, lastUARule + 1, m_matchedDecls.size() - 1); 1477 applyDeclarations<false>(true, firstAuthorRule, lastAuthorRule); 1478 applyDeclarations<false>(true, firstUserRule, lastUserRule); 1479 } 1480 applyDeclarations<false>(true, firstUARule, lastUARule); 1481 1482 ASSERT(!m_fontDirty); 1483 // If our font got dirtied by one of the non-essential font props, 1484 // go ahead and update it a second time. 1485 if (m_fontDirty) 1486 updateFont(); 1487 1488 // Clean up our style object's display and text decorations (among other fixups). 1489 adjustRenderStyle(style(), m_parentStyle, e); 1490 1491 // Start loading images referenced by this style. 1492 loadPendingImages(); 1493 1494 // If we have first-letter pseudo style, do not share this style 1495 if (m_style->hasPseudoStyle(FIRST_LETTER)) 1496 m_style->setUnique(); 1497 1498 if (visitedStyle) { 1499 // Add the visited style off the main style. 1500 m_style->addCachedPseudoStyle(visitedStyle.release()); 1501 } 1502 1503 if (!matchVisitedPseudoClass) 1504 initElement(0); // Clear out for the next resolve. 1505 1506 // Now return the style. 1507 return m_style.release(); 1508 } 1509 1510 PassRefPtr<RenderStyle> CSSStyleSelector::styleForKeyframe(const RenderStyle* elementStyle, const WebKitCSSKeyframeRule* keyframeRule, KeyframeValue& keyframe) 1511 { 1512 if (keyframeRule->style()) 1513 addMatchedDeclaration(keyframeRule->style()); 1514 1515 ASSERT(!m_style); 1516 1517 // Create the style 1518 m_style = RenderStyle::clone(elementStyle); 1519 1520 m_lineHeightValue = 0; 1521 1522 // We don't need to bother with !important. Since there is only ever one 1523 // decl, there's nothing to override. So just add the first properties. 1524 if (keyframeRule->style()) 1525 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1); 1526 1527 // If our font got dirtied, go ahead and update it now. 1528 if (m_fontDirty) 1529 updateFont(); 1530 1531 // Line-height is set when we are sure we decided on the font-size 1532 if (m_lineHeightValue) 1533 applyProperty(CSSPropertyLineHeight, m_lineHeightValue); 1534 1535 // Now do rest of the properties. 1536 if (keyframeRule->style()) 1537 applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1); 1538 1539 // If our font got dirtied by one of the non-essential font props, 1540 // go ahead and update it a second time. 1541 if (m_fontDirty) 1542 updateFont(); 1543 1544 // Start loading images referenced by this style. 1545 loadPendingImages(); 1546 1547 // Add all the animating properties to the keyframe. 1548 if (keyframeRule->style()) { 1549 CSSMutableStyleDeclaration::const_iterator end = keyframeRule->style()->end(); 1550 for (CSSMutableStyleDeclaration::const_iterator it = keyframeRule->style()->begin(); it != end; ++it) { 1551 int property = (*it).id(); 1552 // Timing-function within keyframes is special, because it is not animated; it just 1553 // describes the timing function between this keyframe and the next. 1554 if (property != CSSPropertyWebkitAnimationTimingFunction) 1555 keyframe.addProperty(property); 1556 } 1557 } 1558 1559 return m_style.release(); 1560 } 1561 1562 void CSSStyleSelector::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list) 1563 { 1564 list.clear(); 1565 1566 // Get the keyframesRule for this name 1567 if (!e || list.animationName().isEmpty()) 1568 return; 1569 1570 m_keyframesRuleMap.checkConsistency(); 1571 1572 if (!m_keyframesRuleMap.contains(list.animationName().impl())) 1573 return; 1574 1575 const WebKitCSSKeyframesRule* rule = m_keyframesRuleMap.find(list.animationName().impl()).get()->second.get(); 1576 1577 // Construct and populate the style for each keyframe 1578 for (unsigned i = 0; i < rule->length(); ++i) { 1579 // Apply the declaration to the style. This is a simplified version of the logic in styleForElement 1580 initElement(e); 1581 initForStyleResolve(e); 1582 1583 const WebKitCSSKeyframeRule* keyframeRule = rule->item(i); 1584 1585 KeyframeValue keyframe(0, 0); 1586 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule, keyframe)); 1587 1588 // Add this keyframe style to all the indicated key times 1589 Vector<float> keys; 1590 keyframeRule->getKeys(keys); 1591 for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) { 1592 keyframe.setKey(keys[keyIndex]); 1593 list.insert(keyframe); 1594 } 1595 } 1596 1597 // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe) 1598 int initialListSize = list.size(); 1599 if (initialListSize > 0 && list[0].key() != 0) { 1600 RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create(); 1601 keyframeRule->setKeyText("0%"); 1602 KeyframeValue keyframe(0, 0); 1603 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe)); 1604 list.insert(keyframe); 1605 } 1606 1607 // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe) 1608 if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) { 1609 RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create(); 1610 keyframeRule->setKeyText("100%"); 1611 KeyframeValue keyframe(1, 0); 1612 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe)); 1613 list.insert(keyframe); 1614 } 1615 } 1616 1617 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForElement(PseudoId pseudo, Element* e, RenderStyle* parentStyle, bool matchVisitedPseudoClass) 1618 { 1619 if (!e) 1620 return 0; 1621 1622 initElement(e); 1623 1624 // Compute our :visited style first, so that we know whether or not we'll need to create a normal style just to hang it 1625 // off of. 1626 RefPtr<RenderStyle> visitedStyle; 1627 if (!matchVisitedPseudoClass && parentStyle && parentStyle->insideLink()) { 1628 // Fetch our parent style with :visited in effect. 1629 RenderStyle* parentVisitedStyle = parentStyle->getCachedPseudoStyle(VISITED_LINK); 1630 visitedStyle = pseudoStyleForElement(pseudo, e, parentVisitedStyle ? parentVisitedStyle : parentStyle, true); 1631 if (visitedStyle) 1632 visitedStyle->setStyleType(VISITED_LINK); 1633 } 1634 1635 initForStyleResolve(e, parentStyle, pseudo); 1636 m_style = RenderStyle::create(); 1637 if (parentStyle) 1638 m_style->inheritFrom(parentStyle); 1639 1640 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass; 1641 1642 // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking 1643 // those rules. 1644 1645 // Check UA, user and author rules. 1646 int firstUARule = -1, lastUARule = -1, firstUserRule = -1, lastUserRule = -1, firstAuthorRule = -1, lastAuthorRule = -1; 1647 matchUARules(firstUARule, lastUARule); 1648 1649 if (m_matchAuthorAndUserStyles) { 1650 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, false); 1651 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, false); 1652 } 1653 1654 if (m_matchedDecls.isEmpty() && !visitedStyle) 1655 return 0; 1656 1657 m_style->setStyleType(pseudo); 1658 1659 m_lineHeightValue = 0; 1660 1661 // Reset the value back before applying properties, so that -webkit-link knows what color to use. 1662 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass; 1663 1664 // High-priority properties. 1665 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1); 1666 applyDeclarations<true>(true, firstAuthorRule, lastAuthorRule); 1667 applyDeclarations<true>(true, firstUserRule, lastUserRule); 1668 applyDeclarations<true>(true, firstUARule, lastUARule); 1669 1670 // If our font got dirtied, go ahead and update it now. 1671 if (m_fontDirty) 1672 updateFont(); 1673 1674 // Line-height is set when we are sure we decided on the font-size 1675 if (m_lineHeightValue) 1676 applyProperty(CSSPropertyLineHeight, m_lineHeightValue); 1677 1678 // Now do the normal priority properties. 1679 applyDeclarations<false>(false, firstUARule, lastUARule); 1680 1681 // Cache our border and background so that we can examine them later. 1682 cacheBorderAndBackground(); 1683 1684 applyDeclarations<false>(false, lastUARule + 1, m_matchedDecls.size() - 1); 1685 applyDeclarations<false>(true, firstAuthorRule, lastAuthorRule); 1686 applyDeclarations<false>(true, firstUserRule, lastUserRule); 1687 applyDeclarations<false>(true, firstUARule, lastUARule); 1688 1689 // If our font got dirtied by one of the non-essential font props, 1690 // go ahead and update it a second time. 1691 if (m_fontDirty) 1692 updateFont(); 1693 1694 // Clean up our style object's display and text decorations (among other fixups). 1695 adjustRenderStyle(style(), parentStyle, 0); 1696 1697 // Start loading images referenced by this style. 1698 loadPendingImages(); 1699 1700 // Hang our visited style off m_style. 1701 if (visitedStyle) 1702 m_style->addCachedPseudoStyle(visitedStyle.release()); 1703 1704 // Now return the style. 1705 return m_style.release(); 1706 } 1707 1708 PassRefPtr<RenderStyle> CSSStyleSelector::styleForPage(int pageIndex) 1709 { 1710 initForStyleResolve(m_checker.m_document->documentElement()); // m_rootElementStyle will be set to the document style. 1711 1712 m_style = RenderStyle::create(); 1713 m_style->inheritFrom(m_rootElementStyle); 1714 1715 const bool isLeft = isLeftPage(pageIndex); 1716 const bool isFirst = isFirstPage(pageIndex); 1717 const String page = pageName(pageIndex); 1718 matchPageRules(defaultPrintStyle, isLeft, isFirst, page); 1719 matchPageRules(m_userStyle.get(), isLeft, isFirst, page); 1720 matchPageRules(m_authorStyle.get(), isLeft, isFirst, page); 1721 m_lineHeightValue = 0; 1722 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1); 1723 1724 // If our font got dirtied, go ahead and update it now. 1725 if (m_fontDirty) 1726 updateFont(); 1727 1728 // Line-height is set when we are sure we decided on the font-size 1729 if (m_lineHeightValue) 1730 applyProperty(CSSPropertyLineHeight, m_lineHeightValue); 1731 1732 applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1); 1733 1734 // Start loading images referenced by this style. 1735 loadPendingImages(); 1736 1737 // Now return the style. 1738 return m_style.release(); 1739 } 1740 1741 #if ENABLE(DATAGRID) 1742 1743 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForDataGridColumn(DataGridColumn*, RenderStyle*) 1744 { 1745 // FIXME: Implement 1746 return 0; 1747 } 1748 1749 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForDataGridColumnHeader(DataGridColumn*, RenderStyle*) 1750 { 1751 // FIXME: Implement 1752 return 0; 1753 } 1754 1755 #endif 1756 1757 static void addIntrinsicMargins(RenderStyle* style) 1758 { 1759 // Intrinsic margin value. 1760 const int intrinsicMargin = 2 * style->effectiveZoom(); 1761 1762 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed. 1763 // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame. 1764 if (style->width().isIntrinsicOrAuto()) { 1765 if (style->marginLeft().quirk()) 1766 style->setMarginLeft(Length(intrinsicMargin, Fixed)); 1767 if (style->marginRight().quirk()) 1768 style->setMarginRight(Length(intrinsicMargin, Fixed)); 1769 } 1770 1771 if (style->height().isAuto()) { 1772 if (style->marginTop().quirk()) 1773 style->setMarginTop(Length(intrinsicMargin, Fixed)); 1774 if (style->marginBottom().quirk()) 1775 style->setMarginBottom(Length(intrinsicMargin, Fixed)); 1776 } 1777 } 1778 1779 static inline bool isAtShadowBoundary(Element* element) 1780 { 1781 if (!element) 1782 return false; 1783 1784 ContainerNode* parentNode = element->parentNode(); 1785 return parentNode && parentNode->isShadowBoundary(); 1786 } 1787 1788 void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, RenderStyle* parentStyle, Element *e) 1789 { 1790 // Cache our original display. 1791 style->setOriginalDisplay(style->display()); 1792 1793 if (style->display() != NONE) { 1794 // If we have a <td> that specifies a float property, in quirks mode we just drop the float 1795 // property. 1796 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force 1797 // these tags to retain their display types. 1798 if (!m_checker.m_strictParsing && e) { 1799 if (e->hasTagName(tdTag)) { 1800 style->setDisplay(TABLE_CELL); 1801 style->setFloating(FNONE); 1802 } 1803 else if (e->hasTagName(tableTag)) 1804 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE); 1805 } 1806 1807 if (e && (e->hasTagName(tdTag) || e->hasTagName(thTag))) { 1808 if (style->whiteSpace() == KHTML_NOWRAP) { 1809 // Figure out if we are really nowrapping or if we should just 1810 // use normal instead. If the width of the cell is fixed, then 1811 // we don't actually use NOWRAP. 1812 if (style->width().isFixed()) 1813 style->setWhiteSpace(NORMAL); 1814 else 1815 style->setWhiteSpace(NOWRAP); 1816 } 1817 } 1818 1819 // Tables never support the -webkit-* values for text-align and will reset back to the default. 1820 if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT)) 1821 style->setTextAlign(TAAUTO); 1822 1823 // Frames and framesets never honor position:relative or position:absolute. This is necessary to 1824 // fix a crash where a site tries to position these objects. They also never honor display. 1825 if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) { 1826 style->setPosition(StaticPosition); 1827 style->setDisplay(BLOCK); 1828 } 1829 1830 // Table headers with a text-align of auto will change the text-align to center. 1831 if (e && e->hasTagName(thTag) && style->textAlign() == TAAUTO) 1832 style->setTextAlign(CENTER); 1833 1834 if (e && e->hasTagName(legendTag)) 1835 style->setDisplay(BLOCK); 1836 1837 // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to 1838 // position or float an inline, compact, or run-in. Cache the original display, since it 1839 // may be needed for positioned elements that have to compute their static normal flow 1840 // positions. We also force inline-level roots to be block-level. 1841 if (style->display() != BLOCK && style->display() != TABLE && style->display() != BOX && 1842 (style->position() == AbsolutePosition || style->position() == FixedPosition || style->floating() != FNONE || 1843 (e && e->document()->documentElement() == e))) { 1844 if (style->display() == INLINE_TABLE) 1845 style->setDisplay(TABLE); 1846 else if (style->display() == INLINE_BOX) 1847 style->setDisplay(BOX); 1848 else if (style->display() == LIST_ITEM) { 1849 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, 1850 // but only in quirks mode. 1851 if (!m_checker.m_strictParsing && style->floating() != FNONE) 1852 style->setDisplay(BLOCK); 1853 } 1854 else 1855 style->setDisplay(BLOCK); 1856 } 1857 1858 // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely 1859 // clear how that should work. 1860 if (style->display() == INLINE && style->styleType() == NOPSEUDO && parentStyle && style->writingMode() != parentStyle->writingMode()) 1861 style->setDisplay(INLINE_BLOCK); 1862 1863 // After performing the display mutation, check table rows. We do not honor position:relative on 1864 // table rows or cells. This has been established in CSS2.1 (and caused a crash in containingBlock() 1865 // on some sites). 1866 if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP 1867 || style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW) && 1868 style->position() == RelativePosition) 1869 style->setPosition(StaticPosition); 1870 1871 // writing-mode does not apply to table row groups, table column groups, table rows, and table columns. 1872 // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though. 1873 if (style->display() == TABLE_COLUMN || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_FOOTER_GROUP 1874 || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_ROW_GROUP 1875 || style->display() == TABLE_CELL) 1876 style->setWritingMode(parentStyle->writingMode()); 1877 1878 // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting 1879 // of block-flow to anything other than TopToBottomWritingMode. 1880 // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support. 1881 if (style->writingMode() != TopToBottomWritingMode && (style->display() == BOX || style->display() == INLINE_BOX)) 1882 style->setWritingMode(TopToBottomWritingMode); 1883 } 1884 1885 // Make sure our z-index value is only applied if the object is positioned. 1886 if (style->position() == StaticPosition) 1887 style->setHasAutoZIndex(); 1888 1889 // Auto z-index becomes 0 for the root element and transparent objects. This prevents 1890 // cases where objects that should be blended as a single unit end up with a non-transparent 1891 // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections. 1892 if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) || style->opacity() < 1.0f || 1893 style->hasTransformRelatedProperty() || style->hasMask() || style->boxReflect())) 1894 style->setZIndex(0); 1895 1896 #if ENABLE(WML) 1897 if (e && (e->hasTagName(WMLNames::insertedLegendTag) 1898 || e->hasTagName(WMLNames::inputTag)) 1899 && style->width().isAuto()) 1900 style->setWidth(Length(Intrinsic)); 1901 #endif 1902 1903 // Textarea considers overflow visible as auto. 1904 if (e && e->hasTagName(textareaTag)) { 1905 style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX()); 1906 style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY()); 1907 } 1908 1909 // Finally update our text decorations in effect, but don't allow text-decoration to percolate through 1910 // tables, inline blocks, inline tables, run-ins, or shadow DOM. 1911 if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN 1912 || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX || isAtShadowBoundary(e)) 1913 style->setTextDecorationsInEffect(style->textDecoration()); 1914 else 1915 style->addToTextDecorationsInEffect(style->textDecoration()); 1916 1917 // If either overflow value is not visible, change to auto. 1918 if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE) 1919 style->setOverflowY(OMARQUEE); 1920 else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE) 1921 style->setOverflowX(OMARQUEE); 1922 else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE) 1923 style->setOverflowX(OAUTO); 1924 else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE) 1925 style->setOverflowY(OAUTO); 1926 1927 // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto. 1928 // FIXME: Eventually table sections will support auto and scroll. 1929 if (style->display() == TABLE || style->display() == INLINE_TABLE || 1930 style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) { 1931 if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN) 1932 style->setOverflowX(OVISIBLE); 1933 if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN) 1934 style->setOverflowY(OVISIBLE); 1935 } 1936 1937 // Menulists should have visible overflow 1938 if (style->appearance() == MenulistPart) { 1939 style->setOverflowX(OVISIBLE); 1940 style->setOverflowY(OVISIBLE); 1941 } 1942 1943 // Cull out any useless layers and also repeat patterns into additional layers. 1944 style->adjustBackgroundLayers(); 1945 style->adjustMaskLayers(); 1946 1947 // Do the same for animations and transitions. 1948 style->adjustAnimations(); 1949 style->adjustTransitions(); 1950 1951 // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will 1952 // alter fonts and heights/widths. 1953 if (e && e->isFormControlElement() && style->fontSize() >= 11) { 1954 // Don't apply intrinsic margins to image buttons. The designer knows how big the images are, 1955 // so we have to treat all image buttons as though they were explicitly sized. 1956 if (!e->hasTagName(inputTag) || !static_cast<HTMLInputElement*>(e)->isImageButton()) 1957 addIntrinsicMargins(style); 1958 } 1959 1960 // Let the theme also have a crack at adjusting the style. 1961 if (style->hasAppearance()) 1962 RenderTheme::defaultTheme()->adjustStyle(this, style, e, m_hasUAAppearance, m_borderData, m_backgroundData, m_backgroundColor); 1963 1964 #if ENABLE(SVG) 1965 if (e && e->isSVGElement()) { 1966 // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty 1967 if (style->overflowY() == OSCROLL) 1968 style->setOverflowY(OHIDDEN); 1969 else if (style->overflowY() == OAUTO) 1970 style->setOverflowY(OVISIBLE); 1971 1972 if (style->overflowX() == OSCROLL) 1973 style->setOverflowX(OHIDDEN); 1974 else if (style->overflowX() == OAUTO) 1975 style->setOverflowX(OVISIBLE); 1976 1977 // Only the root <svg> element in an SVG document fragment tree honors css position 1978 if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement())) 1979 style->setPosition(RenderStyle::initialPosition()); 1980 } 1981 #endif 1982 } 1983 1984 void CSSStyleSelector::updateFont() 1985 { 1986 checkForTextSizeAdjust(); 1987 checkForGenericFamilyChange(style(), m_parentStyle); 1988 checkForZoomChange(style(), m_parentStyle); 1989 m_style->font().update(m_fontSelector); 1990 m_fontDirty = false; 1991 } 1992 1993 void CSSStyleSelector::cacheBorderAndBackground() 1994 { 1995 m_hasUAAppearance = m_style->hasAppearance(); 1996 if (m_hasUAAppearance) { 1997 m_borderData = m_style->border(); 1998 m_backgroundData = *m_style->backgroundLayers(); 1999 m_backgroundColor = m_style->backgroundColor(); 2000 } 2001 } 2002 2003 PassRefPtr<CSSRuleList> CSSStyleSelector::styleRulesForElement(Element* e, bool authorOnly, bool includeEmptyRules, CSSRuleFilter filter) 2004 { 2005 return pseudoStyleRulesForElement(e, NOPSEUDO, authorOnly, includeEmptyRules, filter); 2006 } 2007 2008 PassRefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, bool authorOnly, bool includeEmptyRules, CSSRuleFilter filter) 2009 { 2010 if (!e || !e->document()->haveStylesheetsLoaded()) 2011 return 0; 2012 2013 m_checker.m_collectRulesOnly = true; 2014 2015 initElement(e); 2016 initForStyleResolve(e, 0, pseudoId); 2017 2018 if (!authorOnly) { 2019 int firstUARule = -1, lastUARule = -1; 2020 // First we match rules from the user agent sheet. 2021 matchUARules(firstUARule, lastUARule); 2022 2023 // Now we check user sheet rules. 2024 if (m_matchAuthorAndUserStyles) { 2025 int firstUserRule = -1, lastUserRule = -1; 2026 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, includeEmptyRules); 2027 } 2028 } 2029 2030 if (m_matchAuthorAndUserStyles) { 2031 m_checker.m_sameOriginOnly = (filter == SameOriginCSSRulesOnly); 2032 2033 // Check the rules in author sheets. 2034 int firstAuthorRule = -1, lastAuthorRule = -1; 2035 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, includeEmptyRules); 2036 2037 m_checker.m_sameOriginOnly = false; 2038 } 2039 2040 m_checker.m_collectRulesOnly = false; 2041 2042 return m_ruleList.release(); 2043 } 2044 2045 inline bool CSSStyleSelector::checkSelector(const RuleData& ruleData) 2046 { 2047 m_dynamicPseudo = NOPSEUDO; 2048 2049 // Let the slow path handle SVG as it has some additional rules regarding shadow trees. 2050 if (ruleData.hasFastCheckableSelector() && !m_element->isSVGElement()) { 2051 // We know this selector does not include any pseudo selectors. 2052 if (m_checker.m_pseudoStyle != NOPSEUDO) 2053 return false; 2054 // We know a sufficiently simple single part selector matches simply because we found it from the rule hash. 2055 // This is limited to HTML only so we don't need to check the namespace. 2056 if (ruleData.hasTopSelectorMatchingHTMLBasedOnRuleHash() && !ruleData.hasMultipartSelector() && m_element->isHTMLElement()) 2057 return true; 2058 return SelectorChecker::fastCheckSelector(ruleData.selector(), m_element); 2059 } 2060 2061 // Slow path. 2062 SelectorMatch match = m_checker.checkSelector(ruleData.selector(), m_element, &m_selectorAttrs, m_dynamicPseudo, false, false, style(), m_parentNode ? m_parentNode->renderStyle() : 0); 2063 if (match != SelectorMatches) 2064 return false; 2065 if (m_checker.m_pseudoStyle != NOPSEUDO && m_checker.m_pseudoStyle != m_dynamicPseudo) 2066 return false; 2067 return true; 2068 } 2069 2070 static inline bool selectorTagMatches(const Element* element, const CSSSelector* selector) 2071 { 2072 if (!selector->hasTag()) 2073 return true; 2074 const AtomicString& localName = selector->tag().localName(); 2075 if (localName != starAtom && localName != element->localName()) 2076 return false; 2077 const AtomicString& namespaceURI = selector->tag().namespaceURI(); 2078 return namespaceURI == starAtom || namespaceURI == element->namespaceURI(); 2079 } 2080 2081 static inline bool isFastCheckableSelector(const CSSSelector* selector) 2082 { 2083 for (; selector; selector = selector->tagHistory()) { 2084 if (selector->relation() != CSSSelector::Descendant && selector->relation() != CSSSelector::Child && selector->relation() != CSSSelector::SubSelector) 2085 return false; 2086 if (selector->m_match != CSSSelector::None && selector->m_match != CSSSelector::Id && selector->m_match != CSSSelector::Class) 2087 return false; 2088 } 2089 return true; 2090 } 2091 2092 template <class ValueChecker> 2093 inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement) 2094 { 2095 AtomicStringImpl* value = selector->value().impl(); 2096 for (; element; element = element->parentElement()) { 2097 if (ValueChecker::checkValue(element, value) && selectorTagMatches(element, selector)) { 2098 if (selector->relation() == CSSSelector::Descendant) 2099 topChildOrSubselector = 0; 2100 else if (!topChildOrSubselector) { 2101 ASSERT(selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector); 2102 topChildOrSubselector = selector; 2103 topChildOrSubselectorMatchElement = element; 2104 } 2105 if (selector->relation() != CSSSelector::SubSelector) 2106 element = element->parentElement(); 2107 selector = selector->tagHistory(); 2108 return true; 2109 } 2110 if (topChildOrSubselector) { 2111 // Child or subselector check failed. 2112 // If the match element is null, topChildOrSubselector was also the very topmost selector and had to match 2113 // the original element we were checking. 2114 if (!topChildOrSubselectorMatchElement) 2115 return false; 2116 // There may be other matches down the ancestor chain. 2117 // Rewind to the topmost child or subselector and the element it matched, continue checking ancestors. 2118 selector = topChildOrSubselector; 2119 element = topChildOrSubselectorMatchElement->parentElement(); 2120 topChildOrSubselector = 0; 2121 return true; 2122 } 2123 } 2124 return false; 2125 } 2126 2127 struct ClassCheck { 2128 static bool checkValue(const Element* element, AtomicStringImpl* value) 2129 { 2130 return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(value); 2131 } 2132 }; 2133 struct IdCheck { 2134 static bool checkValue(const Element* element, AtomicStringImpl* value) 2135 { 2136 return element->hasID() && element->idForStyleResolution().impl() == value; 2137 } 2138 }; 2139 struct TagCheck { 2140 static bool checkValue(const Element*, AtomicStringImpl*) 2141 { 2142 return true; 2143 } 2144 }; 2145 2146 bool CSSStyleSelector::SelectorChecker::fastCheckSelector(const CSSSelector* selector, const Element* element) 2147 { 2148 ASSERT(isFastCheckableSelector(selector)); 2149 2150 // The top selector requires tag check only as rule hashes have already handled id and class matches. 2151 if (!selectorTagMatches(element, selector)) 2152 return false; 2153 2154 const CSSSelector* topChildOrSubselector = 0; 2155 const Element* topChildOrSubselectorMatchElement = 0; 2156 if (selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector) 2157 topChildOrSubselector = selector; 2158 2159 if (selector->relation() != CSSSelector::SubSelector) 2160 element = element->parentElement(); 2161 2162 selector = selector->tagHistory(); 2163 2164 // We know this compound selector has descendant, child and subselector combinators only and all components are simple. 2165 while (selector) { 2166 switch (selector->m_match) { 2167 case CSSSelector::Class: 2168 if (!fastCheckSingleSelector<ClassCheck>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) 2169 return false; 2170 break; 2171 case CSSSelector::Id: 2172 if (!fastCheckSingleSelector<IdCheck>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) 2173 return false; 2174 break; 2175 case CSSSelector::None: 2176 if (!fastCheckSingleSelector<TagCheck>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) 2177 return false; 2178 break; 2179 default: 2180 ASSERT_NOT_REACHED(); 2181 } 2182 } 2183 return true; 2184 } 2185 2186 // Recursive check of selectors and combinators 2187 // It can return 3 different values: 2188 // * SelectorMatches - the selector matches the element e 2189 // * SelectorFailsLocally - the selector fails for the element e 2190 // * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e 2191 CSSStyleSelector::SelectorMatch CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const 2192 { 2193 #if ENABLE(SVG) 2194 // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree 2195 // because its contents are not part of the formal document structure. 2196 if (e->isSVGElement() && e->isShadowRoot()) 2197 return SelectorFailsCompletely; 2198 #endif 2199 2200 // first selector has to match 2201 if (!checkOneSelector(sel, e, selectorAttrs, dynamicPseudo, isSubSelector, encounteredLink, elementStyle, elementParentStyle)) 2202 return SelectorFailsLocally; 2203 2204 // The rest of the selectors has to match 2205 CSSSelector::Relation relation = sel->relation(); 2206 2207 // Prepare next sel 2208 sel = sel->tagHistory(); 2209 if (!sel) 2210 return SelectorMatches; 2211 2212 if (relation != CSSSelector::SubSelector) 2213 // Bail-out if this selector is irrelevant for the pseudoStyle 2214 if (m_pseudoStyle != NOPSEUDO && m_pseudoStyle != dynamicPseudo) 2215 return SelectorFailsCompletely; 2216 2217 // Check for nested links. 2218 if (m_matchVisitedPseudoClass && !isSubSelector) { 2219 RenderStyle* currentStyle = elementStyle ? elementStyle : e->renderStyle(); 2220 if (currentStyle && currentStyle->insideLink() && e->isLink()) { 2221 if (encounteredLink) 2222 m_matchVisitedPseudoClass = false; // This link is not relevant to the style being resolved, so disable matching. 2223 else 2224 encounteredLink = true; 2225 } 2226 } 2227 2228 switch (relation) { 2229 case CSSSelector::Descendant: 2230 while (true) { 2231 ContainerNode* n = e->parentNode(); 2232 if (!n || !n->isElementNode()) 2233 return SelectorFailsCompletely; 2234 e = static_cast<Element*>(n); 2235 SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); 2236 if (match != SelectorFailsLocally) 2237 return match; 2238 } 2239 break; 2240 case CSSSelector::Child: 2241 { 2242 ContainerNode* n = e->parentNode(); 2243 if (!n || !n->isElementNode()) 2244 return SelectorFailsCompletely; 2245 e = static_cast<Element*>(n); 2246 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); 2247 } 2248 case CSSSelector::DirectAdjacent: 2249 { 2250 if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) { 2251 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); 2252 if (parentStyle) 2253 parentStyle->setChildrenAffectedByDirectAdjacentRules(); 2254 } 2255 Node* n = e->previousSibling(); 2256 while (n && !n->isElementNode()) 2257 n = n->previousSibling(); 2258 if (!n) 2259 return SelectorFailsLocally; 2260 e = static_cast<Element*>(n); 2261 m_matchVisitedPseudoClass = false; 2262 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); 2263 } 2264 case CSSSelector::IndirectAdjacent: 2265 if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) { 2266 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); 2267 if (parentStyle) 2268 parentStyle->setChildrenAffectedByForwardPositionalRules(); 2269 } 2270 while (true) { 2271 Node* n = e->previousSibling(); 2272 while (n && !n->isElementNode()) 2273 n = n->previousSibling(); 2274 if (!n) 2275 return SelectorFailsLocally; 2276 e = static_cast<Element*>(n); 2277 m_matchVisitedPseudoClass = false; 2278 SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); 2279 if (match != SelectorFailsLocally) 2280 return match; 2281 }; 2282 break; 2283 case CSSSelector::SubSelector: 2284 // a selector is invalid if something follows a pseudo-element 2285 // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else) 2286 // to follow the pseudo elements. 2287 if ((elementStyle || m_collectRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION && 2288 !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && sel->m_match == CSSSelector::PseudoClass)) 2289 return SelectorFailsCompletely; 2290 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle); 2291 case CSSSelector::ShadowDescendant: 2292 { 2293 Node* shadowHostNode = e->shadowAncestorNode(); 2294 if (shadowHostNode == e || !shadowHostNode->isElementNode()) 2295 return SelectorFailsCompletely; 2296 e = static_cast<Element*>(shadowHostNode); 2297 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); 2298 } 2299 } 2300 2301 return SelectorFailsCompletely; 2302 } 2303 2304 static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName) 2305 { 2306 set->add(qName.localName().impl()); 2307 } 2308 2309 static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet() 2310 { 2311 // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive 2312 // Mozilla treats all other values as case-sensitive, thus so do we. 2313 HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>; 2314 2315 addLocalNameToSet(attrSet, accept_charsetAttr); 2316 addLocalNameToSet(attrSet, acceptAttr); 2317 addLocalNameToSet(attrSet, alignAttr); 2318 addLocalNameToSet(attrSet, alinkAttr); 2319 addLocalNameToSet(attrSet, axisAttr); 2320 addLocalNameToSet(attrSet, bgcolorAttr); 2321 addLocalNameToSet(attrSet, charsetAttr); 2322 addLocalNameToSet(attrSet, checkedAttr); 2323 addLocalNameToSet(attrSet, clearAttr); 2324 addLocalNameToSet(attrSet, codetypeAttr); 2325 addLocalNameToSet(attrSet, colorAttr); 2326 addLocalNameToSet(attrSet, compactAttr); 2327 addLocalNameToSet(attrSet, declareAttr); 2328 addLocalNameToSet(attrSet, deferAttr); 2329 addLocalNameToSet(attrSet, dirAttr); 2330 addLocalNameToSet(attrSet, disabledAttr); 2331 addLocalNameToSet(attrSet, enctypeAttr); 2332 addLocalNameToSet(attrSet, faceAttr); 2333 addLocalNameToSet(attrSet, frameAttr); 2334 addLocalNameToSet(attrSet, hreflangAttr); 2335 addLocalNameToSet(attrSet, http_equivAttr); 2336 addLocalNameToSet(attrSet, langAttr); 2337 addLocalNameToSet(attrSet, languageAttr); 2338 addLocalNameToSet(attrSet, linkAttr); 2339 addLocalNameToSet(attrSet, mediaAttr); 2340 addLocalNameToSet(attrSet, methodAttr); 2341 addLocalNameToSet(attrSet, multipleAttr); 2342 addLocalNameToSet(attrSet, nohrefAttr); 2343 addLocalNameToSet(attrSet, noresizeAttr); 2344 addLocalNameToSet(attrSet, noshadeAttr); 2345 addLocalNameToSet(attrSet, nowrapAttr); 2346 addLocalNameToSet(attrSet, readonlyAttr); 2347 addLocalNameToSet(attrSet, relAttr); 2348 addLocalNameToSet(attrSet, revAttr); 2349 addLocalNameToSet(attrSet, rulesAttr); 2350 addLocalNameToSet(attrSet, scopeAttr); 2351 addLocalNameToSet(attrSet, scrollingAttr); 2352 addLocalNameToSet(attrSet, selectedAttr); 2353 addLocalNameToSet(attrSet, shapeAttr); 2354 addLocalNameToSet(attrSet, targetAttr); 2355 addLocalNameToSet(attrSet, textAttr); 2356 addLocalNameToSet(attrSet, typeAttr); 2357 addLocalNameToSet(attrSet, valignAttr); 2358 addLocalNameToSet(attrSet, valuetypeAttr); 2359 addLocalNameToSet(attrSet, vlinkAttr); 2360 2361 return attrSet; 2362 } 2363 2364 static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr) 2365 { 2366 static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet(); 2367 bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom); 2368 return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl()); 2369 } 2370 2371 bool CSSStyleSelector::SelectorChecker::checkOneSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const 2372 { 2373 ASSERT(e); 2374 if (!e) 2375 return false; 2376 2377 if (!selectorTagMatches(e, sel)) 2378 return false; 2379 2380 if (sel->hasAttribute()) { 2381 if (sel->m_match == CSSSelector::Class) 2382 return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value()); 2383 2384 if (sel->m_match == CSSSelector::Id) 2385 return e->hasID() && e->idForStyleResolution() == sel->value(); 2386 2387 const QualifiedName& attr = sel->attribute(); 2388 2389 // FIXME: Handle the case were elementStyle is 0. 2390 if (elementStyle && (!e->isStyledElement() || (!static_cast<StyledElement*>(e)->isMappedAttribute(attr) && attr != typeAttr && attr != readonlyAttr))) { 2391 elementStyle->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style. 2392 if (selectorAttrs) 2393 selectorAttrs->add(attr.localName().impl()); 2394 } 2395 2396 const AtomicString& value = e->getAttribute(attr); 2397 if (value.isNull()) 2398 return false; // attribute is not set 2399 2400 bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr); 2401 2402 switch (sel->m_match) { 2403 case CSSSelector::Exact: 2404 if (caseSensitive ? sel->value() != value : !equalIgnoringCase(sel->value(), value)) 2405 return false; 2406 break; 2407 case CSSSelector::List: 2408 { 2409 // Ignore empty selectors or selectors containing spaces 2410 if (sel->value().contains(' ') || sel->value().isEmpty()) 2411 return false; 2412 2413 unsigned startSearchAt = 0; 2414 while (true) { 2415 size_t foundPos = value.find(sel->value(), startSearchAt, caseSensitive); 2416 if (foundPos == notFound) 2417 return false; 2418 if (foundPos == 0 || value[foundPos - 1] == ' ') { 2419 unsigned endStr = foundPos + sel->value().length(); 2420 if (endStr == value.length() || value[endStr] == ' ') 2421 break; // We found a match. 2422 } 2423 2424 // No match. Keep looking. 2425 startSearchAt = foundPos + 1; 2426 } 2427 break; 2428 } 2429 case CSSSelector::Contain: 2430 if (!value.contains(sel->value(), caseSensitive) || sel->value().isEmpty()) 2431 return false; 2432 break; 2433 case CSSSelector::Begin: 2434 if (!value.startsWith(sel->value(), caseSensitive) || sel->value().isEmpty()) 2435 return false; 2436 break; 2437 case CSSSelector::End: 2438 if (!value.endsWith(sel->value(), caseSensitive) || sel->value().isEmpty()) 2439 return false; 2440 break; 2441 case CSSSelector::Hyphen: 2442 if (value.length() < sel->value().length()) 2443 return false; 2444 if (!value.startsWith(sel->value(), caseSensitive)) 2445 return false; 2446 // It they start the same, check for exact match or following '-': 2447 if (value.length() != sel->value().length() && value[sel->value().length()] != '-') 2448 return false; 2449 break; 2450 case CSSSelector::PseudoClass: 2451 case CSSSelector::PseudoElement: 2452 default: 2453 break; 2454 } 2455 } 2456 2457 if (sel->m_match == CSSSelector::PseudoClass) { 2458 // Handle :not up front. 2459 if (sel->pseudoType() == CSSSelector::PseudoNot) { 2460 ASSERT(sel->selectorList()); 2461 for (CSSSelector* subSel = sel->selectorList()->first(); subSel; subSel = subSel->tagHistory()) { 2462 // :not cannot nest. I don't really know why this is a 2463 // restriction in CSS3, but it is, so let's honor it. 2464 // the parser enforces that this never occurs 2465 ASSERT(subSel->pseudoType() != CSSSelector::PseudoNot); 2466 2467 if (!checkOneSelector(subSel, e, selectorAttrs, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle)) 2468 return true; 2469 } 2470 } else if (dynamicPseudo != NOPSEUDO && (RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER)) { 2471 // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each 2472 // (since there are no elements involved). 2473 return checkScrollbarPseudoClass(sel, dynamicPseudo); 2474 } else if (dynamicPseudo == SELECTION) { 2475 if (sel->pseudoType() == CSSSelector::PseudoWindowInactive) 2476 return !m_document->page()->focusController()->isActive(); 2477 } 2478 2479 // Normal element pseudo class checking. 2480 switch (sel->pseudoType()) { 2481 // Pseudo classes: 2482 case CSSSelector::PseudoNot: 2483 break; // Already handled up above. 2484 case CSSSelector::PseudoEmpty: { 2485 bool result = true; 2486 for (Node* n = e->firstChild(); n; n = n->nextSibling()) { 2487 if (n->isElementNode()) { 2488 result = false; 2489 break; 2490 } else if (n->isTextNode()) { 2491 Text* textNode = static_cast<Text*>(n); 2492 if (!textNode->data().isEmpty()) { 2493 result = false; 2494 break; 2495 } 2496 } 2497 } 2498 if (!m_collectRulesOnly) { 2499 if (elementStyle) 2500 elementStyle->setEmptyState(result); 2501 else if (e->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique())) 2502 e->renderStyle()->setEmptyState(result); 2503 } 2504 return result; 2505 } 2506 case CSSSelector::PseudoFirstChild: { 2507 // first-child matches the first child that is an element 2508 if (e->parentNode() && e->parentNode()->isElementNode()) { 2509 bool result = false; 2510 Node* n = e->previousSibling(); 2511 while (n && !n->isElementNode()) 2512 n = n->previousSibling(); 2513 if (!n) 2514 result = true; 2515 if (!m_collectRulesOnly) { 2516 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); 2517 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); 2518 if (parentStyle) 2519 parentStyle->setChildrenAffectedByFirstChildRules(); 2520 if (result && childStyle) 2521 childStyle->setFirstChildState(); 2522 } 2523 return result; 2524 } 2525 break; 2526 } 2527 case CSSSelector::PseudoFirstOfType: { 2528 // first-of-type matches the first element of its type 2529 if (e->parentNode() && e->parentNode()->isElementNode()) { 2530 bool result = false; 2531 const QualifiedName& type = e->tagQName(); 2532 Node* n = e->previousSibling(); 2533 while (n) { 2534 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) 2535 break; 2536 n = n->previousSibling(); 2537 } 2538 if (!n) 2539 result = true; 2540 if (!m_collectRulesOnly) { 2541 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); 2542 if (parentStyle) 2543 parentStyle->setChildrenAffectedByForwardPositionalRules(); 2544 } 2545 return result; 2546 } 2547 break; 2548 } 2549 case CSSSelector::PseudoLastChild: { 2550 // last-child matches the last child that is an element 2551 if (Element* parentElement = e->parentElement()) { 2552 bool result = false; 2553 if (parentElement->isFinishedParsingChildren()) { 2554 Node* n = e->nextSibling(); 2555 while (n && !n->isElementNode()) 2556 n = n->nextSibling(); 2557 if (!n) 2558 result = true; 2559 } 2560 if (!m_collectRulesOnly) { 2561 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); 2562 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); 2563 if (parentStyle) 2564 parentStyle->setChildrenAffectedByLastChildRules(); 2565 if (result && childStyle) 2566 childStyle->setLastChildState(); 2567 } 2568 return result; 2569 } 2570 break; 2571 } 2572 case CSSSelector::PseudoLastOfType: { 2573 // last-of-type matches the last element of its type 2574 if (Element* parentElement = e->parentElement()) { 2575 if (!m_collectRulesOnly) { 2576 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); 2577 if (parentStyle) 2578 parentStyle->setChildrenAffectedByBackwardPositionalRules(); 2579 } 2580 if (!parentElement->isFinishedParsingChildren()) 2581 return false; 2582 bool result = false; 2583 const QualifiedName& type = e->tagQName(); 2584 Node* n = e->nextSibling(); 2585 while (n) { 2586 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) 2587 break; 2588 n = n->nextSibling(); 2589 } 2590 if (!n) 2591 result = true; 2592 return result; 2593 } 2594 break; 2595 } 2596 case CSSSelector::PseudoOnlyChild: { 2597 if (Element* parentElement = e->parentElement()) { 2598 bool firstChild = false; 2599 bool lastChild = false; 2600 2601 Node* n = e->previousSibling(); 2602 while (n && !n->isElementNode()) 2603 n = n->previousSibling(); 2604 if (!n) 2605 firstChild = true; 2606 if (firstChild && parentElement->isFinishedParsingChildren()) { 2607 n = e->nextSibling(); 2608 while (n && !n->isElementNode()) 2609 n = n->nextSibling(); 2610 if (!n) 2611 lastChild = true; 2612 } 2613 if (!m_collectRulesOnly) { 2614 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); 2615 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); 2616 if (parentStyle) { 2617 parentStyle->setChildrenAffectedByFirstChildRules(); 2618 parentStyle->setChildrenAffectedByLastChildRules(); 2619 } 2620 if (firstChild && childStyle) 2621 childStyle->setFirstChildState(); 2622 if (lastChild && childStyle) 2623 childStyle->setLastChildState(); 2624 } 2625 return firstChild && lastChild; 2626 } 2627 break; 2628 } 2629 case CSSSelector::PseudoOnlyOfType: { 2630 // FIXME: This selector is very slow. 2631 if (Element* parentElement = e->parentElement()) { 2632 if (!m_collectRulesOnly) { 2633 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); 2634 if (parentStyle) { 2635 parentStyle->setChildrenAffectedByForwardPositionalRules(); 2636 parentStyle->setChildrenAffectedByBackwardPositionalRules(); 2637 } 2638 } 2639 if (!parentElement->isFinishedParsingChildren()) 2640 return false; 2641 bool firstChild = false; 2642 bool lastChild = false; 2643 const QualifiedName& type = e->tagQName(); 2644 Node* n = e->previousSibling(); 2645 while (n) { 2646 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) 2647 break; 2648 n = n->previousSibling(); 2649 } 2650 if (!n) 2651 firstChild = true; 2652 if (firstChild) { 2653 n = e->nextSibling(); 2654 while (n) { 2655 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) 2656 break; 2657 n = n->nextSibling(); 2658 } 2659 if (!n) 2660 lastChild = true; 2661 } 2662 return firstChild && lastChild; 2663 } 2664 break; 2665 } 2666 case CSSSelector::PseudoNthChild: { 2667 if (!sel->parseNth()) 2668 break; 2669 if (Element* parentElement = e->parentElement()) { 2670 int count = 1; 2671 Node* n = e->previousSibling(); 2672 while (n) { 2673 if (n->isElementNode()) { 2674 RenderStyle* s = n->renderStyle(); 2675 unsigned index = s ? s->childIndex() : 0; 2676 if (index) { 2677 count += index; 2678 break; 2679 } 2680 count++; 2681 } 2682 n = n->previousSibling(); 2683 } 2684 2685 if (!m_collectRulesOnly) { 2686 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); 2687 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); 2688 if (childStyle) 2689 childStyle->setChildIndex(count); 2690 if (parentStyle) 2691 parentStyle->setChildrenAffectedByForwardPositionalRules(); 2692 } 2693 2694 if (sel->matchNth(count)) 2695 return true; 2696 } 2697 break; 2698 } 2699 case CSSSelector::PseudoNthOfType: { 2700 if (!sel->parseNth()) 2701 break; 2702 if (Element* parentElement = e->parentElement()) { 2703 int count = 1; 2704 const QualifiedName& type = e->tagQName(); 2705 Node* n = e->previousSibling(); 2706 while (n) { 2707 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) 2708 count++; 2709 n = n->previousSibling(); 2710 } 2711 2712 if (!m_collectRulesOnly) { 2713 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); 2714 if (parentStyle) 2715 parentStyle->setChildrenAffectedByForwardPositionalRules(); 2716 } 2717 2718 if (sel->matchNth(count)) 2719 return true; 2720 } 2721 break; 2722 } 2723 case CSSSelector::PseudoNthLastChild: { 2724 if (!sel->parseNth()) 2725 break; 2726 if (Element* parentElement = e->parentElement()) { 2727 if (!m_collectRulesOnly) { 2728 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); 2729 if (parentStyle) 2730 parentStyle->setChildrenAffectedByBackwardPositionalRules(); 2731 } 2732 if (!parentElement->isFinishedParsingChildren()) 2733 return false; 2734 int count = 1; 2735 Node* n = e->nextSibling(); 2736 while (n) { 2737 if (n->isElementNode()) 2738 count++; 2739 n = n->nextSibling(); 2740 } 2741 if (sel->matchNth(count)) 2742 return true; 2743 } 2744 break; 2745 } 2746 case CSSSelector::PseudoNthLastOfType: { 2747 if (!sel->parseNth()) 2748 break; 2749 if (Element* parentElement = e->parentElement()) { 2750 if (!m_collectRulesOnly) { 2751 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); 2752 if (parentStyle) 2753 parentStyle->setChildrenAffectedByBackwardPositionalRules(); 2754 } 2755 if (!parentElement->isFinishedParsingChildren()) 2756 return false; 2757 int count = 1; 2758 const QualifiedName& type = e->tagQName(); 2759 Node* n = e->nextSibling(); 2760 while (n) { 2761 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) 2762 count++; 2763 n = n->nextSibling(); 2764 } 2765 if (sel->matchNth(count)) 2766 return true; 2767 } 2768 break; 2769 } 2770 case CSSSelector::PseudoTarget: 2771 if (e == e->document()->cssTarget()) 2772 return true; 2773 break; 2774 case CSSSelector::PseudoAny: 2775 for (CSSSelector* selector = sel->selectorList()->first(); selector; selector = CSSSelectorList::next(selector)) { 2776 if (checkSelector(selector, e, selectorAttrs, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle) == SelectorMatches) 2777 return true; 2778 } 2779 break; 2780 case CSSSelector::PseudoAnyLink: 2781 if (e && e->isLink()) 2782 return true; 2783 break; 2784 case CSSSelector::PseudoAutofill: { 2785 if (!e || !e->isFormControlElement()) 2786 break; 2787 if (InputElement* inputElement = e->toInputElement()) 2788 return inputElement->isAutofilled(); 2789 break; 2790 } 2791 case CSSSelector::PseudoLink: 2792 if (e && e->isLink()) 2793 return !m_matchVisitedPseudoClass; 2794 break; 2795 case CSSSelector::PseudoVisited: 2796 if (e && e->isLink()) 2797 return m_matchVisitedPseudoClass; 2798 break; 2799 case CSSSelector::PseudoDrag: { 2800 if (elementStyle) 2801 elementStyle->setAffectedByDragRules(true); 2802 else if (e->renderStyle()) 2803 e->renderStyle()->setAffectedByDragRules(true); 2804 if (e->renderer() && e->renderer()->isDragging()) 2805 return true; 2806 break; 2807 } 2808 case CSSSelector::PseudoFocus: 2809 if (e && e->focused() && e->document()->frame() && e->document()->frame()->selection()->isFocusedAndActive()) 2810 return true; 2811 break; 2812 case CSSSelector::PseudoHover: { 2813 // If we're in quirks mode, then hover should never match anchors with no 2814 // href and *:hover should not match anything. This is important for sites like wsj.com. 2815 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) { 2816 if (elementStyle) 2817 elementStyle->setAffectedByHoverRules(true); 2818 else if (e->renderStyle()) 2819 e->renderStyle()->setAffectedByHoverRules(true); 2820 if (e->hovered()) 2821 return true; 2822 } 2823 break; 2824 } 2825 case CSSSelector::PseudoActive: 2826 // If we're in quirks mode, then :active should never match anchors with no 2827 // href and *:active should not match anything. 2828 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) { 2829 if (elementStyle) 2830 elementStyle->setAffectedByActiveRules(true); 2831 else if (e->renderStyle()) 2832 e->renderStyle()->setAffectedByActiveRules(true); 2833 if (e->active()) 2834 return true; 2835 } 2836 break; 2837 case CSSSelector::PseudoEnabled: 2838 if (e && e->isFormControlElement()) 2839 return e->isEnabledFormControl(); 2840 break; 2841 case CSSSelector::PseudoFullPageMedia: 2842 return e && e->document() && e->document()->isMediaDocument(); 2843 break; 2844 case CSSSelector::PseudoDefault: 2845 return e && e->isDefaultButtonForForm(); 2846 case CSSSelector::PseudoDisabled: 2847 if (e && e->isFormControlElement()) 2848 return !e->isEnabledFormControl(); 2849 break; 2850 case CSSSelector::PseudoReadOnly: { 2851 if (!e || !e->isFormControlElement()) 2852 return false; 2853 return e->isTextFormControl() && e->isReadOnlyFormControl(); 2854 } 2855 case CSSSelector::PseudoReadWrite: { 2856 if (!e || !e->isFormControlElement()) 2857 return false; 2858 return e->isTextFormControl() && !e->isReadOnlyFormControl(); 2859 } 2860 case CSSSelector::PseudoOptional: 2861 return e && e->isOptionalFormControl(); 2862 case CSSSelector::PseudoRequired: 2863 return e && e->isRequiredFormControl(); 2864 case CSSSelector::PseudoValid: { 2865 if (!e) 2866 return false; 2867 e->document()->setContainsValidityStyleRules(); 2868 return e->willValidate() && e->isValidFormControlElement(); 2869 } case CSSSelector::PseudoInvalid: { 2870 if (!e) 2871 return false; 2872 e->document()->setContainsValidityStyleRules(); 2873 return (e->willValidate() && !e->isValidFormControlElement()) || e->hasUnacceptableValue(); 2874 } case CSSSelector::PseudoChecked: { 2875 if (!e || !e->isFormControlElement()) 2876 break; 2877 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that 2878 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just 2879 // obey the CSS spec here in the test for matching the pseudo. 2880 InputElement* inputElement = e->toInputElement(); 2881 if (inputElement && inputElement->isChecked() && !inputElement->isIndeterminate()) 2882 return true; 2883 break; 2884 } 2885 case CSSSelector::PseudoIndeterminate: { 2886 if (!e || !e->isFormControlElement()) 2887 break; 2888 InputElement* inputElement = e->toInputElement(); 2889 if (inputElement && inputElement->isIndeterminate()) 2890 return true; 2891 break; 2892 } 2893 case CSSSelector::PseudoRoot: 2894 if (e == e->document()->documentElement()) 2895 return true; 2896 break; 2897 case CSSSelector::PseudoLang: { 2898 AtomicString value = e->computeInheritedLanguage(); 2899 const AtomicString& argument = sel->argument(); 2900 if (value.isEmpty() || !value.startsWith(argument, false)) 2901 break; 2902 if (value.length() != argument.length() && value[argument.length()] != '-') 2903 break; 2904 return true; 2905 } 2906 #if ENABLE(FULLSCREEN_API) 2907 case CSSSelector::PseudoFullScreen: 2908 // While a Document is in the fullscreen state, and the document's current fullscreen 2909 // element is an element in the document, the 'full-screen' pseudoclass applies to 2910 // that element. Also, an <iframe>, <object> or <embed> element whose child browsing 2911 // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied. 2912 if (!e->document()->webkitIsFullScreen()) 2913 return false; 2914 if (e != e->document()->webkitCurrentFullScreenElement()) 2915 return false; 2916 return true; 2917 case CSSSelector::PseudoFullScreenDocument: 2918 // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies 2919 // t