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, 2012, 2013 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 * Copyright (C) Research In Motion Limited 2011. All rights reserved. 11 * Copyright (C) 2012 Google Inc. All rights reserved. 12 * 13 * This library is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU Library General Public 15 * License as published by the Free Software Foundation; either 16 * version 2 of the License, or (at your option) any later version. 17 * 18 * This library is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 * Library General Public License for more details. 22 * 23 * You should have received a copy of the GNU Library General Public License 24 * along with this library; see the file COPYING.LIB. If not, write to 25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 * Boston, MA 02110-1301, USA. 27 */ 28 29 #include "config.h" 30 #include "core/css/resolver/StyleResolver.h" 31 32 #include "CSSPropertyNames.h" 33 #include "HTMLNames.h" 34 #include "RuntimeEnabledFeatures.h" 35 #include "StylePropertyShorthand.h" 36 #include "core/animation/AnimatableNumber.h" 37 #include "core/animation/AnimatableValue.h" 38 #include "core/animation/Animation.h" 39 #include "core/animation/DocumentTimeline.h" 40 #include "core/animation/css/CSSAnimatableValueFactory.h" 41 #include "core/animation/css/CSSAnimations.h" 42 #include "core/css/CSSCalculationValue.h" 43 #include "core/css/CSSDefaultStyleSheets.h" 44 #include "core/css/CSSFontSelector.h" 45 #include "core/css/CSSKeyframeRule.h" 46 #include "core/css/CSSKeyframesRule.h" 47 #include "core/css/CSSParser.h" 48 #include "core/css/CSSReflectValue.h" 49 #include "core/css/CSSRuleList.h" 50 #include "core/css/CSSSelector.h" 51 #include "core/css/CSSStyleRule.h" 52 #include "core/css/CSSValueList.h" 53 #include "core/css/CSSVariableValue.h" 54 #include "core/css/ElementRuleCollector.h" 55 #include "core/css/MediaQueryEvaluator.h" 56 #include "core/css/PageRuleCollector.h" 57 #include "core/css/RuleSet.h" 58 #include "core/css/StylePropertySet.h" 59 #include "core/css/resolver/AnimatedStyleBuilder.h" 60 #include "core/css/resolver/MatchResult.h" 61 #include "core/css/resolver/MediaQueryResult.h" 62 #include "core/css/resolver/SharedStyleFinder.h" 63 #include "core/css/resolver/StyleAdjuster.h" 64 #include "core/css/resolver/StyleBuilder.h" 65 #include "core/css/resolver/ViewportStyleResolver.h" 66 #include "core/dom/DocumentStyleSheetCollection.h" 67 #include "core/dom/NodeRenderStyle.h" 68 #include "core/dom/NodeRenderingContext.h" 69 #include "core/dom/Text.h" 70 #include "core/dom/shadow/ContentDistributor.h" 71 #include "core/dom/shadow/ElementShadow.h" 72 #include "core/dom/shadow/ShadowRoot.h" 73 #include "core/html/HTMLIFrameElement.h" 74 #include "core/inspector/InspectorInstrumentation.h" 75 #include "core/page/Frame.h" 76 #include "core/page/FrameView.h" 77 #include "core/rendering/RenderView.h" 78 #include "core/rendering/style/KeyframeList.h" 79 #include "core/rendering/style/StyleCustomFilterProgramCache.h" 80 #include "core/svg/SVGDocumentExtensions.h" 81 #include "core/svg/SVGElement.h" 82 #include "core/svg/SVGFontFaceElement.h" 83 #include "wtf/StdLibExtras.h" 84 #include "wtf/Vector.h" 85 86 using namespace std; 87 88 namespace WebCore { 89 90 using namespace HTMLNames; 91 92 RenderStyle* StyleResolver::s_styleNotYetAvailable; 93 94 static StylePropertySet* leftToRightDeclaration() 95 { 96 DEFINE_STATIC_LOCAL(RefPtr<MutableStylePropertySet>, leftToRightDecl, (MutableStylePropertySet::create())); 97 if (leftToRightDecl->isEmpty()) 98 leftToRightDecl->setProperty(CSSPropertyDirection, CSSValueLtr); 99 return leftToRightDecl.get(); 100 } 101 102 static StylePropertySet* rightToLeftDeclaration() 103 { 104 DEFINE_STATIC_LOCAL(RefPtr<MutableStylePropertySet>, rightToLeftDecl, (MutableStylePropertySet::create())); 105 if (rightToLeftDecl->isEmpty()) 106 rightToLeftDecl->setProperty(CSSPropertyDirection, CSSValueRtl); 107 return rightToLeftDecl.get(); 108 } 109 110 StyleResolver::StyleResolver(Document* document, bool matchAuthorAndUserStyles) 111 : m_document(document) 112 , m_matchAuthorAndUserStyles(matchAuthorAndUserStyles) 113 , m_fontSelector(CSSFontSelector::create(document)) 114 , m_viewportStyleResolver(ViewportStyleResolver::create(document)) 115 , m_styleResourceLoader(document->fetcher()) 116 { 117 Element* root = document->documentElement(); 118 119 CSSDefaultStyleSheets::initDefaultStyle(root); 120 121 // construct document root element default style. this is needed 122 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)" 123 // This is here instead of constructor, because when constructor is run, 124 // document doesn't have documentElement 125 // NOTE: this assumes that element that gets passed to styleForElement -call 126 // is always from the document that owns the style selector 127 FrameView* view = document->view(); 128 if (view) 129 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType())); 130 else 131 m_medium = adoptPtr(new MediaQueryEvaluator("all")); 132 133 if (root) 134 m_rootDefaultStyle = styleForElement(root, 0, DisallowStyleSharing, MatchOnlyUserAgentRules); 135 136 if (m_rootDefaultStyle && view) 137 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle.get())); 138 139 m_styleTree.clear(); 140 141 DocumentStyleSheetCollection* styleSheetCollection = document->styleSheetCollection(); 142 m_ruleSets.initUserStyle(styleSheetCollection, *m_medium, *this); 143 144 #if ENABLE(SVG_FONTS) 145 if (document->svgExtensions()) { 146 const HashSet<SVGFontFaceElement*>& svgFontFaceElements = document->svgExtensions()->svgFontFaceElements(); 147 HashSet<SVGFontFaceElement*>::const_iterator end = svgFontFaceElements.end(); 148 for (HashSet<SVGFontFaceElement*>::const_iterator it = svgFontFaceElements.begin(); it != end; ++it) 149 fontSelector()->addFontFaceRule((*it)->fontFaceRule()); 150 } 151 #endif 152 m_styleTree.setBuildInDocumentOrder(!styleSheetCollection->hasScopedStyleSheet()); 153 appendAuthorStyleSheets(0, styleSheetCollection->activeAuthorStyleSheets()); 154 } 155 156 void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets) 157 { 158 // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver 159 // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated. 160 unsigned size = styleSheets.size(); 161 for (unsigned i = firstNew; i < size; ++i) { 162 CSSStyleSheet* cssSheet = styleSheets[i].get(); 163 ASSERT(!cssSheet->disabled()); 164 if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), this)) 165 continue; 166 167 StyleSheetContents* sheet = cssSheet->contents(); 168 ScopedStyleResolver* resolver = ensureScopedStyleResolver(ScopedStyleResolver::scopingNodeFor(cssSheet)); 169 ASSERT(resolver); 170 resolver->addRulesFromSheet(sheet, *m_medium, this); 171 m_inspectorCSSOMWrappers.collectFromStyleSheetIfNeeded(cssSheet); 172 } 173 174 collectFeatures(); 175 176 if (document()->renderer() && document()->renderer()->style()) 177 document()->renderer()->style()->font().update(fontSelector()); 178 179 if (RuntimeEnabledFeatures::cssViewportEnabled()) 180 collectViewportRules(); 181 } 182 183 void StyleResolver::resetAuthorStyle(const ContainerNode* scopingNode) 184 { 185 m_styleTree.clear(); 186 ScopedStyleResolver* resolver = scopingNode ? m_styleTree.scopedStyleResolverFor(scopingNode) : m_styleTree.scopedStyleResolverForDocument(); 187 if (!resolver) 188 return; 189 190 m_ruleSets.shadowDistributedRules().reset(scopingNode); 191 192 resolver->resetAuthorStyle(); 193 194 if (!scopingNode || !resolver->hasOnlyEmptyRuleSets()) 195 return; 196 197 m_styleTree.remove(scopingNode); 198 } 199 200 void StyleResolver::resetAtHostRules(const ContainerNode* scopingNode) 201 { 202 ASSERT(scopingNode); 203 ASSERT(scopingNode->isShadowRoot()); 204 205 const ShadowRoot* shadowRoot = toShadowRoot(scopingNode); 206 const ContainerNode* shadowHost = shadowRoot->shadowHost(); 207 ScopedStyleResolver* resolver = m_styleTree.scopedStyleResolverFor(shadowHost); 208 if (!resolver) 209 return; 210 211 resolver->resetAtHostRules(shadowRoot); 212 if (!resolver->hasOnlyEmptyRuleSets()) 213 return; 214 215 m_styleTree.remove(shadowHost); 216 } 217 218 static PassOwnPtr<RuleSet> makeRuleSet(const Vector<RuleFeature>& rules) 219 { 220 size_t size = rules.size(); 221 if (!size) 222 return nullptr; 223 OwnPtr<RuleSet> ruleSet = RuleSet::create(); 224 for (size_t i = 0; i < size; ++i) 225 ruleSet->addRule(rules[i].rule, rules[i].selectorIndex, rules[i].hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState); 226 return ruleSet.release(); 227 } 228 229 void StyleResolver::collectFeatures() 230 { 231 m_features.clear(); 232 m_ruleSets.collectFeaturesTo(m_features, document()->isViewSource()); 233 m_styleTree.collectFeaturesTo(m_features); 234 235 m_siblingRuleSet = makeRuleSet(m_features.siblingRules); 236 m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules); 237 } 238 239 void StyleResolver::pushParentElement(Element* parent) 240 { 241 const ContainerNode* parentsParent = parent->parentOrShadowHostElement(); 242 243 // We are not always invoked consistently. For example, script execution can cause us to enter 244 // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree. 245 // Reset the stack in this case, or if we see a new root element. 246 // Otherwise just push the new parent. 247 if (!parentsParent || m_selectorFilter.parentStackIsEmpty()) 248 m_selectorFilter.setupParentStack(parent); 249 else 250 m_selectorFilter.pushParent(parent); 251 252 // Note: We mustn't skip ShadowRoot nodes for the scope stack. 253 m_styleTree.pushStyleCache(parent, parent->parentOrShadowHostNode()); 254 } 255 256 void StyleResolver::popParentElement(Element* parent) 257 { 258 // Note that we may get invoked for some random elements in some wacky cases during style resolve. 259 // Pause maintaining the stack in this case. 260 if (m_selectorFilter.parentStackIsConsistent(parent)) 261 m_selectorFilter.popParent(); 262 263 m_styleTree.popStyleCache(parent); 264 } 265 266 void StyleResolver::pushParentShadowRoot(const ShadowRoot* shadowRoot) 267 { 268 ASSERT(shadowRoot->host()); 269 m_styleTree.pushStyleCache(shadowRoot, shadowRoot->host()); 270 } 271 272 void StyleResolver::popParentShadowRoot(const ShadowRoot* shadowRoot) 273 { 274 ASSERT(shadowRoot->host()); 275 m_styleTree.popStyleCache(shadowRoot); 276 } 277 278 // This is a simplified style setting function for keyframe styles 279 void StyleResolver::addKeyframeStyle(PassRefPtr<StyleRuleKeyframes> rule) 280 { 281 AtomicString s(rule->name()); 282 m_keyframesRuleMap.set(s.impl(), rule); 283 } 284 285 StyleResolver::~StyleResolver() 286 { 287 m_fontSelector->clearDocument(); 288 m_viewportStyleResolver->clearDocument(); 289 } 290 291 inline void StyleResolver::matchShadowDistributedRules(ElementRuleCollector& collector, bool includeEmptyRules) 292 { 293 // FIXME: Determine tree position. 294 CascadeScope cascadeScope = ignoreCascadeScope; 295 296 if (m_ruleSets.shadowDistributedRules().isEmpty()) 297 return; 298 299 bool previousCanUseFastReject = collector.canUseFastReject(); 300 SelectorChecker::BehaviorAtBoundary previousBoundary = collector.behaviorAtBoundary(); 301 collector.setBehaviorAtBoundary(static_cast<SelectorChecker::BehaviorAtBoundary>(SelectorChecker::CrossesBoundary | SelectorChecker::ScopeContainsLastMatchedElement)); 302 collector.setCanUseFastReject(false); 303 304 collector.clearMatchedRules(); 305 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; 306 RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); 307 308 Vector<MatchRequest> matchRequests; 309 m_ruleSets.shadowDistributedRules().collectMatchRequests(includeEmptyRules, matchRequests); 310 for (size_t i = 0; i < matchRequests.size(); ++i) 311 collector.collectMatchingRules(matchRequests[i], ruleRange, cascadeScope); 312 collector.sortAndTransferMatchedRules(); 313 314 collector.setBehaviorAtBoundary(previousBoundary); 315 collector.setCanUseFastReject(previousCanUseFastReject); 316 } 317 318 void StyleResolver::matchHostRules(Element* element, ScopedStyleResolver* resolver, ElementRuleCollector& collector, bool includeEmptyRules) 319 { 320 if (element != resolver->scopingNode()) 321 return; 322 resolver->matchHostRules(collector, includeEmptyRules); 323 } 324 325 static inline bool applyAuthorStylesOf(const Element* element) 326 { 327 return element->treeScope()->applyAuthorStyles() || (element->shadow() && element->shadow()->applyAuthorStyles()); 328 } 329 330 void StyleResolver::matchScopedAuthorRulesForShadowHost(Element* element, ElementRuleCollector& collector, bool includeEmptyRules, Vector<ScopedStyleResolver*, 8>& resolvers, Vector<ScopedStyleResolver*, 8>& resolversInShadowTree) 331 { 332 collector.clearMatchedRules(); 333 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; 334 335 CascadeScope cascadeScope = (resolvers.isEmpty() || resolvers.first()->treeScope() != element->treeScope()) ? resolvers.size() + 1 : resolvers.size(); 336 CascadeOrder cascadeOrder = 0; 337 bool applyAuthorStyles = applyAuthorStylesOf(element); 338 339 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j) 340 resolversInShadowTree.at(j)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope, cascadeOrder++); 341 342 cascadeScope = resolvers.size(); 343 for (unsigned i = 0; i < resolvers.size(); ++i) 344 resolvers.at(i)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope--, cascadeOrder); 345 346 collector.sortAndTransferMatchedRules(); 347 348 if (!resolvers.isEmpty()) 349 matchHostRules(element, resolvers.first(), collector, includeEmptyRules); 350 } 351 352 void StyleResolver::matchScopedAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules) 353 { 354 if (m_styleTree.hasOnlyScopedResolverForDocument()) { 355 m_styleTree.scopedStyleResolverForDocument()->matchAuthorRules(collector, includeEmptyRules, applyAuthorStylesOf(element)); 356 return; 357 } 358 359 Vector<ScopedStyleResolver*, 8> resolvers; 360 m_styleTree.resolveScopedStyles(element, resolvers); 361 362 Vector<ScopedStyleResolver*, 8> resolversInShadowTree; 363 m_styleTree.collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree); 364 if (!resolversInShadowTree.isEmpty()) { 365 matchScopedAuthorRulesForShadowHost(element, collector, includeEmptyRules, resolvers, resolversInShadowTree); 366 return; 367 } 368 369 if (resolvers.isEmpty()) 370 return; 371 372 bool applyAuthorStyles = applyAuthorStylesOf(element); 373 CascadeScope cascadeScope = resolvers.size(); 374 collector.clearMatchedRules(); 375 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; 376 377 for (unsigned i = 0; i < resolvers.size(); ++i) 378 resolvers.at(i)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope--); 379 collector.sortAndTransferMatchedRules(); 380 381 matchHostRules(element, resolvers.first(), collector, includeEmptyRules); 382 } 383 384 void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules) 385 { 386 matchScopedAuthorRules(element, collector, includeEmptyRules); 387 matchShadowDistributedRules(collector, includeEmptyRules); 388 } 389 390 void StyleResolver::matchUserRules(ElementRuleCollector& collector, bool includeEmptyRules) 391 { 392 if (!m_ruleSets.userStyle()) 393 return; 394 395 collector.clearMatchedRules(); 396 collector.matchedResult().ranges.lastUserRule = collector.matchedResult().matchedProperties.size() - 1; 397 398 MatchRequest matchRequest(m_ruleSets.userStyle(), includeEmptyRules); 399 RuleRange ruleRange = collector.matchedResult().ranges.userRuleRange(); 400 collector.collectMatchingRules(matchRequest, ruleRange); 401 collector.collectMatchingRulesForRegion(matchRequest, ruleRange); 402 403 collector.sortAndTransferMatchedRules(); 404 } 405 406 void StyleResolver::matchUARules(ElementRuleCollector& collector) 407 { 408 collector.setMatchingUARules(true); 409 410 // First we match rules from the user agent sheet. 411 if (CSSDefaultStyleSheets::simpleDefaultStyleSheet) 412 collector.matchedResult().isCacheable = false; 413 414 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print") 415 ? CSSDefaultStyleSheets::defaultPrintStyle : CSSDefaultStyleSheets::defaultStyle; 416 matchUARules(collector, userAgentStyleSheet); 417 418 // In quirks mode, we match rules from the quirks user agent sheet. 419 if (document()->inQuirksMode()) 420 matchUARules(collector, CSSDefaultStyleSheets::defaultQuirksStyle); 421 422 // 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. 423 if (document()->isViewSource()) 424 matchUARules(collector, CSSDefaultStyleSheets::viewSourceStyle()); 425 426 collector.setMatchingUARules(false); 427 } 428 429 void StyleResolver::matchUARules(ElementRuleCollector& collector, RuleSet* rules) 430 { 431 collector.clearMatchedRules(); 432 collector.matchedResult().ranges.lastUARule = collector.matchedResult().matchedProperties.size() - 1; 433 434 RuleRange ruleRange = collector.matchedResult().ranges.UARuleRange(); 435 collector.collectMatchingRules(MatchRequest(rules), ruleRange); 436 437 collector.sortAndTransferMatchedRules(); 438 } 439 440 void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollector& collector, bool matchAuthorAndUserStyles, bool includeSMILProperties) 441 { 442 matchUARules(collector); 443 444 // Now we check user sheet rules. 445 if (matchAuthorAndUserStyles) 446 matchUserRules(collector, false); 447 448 // Now check author rules, beginning first with presentational attributes mapped from HTML. 449 if (state.element()->isStyledElement()) { 450 collector.addElementStyleProperties(state.element()->presentationAttributeStyle()); 451 452 // Now we check additional mapped declarations. 453 // Tables and table cells share an additional mapped rule that must be applied 454 // after all attributes, since their mapped style depends on the values of multiple attributes. 455 collector.addElementStyleProperties(state.element()->additionalPresentationAttributeStyle()); 456 457 if (state.element()->isHTMLElement()) { 458 bool isAuto; 459 TextDirection textDirection = toHTMLElement(state.element())->directionalityIfhasDirAutoAttribute(isAuto); 460 if (isAuto) 461 collector.matchedResult().addMatchedProperties(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration()); 462 } 463 } 464 465 // Check the rules in author sheets next. 466 if (matchAuthorAndUserStyles) 467 matchAuthorRules(state.element(), collector, false); 468 469 if (state.element()->isStyledElement()) { 470 // Now check our inline style attribute. 471 if (matchAuthorAndUserStyles && state.element()->inlineStyle()) { 472 // Inline style is immutable as long as there is no CSSOM wrapper. 473 // FIXME: Media control shadow trees seem to have problems with caching. 474 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMutable() && !state.element()->isInShadowTree(); 475 // FIXME: Constify. 476 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable); 477 } 478 479 // Now check SMIL animation override style. 480 if (includeSMILProperties && matchAuthorAndUserStyles && state.element()->isSVGElement()) 481 collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */); 482 483 if (state.element()->hasActiveAnimations()) 484 collector.matchedResult().isCacheable = false; 485 } 486 } 487 488 bool StyleResolver::styleSharingCandidateMatchesRuleSet(const ElementResolveContext& context, RenderStyle* style, RuleSet* ruleSet) 489 { 490 if (!ruleSet) 491 return false; 492 493 ElementRuleCollector collector(context, m_selectorFilter, style); 494 return collector.hasAnyMatchingRules(ruleSet); 495 } 496 497 PassRefPtr<RenderStyle> StyleResolver::styleForDocument(const Document* document, CSSFontSelector* fontSelector) 498 { 499 const Frame* frame = document->frame(); 500 501 // HTML5 states that seamless iframes should replace default CSS values 502 // with values inherited from the containing iframe element. However, 503 // some values (such as the case of designMode = "on") still need to 504 // be set by this "document style". 505 RefPtr<RenderStyle> documentStyle = RenderStyle::create(); 506 bool seamlessWithParent = document->shouldDisplaySeamlesslyWithParent(); 507 if (seamlessWithParent) { 508 RenderStyle* iframeStyle = document->seamlessParentIFrame()->renderStyle(); 509 if (iframeStyle) 510 documentStyle->inheritFrom(iframeStyle); 511 } 512 513 // FIXME: It's not clear which values below we want to override in the seamless case! 514 documentStyle->setDisplay(BLOCK); 515 if (!seamlessWithParent) { 516 documentStyle->setRTLOrdering(document->visuallyOrdered() ? VisualOrder : LogicalOrder); 517 documentStyle->setZoom(frame && !document->printing() ? frame->pageZoomFactor() : 1); 518 documentStyle->setLocale(document->contentLanguage()); 519 } 520 // This overrides any -webkit-user-modify inherited from the parent iframe. 521 documentStyle->setUserModify(document->inDesignMode() ? READ_WRITE : READ_ONLY); 522 523 Element* docElement = document->documentElement(); 524 RenderObject* docElementRenderer = docElement ? docElement->renderer() : 0; 525 if (docElementRenderer) { 526 // Use the direction and writing-mode of the body to set the 527 // viewport's direction and writing-mode unless the property is set on the document element. 528 // If there is no body, then use the document element. 529 RenderObject* bodyRenderer = document->body() ? document->body()->renderer() : 0; 530 if (bodyRenderer && !document->writingModeSetOnDocumentElement()) 531 documentStyle->setWritingMode(bodyRenderer->style()->writingMode()); 532 else 533 documentStyle->setWritingMode(docElementRenderer->style()->writingMode()); 534 if (bodyRenderer && !document->directionSetOnDocumentElement()) 535 documentStyle->setDirection(bodyRenderer->style()->direction()); 536 else 537 documentStyle->setDirection(docElementRenderer->style()->direction()); 538 } 539 540 if (frame) { 541 if (FrameView* frameView = frame->view()) { 542 const Pagination& pagination = frameView->pagination(); 543 if (pagination.mode != Pagination::Unpaginated) { 544 Pagination::setStylesForPaginationMode(pagination.mode, documentStyle.get()); 545 documentStyle->setColumnGap(pagination.gap); 546 if (RenderView* view = document->renderView()) { 547 if (view->hasColumns()) 548 view->updateColumnInfoFromStyle(documentStyle.get()); 549 } 550 } 551 } 552 } 553 554 // Seamless iframes want to inherit their font from their parent iframe, so early return before setting the font. 555 if (seamlessWithParent) 556 return documentStyle.release(); 557 558 FontBuilder fontBuilder; 559 fontBuilder.initForStyleResolve(document, documentStyle.get(), document->isSVGDocument()); 560 fontBuilder.createFontForDocument(fontSelector, documentStyle.get()); 561 562 return documentStyle.release(); 563 } 564 565 // FIXME: This is duplicated with StyleAdjuster.cpp 566 // Perhaps this should move onto ElementResolveContext or even Element? 567 static inline bool isAtShadowBoundary(const Element* element) 568 { 569 if (!element) 570 return false; 571 ContainerNode* parentNode = element->parentNode(); 572 return parentNode && parentNode->isShadowRoot(); 573 } 574 575 static inline void resetDirectionAndWritingModeOnDocument(Document* document) 576 { 577 document->setDirectionSetOnDocumentElement(false); 578 document->setWritingModeSetOnDocumentElement(false); 579 } 580 581 static void addContentAttrValuesToFeatures(const Vector<AtomicString>& contentAttrValues, RuleFeatureSet& features) 582 { 583 for (size_t i = 0; i < contentAttrValues.size(); ++i) 584 features.attrsInRules.add(contentAttrValues[i].impl()); 585 } 586 587 PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent, StyleSharingBehavior sharingBehavior, 588 RuleMatchingBehavior matchingBehavior, RenderRegion* regionForStyling) 589 { 590 ASSERT(document()->frame()); 591 ASSERT(documentSettings()); 592 593 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer 594 // will vanish if a style recalc happens during loading. 595 if (sharingBehavior == AllowStyleSharing && !element->document()->haveStylesheetsLoaded() && !element->renderer()) { 596 if (!s_styleNotYetAvailable) { 597 s_styleNotYetAvailable = RenderStyle::create().leakRef(); 598 s_styleNotYetAvailable->setDisplay(NONE); 599 s_styleNotYetAvailable->font().update(m_fontSelector); 600 } 601 element->document()->setHasNodesWithPlaceholderStyle(); 602 return s_styleNotYetAvailable; 603 } 604 605 if (element == document()->documentElement()) 606 resetDirectionAndWritingModeOnDocument(document()); 607 StyleResolverState state(document(), element, defaultParent, regionForStyling); 608 609 if (sharingBehavior == AllowStyleSharing && !state.distributedToInsertionPoint() && state.parentStyle()) { 610 SharedStyleFinder styleFinder(m_features, m_siblingRuleSet.get(), m_uncommonAttributeRuleSet.get(), this); 611 RefPtr<RenderStyle> sharedStyle = styleFinder.locateSharedStyle(state.elementContext(), state.style()); 612 if (sharedStyle) 613 return sharedStyle.release(); 614 } 615 616 if (state.parentStyle()) { 617 state.setStyle(RenderStyle::create()); 618 state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary); 619 } else { 620 state.setStyle(defaultStyleForElement()); 621 state.setParentStyle(RenderStyle::clone(state.style())); 622 } 623 // contenteditable attribute (implemented by -webkit-user-modify) should 624 // be propagated from shadow host to distributed node. 625 if (state.distributedToInsertionPoint()) { 626 if (Element* parent = element->parentElement()) { 627 if (RenderStyle* styleOfShadowHost = parent->renderStyle()) 628 state.style()->setUserModify(styleOfShadowHost->userModify()); 629 } 630 } 631 632 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules()); 633 634 if (element->isLink()) { 635 state.style()->setIsLink(true); 636 EInsideLink linkState = state.elementLinkState(); 637 if (linkState != NotInsideLink) { 638 bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited); 639 if (forceVisited) 640 linkState = InsideVisitedLink; 641 } 642 state.style()->setInsideLink(linkState); 643 } 644 645 bool needsCollection = false; 646 CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(element, needsCollection); 647 if (needsCollection) { 648 collectFeatures(); 649 m_inspectorCSSOMWrappers.reset(); 650 } 651 652 { 653 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); 654 collector.setRegionForStyling(regionForStyling); 655 656 if (matchingBehavior == MatchOnlyUserAgentRules) 657 matchUARules(collector); 658 else 659 matchAllRules(state, collector, m_matchAuthorAndUserStyles, matchingBehavior != MatchAllRulesExcludingSMIL); 660 661 applyMatchedProperties(state, collector.matchedResult()); 662 663 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features); 664 } 665 { 666 StyleAdjuster adjuster(state.cachedUAStyle(), m_document->inQuirksMode()); 667 adjuster.adjustRenderStyle(state.style(), state.parentStyle(), element); 668 } 669 document()->didAccessStyleResolver(); 670 671 // FIXME: Shouldn't this be on RenderBody::styleDidChange? 672 if (element->hasTagName(bodyTag)) 673 document()->textLinkColors().setTextColor(state.style()->visitedDependentColor(CSSPropertyColor)); 674 675 // Now return the style. 676 return state.takeStyle(); 677 } 678 679 PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* e, const RenderStyle* elementStyle, const StyleKeyframe* keyframe) 680 { 681 ASSERT(document()->frame()); 682 ASSERT(documentSettings()); 683 684 if (e == document()->documentElement()) 685 resetDirectionAndWritingModeOnDocument(document()); 686 StyleResolverState state(document(), e); 687 688 MatchResult result; 689 if (keyframe->properties()) 690 result.addMatchedProperties(keyframe->properties()); 691 692 ASSERT(!state.style()); 693 694 // Create the style 695 state.setStyle(RenderStyle::clone(elementStyle)); 696 state.setLineHeightValue(0); 697 698 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules()); 699 700 // We don't need to bother with !important. Since there is only ever one 701 // decl, there's nothing to override. So just add the first properties. 702 bool inheritedOnly = false; 703 if (keyframe->properties()) { 704 // FIXME: Can't keyframes contain variables? 705 applyMatchedProperties<AnimationProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 706 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 707 } 708 709 // If our font got dirtied, go ahead and update it now. 710 updateFont(state); 711 712 // Line-height is set when we are sure we decided on the font-size 713 if (state.lineHeightValue()) 714 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue()); 715 716 // Now do rest of the properties. 717 if (keyframe->properties()) 718 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 719 720 // If our font got dirtied by one of the non-essential font props, 721 // go ahead and update it a second time. 722 updateFont(state); 723 724 // Start loading resources referenced by this style. 725 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources()); 726 727 document()->didAccessStyleResolver(); 728 729 return state.takeStyle(); 730 } 731 732 const StyleRuleKeyframes* StyleResolver::matchScopedKeyframesRule(const Element* e, const StringImpl* animationName) 733 { 734 if (m_styleTree.hasOnlyScopedResolverForDocument()) 735 return m_styleTree.scopedStyleResolverForDocument()->keyframeStylesForAnimation(animationName); 736 737 Vector<ScopedStyleResolver*, 8> stack; 738 m_styleTree.resolveScopedKeyframesRules(e, stack); 739 if (stack.isEmpty()) 740 return 0; 741 742 for (size_t i = 0; i < stack.size(); ++i) { 743 if (const StyleRuleKeyframes* keyframesRule = stack.at(i)->keyframeStylesForAnimation(animationName)) 744 return keyframesRule; 745 } 746 return 0; 747 } 748 749 void StyleResolver::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list) 750 { 751 ASSERT(!RuntimeEnabledFeatures::webAnimationsCSSEnabled()); 752 list.clear(); 753 754 // Get the keyframesRule for this name 755 if (!e || list.animationName().isEmpty()) 756 return; 757 758 const StyleRuleKeyframes* keyframesRule = matchScopedKeyframesRule(e, list.animationName().impl()); 759 if (!keyframesRule) 760 return; 761 762 // Construct and populate the style for each keyframe 763 const Vector<RefPtr<StyleKeyframe> >& keyframes = keyframesRule->keyframes(); 764 for (unsigned i = 0; i < keyframes.size(); ++i) { 765 // Apply the declaration to the style. This is a simplified version of the logic in styleForElement 766 const StyleKeyframe* keyframe = keyframes[i].get(); 767 768 KeyframeValue keyframeValue(0, 0); 769 keyframeValue.setStyle(styleForKeyframe(e, elementStyle, keyframe)); 770 keyframeValue.addProperties(keyframe->properties()); 771 772 // Add this keyframe style to all the indicated key times 773 Vector<float> keys; 774 keyframe->getKeys(keys); 775 for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) { 776 keyframeValue.setKey(keys[keyIndex]); 777 list.insert(keyframeValue); 778 } 779 } 780 781 // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe) 782 int initialListSize = list.size(); 783 if (initialListSize > 0 && list[0].key()) { 784 static StyleKeyframe* zeroPercentKeyframe; 785 if (!zeroPercentKeyframe) { 786 zeroPercentKeyframe = StyleKeyframe::create().leakRef(); 787 zeroPercentKeyframe->setKeyText("0%"); 788 } 789 KeyframeValue keyframeValue(0, 0); 790 keyframeValue.setStyle(styleForKeyframe(e, elementStyle, zeroPercentKeyframe)); 791 keyframeValue.addProperties(zeroPercentKeyframe->properties()); 792 list.insert(keyframeValue); 793 } 794 795 // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe) 796 if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) { 797 static StyleKeyframe* hundredPercentKeyframe; 798 if (!hundredPercentKeyframe) { 799 hundredPercentKeyframe = StyleKeyframe::create().leakRef(); 800 hundredPercentKeyframe->setKeyText("100%"); 801 } 802 KeyframeValue keyframeValue(1, 0); 803 keyframeValue.setStyle(styleForKeyframe(e, elementStyle, hundredPercentKeyframe)); 804 keyframeValue.addProperties(hundredPercentKeyframe->properties()); 805 list.insert(keyframeValue); 806 } 807 } 808 809 void StyleResolver::resolveKeyframes(Element* element, const RenderStyle* style, const StringImpl* name, KeyframeAnimationEffect::KeyframeVector& keyframes) 810 { 811 ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled()); 812 const StyleRuleKeyframes* keyframesRule = matchScopedKeyframesRule(element, name); 813 if (!keyframesRule) 814 return; 815 816 // Construct and populate the style for each keyframe 817 const Vector<RefPtr<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes(); 818 for (size_t i = 0; i < styleKeyframes.size(); ++i) { 819 const StyleKeyframe* styleKeyframe = styleKeyframes[i].get(); 820 RefPtr<RenderStyle> keyframeStyle = styleForKeyframe(element, style, styleKeyframe); 821 Vector<float> offsets; 822 styleKeyframe->getKeys(offsets); 823 RefPtr<Keyframe> firstOffsetKeyframe; 824 for (size_t j = 0; j < offsets.size(); ++j) { 825 RefPtr<Keyframe> keyframe = Keyframe::create(); 826 keyframe->setOffset(offsets[j]); 827 const StylePropertySet* properties = styleKeyframe->properties(); 828 for (unsigned k = 0; k < properties->propertyCount(); k++) { 829 CSSPropertyID property = properties->propertyAt(k).id(); 830 keyframe->setPropertyValue(property, firstOffsetKeyframe ? firstOffsetKeyframe->propertyValue(property) : CSSAnimatableValueFactory::create(property, keyframeStyle.get()).get()); 831 } 832 if (!firstOffsetKeyframe) 833 firstOffsetKeyframe = keyframe; 834 keyframes.append(keyframe); 835 } 836 } 837 838 if (keyframes.isEmpty()) 839 return; 840 841 // Remove duplicate keyframes. In CSS the last keyframe at a given offset takes priority. 842 std::stable_sort(keyframes.begin(), keyframes.end(), Keyframe::compareOffsets); 843 size_t targetIndex = 0; 844 for (size_t i = 1; i < keyframes.size(); i++) { 845 if (keyframes[i]->offset() != keyframes[targetIndex]->offset()) 846 targetIndex++; 847 if (targetIndex != i) 848 keyframes[targetIndex] = keyframes[i]; 849 } 850 keyframes.shrink(targetIndex + 1); 851 852 HashSet<CSSPropertyID> allProperties; 853 for (size_t i = 0; i < keyframes.size(); i++) { 854 const HashSet<CSSPropertyID> keyframeProperties = keyframes[i]->properties(); 855 for (HashSet<CSSPropertyID>::const_iterator iter = keyframeProperties.begin(); iter != keyframeProperties.end(); ++iter) 856 allProperties.add(*iter); 857 } 858 859 // Snapshot current property values for 0% and 100% if missing. 860 RefPtr<Keyframe> startKeyframe = keyframes[0]; 861 if (startKeyframe->offset()) { 862 startKeyframe = Keyframe::create(); 863 startKeyframe->setOffset(0); 864 keyframes.prepend(startKeyframe); 865 } 866 RefPtr<Keyframe> endKeyframe = keyframes[keyframes.size() - 1]; 867 if (endKeyframe->offset() != 1) { 868 endKeyframe = Keyframe::create(); 869 endKeyframe->setOffset(1); 870 keyframes.append(endKeyframe); 871 } 872 const HashSet<CSSPropertyID>& startKeyframeProperties = startKeyframe->properties(); 873 const HashSet<CSSPropertyID>& endKeyframeProperties = endKeyframe->properties(); 874 bool missingStartValues = startKeyframeProperties.size() < allProperties.size(); 875 bool missingEndValues = endKeyframeProperties.size() < allProperties.size(); 876 if (!missingStartValues && !missingEndValues) 877 return; 878 for (HashSet<CSSPropertyID>::const_iterator iter = allProperties.begin(); iter != allProperties.end(); ++iter) { 879 const CSSPropertyID property = *iter; 880 bool startNeedsValue = missingStartValues && !startKeyframeProperties.contains(property); 881 bool endNeedsValue = missingEndValues && !endKeyframeProperties.contains(property); 882 if (!startNeedsValue && !endNeedsValue) 883 continue; 884 RefPtr<AnimatableValue> snapshotValue = CSSAnimatableValueFactory::create(property, style); 885 if (startNeedsValue) 886 startKeyframe->setPropertyValue(property, snapshotValue.get()); 887 if (endNeedsValue) 888 endKeyframe->setPropertyValue(property, snapshotValue.get()); 889 } 890 } 891 892 const StylePropertySet* StyleResolver::firstKeyframeStyles(const Element* element, const StringImpl* animationName) 893 { 894 ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled()); 895 const StyleRuleKeyframes* keyframesRule = matchScopedKeyframesRule(element, animationName); 896 if (!keyframesRule) 897 return 0; 898 899 // Find the last keyframe at offset 0 900 const StyleKeyframe* firstKeyframe = 0; 901 const Vector<RefPtr<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes(); 902 for (unsigned i = 0; i < styleKeyframes.size(); ++i) { 903 const StyleKeyframe* styleKeyframe = styleKeyframes[i].get(); 904 905 Vector<float> offsets; 906 styleKeyframe->getKeys(offsets); 907 for (size_t j = 0; j < offsets.size(); ++j) { 908 if (!offsets[j]) { 909 firstKeyframe = styleKeyframe; 910 break; 911 } 912 } 913 } 914 915 return firstKeyframe ? firstKeyframe->properties() : 0; 916 } 917 918 919 PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* e, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle) 920 { 921 ASSERT(document()->frame()); 922 ASSERT(documentSettings()); 923 ASSERT(parentStyle); 924 if (!e) 925 return 0; 926 927 if (e == document()->documentElement()) 928 resetDirectionAndWritingModeOnDocument(document()); 929 StyleResolverState state(document(), e, parentStyle); 930 931 if (pseudoStyleRequest.allowsInheritance(state.parentStyle())) { 932 state.setStyle(RenderStyle::create()); 933 state.style()->inheritFrom(state.parentStyle()); 934 } else { 935 state.setStyle(defaultStyleForElement()); 936 state.setParentStyle(RenderStyle::clone(state.style())); 937 } 938 939 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules()); 940 941 // Since we don't use pseudo-elements in any of our quirk/print 942 // user agent rules, don't waste time walking those rules. 943 944 { 945 // Check UA, user and author rules. 946 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); 947 collector.setPseudoStyleRequest(pseudoStyleRequest); 948 949 matchUARules(collector); 950 if (m_matchAuthorAndUserStyles) { 951 matchUserRules(collector, false); 952 matchAuthorRules(state.element(), collector, false); 953 } 954 955 if (collector.matchedResult().matchedProperties.isEmpty()) 956 return 0; 957 958 state.style()->setStyleType(pseudoStyleRequest.pseudoId); 959 960 applyMatchedProperties(state, collector.matchedResult()); 961 962 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features); 963 } 964 { 965 StyleAdjuster adjuster(state.cachedUAStyle(), m_document->inQuirksMode()); 966 // FIXME: Passing 0 as the Element* introduces a lot of complexity 967 // in the adjustRenderStyle code. 968 adjuster.adjustRenderStyle(state.style(), state.parentStyle(), 0); 969 } 970 971 // Start loading resources referenced by this style. 972 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources()); 973 974 document()->didAccessStyleResolver(); 975 976 // Now return the style. 977 return state.takeStyle(); 978 } 979 980 PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex) 981 { 982 resetDirectionAndWritingModeOnDocument(document()); 983 StyleResolverState state(document(), document()->documentElement()); // m_rootElementStyle will be set to the document style. 984 985 state.setStyle(RenderStyle::create()); 986 state.style()->inheritFrom(state.rootElementStyle()); 987 988 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules()); 989 990 PageRuleCollector collector(state.elementContext(), pageIndex); 991 992 collector.matchPageRules(CSSDefaultStyleSheets::defaultPrintStyle); 993 collector.matchPageRules(m_ruleSets.userStyle()); 994 995 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument()) 996 scopedResolver->matchPageRules(collector); 997 998 state.setLineHeightValue(0); 999 bool inheritedOnly = false; 1000 1001 MatchResult& result = collector.matchedResult(); 1002 applyMatchedProperties<VariableDefinitions>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 1003 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 1004 1005 // If our font got dirtied, go ahead and update it now. 1006 updateFont(state); 1007 1008 // Line-height is set when we are sure we decided on the font-size. 1009 if (state.lineHeightValue()) 1010 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue()); 1011 1012 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 1013 1014 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features); 1015 1016 // Start loading resources referenced by this style. 1017 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources()); 1018 1019 document()->didAccessStyleResolver(); 1020 1021 // Now return the style. 1022 return state.takeStyle(); 1023 } 1024 1025 void StyleResolver::collectViewportRules() 1026 { 1027 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled()); 1028 1029 collectViewportRules(CSSDefaultStyleSheets::defaultStyle); 1030 if (m_ruleSets.userStyle()) 1031 collectViewportRules(m_ruleSets.userStyle()); 1032 1033 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument()) 1034 scopedResolver->collectViewportRulesTo(this); 1035 1036 viewportStyleResolver()->resolve(); 1037 } 1038 1039 void StyleResolver::collectViewportRules(RuleSet* rules) 1040 { 1041 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled()); 1042 1043 rules->compactRulesIfNeeded(); 1044 1045 const Vector<StyleRuleViewport*>& viewportRules = rules->viewportRules(); 1046 for (size_t i = 0; i < viewportRules.size(); ++i) 1047 viewportStyleResolver()->addViewportRule(viewportRules[i]); 1048 } 1049 1050 PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement() 1051 { 1052 StyleResolverState state(document(), 0); 1053 state.setStyle(RenderStyle::create()); 1054 state.fontBuilder().initForStyleResolve(document(), state.style(), state.useSVGZoomRules()); 1055 state.style()->setLineHeight(RenderStyle::initialLineHeight()); 1056 state.setLineHeightValue(0); 1057 state.fontBuilder().setInitial(state.style()->effectiveZoom()); 1058 state.style()->font().update(fontSelector()); 1059 return state.takeStyle(); 1060 } 1061 1062 PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode) 1063 { 1064 ASSERT(textNode); 1065 1066 NodeRenderingTraversal::ParentDetails parentDetails; 1067 Node* parentNode = NodeRenderingTraversal::parent(textNode, &parentDetails); 1068 if (!parentNode || !parentNode->renderStyle() || parentDetails.resetStyleInheritance()) 1069 return defaultStyleForElement(); 1070 return parentNode->renderStyle(); 1071 } 1072 1073 bool StyleResolver::checkRegionStyle(Element* regionElement) 1074 { 1075 // FIXME (BUG 72472): We don't add @-webkit-region rules of scoped style sheets for the moment, 1076 // so all region rules are global by default. Verify whether that can stand or needs changing. 1077 1078 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument()) 1079 if (scopedResolver->checkRegionStyle(regionElement)) 1080 return true; 1081 1082 if (m_ruleSets.userStyle()) { 1083 unsigned rulesSize = m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.size(); 1084 for (unsigned i = 0; i < rulesSize; ++i) { 1085 ASSERT(m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.at(i).ruleSet.get()); 1086 if (checkRegionSelector(m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.at(i).selector, regionElement)) 1087 return true; 1088 } 1089 } 1090 1091 return false; 1092 } 1093 1094 void StyleResolver::updateFont(StyleResolverState& state) 1095 { 1096 state.fontBuilder().createFont(m_fontSelector, state.parentStyle(), state.style()); 1097 } 1098 1099 PassRefPtr<CSSRuleList> StyleResolver::styleRulesForElement(Element* e, unsigned rulesToInclude) 1100 { 1101 return pseudoStyleRulesForElement(e, NOPSEUDO, rulesToInclude); 1102 } 1103 1104 PassRefPtr<CSSRuleList> StyleResolver::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, unsigned rulesToInclude) 1105 { 1106 if (!e || !e->document()->haveStylesheetsLoaded()) 1107 return 0; 1108 1109 if (e == document()->documentElement()) 1110 resetDirectionAndWritingModeOnDocument(document()); 1111 StyleResolverState state(document(), e); 1112 1113 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); 1114 collector.setMode(SelectorChecker::CollectingRules); 1115 collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId)); 1116 1117 if (rulesToInclude & UAAndUserCSSRules) { 1118 // First we match rules from the user agent sheet. 1119 matchUARules(collector); 1120 1121 // Now we check user sheet rules. 1122 if (m_matchAuthorAndUserStyles) 1123 matchUserRules(collector, rulesToInclude & EmptyCSSRules); 1124 } 1125 1126 if (m_matchAuthorAndUserStyles && (rulesToInclude & AuthorCSSRules)) { 1127 collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules)); 1128 1129 // Check the rules in author sheets. 1130 matchAuthorRules(state.element(), collector, rulesToInclude & EmptyCSSRules); 1131 } 1132 1133 return collector.matchedRuleList(); 1134 } 1135 1136 // ------------------------------------------------------------------------------------- 1137 // this is mostly boring stuff on how to apply a certain rule to the renderstyle... 1138 1139 template <StyleResolver::StyleApplicationPass pass> 1140 void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const Element* target, const DocumentTimeline* timeline, const CSSAnimationUpdate* update) 1141 { 1142 ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled()); 1143 ASSERT(pass != VariableDefinitions); 1144 ASSERT(pass != AnimationProperties); 1145 if (update && update->styles()) { 1146 bool applyInheritedOnly = false; 1147 bool isImportant = false; 1148 StyleRule* rule = 0; 1149 applyProperties<pass>(state, update->styles(), rule, isImportant, applyInheritedOnly, PropertyWhitelistNone); 1150 isImportant = true; 1151 applyProperties<pass>(state, update->styles(), rule, isImportant, applyInheritedOnly, PropertyWhitelistNone); 1152 } 1153 AnimationStack* animationStack = timeline->animationStack(target); 1154 if (!animationStack) 1155 return; 1156 const Vector<Animation*>& animations = animationStack->activeAnimations(target); 1157 1158 for (size_t i = 0; i < animations.size(); ++i) { 1159 RefPtr<Animation> animation = animations.at(i); 1160 if (update && update->isFiltered(animation->player())) 1161 continue; 1162 const AnimationEffect::CompositableValueMap* compositableValues = animation->compositableValues(); 1163 for (AnimationEffect::CompositableValueMap::const_iterator iter = compositableValues->begin(); iter != compositableValues->end(); ++iter) { 1164 CSSPropertyID property = iter->key; 1165 if (!isPropertyForPass<pass>(property)) 1166 continue; 1167 RELEASE_ASSERT_WITH_MESSAGE(!iter->value->dependsOnUnderlyingValue(), "Not yet implemented: An interface for compositing onto the underlying value."); 1168 RefPtr<AnimatableValue> animatableValue = iter->value->compositeOnto(0); 1169 if (pass == HighPriorityProperties && property == CSSPropertyLineHeight) 1170 state.setLineHeightValue(toAnimatableNumber(animatableValue.get())->toCSSValue().get()); 1171 else 1172 AnimatedStyleBuilder::applyProperty(property, state, animatableValue.get()); 1173 } 1174 } 1175 } 1176 1177 // http://dev.w3.org/csswg/css3-regions/#the-at-region-style-rule 1178 // FIXME: add incremental support for other region styling properties. 1179 static inline bool isValidRegionStyleProperty(CSSPropertyID id) 1180 { 1181 switch (id) { 1182 case CSSPropertyBackgroundColor: 1183 case CSSPropertyColor: 1184 return true; 1185 default: 1186 break; 1187 } 1188 1189 return false; 1190 } 1191 1192 static inline bool isValidCueStyleProperty(CSSPropertyID id) 1193 { 1194 switch (id) { 1195 case CSSPropertyBackground: 1196 case CSSPropertyBackgroundAttachment: 1197 case CSSPropertyBackgroundClip: 1198 case CSSPropertyBackgroundColor: 1199 case CSSPropertyBackgroundImage: 1200 case CSSPropertyBackgroundOrigin: 1201 case CSSPropertyBackgroundPosition: 1202 case CSSPropertyBackgroundPositionX: 1203 case CSSPropertyBackgroundPositionY: 1204 case CSSPropertyBackgroundRepeat: 1205 case CSSPropertyBackgroundRepeatX: 1206 case CSSPropertyBackgroundRepeatY: 1207 case CSSPropertyBackgroundSize: 1208 case CSSPropertyColor: 1209 case CSSPropertyFont: 1210 case CSSPropertyFontFamily: 1211 case CSSPropertyFontSize: 1212 case CSSPropertyFontStyle: 1213 case CSSPropertyFontVariant: 1214 case CSSPropertyFontWeight: 1215 case CSSPropertyLineHeight: 1216 case CSSPropertyOpacity: 1217 case CSSPropertyOutline: 1218 case CSSPropertyOutlineColor: 1219 case CSSPropertyOutlineOffset: 1220 case CSSPropertyOutlineStyle: 1221 case CSSPropertyOutlineWidth: 1222 case CSSPropertyVisibility: 1223 case CSSPropertyWhiteSpace: 1224 // FIXME: 'text-decoration' shorthand to be handled when available. 1225 // See https://chromiumcodereview.appspot.com/19516002 for details. 1226 case CSSPropertyTextDecoration: 1227 case CSSPropertyTextShadow: 1228 case CSSPropertyBorderStyle: 1229 return true; 1230 case CSSPropertyTextDecorationLine: 1231 case CSSPropertyTextDecorationStyle: 1232 case CSSPropertyTextDecorationColor: 1233 return RuntimeEnabledFeatures::css3TextDecorationsEnabled(); 1234 default: 1235 break; 1236 } 1237 return false; 1238 } 1239 1240 template <StyleResolver::StyleApplicationPass pass> 1241 bool StyleResolver::isPropertyForPass(CSSPropertyID property) 1242 { 1243 COMPILE_ASSERT(CSSPropertyVariable < firstCSSProperty, CSS_variable_is_before_first_property); 1244 const CSSPropertyID firstAnimationProperty = CSSPropertyDisplay; 1245 const CSSPropertyID lastAnimationProperty = CSSPropertyTransitionTimingFunction; 1246 COMPILE_ASSERT(firstCSSProperty == firstAnimationProperty, CSS_first_animation_property_should_be_first_property); 1247 const CSSPropertyID firstHighPriorityProperty = CSSPropertyColor; 1248 const CSSPropertyID lastHighPriorityProperty = CSSPropertyLineHeight; 1249 COMPILE_ASSERT(lastAnimationProperty + 1 == firstHighPriorityProperty, CSS_color_is_first_high_priority_property); 1250 COMPILE_ASSERT(CSSPropertyLineHeight == firstHighPriorityProperty + 17, CSS_line_height_is_end_of_high_prioity_property_range); 1251 COMPILE_ASSERT(CSSPropertyZoom == lastHighPriorityProperty - 1, CSS_zoom_is_before_line_height); 1252 switch (pass) { 1253 case VariableDefinitions: 1254 return property == CSSPropertyVariable; 1255 case AnimationProperties: 1256 return property >= firstAnimationProperty && property <= lastAnimationProperty; 1257 case HighPriorityProperties: 1258 return property >= firstHighPriorityProperty && property <= lastHighPriorityProperty; 1259 case LowPriorityProperties: 1260 return property > lastHighPriorityProperty; 1261 } 1262 ASSERT_NOT_REACHED(); 1263 return false; 1264 } 1265 1266 template <StyleResolver::StyleApplicationPass pass> 1267 void StyleResolver::applyProperties(StyleResolverState& state, const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType) 1268 { 1269 ASSERT((propertyWhitelistType != PropertyWhitelistRegion) || state.regionForStyling()); 1270 1271 unsigned propertyCount = properties->propertyCount(); 1272 for (unsigned i = 0; i < propertyCount; ++i) { 1273 StylePropertySet::PropertyReference current = properties->propertyAt(i); 1274 if (isImportant != current.isImportant()) 1275 continue; 1276 if (inheritedOnly && !current.isInherited()) { 1277 // If the property value is explicitly inherited, we need to apply further non-inherited properties 1278 // as they might override the value inherited here. For this reason we don't allow declarations with 1279 // explicitly inherited properties to be cached. 1280 ASSERT(!current.value()->isInheritedValue()); 1281 continue; 1282 } 1283 CSSPropertyID property = current.id(); 1284 1285 if (propertyWhitelistType == PropertyWhitelistRegion && !isValidRegionStyleProperty(property)) 1286 continue; 1287 if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property)) 1288 continue; 1289 if (!isPropertyForPass<pass>(property)) 1290 continue; 1291 if (pass == HighPriorityProperties && property == CSSPropertyLineHeight) 1292 state.setLineHeightValue(current.value()); 1293 else 1294 StyleBuilder::applyProperty(current.id(), state, current.value()); 1295 } 1296 } 1297 1298 template <StyleResolver::StyleApplicationPass pass> 1299 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly) 1300 { 1301 if (startIndex == -1) 1302 return; 1303 1304 if (state.style()->insideLink() != NotInsideLink) { 1305 for (int i = startIndex; i <= endIndex; ++i) { 1306 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; 1307 unsigned linkMatchType = matchedProperties.linkMatchType; 1308 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places. 1309 state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink); 1310 state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited); 1311 1312 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType)); 1313 } 1314 state.setApplyPropertyToRegularStyle(true); 1315 state.setApplyPropertyToVisitedLinkStyle(false); 1316 return; 1317 } 1318 for (int i = startIndex; i <= endIndex; ++i) { 1319 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; 1320 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType)); 1321 } 1322 } 1323 1324 static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size) 1325 { 1326 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size); 1327 } 1328 1329 void StyleResolver::invalidateMatchedPropertiesCache() 1330 { 1331 m_matchedPropertiesCache.clear(); 1332 } 1333 1334 PassOwnPtr<CSSAnimationUpdate> StyleResolver::calculateCSSAnimationUpdate(StyleResolverState& state) 1335 { 1336 if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) 1337 return nullptr; 1338 1339 const Element* element = state.element(); 1340 ASSERT(element); 1341 1342 if (!CSSAnimations::needsUpdate(element, state.style())) 1343 return nullptr; 1344 1345 ActiveAnimations* activeAnimations = element->activeAnimations(); 1346 const CSSAnimationDataList* animations = state.style()->animations(); 1347 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnimations() : 0; 1348 EDisplay display = state.style()->display(); 1349 return CSSAnimations::calculateUpdate(element, display, cssAnimations, animations, this); 1350 } 1351 1352 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult) 1353 { 1354 const Element* element = state.element(); 1355 ASSERT(element); 1356 STYLE_STATS_ADD_MATCHED_PROPERTIES_SEARCH(); 1357 1358 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0; 1359 bool applyInheritedOnly = false; 1360 const CachedMatchedProperties* cachedMatchedProperties = 0; 1361 1362 if (cacheHash && (cachedMatchedProperties = m_matchedPropertiesCache.find(cacheHash, state, matchResult)) 1363 && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) { 1364 STYLE_STATS_ADD_MATCHED_PROPERTIES_HIT(); 1365 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact 1366 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the 1367 // element context. This is fast and saves memory by reusing the style data structures. 1368 state.style()->copyNonInheritedFrom(cachedMatchedProperties->renderStyle.get()); 1369 if (state.parentStyle()->inheritedDataShared(cachedMatchedProperties->parentRenderStyle.get()) && !isAtShadowBoundary(element)) { 1370 STYLE_STATS_ADD_MATCHED_PROPERTIES_HIT_SHARED_INHERITED(); 1371 1372 EInsideLink linkStatus = state.style()->insideLink(); 1373 // If the cache item parent style has identical inherited properties to the current parent style then the 1374 // resulting style will be identical too. We copy the inherited properties over from the cache and are done. 1375 state.style()->inheritFrom(cachedMatchedProperties->renderStyle.get()); 1376 1377 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it. 1378 state.style()->setInsideLink(linkStatus); 1379 return; 1380 } 1381 applyInheritedOnly = true; 1382 } 1383 1384 // First apply all variable definitions, as they may be used during application of later properties. 1385 applyMatchedProperties<VariableDefinitions>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1386 applyMatchedProperties<VariableDefinitions>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1387 applyMatchedProperties<VariableDefinitions>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1388 applyMatchedProperties<VariableDefinitions>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1389 1390 // Apply animation properties in order to apply animation results and trigger transitions below. 1391 applyMatchedProperties<AnimationProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1392 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1393 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1394 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1395 1396 OwnPtr<CSSAnimationUpdate> cssAnimationUpdate = calculateCSSAnimationUpdate(state); 1397 1398 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply 1399 // high-priority properties first, i.e., those properties that other properties depend on. 1400 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important 1401 // and (4) normal important. 1402 state.setLineHeightValue(0); 1403 applyMatchedProperties<HighPriorityProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1404 // Animation contributions are processed here because CSS Animations are overridable by user !important rules. 1405 if (RuntimeEnabledFeatures::webAnimationsEnabled() && !applyInheritedOnly) 1406 applyAnimatedProperties<HighPriorityProperties>(state, element, element->document()->timeline(), cssAnimationUpdate.get()); 1407 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1408 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1409 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1410 1411 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) { 1412 state.fontBuilder().setFontDirty(true); 1413 applyInheritedOnly = false; 1414 } 1415 1416 // If our font got dirtied, go ahead and update it now. 1417 updateFont(state); 1418 1419 // Line-height is set when we are sure we decided on the font-size. 1420 if (state.lineHeightValue()) 1421 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue()); 1422 1423 // Many properties depend on the font. If it changes we just apply all properties. 1424 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription()) 1425 applyInheritedOnly = false; 1426 1427 // Now do the normal priority UA properties. 1428 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1429 1430 // Cache the UA properties to pass them to RenderTheme in adjustRenderStyle. 1431 state.cacheUserAgentBorderAndBackground(); 1432 1433 // Now do the author and user normal priority properties and all the !important properties. 1434 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1435 if (RuntimeEnabledFeatures::webAnimationsEnabled() && !applyInheritedOnly) 1436 applyAnimatedProperties<LowPriorityProperties>(state, element, element->document()->timeline(), cssAnimationUpdate.get()); 1437 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1438 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1439 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1440 1441 // Start loading resources referenced by this style. 1442 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources()); 1443 1444 ASSERT(!state.fontBuilder().fontDirty()); 1445 1446 #ifdef STYLE_STATS 1447 if (!cachedMatchedProperties) 1448 STYLE_STATS_ADD_MATCHED_PROPERTIES_TO_CACHE(); 1449 #endif 1450 1451 if (cachedMatchedProperties || !cacheHash) 1452 return; 1453 if (!MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) 1454 return; 1455 STYLE_STATS_ADD_MATCHED_PROPERTIES_ENTERED_INTO_CACHE(); 1456 m_matchedPropertiesCache.add(state.style(), state.parentStyle(), cacheHash, matchResult); 1457 } 1458 1459 CSSPropertyValue::CSSPropertyValue(CSSPropertyID id, const StylePropertySet& propertySet) 1460 : property(id), value(propertySet.getPropertyCSSValue(id).get()) 1461 { } 1462 1463 void StyleResolver::applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle* style) 1464 { 1465 StyleResolverState state(document(), 0, style); 1466 state.setStyle(style); 1467 1468 state.fontBuilder().initForStyleResolve(document(), style, state.useSVGZoomRules()); 1469 1470 for (size_t i = 0; i < count; ++i) { 1471 if (properties[i].value) { 1472 // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call, 1473 // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122). 1474 // The updateFont() call below updates the fontMetrics and ensure the proper setting of font-size and line-height. 1475 switch (properties[i].property) { 1476 case CSSPropertyFontSize: 1477 case CSSPropertyLineHeight: 1478 updateFont(state); 1479 break; 1480 default: 1481 break; 1482 } 1483 StyleBuilder::applyProperty(properties[i].property, state, properties[i].value); 1484 } 1485 } 1486 } 1487 1488 void StyleResolver::addViewportDependentMediaQueryResult(const MediaQueryExp* expr, bool result) 1489 { 1490 m_viewportDependentMediaQueryResults.append(adoptPtr(new MediaQueryResult(*expr, result))); 1491 } 1492 1493 bool StyleResolver::affectedByViewportChange() const 1494 { 1495 unsigned s = m_viewportDependentMediaQueryResults.size(); 1496 for (unsigned i = 0; i < s; i++) { 1497 if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result) 1498 return true; 1499 } 1500 return false; 1501 } 1502 1503 #ifdef STYLE_STATS 1504 StyleSharingStats StyleResolver::m_styleSharingStats; 1505 1506 static void printStyleStats(unsigned searches, unsigned elementsEligibleForSharing, unsigned stylesShared, unsigned searchFoundSiblingForSharing, unsigned searchesMissedSharing, 1507 unsigned matchedPropertiesSearches, unsigned matchedPropertiesHit, unsigned matchedPropertiesSharedInheritedHit, unsigned matchedPropertiesToCache, unsigned matchedPropertiesEnteredIntoCache) 1508 { 1509 double percentOfElementsSharingStyle = (stylesShared * 100.0) / searches; 1510 double percentOfNodesEligibleForSharing = (elementsEligibleForSharing * 100.0) / searches; 1511 double percentOfEligibleSharingRelativesFound = (searchFoundSiblingForSharing * 100.0) / searches; 1512 double percentOfMatchedPropertiesHit = (matchedPropertiesHit * 100.0) / matchedPropertiesSearches; 1513 double percentOfMatchedPropertiesSharedInheritedHit = (matchedPropertiesSharedInheritedHit * 100.0) / matchedPropertiesSearches; 1514 double percentOfMatchedPropertiesEnteredIntoCache = (matchedPropertiesEnteredIntoCache * 100.0) / matchedPropertiesToCache; 1515 1516 fprintf(stderr, "%u elements checked, %u were eligible for style sharing (%.2f%%).\n", searches, elementsEligibleForSharing, percentOfNodesEligibleForSharing); 1517 fprintf(stderr, "%u elements were found to share with, %u were possible (%.2f%%).\n", searchFoundSiblingForSharing, searchesMissedSharing + searchFoundSiblingForSharing, percentOfEligibleSharingRelativesFound); 1518 fprintf(stderr, "%u styles were actually shared once sibling and attribute rules were considered (%.2f%%).\n", stylesShared, percentOfElementsSharingStyle); 1519 fprintf(stderr, "%u/%u (%.2f%%) matched property lookups hit the cache.\n", matchedPropertiesHit, matchedPropertiesSearches, percentOfMatchedPropertiesHit); 1520 fprintf(stderr, "%u/%u (%.2f%%) matched property lookups hit the cache and shared inherited data.\n", matchedPropertiesSharedInheritedHit, matchedPropertiesSearches, percentOfMatchedPropertiesSharedInheritedHit); 1521 fprintf(stderr, "%u/%u (%.2f%%) matched properties were cacheable\n", matchedPropertiesEnteredIntoCache, matchedPropertiesToCache, percentOfMatchedPropertiesEnteredIntoCache); 1522 } 1523 1524 void StyleSharingStats::printStats() const 1525 { 1526 fprintf(stderr, "--------------------------------------------------------------------------------\n"); 1527 fprintf(stderr, "This recalc style:\n"); 1528 printStyleStats(m_searches, m_elementsEligibleForSharing, m_stylesShared, m_searchFoundSiblingForSharing, m_searchesMissedSharing, 1529 m_matchedPropertiesSearches, m_matchedPropertiesHit, m_matchedPropertiesSharedInheritedHit, m_matchedPropertiesToCache, m_matchedPropertiesEnteredIntoCache); 1530 1531 fprintf(stderr, "Total:\n"); 1532 printStyleStats(m_totalSearches, m_totalElementsEligibleForSharing, m_totalStylesShared, m_totalSearchFoundSiblingForSharing, m_totalSearchesMissedSharing, 1533 m_totalMatchedPropertiesSearches, m_totalMatchedPropertiesHit, m_totalMatchedPropertiesSharedInheritedHit, m_totalMatchedPropertiesToCache, m_totalMatchedPropertiesEnteredIntoCache); 1534 fprintf(stderr, "--------------------------------------------------------------------------------\n"); 1535 } 1536 #endif 1537 1538 } // namespace WebCore 1539