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 "core/CSSPropertyNames.h" 33 #include "core/HTMLNames.h" 34 #include "core/StylePropertyShorthand.h" 35 #include "core/animation/ActiveAnimations.h" 36 #include "core/animation/AnimatableValue.h" 37 #include "core/animation/Animation.h" 38 #include "core/animation/AnimationTimeline.h" 39 #include "core/animation/css/CSSAnimatableValueFactory.h" 40 #include "core/animation/css/CSSAnimations.h" 41 #include "core/animation/interpolation/StyleInterpolation.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/CSSReflectValue.h" 48 #include "core/css/CSSRuleList.h" 49 #include "core/css/CSSSelector.h" 50 #include "core/css/CSSStyleRule.h" 51 #include "core/css/CSSValueList.h" 52 #include "core/css/CSSValuePool.h" 53 #include "core/css/ElementRuleCollector.h" 54 #include "core/css/FontFace.h" 55 #include "core/css/MediaQueryEvaluator.h" 56 #include "core/css/PageRuleCollector.h" 57 #include "core/css/StylePropertySet.h" 58 #include "core/css/StyleRuleImport.h" 59 #include "core/css/StyleSheetContents.h" 60 #include "core/css/parser/BisonCSSParser.h" 61 #include "core/css/resolver/AnimatedStyleBuilder.h" 62 #include "core/css/resolver/MatchResult.h" 63 #include "core/css/resolver/MediaQueryResult.h" 64 #include "core/css/resolver/SharedStyleFinder.h" 65 #include "core/css/resolver/StyleAdjuster.h" 66 #include "core/css/resolver/StyleResolverParentScope.h" 67 #include "core/css/resolver/StyleResolverState.h" 68 #include "core/css/resolver/StyleResolverStats.h" 69 #include "core/css/resolver/ViewportStyleResolver.h" 70 #include "core/dom/CSSSelectorWatch.h" 71 #include "core/dom/NodeRenderStyle.h" 72 #include "core/dom/StyleEngine.h" 73 #include "core/dom/Text.h" 74 #include "core/dom/shadow/ElementShadow.h" 75 #include "core/dom/shadow/ShadowRoot.h" 76 #include "core/frame/FrameView.h" 77 #include "core/frame/LocalFrame.h" 78 #include "core/html/HTMLIFrameElement.h" 79 #include "core/inspector/InspectorInstrumentation.h" 80 #include "core/rendering/RenderView.h" 81 #include "core/rendering/style/KeyframeList.h" 82 #include "core/svg/SVGDocumentExtensions.h" 83 #include "core/svg/SVGElement.h" 84 #include "core/svg/SVGFontFaceElement.h" 85 #include "platform/RuntimeEnabledFeatures.h" 86 #include "wtf/StdLibExtras.h" 87 88 namespace { 89 90 using namespace WebCore; 91 92 void setAnimationUpdateIfNeeded(StyleResolverState& state, Element& element) 93 { 94 // If any changes to CSS Animations were detected, stash the update away for application after the 95 // render object is updated if we're in the appropriate scope. 96 if (state.animationUpdate()) 97 element.ensureActiveAnimations().cssAnimations().setPendingUpdate(state.takeAnimationUpdate()); 98 } 99 100 } // namespace 101 102 namespace WebCore { 103 104 using namespace HTMLNames; 105 106 RenderStyle* StyleResolver::s_styleNotYetAvailable; 107 108 static StylePropertySet* leftToRightDeclaration() 109 { 110 DEFINE_STATIC_REF(MutableStylePropertySet, leftToRightDecl, (MutableStylePropertySet::create())); 111 if (leftToRightDecl->isEmpty()) 112 leftToRightDecl->setProperty(CSSPropertyDirection, CSSValueLtr); 113 return leftToRightDecl; 114 } 115 116 static StylePropertySet* rightToLeftDeclaration() 117 { 118 DEFINE_STATIC_REF(MutableStylePropertySet, rightToLeftDecl, (MutableStylePropertySet::create())); 119 if (rightToLeftDecl->isEmpty()) 120 rightToLeftDecl->setProperty(CSSPropertyDirection, CSSValueRtl); 121 return rightToLeftDecl; 122 } 123 124 static void addFontFaceRule(Document* document, CSSFontSelector* cssFontSelector, const StyleRuleFontFace* fontFaceRule) 125 { 126 RefPtrWillBeRawPtr<FontFace> fontFace = FontFace::create(document, fontFaceRule); 127 if (fontFace) 128 cssFontSelector->fontFaceCache()->add(cssFontSelector, fontFaceRule, fontFace); 129 } 130 131 StyleResolver::StyleResolver(Document& document) 132 : m_document(document) 133 , m_viewportStyleResolver(ViewportStyleResolver::create(&document)) 134 , m_needCollectFeatures(false) 135 , m_styleResourceLoader(document.fetcher()) 136 , m_styleSharingDepth(0) 137 , m_styleResolverStatsSequence(0) 138 , m_accessCount(0) 139 { 140 FrameView* view = document.view(); 141 if (view) 142 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), &view->frame())); 143 else 144 m_medium = adoptPtr(new MediaQueryEvaluator("all")); 145 146 m_styleTree.clear(); 147 148 initWatchedSelectorRules(CSSSelectorWatch::from(document).watchedCallbackSelectors()); 149 150 #if ENABLE(SVG_FONTS) 151 if (document.svgExtensions()) { 152 const WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >& svgFontFaceElements = document.svgExtensions()->svgFontFaceElements(); 153 WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >::const_iterator end = svgFontFaceElements.end(); 154 for (WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >::const_iterator it = svgFontFaceElements.begin(); it != end; ++it) 155 addFontFaceRule(&document, document.styleEngine()->fontSelector(), (*it)->fontFaceRule()); 156 } 157 #endif 158 } 159 160 void StyleResolver::initWatchedSelectorRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRule> >& watchedSelectors) 161 { 162 if (!watchedSelectors.size()) 163 return; 164 m_watchedSelectorsRules = RuleSet::create(); 165 for (unsigned i = 0; i < watchedSelectors.size(); ++i) 166 m_watchedSelectorsRules->addStyleRule(watchedSelectors[i].get(), RuleHasNoSpecialState); 167 } 168 169 void StyleResolver::lazyAppendAuthorStyleSheets(unsigned firstNew, const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets) 170 { 171 unsigned size = styleSheets.size(); 172 for (unsigned i = firstNew; i < size; ++i) 173 m_pendingStyleSheets.add(styleSheets[i].get()); 174 } 175 176 void StyleResolver::removePendingAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets) 177 { 178 for (unsigned i = 0; i < styleSheets.size(); ++i) 179 m_pendingStyleSheets.remove(styleSheets[i].get()); 180 } 181 182 void StyleResolver::appendCSSStyleSheet(CSSStyleSheet* cssSheet) 183 { 184 ASSERT(cssSheet); 185 ASSERT(!cssSheet->disabled()); 186 if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), &m_viewportDependentMediaQueryResults)) 187 return; 188 189 ContainerNode* scopingNode = ScopedStyleResolver::scopingNodeFor(document(), cssSheet); 190 if (!scopingNode) 191 return; 192 193 ScopedStyleResolver* resolver = ensureScopedStyleResolver(scopingNode); 194 ASSERT(resolver); 195 resolver->addRulesFromSheet(cssSheet, *m_medium, this); 196 } 197 198 void StyleResolver::appendPendingAuthorStyleSheets() 199 { 200 setBuildScopedStyleTreeInDocumentOrder(false); 201 for (WillBeHeapListHashSet<RawPtrWillBeMember<CSSStyleSheet>, 16>::iterator it = m_pendingStyleSheets.begin(); it != m_pendingStyleSheets.end(); ++it) 202 appendCSSStyleSheet(*it); 203 204 m_pendingStyleSheets.clear(); 205 finishAppendAuthorStyleSheets(); 206 } 207 208 void StyleResolver::appendAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets) 209 { 210 // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver 211 // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated. 212 unsigned size = styleSheets.size(); 213 for (unsigned i = 0; i < size; ++i) 214 appendCSSStyleSheet(styleSheets[i].get()); 215 } 216 217 void StyleResolver::finishAppendAuthorStyleSheets() 218 { 219 collectFeatures(); 220 221 if (document().renderView() && document().renderView()->style()) 222 document().renderView()->style()->font().update(document().styleEngine()->fontSelector()); 223 224 collectViewportRules(); 225 226 document().styleEngine()->resetCSSFeatureFlags(m_features); 227 } 228 229 void StyleResolver::resetRuleFeatures() 230 { 231 // Need to recreate RuleFeatureSet. 232 m_features.clear(); 233 m_siblingRuleSet.clear(); 234 m_uncommonAttributeRuleSet.clear(); 235 m_needCollectFeatures = true; 236 } 237 238 void StyleResolver::processScopedRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, ContainerNode& scope) 239 { 240 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes> > keyframesRules = authorRules.keyframesRules(); 241 for (unsigned i = 0; i < keyframesRules.size(); ++i) 242 ensureScopedStyleResolver(&scope)->addKeyframeStyle(keyframesRules[i]); 243 244 m_treeBoundaryCrossingRules.addTreeBoundaryCrossingRules(authorRules, scope, parentStyleSheet); 245 246 // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for the moment. 247 if (scope.isDocumentNode()) { 248 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace> > fontFaceRules = authorRules.fontFaceRules(); 249 for (unsigned i = 0; i < fontFaceRules.size(); ++i) 250 addFontFaceRule(&m_document, document().styleEngine()->fontSelector(), fontFaceRules[i]); 251 if (fontFaceRules.size()) 252 invalidateMatchedPropertiesCache(); 253 } 254 } 255 256 void StyleResolver::resetAuthorStyle(const ContainerNode* scopingNode) 257 { 258 ScopedStyleResolver* resolver = scopingNode ? m_styleTree.lookupScopedStyleResolverFor(scopingNode) : m_styleTree.scopedStyleResolverForDocument(); 259 if (!resolver) 260 return; 261 262 m_treeBoundaryCrossingRules.reset(scopingNode); 263 264 resolver->resetAuthorStyle(); 265 resetRuleFeatures(); 266 if (!scopingNode) 267 return; 268 269 m_styleTree.remove(scopingNode); 270 } 271 272 static PassOwnPtrWillBeRawPtr<RuleSet> makeRuleSet(const WillBeHeapVector<RuleFeature>& rules) 273 { 274 size_t size = rules.size(); 275 if (!size) 276 return nullptr; 277 OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create(); 278 for (size_t i = 0; i < size; ++i) 279 ruleSet->addRule(rules[i].rule, rules[i].selectorIndex, rules[i].hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState); 280 return ruleSet.release(); 281 } 282 283 void StyleResolver::collectFeatures() 284 { 285 m_features.clear(); 286 // Collect all ids and rules using sibling selectors (:first-child and similar) 287 // in the current set of stylesheets. Style sharing code uses this information to reject 288 // sharing candidates. 289 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance(); 290 if (defaultStyleSheets.defaultStyle()) 291 m_features.add(defaultStyleSheets.defaultStyle()->features()); 292 293 if (document().isViewSource()) 294 m_features.add(defaultStyleSheets.defaultViewSourceStyle()->features()); 295 296 if (document().isTransitionDocument()) 297 m_features.add(defaultStyleSheets.defaultTransitionStyle()->features()); 298 299 if (m_watchedSelectorsRules) 300 m_features.add(m_watchedSelectorsRules->features()); 301 302 m_treeBoundaryCrossingRules.collectFeaturesTo(m_features); 303 304 m_styleTree.collectFeaturesTo(m_features); 305 306 m_siblingRuleSet = makeRuleSet(m_features.siblingRules); 307 m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules); 308 m_needCollectFeatures = false; 309 } 310 311 bool StyleResolver::hasRulesForId(const AtomicString& id) const 312 { 313 return m_features.hasSelectorForId(id); 314 } 315 316 void StyleResolver::addToStyleSharingList(Element& element) 317 { 318 // Never add elements to the style sharing list if we're not in a recalcStyle, 319 // otherwise we could leave stale pointers in there. 320 if (!document().inStyleRecalc()) 321 return; 322 INCREMENT_STYLE_STATS_COUNTER(*this, sharedStyleCandidates); 323 StyleSharingList& list = styleSharingList(); 324 if (list.size() >= styleSharingListSize) 325 list.remove(--list.end()); 326 list.prepend(&element); 327 } 328 329 StyleSharingList& StyleResolver::styleSharingList() 330 { 331 m_styleSharingLists.resize(styleSharingMaxDepth); 332 333 // We never put things at depth 0 into the list since that's only the <html> element 334 // and it has no siblings or cousins to share with. 335 unsigned depth = std::max(std::min(m_styleSharingDepth, styleSharingMaxDepth), 1u) - 1u; 336 ASSERT(depth >= 0); 337 338 if (!m_styleSharingLists[depth]) 339 m_styleSharingLists[depth] = adoptPtr(new StyleSharingList); 340 return *m_styleSharingLists[depth]; 341 } 342 343 void StyleResolver::clearStyleSharingList() 344 { 345 m_styleSharingLists.resize(0); 346 } 347 348 void StyleResolver::pushParentElement(Element& parent) 349 { 350 const ContainerNode* parentsParent = parent.parentOrShadowHostElement(); 351 352 // We are not always invoked consistently. For example, script execution can cause us to enter 353 // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree. 354 // Reset the stack in this case, or if we see a new root element. 355 // Otherwise just push the new parent. 356 if (!parentsParent || m_selectorFilter.parentStackIsEmpty()) 357 m_selectorFilter.setupParentStack(parent); 358 else 359 m_selectorFilter.pushParent(parent); 360 361 // Note: We mustn't skip ShadowRoot nodes for the scope stack. 362 m_styleTree.pushStyleCache(parent, parent.parentOrShadowHostNode()); 363 } 364 365 void StyleResolver::popParentElement(Element& parent) 366 { 367 // Note that we may get invoked for some random elements in some wacky cases during style resolve. 368 // Pause maintaining the stack in this case. 369 if (m_selectorFilter.parentStackIsConsistent(&parent)) 370 m_selectorFilter.popParent(); 371 372 m_styleTree.popStyleCache(parent); 373 } 374 375 void StyleResolver::pushParentShadowRoot(const ShadowRoot& shadowRoot) 376 { 377 ASSERT(shadowRoot.host()); 378 m_styleTree.pushStyleCache(shadowRoot, shadowRoot.host()); 379 } 380 381 void StyleResolver::popParentShadowRoot(const ShadowRoot& shadowRoot) 382 { 383 ASSERT(shadowRoot.host()); 384 m_styleTree.popStyleCache(shadowRoot); 385 } 386 387 StyleResolver::~StyleResolver() 388 { 389 } 390 391 static inline bool applyAuthorStylesOf(const Element* element) 392 { 393 return element->treeScope().applyAuthorStyles(); 394 } 395 396 void StyleResolver::matchAuthorRulesForShadowHost(Element* element, ElementRuleCollector& collector, bool includeEmptyRules, Vector<ScopedStyleResolver*, 8>& resolvers, Vector<ScopedStyleResolver*, 8>& resolversInShadowTree) 397 { 398 collector.clearMatchedRules(); 399 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; 400 401 CascadeScope cascadeScope = 0; 402 CascadeOrder cascadeOrder = 0; 403 bool applyAuthorStyles = applyAuthorStylesOf(element); 404 405 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j) 406 resolversInShadowTree.at(j)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope, cascadeOrder++); 407 408 if (resolvers.isEmpty() || resolvers.first()->treeScope() != element->treeScope()) 409 ++cascadeScope; 410 cascadeOrder += resolvers.size(); 411 for (unsigned i = 0; i < resolvers.size(); ++i) 412 resolvers.at(i)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, --cascadeOrder); 413 414 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules); 415 collector.sortAndTransferMatchedRules(); 416 } 417 418 void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules) 419 { 420 collector.clearMatchedRules(); 421 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; 422 423 bool applyAuthorStyles = applyAuthorStylesOf(element); 424 if (m_styleTree.hasOnlyScopedResolverForDocument()) { 425 m_styleTree.scopedStyleResolverForDocument()->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, ignoreCascadeScope); 426 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules); 427 collector.sortAndTransferMatchedRules(); 428 return; 429 } 430 431 Vector<ScopedStyleResolver*, 8> resolvers; 432 m_styleTree.resolveScopedStyles(element, resolvers); 433 434 Vector<ScopedStyleResolver*, 8> resolversInShadowTree; 435 m_styleTree.collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree); 436 if (!resolversInShadowTree.isEmpty()) { 437 matchAuthorRulesForShadowHost(element, collector, includeEmptyRules, resolvers, resolversInShadowTree); 438 return; 439 } 440 441 if (resolvers.isEmpty()) 442 return; 443 444 CascadeScope cascadeScope = 0; 445 CascadeOrder cascadeOrder = resolvers.size(); 446 for (unsigned i = 0; i < resolvers.size(); ++i, --cascadeOrder) { 447 ScopedStyleResolver* resolver = resolvers.at(i); 448 // FIXME: Need to clarify how to treat style scoped. 449 resolver->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, resolver->treeScope() == element->treeScope() && resolver->scopingNode().isShadowRoot() ? 0 : cascadeOrder); 450 } 451 452 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules); 453 collector.sortAndTransferMatchedRules(); 454 } 455 456 void StyleResolver::matchWatchSelectorRules(ElementRuleCollector& collector) 457 { 458 if (!m_watchedSelectorsRules) 459 return; 460 461 collector.clearMatchedRules(); 462 collector.matchedResult().ranges.lastUserRule = collector.matchedResult().matchedProperties.size() - 1; 463 464 MatchRequest matchRequest(m_watchedSelectorsRules.get()); 465 RuleRange ruleRange = collector.matchedResult().ranges.userRuleRange(); 466 collector.collectMatchingRules(matchRequest, ruleRange); 467 468 collector.sortAndTransferMatchedRules(); 469 } 470 471 void StyleResolver::matchUARules(ElementRuleCollector& collector) 472 { 473 collector.setMatchingUARules(true); 474 475 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance(); 476 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print") 477 ? defaultStyleSheets.defaultPrintStyle() : defaultStyleSheets.defaultStyle(); 478 matchUARules(collector, userAgentStyleSheet); 479 480 // In quirks mode, we match rules from the quirks user agent sheet. 481 if (document().inQuirksMode()) 482 matchUARules(collector, defaultStyleSheets.defaultQuirksStyle()); 483 484 // 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. 485 if (document().isViewSource()) 486 matchUARules(collector, defaultStyleSheets.defaultViewSourceStyle()); 487 488 if (document().isTransitionDocument()) 489 matchUARules(collector, defaultStyleSheets.defaultTransitionStyle()); 490 491 collector.setMatchingUARules(false); 492 493 matchWatchSelectorRules(collector); 494 } 495 496 void StyleResolver::matchUARules(ElementRuleCollector& collector, RuleSet* rules) 497 { 498 collector.clearMatchedRules(); 499 collector.matchedResult().ranges.lastUARule = collector.matchedResult().matchedProperties.size() - 1; 500 501 RuleRange ruleRange = collector.matchedResult().ranges.UARuleRange(); 502 collector.collectMatchingRules(MatchRequest(rules), ruleRange); 503 504 collector.sortAndTransferMatchedRules(); 505 } 506 507 void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollector& collector, bool includeSMILProperties) 508 { 509 matchUARules(collector); 510 511 // Now check author rules, beginning first with presentational attributes mapped from HTML. 512 if (state.element()->isStyledElement()) { 513 collector.addElementStyleProperties(state.element()->presentationAttributeStyle()); 514 515 // Now we check additional mapped declarations. 516 // Tables and table cells share an additional mapped rule that must be applied 517 // after all attributes, since their mapped style depends on the values of multiple attributes. 518 collector.addElementStyleProperties(state.element()->additionalPresentationAttributeStyle()); 519 520 if (state.element()->isHTMLElement()) { 521 bool isAuto; 522 TextDirection textDirection = toHTMLElement(state.element())->directionalityIfhasDirAutoAttribute(isAuto); 523 if (isAuto) 524 collector.matchedResult().addMatchedProperties(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration()); 525 } 526 } 527 528 matchAuthorRules(state.element(), collector, false); 529 530 if (state.element()->isStyledElement()) { 531 if (state.element()->inlineStyle()) { 532 // Inline style is immutable as long as there is no CSSOM wrapper. 533 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMutable(); 534 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable); 535 } 536 537 // Now check SMIL animation override style. 538 if (includeSMILProperties && state.element()->isSVGElement()) 539 collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */); 540 } 541 } 542 543 PassRefPtr<RenderStyle> StyleResolver::styleForDocument(Document& document) 544 { 545 const LocalFrame* frame = document.frame(); 546 547 RefPtr<RenderStyle> documentStyle = RenderStyle::create(); 548 documentStyle->setDisplay(BLOCK); 549 documentStyle->setRTLOrdering(document.visuallyOrdered() ? VisualOrder : LogicalOrder); 550 documentStyle->setZoom(frame && !document.printing() ? frame->pageZoomFactor() : 1); 551 documentStyle->setLocale(document.contentLanguage()); 552 documentStyle->setZIndex(0); 553 documentStyle->setUserModify(document.inDesignMode() ? READ_WRITE : READ_ONLY); 554 555 document.setupFontBuilder(documentStyle.get()); 556 557 return documentStyle.release(); 558 } 559 560 // FIXME: This is duplicated with StyleAdjuster.cpp 561 // Perhaps this should move onto ElementResolveContext or even Element? 562 static inline bool isAtShadowBoundary(const Element* element) 563 { 564 if (!element) 565 return false; 566 ContainerNode* parentNode = element->parentNode(); 567 return parentNode && parentNode->isShadowRoot(); 568 } 569 570 static inline void resetDirectionAndWritingModeOnDocument(Document& document) 571 { 572 document.setDirectionSetOnDocumentElement(false); 573 document.setWritingModeSetOnDocumentElement(false); 574 } 575 576 static void addContentAttrValuesToFeatures(const Vector<AtomicString>& contentAttrValues, RuleFeatureSet& features) 577 { 578 for (size_t i = 0; i < contentAttrValues.size(); ++i) 579 features.addContentAttr(contentAttrValues[i]); 580 } 581 582 void StyleResolver::adjustRenderStyle(StyleResolverState& state, Element* element) 583 { 584 StyleAdjuster adjuster(m_document.inQuirksMode()); 585 adjuster.adjustRenderStyle(state.style(), state.parentStyle(), element, state.cachedUAStyle()); 586 } 587 588 // Start loading resources referenced by this style. 589 void StyleResolver::loadPendingResources(StyleResolverState& state) 590 { 591 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources()); 592 document().styleEngine()->fontSelector()->fontLoader()->loadPendingFonts(); 593 } 594 595 PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent, StyleSharingBehavior sharingBehavior, 596 RuleMatchingBehavior matchingBehavior) 597 { 598 ASSERT(document().frame()); 599 ASSERT(documentSettings()); 600 ASSERT(!hasPendingAuthorStyleSheets()); 601 ASSERT(!m_needCollectFeatures); 602 603 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer 604 // will vanish if a style recalc happens during loading. 605 if (sharingBehavior == AllowStyleSharing && !document().isRenderingReady() && !element->renderer()) { 606 if (!s_styleNotYetAvailable) { 607 s_styleNotYetAvailable = RenderStyle::create().leakRef(); 608 s_styleNotYetAvailable->setDisplay(NONE); 609 s_styleNotYetAvailable->font().update(document().styleEngine()->fontSelector()); 610 } 611 612 document().setHasNodesWithPlaceholderStyle(); 613 return s_styleNotYetAvailable; 614 } 615 616 didAccess(); 617 618 StyleResolverParentScope::ensureParentStackIsPushed(); 619 620 if (element == document().documentElement()) 621 resetDirectionAndWritingModeOnDocument(document()); 622 StyleResolverState state(document(), element, defaultParent); 623 624 if (sharingBehavior == AllowStyleSharing && state.parentStyle()) { 625 SharedStyleFinder styleFinder(state.elementContext(), m_features, m_siblingRuleSet.get(), m_uncommonAttributeRuleSet.get(), *this); 626 if (RefPtr<RenderStyle> sharedStyle = styleFinder.findSharedStyle()) 627 return sharedStyle.release(); 628 } 629 630 if (state.parentStyle()) { 631 state.setStyle(RenderStyle::create()); 632 state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary); 633 } else { 634 state.setStyle(defaultStyleForElement()); 635 state.setParentStyle(RenderStyle::clone(state.style())); 636 } 637 // contenteditable attribute (implemented by -webkit-user-modify) should 638 // be propagated from shadow host to distributed node. 639 if (state.distributedToInsertionPoint()) { 640 if (Element* parent = element->parentElement()) { 641 if (RenderStyle* styleOfShadowHost = parent->renderStyle()) 642 state.style()->setUserModify(styleOfShadowHost->userModify()); 643 } 644 } 645 646 state.fontBuilder().initForStyleResolve(state.document(), state.style()); 647 648 if (element->isLink()) { 649 state.style()->setIsLink(true); 650 EInsideLink linkState = state.elementLinkState(); 651 if (linkState != NotInsideLink) { 652 bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited); 653 if (forceVisited) 654 linkState = InsideVisitedLink; 655 } 656 state.style()->setInsideLink(linkState); 657 } 658 659 bool needsCollection = false; 660 CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection); 661 if (needsCollection) 662 collectFeatures(); 663 664 { 665 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); 666 667 matchAllRules(state, collector, matchingBehavior != MatchAllRulesExcludingSMIL); 668 669 applyMatchedProperties(state, collector.matchedResult()); 670 671 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features); 672 } 673 674 // Cache our original display. 675 state.style()->setOriginalDisplay(state.style()->display()); 676 677 adjustRenderStyle(state, element); 678 679 // FIXME: The CSSWG wants to specify that the effects of animations are applied before 680 // important rules, but this currently happens here as we require adjustment to have happened 681 // before deciding which properties to transition. 682 if (applyAnimatedProperties(state, element)) 683 adjustRenderStyle(state, element); 684 685 // FIXME: Shouldn't this be on RenderBody::styleDidChange? 686 if (isHTMLBodyElement(*element)) 687 document().textLinkColors().setTextColor(state.style()->color()); 688 689 setAnimationUpdateIfNeeded(state, *element); 690 691 if (state.style()->hasViewportUnits()) 692 document().setHasViewportUnits(); 693 694 // Now return the style. 695 return state.takeStyle(); 696 } 697 698 PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const RenderStyle& elementStyle, RenderStyle* parentStyle, const StyleKeyframe* keyframe, const AtomicString& animationName) 699 { 700 ASSERT(document().frame()); 701 ASSERT(documentSettings()); 702 ASSERT(!hasPendingAuthorStyleSheets()); 703 704 if (element == document().documentElement()) 705 resetDirectionAndWritingModeOnDocument(document()); 706 StyleResolverState state(document(), element, parentStyle); 707 708 MatchResult result; 709 result.addMatchedProperties(&keyframe->properties()); 710 711 ASSERT(!state.style()); 712 713 // Create the style 714 state.setStyle(RenderStyle::clone(&elementStyle)); 715 state.setLineHeightValue(0); 716 717 state.fontBuilder().initForStyleResolve(state.document(), state.style()); 718 719 // We don't need to bother with !important. Since there is only ever one 720 // decl, there's nothing to override. So just add the first properties. 721 // We also don't need to bother with animation properties since the only 722 // relevant one is animation-timing-function and we special-case that in 723 // CSSAnimations.cpp 724 bool inheritedOnly = false; 725 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 726 727 // If our font got dirtied, go ahead and update it now. 728 updateFont(state); 729 730 // Line-height is set when we are sure we decided on the font-size 731 if (state.lineHeightValue()) 732 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue()); 733 734 // Now do rest of the properties. 735 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 736 737 // If our font got dirtied by one of the non-essential font props, 738 // go ahead and update it a second time. 739 updateFont(state); 740 741 loadPendingResources(state); 742 743 didAccess(); 744 745 return state.takeStyle(); 746 } 747 748 // This function is used by the WebAnimations JavaScript API method animate(). 749 // FIXME: Remove this when animate() switches away from resolution-dependent parsing. 750 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(Element& element, CSSPropertyID property, CSSValue& value) 751 { 752 RefPtr<RenderStyle> style; 753 if (element.renderStyle()) 754 style = RenderStyle::clone(element.renderStyle()); 755 else 756 style = RenderStyle::create(); 757 StyleResolverState state(element.document(), &element); 758 state.setStyle(style); 759 state.fontBuilder().initForStyleResolve(state.document(), state.style()); 760 return createAnimatableValueSnapshot(state, property, value); 761 } 762 763 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(StyleResolverState& state, CSSPropertyID property, CSSValue& value) 764 { 765 StyleBuilder::applyProperty(property, state, &value); 766 return CSSAnimatableValueFactory::create(property, *state.style()); 767 } 768 769 PassRefPtrWillBeRawPtr<PseudoElement> StyleResolver::createPseudoElementIfNeeded(Element& parent, PseudoId pseudoId) 770 { 771 RenderObject* parentRenderer = parent.renderer(); 772 if (!parentRenderer) 773 return nullptr; 774 775 if (pseudoId < FIRST_INTERNAL_PSEUDOID && !parentRenderer->style()->hasPseudoStyle(pseudoId)) 776 return nullptr; 777 778 if (pseudoId == BACKDROP && !parent.isInTopLayer()) 779 return nullptr; 780 781 if (!parentRenderer->canHaveGeneratedChildren()) 782 return nullptr; 783 784 RenderStyle* parentStyle = parentRenderer->style(); 785 if (RenderStyle* cachedStyle = parentStyle->getCachedPseudoStyle(pseudoId)) { 786 if (!pseudoElementRendererIsNeeded(cachedStyle)) 787 return nullptr; 788 return PseudoElement::create(&parent, pseudoId); 789 } 790 791 StyleResolverState state(document(), &parent, parentStyle); 792 if (!pseudoStyleForElementInternal(parent, pseudoId, parentStyle, state)) 793 return nullptr; 794 RefPtr<RenderStyle> style = state.takeStyle(); 795 ASSERT(style); 796 parentStyle->addCachedPseudoStyle(style); 797 798 if (!pseudoElementRendererIsNeeded(style.get())) 799 return nullptr; 800 801 RefPtrWillBeRawPtr<PseudoElement> pseudo = PseudoElement::create(&parent, pseudoId); 802 803 setAnimationUpdateIfNeeded(state, *pseudo); 804 if (ActiveAnimations* activeAnimations = pseudo->activeAnimations()) 805 activeAnimations->cssAnimations().maybeApplyPendingUpdate(pseudo.get()); 806 return pseudo.release(); 807 } 808 809 bool StyleResolver::pseudoStyleForElementInternal(Element& element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, StyleResolverState& state) 810 { 811 ASSERT(document().frame()); 812 ASSERT(documentSettings()); 813 ASSERT(pseudoStyleRequest.pseudoId != FIRST_LINE_INHERITED); 814 815 StyleResolverParentScope::ensureParentStackIsPushed(); 816 817 if (pseudoStyleRequest.allowsInheritance(state.parentStyle())) { 818 state.setStyle(RenderStyle::create()); 819 state.style()->inheritFrom(state.parentStyle()); 820 } else { 821 state.setStyle(defaultStyleForElement()); 822 state.setParentStyle(RenderStyle::clone(state.style())); 823 } 824 825 state.fontBuilder().initForStyleResolve(state.document(), state.style()); 826 827 // Since we don't use pseudo-elements in any of our quirk/print 828 // user agent rules, don't waste time walking those rules. 829 830 { 831 // Check UA, user and author rules. 832 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); 833 collector.setPseudoStyleRequest(pseudoStyleRequest); 834 835 matchUARules(collector); 836 matchAuthorRules(state.element(), collector, false); 837 838 if (collector.matchedResult().matchedProperties.isEmpty()) 839 return false; 840 841 state.style()->setStyleType(pseudoStyleRequest.pseudoId); 842 843 applyMatchedProperties(state, collector.matchedResult()); 844 845 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features); 846 } 847 848 // Cache our original display. 849 state.style()->setOriginalDisplay(state.style()->display()); 850 851 // FIXME: Passing 0 as the Element* introduces a lot of complexity 852 // in the adjustRenderStyle code. 853 adjustRenderStyle(state, 0); 854 855 // FIXME: The CSSWG wants to specify that the effects of animations are applied before 856 // important rules, but this currently happens here as we require adjustment to have happened 857 // before deciding which properties to transition. 858 if (applyAnimatedProperties(state, element.pseudoElement(pseudoStyleRequest.pseudoId))) 859 adjustRenderStyle(state, 0); 860 861 didAccess(); 862 863 if (state.style()->hasViewportUnits()) 864 document().setHasViewportUnits(); 865 866 return true; 867 } 868 869 PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle) 870 { 871 ASSERT(parentStyle); 872 if (!element) 873 return nullptr; 874 875 StyleResolverState state(document(), element, parentStyle); 876 if (!pseudoStyleForElementInternal(*element, pseudoStyleRequest, parentStyle, state)) 877 return nullptr; 878 879 if (PseudoElement* pseudoElement = element->pseudoElement(pseudoStyleRequest.pseudoId)) 880 setAnimationUpdateIfNeeded(state, *pseudoElement); 881 882 // Now return the style. 883 return state.takeStyle(); 884 } 885 886 PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex) 887 { 888 ASSERT(!hasPendingAuthorStyleSheets()); 889 resetDirectionAndWritingModeOnDocument(document()); 890 StyleResolverState state(document(), document().documentElement()); // m_rootElementStyle will be set to the document style. 891 892 state.setStyle(RenderStyle::create()); 893 const RenderStyle* rootElementStyle = state.rootElementStyle() ? state.rootElementStyle() : document().renderStyle(); 894 ASSERT(rootElementStyle); 895 state.style()->inheritFrom(rootElementStyle); 896 897 state.fontBuilder().initForStyleResolve(state.document(), state.style()); 898 899 PageRuleCollector collector(rootElementStyle, pageIndex); 900 901 collector.matchPageRules(CSSDefaultStyleSheets::instance().defaultPrintStyle()); 902 903 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument()) 904 scopedResolver->matchPageRules(collector); 905 906 state.setLineHeightValue(0); 907 bool inheritedOnly = false; 908 909 MatchResult& result = collector.matchedResult(); 910 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 911 912 // If our font got dirtied, go ahead and update it now. 913 updateFont(state); 914 915 // Line-height is set when we are sure we decided on the font-size. 916 if (state.lineHeightValue()) 917 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue()); 918 919 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 920 921 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features); 922 923 loadPendingResources(state); 924 925 didAccess(); 926 927 // Now return the style. 928 return state.takeStyle(); 929 } 930 931 void StyleResolver::collectViewportRules() 932 { 933 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance(); 934 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultStyle(), ViewportStyleResolver::UserAgentOrigin); 935 936 if (!InspectorInstrumentation::applyViewportStyleOverride(&document(), this)) 937 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultViewportStyle(), ViewportStyleResolver::UserAgentOrigin); 938 939 if (document().isMobileDocument()) 940 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultXHTMLMobileProfileStyle(), ViewportStyleResolver::UserAgentOrigin); 941 942 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument()) 943 scopedResolver->collectViewportRulesTo(this); 944 945 viewportStyleResolver()->resolve(); 946 } 947 948 PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement() 949 { 950 StyleResolverState state(document(), 0); 951 state.setStyle(RenderStyle::create()); 952 state.fontBuilder().initForStyleResolve(document(), state.style()); 953 state.style()->setLineHeight(RenderStyle::initialLineHeight()); 954 state.setLineHeightValue(0); 955 state.fontBuilder().setInitial(state.style()->effectiveZoom()); 956 state.style()->font().update(document().styleEngine()->fontSelector()); 957 return state.takeStyle(); 958 } 959 960 PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode) 961 { 962 ASSERT(textNode); 963 964 NodeRenderingTraversal::ParentDetails parentDetails; 965 Node* parentNode = NodeRenderingTraversal::parent(textNode, &parentDetails); 966 if (!parentNode || !parentNode->renderStyle()) 967 return defaultStyleForElement(); 968 return parentNode->renderStyle(); 969 } 970 971 void StyleResolver::updateFont(StyleResolverState& state) 972 { 973 state.fontBuilder().createFont(document().styleEngine()->fontSelector(), state.parentStyle(), state.style()); 974 if (state.fontBuilder().fontSizeHasViewportUnits()) 975 state.style()->setHasViewportUnits(); 976 } 977 978 PassRefPtrWillBeRawPtr<StyleRuleList> StyleResolver::styleRulesForElement(Element* element, unsigned rulesToInclude) 979 { 980 ASSERT(element); 981 StyleResolverState state(document(), element); 982 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); 983 collector.setMode(SelectorChecker::CollectingStyleRules); 984 collectPseudoRulesForElement(element, collector, NOPSEUDO, rulesToInclude); 985 return collector.matchedStyleRuleList(); 986 } 987 988 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::pseudoCSSRulesForElement(Element* element, PseudoId pseudoId, unsigned rulesToInclude) 989 { 990 ASSERT(element); 991 StyleResolverState state(document(), element); 992 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); 993 collector.setMode(SelectorChecker::CollectingCSSRules); 994 collectPseudoRulesForElement(element, collector, pseudoId, rulesToInclude); 995 return collector.matchedCSSRuleList(); 996 } 997 998 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::cssRulesForElement(Element* element, unsigned rulesToInclude) 999 { 1000 return pseudoCSSRulesForElement(element, NOPSEUDO, rulesToInclude); 1001 } 1002 1003 void StyleResolver::collectPseudoRulesForElement(Element* element, ElementRuleCollector& collector, PseudoId pseudoId, unsigned rulesToInclude) 1004 { 1005 collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId)); 1006 1007 if (rulesToInclude & UAAndUserCSSRules) 1008 matchUARules(collector); 1009 1010 if (rulesToInclude & AuthorCSSRules) { 1011 collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules)); 1012 matchAuthorRules(element, collector, rulesToInclude & EmptyCSSRules); 1013 } 1014 } 1015 1016 // ------------------------------------------------------------------------------------- 1017 // this is mostly boring stuff on how to apply a certain rule to the renderstyle... 1018 1019 bool StyleResolver::applyAnimatedProperties(StyleResolverState& state, Element* animatingElement) 1020 { 1021 const Element* element = state.element(); 1022 ASSERT(element); 1023 1024 // The animating element may be this element, or its pseudo element. It is 1025 // null when calculating the style for a potential pseudo element that has 1026 // yet to be created. 1027 ASSERT(animatingElement == element || !animatingElement || animatingElement->parentOrShadowHostElement() == element); 1028 1029 if (!(animatingElement && animatingElement->hasActiveAnimations()) 1030 && !state.style()->transitions() && !state.style()->animations()) 1031 return false; 1032 1033 state.setAnimationUpdate(CSSAnimations::calculateUpdate(animatingElement, *element, *state.style(), state.parentStyle(), this)); 1034 if (!state.animationUpdate()) 1035 return false; 1036 1037 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations = state.animationUpdate()->activeInterpolationsForAnimations(); 1038 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForTransitions = state.animationUpdate()->activeInterpolationsForTransitions(); 1039 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForAnimations); 1040 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForTransitions); 1041 1042 updateFont(state); 1043 1044 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForAnimations); 1045 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForTransitions); 1046 1047 // Start loading resources used by animations. 1048 loadPendingResources(state); 1049 1050 ASSERT(!state.fontBuilder().fontDirty()); 1051 1052 return true; 1053 } 1054 1055 template <StyleResolver::StyleApplicationPass pass> 1056 void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolations) 1057 { 1058 ASSERT(pass != AnimationProperties); 1059 1060 for (WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >::const_iterator iter = activeInterpolations.begin(); iter != activeInterpolations.end(); ++iter) { 1061 CSSPropertyID property = iter->key; 1062 if (!isPropertyForPass<pass>(property)) 1063 continue; 1064 const StyleInterpolation* interpolation = toStyleInterpolation(iter->value.get()); 1065 interpolation->apply(state); 1066 } 1067 } 1068 1069 static inline bool isValidCueStyleProperty(CSSPropertyID id) 1070 { 1071 switch (id) { 1072 case CSSPropertyBackground: 1073 case CSSPropertyBackgroundAttachment: 1074 case CSSPropertyBackgroundClip: 1075 case CSSPropertyBackgroundColor: 1076 case CSSPropertyBackgroundImage: 1077 case CSSPropertyBackgroundOrigin: 1078 case CSSPropertyBackgroundPosition: 1079 case CSSPropertyBackgroundPositionX: 1080 case CSSPropertyBackgroundPositionY: 1081 case CSSPropertyBackgroundRepeat: 1082 case CSSPropertyBackgroundRepeatX: 1083 case CSSPropertyBackgroundRepeatY: 1084 case CSSPropertyBackgroundSize: 1085 case CSSPropertyColor: 1086 case CSSPropertyFont: 1087 case CSSPropertyFontFamily: 1088 case CSSPropertyFontSize: 1089 case CSSPropertyFontStyle: 1090 case CSSPropertyFontVariant: 1091 case CSSPropertyFontWeight: 1092 case CSSPropertyLineHeight: 1093 case CSSPropertyOpacity: 1094 case CSSPropertyOutline: 1095 case CSSPropertyOutlineColor: 1096 case CSSPropertyOutlineOffset: 1097 case CSSPropertyOutlineStyle: 1098 case CSSPropertyOutlineWidth: 1099 case CSSPropertyVisibility: 1100 case CSSPropertyWhiteSpace: 1101 // FIXME: 'text-decoration' shorthand to be handled when available. 1102 // See https://chromiumcodereview.appspot.com/19516002 for details. 1103 case CSSPropertyTextDecoration: 1104 case CSSPropertyTextShadow: 1105 case CSSPropertyBorderStyle: 1106 return true; 1107 case CSSPropertyTextDecorationLine: 1108 case CSSPropertyTextDecorationStyle: 1109 case CSSPropertyTextDecorationColor: 1110 return RuntimeEnabledFeatures::css3TextDecorationsEnabled(); 1111 default: 1112 break; 1113 } 1114 return false; 1115 } 1116 1117 static inline bool isValidFirstLetterStyleProperty(CSSPropertyID id) 1118 { 1119 switch (id) { 1120 // Valid ::first-letter properties listed in spec: 1121 // http://www.w3.org/TR/css3-selectors/#application-in-css 1122 case CSSPropertyBackgroundAttachment: 1123 case CSSPropertyBackgroundBlendMode: 1124 case CSSPropertyBackgroundClip: 1125 case CSSPropertyBackgroundColor: 1126 case CSSPropertyBackgroundImage: 1127 case CSSPropertyBackgroundOrigin: 1128 case CSSPropertyBackgroundPosition: 1129 case CSSPropertyBackgroundPositionX: 1130 case CSSPropertyBackgroundPositionY: 1131 case CSSPropertyBackgroundRepeat: 1132 case CSSPropertyBackgroundRepeatX: 1133 case CSSPropertyBackgroundRepeatY: 1134 case CSSPropertyBackgroundSize: 1135 case CSSPropertyBorderBottomColor: 1136 case CSSPropertyBorderBottomLeftRadius: 1137 case CSSPropertyBorderBottomRightRadius: 1138 case CSSPropertyBorderBottomStyle: 1139 case CSSPropertyBorderBottomWidth: 1140 case CSSPropertyBorderImageOutset: 1141 case CSSPropertyBorderImageRepeat: 1142 case CSSPropertyBorderImageSlice: 1143 case CSSPropertyBorderImageSource: 1144 case CSSPropertyBorderImageWidth: 1145 case CSSPropertyBorderLeftColor: 1146 case CSSPropertyBorderLeftStyle: 1147 case CSSPropertyBorderLeftWidth: 1148 case CSSPropertyBorderRightColor: 1149 case CSSPropertyBorderRightStyle: 1150 case CSSPropertyBorderRightWidth: 1151 case CSSPropertyBorderTopColor: 1152 case CSSPropertyBorderTopLeftRadius: 1153 case CSSPropertyBorderTopRightRadius: 1154 case CSSPropertyBorderTopStyle: 1155 case CSSPropertyBorderTopWidth: 1156 case CSSPropertyColor: 1157 case CSSPropertyFloat: 1158 case CSSPropertyFont: 1159 case CSSPropertyFontFamily: 1160 case CSSPropertyFontKerning: 1161 case CSSPropertyFontSize: 1162 case CSSPropertyFontStretch: 1163 case CSSPropertyFontStyle: 1164 case CSSPropertyFontVariant: 1165 case CSSPropertyFontVariantLigatures: 1166 case CSSPropertyFontWeight: 1167 case CSSPropertyLetterSpacing: 1168 case CSSPropertyLineHeight: 1169 case CSSPropertyMarginBottom: 1170 case CSSPropertyMarginLeft: 1171 case CSSPropertyMarginRight: 1172 case CSSPropertyMarginTop: 1173 case CSSPropertyPaddingBottom: 1174 case CSSPropertyPaddingLeft: 1175 case CSSPropertyPaddingRight: 1176 case CSSPropertyPaddingTop: 1177 case CSSPropertyTextTransform: 1178 case CSSPropertyVerticalAlign: 1179 case CSSPropertyWebkitBackgroundClip: 1180 case CSSPropertyWebkitBackgroundComposite: 1181 case CSSPropertyWebkitBackgroundOrigin: 1182 case CSSPropertyWebkitBackgroundSize: 1183 case CSSPropertyWebkitBorderAfter: 1184 case CSSPropertyWebkitBorderAfterColor: 1185 case CSSPropertyWebkitBorderAfterStyle: 1186 case CSSPropertyWebkitBorderAfterWidth: 1187 case CSSPropertyWebkitBorderBefore: 1188 case CSSPropertyWebkitBorderBeforeColor: 1189 case CSSPropertyWebkitBorderBeforeStyle: 1190 case CSSPropertyWebkitBorderBeforeWidth: 1191 case CSSPropertyWebkitBorderEnd: 1192 case CSSPropertyWebkitBorderEndColor: 1193 case CSSPropertyWebkitBorderEndStyle: 1194 case CSSPropertyWebkitBorderEndWidth: 1195 case CSSPropertyWebkitBorderFit: 1196 case CSSPropertyWebkitBorderHorizontalSpacing: 1197 case CSSPropertyWebkitBorderImage: 1198 case CSSPropertyWebkitBorderRadius: 1199 case CSSPropertyWebkitBorderStart: 1200 case CSSPropertyWebkitBorderStartColor: 1201 case CSSPropertyWebkitBorderStartStyle: 1202 case CSSPropertyWebkitBorderStartWidth: 1203 case CSSPropertyWebkitBorderVerticalSpacing: 1204 case CSSPropertyWebkitFontSmoothing: 1205 case CSSPropertyWebkitMarginAfter: 1206 case CSSPropertyWebkitMarginAfterCollapse: 1207 case CSSPropertyWebkitMarginBefore: 1208 case CSSPropertyWebkitMarginBeforeCollapse: 1209 case CSSPropertyWebkitMarginBottomCollapse: 1210 case CSSPropertyWebkitMarginCollapse: 1211 case CSSPropertyWebkitMarginEnd: 1212 case CSSPropertyWebkitMarginStart: 1213 case CSSPropertyWebkitMarginTopCollapse: 1214 case CSSPropertyWordSpacing: 1215 return true; 1216 case CSSPropertyTextDecorationColor: 1217 case CSSPropertyTextDecorationLine: 1218 case CSSPropertyTextDecorationStyle: 1219 return RuntimeEnabledFeatures::css3TextDecorationsEnabled(); 1220 1221 // text-shadow added in text decoration spec: 1222 // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property 1223 case CSSPropertyTextShadow: 1224 // box-shadox added in CSS3 backgrounds spec: 1225 // http://www.w3.org/TR/css3-background/#placement 1226 case CSSPropertyBoxShadow: 1227 case CSSPropertyWebkitBoxShadow: 1228 // Properties that we currently support outside of spec. 1229 case CSSPropertyWebkitLineBoxContain: 1230 case CSSPropertyVisibility: 1231 return true; 1232 1233 default: 1234 return false; 1235 } 1236 } 1237 1238 // FIXME: Consider refactoring to create a new class which owns the following 1239 // first/last/range properties. 1240 // This method returns the first CSSPropertyId of properties which generate 1241 // animations. All animation properties are obtained by using 1242 // firstCSSPropertyId<AnimationProperties> and 1243 // lastCSSPropertyId<AnimationProperties>. 1244 // c.f. //src/third_party/WebKit/Source/core/css/CSSPropertyNames.in. 1245 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::AnimationProperties>() 1246 { 1247 COMPILE_ASSERT(firstCSSProperty == CSSPropertyDisplay, CSS_first_animation_property_should_be_first_property); 1248 return CSSPropertyDisplay; 1249 } 1250 1251 // This method returns the first CSSPropertyId of properties which generate 1252 // animations. 1253 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::AnimationProperties>() 1254 { 1255 COMPILE_ASSERT(CSSPropertyTransitionTimingFunction == CSSPropertyColor - 1, CSS_transition_timing_is_last_animation_property); 1256 return CSSPropertyTransitionTimingFunction; 1257 } 1258 1259 // This method returns the first CSSPropertyId of high priority properties. 1260 // Other properties can depend on high priority properties. For example, 1261 // border-color property with currentColor value depends on color property. 1262 // All high priority properties are obtained by using 1263 // firstCSSPropertyId<HighPriorityProperties> and 1264 // lastCSSPropertyId<HighPriorityProperties>. 1265 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::HighPriorityProperties>() 1266 { 1267 COMPILE_ASSERT(CSSPropertyTransitionTimingFunction + 1 == CSSPropertyColor, CSS_color_is_first_high_priority_property); 1268 return CSSPropertyColor; 1269 } 1270 1271 // This method returns the last CSSPropertyId of high priority properties. 1272 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::HighPriorityProperties>() 1273 { 1274 COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyColor + 17, CSS_line_height_is_end_of_high_prioity_property_range); 1275 COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyLineHeight - 1, CSS_zoom_is_before_line_height); 1276 return CSSPropertyLineHeight; 1277 } 1278 1279 // This method returns the first CSSPropertyId of remaining properties, 1280 // i.e. low priority properties. No properties depend on low priority 1281 // properties. So we don't need to resolve such properties quickly. 1282 // All low priority properties are obtained by using 1283 // firstCSSPropertyId<LowPriorityProperties> and 1284 // lastCSSPropertyId<LowPriorityProperties>. 1285 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::LowPriorityProperties>() 1286 { 1287 COMPILE_ASSERT(CSSPropertyBackground == CSSPropertyLineHeight + 1, CSS_background_is_first_low_priority_property); 1288 return CSSPropertyBackground; 1289 } 1290 1291 // This method returns the last CSSPropertyId of low priority properties. 1292 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::LowPriorityProperties>() 1293 { 1294 return static_cast<CSSPropertyID>(lastCSSProperty); 1295 } 1296 1297 template <StyleResolver::StyleApplicationPass pass> 1298 bool StyleResolver::isPropertyForPass(CSSPropertyID property) 1299 { 1300 return firstCSSPropertyId<pass>() <= property && property <= lastCSSPropertyId<pass>(); 1301 } 1302 1303 // This method expands all shorthand property to longhand properties 1304 // considering StyleApplicationPass, and apply each expanded longhand property. 1305 // For example, if StyleApplicationPass is AnimationProperties, all shorthand 1306 // is expaneded to display, -webkit-animation, -webkit-animation-delay, ..., 1307 // transition-timing-function. So each property's value will be applied 1308 // according to all's value (initial, inherit or unset). 1309 template <StyleResolver::StyleApplicationPass pass> 1310 void StyleResolver::applyAllProperty(StyleResolverState& state, CSSValue* allValue) 1311 { 1312 bool isUnsetValue = !allValue->isInitialValue() && !allValue->isInheritedValue(); 1313 unsigned startCSSProperty = firstCSSPropertyId<pass>(); 1314 unsigned endCSSProperty = lastCSSPropertyId<pass>(); 1315 1316 for (unsigned i = startCSSProperty; i <= endCSSProperty; ++i) { 1317 CSSPropertyID propertyId = static_cast<CSSPropertyID>(i); 1318 1319 // StyleBuilder does not allow any expanded shorthands. 1320 if (isExpandedShorthandForAll(propertyId)) 1321 continue; 1322 1323 // all shorthand spec says: 1324 // The all property is a shorthand that resets all CSS properties 1325 // except direction and unicode-bidi. 1326 // c.f. http://dev.w3.org/csswg/css-cascade/#all-shorthand 1327 // We skip applyProperty when a given property is unicode-bidi or 1328 // direction. 1329 if (!CSSProperty::isAffectedByAllProperty(propertyId)) 1330 continue; 1331 1332 CSSValue* value; 1333 if (!isUnsetValue) { 1334 value = allValue; 1335 } else { 1336 if (CSSProperty::isInheritedProperty(propertyId)) 1337 value = cssValuePool().createInheritedValue().get(); 1338 else 1339 value = cssValuePool().createExplicitInitialValue().get(); 1340 } 1341 StyleBuilder::applyProperty(propertyId, state, value); 1342 } 1343 } 1344 1345 template <StyleResolver::StyleApplicationPass pass> 1346 void StyleResolver::applyProperties(StyleResolverState& state, const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType) 1347 { 1348 state.setCurrentRule(rule); 1349 1350 unsigned propertyCount = properties->propertyCount(); 1351 for (unsigned i = 0; i < propertyCount; ++i) { 1352 StylePropertySet::PropertyReference current = properties->propertyAt(i); 1353 if (isImportant != current.isImportant()) 1354 continue; 1355 1356 CSSPropertyID property = current.id(); 1357 if (property == CSSPropertyAll) { 1358 applyAllProperty<pass>(state, current.value()); 1359 continue; 1360 } 1361 1362 if (inheritedOnly && !current.isInherited()) { 1363 // If the property value is explicitly inherited, we need to apply further non-inherited properties 1364 // as they might override the value inherited here. For this reason we don't allow declarations with 1365 // explicitly inherited properties to be cached. 1366 ASSERT(!current.value()->isInheritedValue()); 1367 continue; 1368 } 1369 1370 if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property)) 1371 continue; 1372 if (propertyWhitelistType == PropertyWhitelistFirstLetter && !isValidFirstLetterStyleProperty(property)) 1373 continue; 1374 if (!isPropertyForPass<pass>(property)) 1375 continue; 1376 if (pass == HighPriorityProperties && property == CSSPropertyLineHeight) 1377 state.setLineHeightValue(current.value()); 1378 else 1379 StyleBuilder::applyProperty(current.id(), state, current.value()); 1380 } 1381 } 1382 1383 template <StyleResolver::StyleApplicationPass pass> 1384 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly) 1385 { 1386 if (startIndex == -1) 1387 return; 1388 1389 if (state.style()->insideLink() != NotInsideLink) { 1390 for (int i = startIndex; i <= endIndex; ++i) { 1391 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; 1392 unsigned linkMatchType = matchedProperties.linkMatchType; 1393 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places. 1394 state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink); 1395 state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited); 1396 1397 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType)); 1398 } 1399 state.setApplyPropertyToRegularStyle(true); 1400 state.setApplyPropertyToVisitedLinkStyle(false); 1401 return; 1402 } 1403 for (int i = startIndex; i <= endIndex; ++i) { 1404 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; 1405 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType)); 1406 } 1407 } 1408 1409 static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size) 1410 { 1411 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size); 1412 } 1413 1414 void StyleResolver::invalidateMatchedPropertiesCache() 1415 { 1416 m_matchedPropertiesCache.clear(); 1417 } 1418 1419 void StyleResolver::notifyResizeForViewportUnits() 1420 { 1421 collectViewportRules(); 1422 m_matchedPropertiesCache.clearViewportDependent(); 1423 } 1424 1425 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult) 1426 { 1427 const Element* element = state.element(); 1428 ASSERT(element); 1429 1430 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply); 1431 1432 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0; 1433 bool applyInheritedOnly = false; 1434 const CachedMatchedProperties* cachedMatchedProperties = 0; 1435 1436 if (cacheHash && (cachedMatchedProperties = m_matchedPropertiesCache.find(cacheHash, state, matchResult)) 1437 && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) { 1438 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit); 1439 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact 1440 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the 1441 // element context. This is fast and saves memory by reusing the style data structures. 1442 state.style()->copyNonInheritedFrom(cachedMatchedProperties->renderStyle.get()); 1443 if (state.parentStyle()->inheritedDataShared(cachedMatchedProperties->parentRenderStyle.get()) && !isAtShadowBoundary(element) 1444 && (!state.distributedToInsertionPoint() || state.style()->userModify() == READ_ONLY)) { 1445 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheInheritedHit); 1446 1447 EInsideLink linkStatus = state.style()->insideLink(); 1448 // If the cache item parent style has identical inherited properties to the current parent style then the 1449 // resulting style will be identical too. We copy the inherited properties over from the cache and are done. 1450 state.style()->inheritFrom(cachedMatchedProperties->renderStyle.get()); 1451 1452 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it. 1453 state.style()->setInsideLink(linkStatus); 1454 return; 1455 } 1456 applyInheritedOnly = true; 1457 } 1458 1459 // Apply animation properties in order to apply animation results and trigger transitions below. 1460 applyMatchedProperties<AnimationProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1461 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1462 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1463 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1464 1465 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply 1466 // high-priority properties first, i.e., those properties that other properties depend on. 1467 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important 1468 // and (4) normal important. 1469 state.setLineHeightValue(0); 1470 applyMatchedProperties<HighPriorityProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1471 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1472 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1473 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1474 1475 if (UNLIKELY(isSVGForeignObjectElement(element))) { 1476 // RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should not be scaled again. 1477 // 1478 // FIXME: The following hijacks the zoom property for foreignObject so that children of foreignObject get the 1479 // correct font-size in case of zooming. 'zoom' is part of HighPriorityProperties, along with other font-related 1480 // properties used as input to the FontBuilder, so resetting it here may cause the FontBuilder to recompute the 1481 // font used as inheritable font for foreignObject content. If we want to support zoom on foreignObject we'll 1482 // need to find another way of handling the SVG zoom model. 1483 state.setEffectiveZoom(RenderStyle::initialZoom()); 1484 } 1485 1486 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) { 1487 state.fontBuilder().setFontDirty(true); 1488 applyInheritedOnly = false; 1489 } 1490 1491 // If our font got dirtied, go ahead and update it now. 1492 updateFont(state); 1493 1494 // Line-height is set when we are sure we decided on the font-size. 1495 if (state.lineHeightValue()) 1496 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue()); 1497 1498 // Many properties depend on the font. If it changes we just apply all properties. 1499 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription()) 1500 applyInheritedOnly = false; 1501 1502 // Now do the normal priority UA properties. 1503 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1504 1505 // Cache the UA properties to pass them to RenderTheme in adjustRenderStyle. 1506 state.cacheUserAgentBorderAndBackground(); 1507 1508 // Now do the author and user normal priority properties and all the !important properties. 1509 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1510 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1511 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1512 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1513 1514 loadPendingResources(state); 1515 1516 if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) { 1517 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded); 1518 m_matchedPropertiesCache.add(state.style(), state.parentStyle(), cacheHash, matchResult); 1519 } 1520 1521 ASSERT(!state.fontBuilder().fontDirty()); 1522 } 1523 1524 CSSPropertyValue::CSSPropertyValue(CSSPropertyID id, const StylePropertySet& propertySet) 1525 : property(id), value(propertySet.getPropertyCSSValue(id).get()) 1526 { } 1527 1528 void StyleResolver::enableStats(StatsReportType reportType) 1529 { 1530 if (m_styleResolverStats) 1531 return; 1532 m_styleResolverStats = StyleResolverStats::create(); 1533 m_styleResolverStatsTotals = StyleResolverStats::create(); 1534 if (reportType == ReportSlowStats) { 1535 m_styleResolverStats->printMissedCandidateCount = true; 1536 m_styleResolverStatsTotals->printMissedCandidateCount = true; 1537 } 1538 } 1539 1540 void StyleResolver::disableStats() 1541 { 1542 m_styleResolverStatsSequence = 0; 1543 m_styleResolverStats.clear(); 1544 m_styleResolverStatsTotals.clear(); 1545 } 1546 1547 void StyleResolver::printStats() 1548 { 1549 if (!m_styleResolverStats) 1550 return; 1551 fprintf(stderr, "=== Style Resolver Stats (resolve #%u) (%s) ===\n", ++m_styleResolverStatsSequence, m_document.url().string().utf8().data()); 1552 fprintf(stderr, "%s\n", m_styleResolverStats->report().utf8().data()); 1553 fprintf(stderr, "== Totals ==\n"); 1554 fprintf(stderr, "%s\n", m_styleResolverStatsTotals->report().utf8().data()); 1555 } 1556 1557 void StyleResolver::applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle* style) 1558 { 1559 StyleResolverState state(document(), document().documentElement(), style); 1560 state.setStyle(style); 1561 1562 state.fontBuilder().initForStyleResolve(document(), style); 1563 1564 for (size_t i = 0; i < count; ++i) { 1565 if (properties[i].value) { 1566 // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call, 1567 // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122). 1568 // The updateFont() call below updates the fontMetrics and ensure the proper setting of font-size and line-height. 1569 switch (properties[i].property) { 1570 case CSSPropertyFontSize: 1571 case CSSPropertyLineHeight: 1572 updateFont(state); 1573 break; 1574 default: 1575 break; 1576 } 1577 StyleBuilder::applyProperty(properties[i].property, state, properties[i].value); 1578 } 1579 } 1580 } 1581 1582 void StyleResolver::addMediaQueryResults(const MediaQueryResultList& list) 1583 { 1584 for (size_t i = 0; i < list.size(); ++i) 1585 m_viewportDependentMediaQueryResults.append(list[i]); 1586 } 1587 1588 bool StyleResolver::mediaQueryAffectedByViewportChange() const 1589 { 1590 for (unsigned i = 0; i < m_viewportDependentMediaQueryResults.size(); ++i) { 1591 if (m_medium->eval(m_viewportDependentMediaQueryResults[i]->expression()) != m_viewportDependentMediaQueryResults[i]->result()) 1592 return true; 1593 } 1594 return false; 1595 } 1596 1597 void StyleResolver::trace(Visitor* visitor) 1598 { 1599 visitor->trace(m_keyframesRuleMap); 1600 visitor->trace(m_viewportDependentMediaQueryResults); 1601 visitor->trace(m_viewportStyleResolver); 1602 visitor->trace(m_features); 1603 visitor->trace(m_siblingRuleSet); 1604 visitor->trace(m_uncommonAttributeRuleSet); 1605 visitor->trace(m_watchedSelectorsRules); 1606 visitor->trace(m_treeBoundaryCrossingRules); 1607 visitor->trace(m_pendingStyleSheets); 1608 } 1609 1610 } // namespace WebCore 1611