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