2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
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.
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.
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.
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.
30 #include "core/css/resolver/StyleResolver.h"
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/CSSFontSelector.h"
46 #include "core/css/CSSKeyframeRule.h"
47 #include "core/css/CSSKeyframesRule.h"
48 #include "core/css/parser/BisonCSSParser.h"
49 #include "core/css/CSSReflectValue.h"
50 #include "core/css/CSSRuleList.h"
51 #include "core/css/CSSSelector.h"
52 #include "core/css/CSSStyleRule.h"
53 #include "core/css/CSSValueList.h"
54 #include "core/css/ElementRuleCollector.h"
55 #include "core/css/FontFace.h"
56 #include "core/css/MediaQueryEvaluator.h"
57 #include "core/css/PageRuleCollector.h"
58 #include "core/css/StylePropertySet.h"
59 #include "core/css/StyleRuleImport.h"
60 #include "core/css/StyleSheetContents.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/StyleResolverStats.h"
67 #include "core/css/resolver/ViewportStyleResolver.h"
68 #include "core/dom/CSSSelectorWatch.h"
69 #include "core/dom/NodeRenderStyle.h"
70 #include "core/dom/StyleEngine.h"
71 #include "core/dom/Text.h"
72 #include "core/dom/shadow/ElementShadow.h"
73 #include "core/dom/shadow/ShadowRoot.h"
74 #include "core/html/HTMLIFrameElement.h"
75 #include "core/inspector/InspectorInstrumentation.h"
76 #include "core/frame/Frame.h"
77 #include "core/frame/FrameView.h"
78 #include "core/rendering/RenderView.h"
79 #include "core/rendering/style/KeyframeList.h"
80 #include "core/svg/SVGDocumentExtensions.h"
81 #include "core/svg/SVGElement.h"
82 #include "core/svg/SVGFontFaceElement.h"
83 #include "wtf/StdLibExtras.h"
89 using namespace WebCore;
91 void setAnimationUpdateIfNeeded(StyleResolverState& state, Element& element)
93 // If any changes to CSS Animations were detected, stash the update away for application after the
94 // render object is updated if we're in the appropriate scope.
95 if (state.animationUpdate())
96 element.ensureActiveAnimations()->cssAnimations().setPendingUpdate(state.takeAnimationUpdate());
103 using namespace HTMLNames;
105 RenderStyle* StyleResolver::s_styleNotYetAvailable;
107 static StylePropertySet* leftToRightDeclaration()
109 DEFINE_STATIC_REF(MutableStylePropertySet, leftToRightDecl, (MutableStylePropertySet::create()));
110 if (leftToRightDecl->isEmpty())
111 leftToRightDecl->setProperty(CSSPropertyDirection, CSSValueLtr);
112 return leftToRightDecl;
115 static StylePropertySet* rightToLeftDeclaration()
117 DEFINE_STATIC_REF(MutableStylePropertySet, rightToLeftDecl, (MutableStylePropertySet::create()));
118 if (rightToLeftDecl->isEmpty())
119 rightToLeftDecl->setProperty(CSSPropertyDirection, CSSValueRtl);
120 return rightToLeftDecl;
123 static void addFontFaceRule(Document* document, CSSFontSelector* cssFontSelector, const StyleRuleFontFace* fontFaceRule)
125 RefPtr<FontFace> fontFace = FontFace::create(document, fontFaceRule);
127 cssFontSelector->fontFaceCache()->add(cssFontSelector, fontFaceRule, fontFace);
130 StyleResolver::StyleResolver(Document& document)
131 : m_document(document)
132 , m_viewportStyleResolver(ViewportStyleResolver::create(&document))
133 , m_needCollectFeatures(false)
134 , m_styleResourceLoader(document.fetcher())
135 , m_styleResolverStatsSequence(0)
138 // Construct document root element default style. This is needed
139 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
140 // This is here instead of constructor because when constructor is run,
141 // Document doesn't have documentElement.
142 // NOTE: This assumes that element that gets passed to the styleForElement call
143 // is always from the document that owns the StyleResolver.
144 FrameView* view = document.view();
146 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType()));
148 m_medium = adoptPtr(new MediaQueryEvaluator("all"));
150 Element* root = document.documentElement();
152 m_rootDefaultStyle = styleForElement(root, 0, DisallowStyleSharing, MatchOnlyUserAgentRules);
154 if (m_rootDefaultStyle && view)
155 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), &view->frame(), m_rootDefaultStyle.get()));
159 initWatchedSelectorRules(CSSSelectorWatch::from(document).watchedCallbackSelectors());
161 #if ENABLE(SVG_FONTS)
162 if (document.svgExtensions()) {
163 const HashSet<SVGFontFaceElement*>& svgFontFaceElements = document.svgExtensions()->svgFontFaceElements();
164 HashSet<SVGFontFaceElement*>::const_iterator end = svgFontFaceElements.end();
165 for (HashSet<SVGFontFaceElement*>::const_iterator it = svgFontFaceElements.begin(); it != end; ++it)
166 addFontFaceRule(&document, document.styleEngine()->fontSelector(), (*it)->fontFaceRule());
171 void StyleResolver::initWatchedSelectorRules(const Vector<RefPtr<StyleRule> >& watchedSelectors)
173 if (!watchedSelectors.size())
175 m_watchedSelectorsRules = RuleSet::create();
176 for (unsigned i = 0; i < watchedSelectors.size(); ++i)
177 m_watchedSelectorsRules->addStyleRule(watchedSelectors[i].get(), RuleHasNoSpecialState);
180 void StyleResolver::lazyAppendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets)
182 unsigned size = styleSheets.size();
183 for (unsigned i = firstNew; i < size; ++i)
184 m_pendingStyleSheets.add(styleSheets[i].get());
187 void StyleResolver::removePendingAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& styleSheets)
189 for (unsigned i = 0; i < styleSheets.size(); ++i)
190 m_pendingStyleSheets.remove(styleSheets[i].get());
193 void StyleResolver::appendCSSStyleSheet(CSSStyleSheet* cssSheet)
196 ASSERT(!cssSheet->disabled());
197 if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), &m_viewportDependentMediaQueryResults))
200 ContainerNode* scopingNode = ScopedStyleResolver::scopingNodeFor(document(), cssSheet);
204 ScopedStyleResolver* resolver = ensureScopedStyleResolver(scopingNode);
206 resolver->addRulesFromSheet(cssSheet, *m_medium, this);
209 void StyleResolver::appendPendingAuthorStyleSheets()
211 setBuildScopedStyleTreeInDocumentOrder(false);
212 for (ListHashSet<CSSStyleSheet*, 16>::iterator it = m_pendingStyleSheets.begin(); it != m_pendingStyleSheets.end(); ++it)
213 appendCSSStyleSheet(*it);
215 m_pendingStyleSheets.clear();
216 finishAppendAuthorStyleSheets();
219 void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets)
221 // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver
222 // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated.
223 unsigned size = styleSheets.size();
224 for (unsigned i = firstNew; i < size; ++i)
225 appendCSSStyleSheet(styleSheets[i].get());
228 void StyleResolver::finishAppendAuthorStyleSheets()
232 if (document().renderer() && document().renderer()->style())
233 document().renderer()->style()->font().update(document().styleEngine()->fontSelector());
235 collectViewportRules();
237 document().styleEngine()->resetCSSFeatureFlags(m_features);
240 void StyleResolver::resetRuleFeatures()
242 // Need to recreate RuleFeatureSet.
244 m_siblingRuleSet.clear();
245 m_uncommonAttributeRuleSet.clear();
246 m_needCollectFeatures = true;
249 void StyleResolver::addTreeBoundaryCrossingRules(const Vector<MinimalRuleData>& rules, ContainerNode* scope)
251 for (unsigned i = 0; i < rules.size(); ++i) {
252 const MinimalRuleData& info = rules[i];
253 m_treeBoundaryCrossingRules.addRule(info.m_rule, info.m_selectorIndex, scope, info.m_flags);
257 void StyleResolver::processScopedRules(const RuleSet& authorRules, const KURL& sheetBaseURL, ContainerNode* scope)
259 const Vector<StyleRuleKeyframes*> keyframesRules = authorRules.keyframesRules();
260 for (unsigned i = 0; i < keyframesRules.size(); ++i)
261 ensureScopedStyleResolver(scope)->addKeyframeStyle(keyframesRules[i]);
263 addTreeBoundaryCrossingRules(authorRules.treeBoundaryCrossingRules(), scope);
265 // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for the moment.
266 if (!scope || scope->isDocumentNode()) {
267 const Vector<StyleRuleFontFace*> fontFaceRules = authorRules.fontFaceRules();
268 for (unsigned i = 0; i < fontFaceRules.size(); ++i)
269 addFontFaceRule(&m_document, document().styleEngine()->fontSelector(), fontFaceRules[i]);
270 if (fontFaceRules.size())
271 invalidateMatchedPropertiesCache();
273 addTreeBoundaryCrossingRules(authorRules.shadowDistributedRules(), scope);
277 void StyleResolver::resetAuthorStyle(const ContainerNode* scopingNode)
279 // FIXME: When chanking scoped attribute, scopingNode's hasScopedHTMLStyleChild has been already modified.
280 // So we cannot use hasScopedHTMLStyleChild flag here.
281 ScopedStyleResolver* resolver = scopingNode ? m_styleTree.lookupScopedStyleResolverFor(scopingNode) : m_styleTree.scopedStyleResolverForDocument();
285 treeBoundaryCrossingRules().reset(scopingNode);
287 resolver->resetAuthorStyle();
292 m_styleTree.remove(scopingNode);
295 static PassOwnPtr<RuleSet> makeRuleSet(const Vector<RuleFeature>& rules)
297 size_t size = rules.size();
300 OwnPtr<RuleSet> ruleSet = RuleSet::create();
301 for (size_t i = 0; i < size; ++i)
302 ruleSet->addRule(rules[i].rule, rules[i].selectorIndex, rules[i].hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState);
303 return ruleSet.release();
306 void StyleResolver::collectFeatures()
309 // Collect all ids and rules using sibling selectors (:first-child and similar)
310 // in the current set of stylesheets. Style sharing code uses this information to reject
311 // sharing candidates.
312 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
313 if (defaultStyleSheets.defaultStyle())
314 m_features.add(defaultStyleSheets.defaultStyle()->features());
316 if (document().isViewSource())
317 m_features.add(defaultStyleSheets.defaultViewSourceStyle()->features());
319 if (m_watchedSelectorsRules)
320 m_features.add(m_watchedSelectorsRules->features());
322 m_treeBoundaryCrossingRules.collectFeaturesTo(m_features);
324 m_styleTree.collectFeaturesTo(m_features);
326 m_siblingRuleSet = makeRuleSet(m_features.siblingRules);
327 m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules);
328 m_needCollectFeatures = false;
331 bool StyleResolver::hasRulesForId(const AtomicString& id) const
333 return m_features.hasSelectorForId(id);
336 void StyleResolver::addToStyleSharingList(Element& element)
338 // Never add elements to the style sharing list if we're not in a recalcStyle,
339 // otherwise we could leave stale pointers in there.
340 if (!document().inStyleRecalc())
342 INCREMENT_STYLE_STATS_COUNTER(*this, sharedStyleCandidates);
343 if (m_styleSharingList.size() >= styleSharingListSize)
344 m_styleSharingList.remove(--m_styleSharingList.end());
345 m_styleSharingList.prepend(&element);
348 void StyleResolver::clearStyleSharingList()
350 m_styleSharingList.clear();
353 void StyleResolver::fontsNeedUpdate(CSSFontSelector* fontSelector)
355 invalidateMatchedPropertiesCache();
356 m_document.setNeedsStyleRecalc(SubtreeStyleChange);
359 void StyleResolver::pushParentElement(Element& parent)
361 const ContainerNode* parentsParent = parent.parentOrShadowHostElement();
363 // We are not always invoked consistently. For example, script execution can cause us to enter
364 // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree.
365 // Reset the stack in this case, or if we see a new root element.
366 // Otherwise just push the new parent.
367 if (!parentsParent || m_selectorFilter.parentStackIsEmpty())
368 m_selectorFilter.setupParentStack(parent);
370 m_selectorFilter.pushParent(parent);
372 // Note: We mustn't skip ShadowRoot nodes for the scope stack.
373 m_styleTree.pushStyleCache(parent, parent.parentOrShadowHostNode());
376 void StyleResolver::popParentElement(Element& parent)
378 // Note that we may get invoked for some random elements in some wacky cases during style resolve.
379 // Pause maintaining the stack in this case.
380 if (m_selectorFilter.parentStackIsConsistent(&parent))
381 m_selectorFilter.popParent();
383 m_styleTree.popStyleCache(parent);
386 void StyleResolver::pushParentShadowRoot(const ShadowRoot& shadowRoot)
388 ASSERT(shadowRoot.host());
389 m_styleTree.pushStyleCache(shadowRoot, shadowRoot.host());
392 void StyleResolver::popParentShadowRoot(const ShadowRoot& shadowRoot)
394 ASSERT(shadowRoot.host());
395 m_styleTree.popStyleCache(shadowRoot);
398 StyleResolver::~StyleResolver()
400 m_viewportStyleResolver->clearDocument();
403 inline void StyleResolver::collectTreeBoundaryCrossingRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules)
405 if (m_treeBoundaryCrossingRules.isEmpty())
408 RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange();
410 // When comparing rules declared in outer treescopes, outer's rules win.
411 CascadeOrder outerCascadeOrder = m_treeBoundaryCrossingRules.size() + m_treeBoundaryCrossingRules.size();
412 // When comparing rules declared in inner treescopes, inner's rules win.
413 CascadeOrder innerCascadeOrder = m_treeBoundaryCrossingRules.size();
415 for (DocumentOrderedList::iterator it = m_treeBoundaryCrossingRules.begin(); it != m_treeBoundaryCrossingRules.end(); ++it) {
416 const ContainerNode* scopingNode = toContainerNode(*it);
418 if (ShadowRoot* shadowRoot = scopingNode->containingShadowRoot()) {
419 if (!shadowRoot->isActiveForStyling())
423 RuleSet* ruleSet = m_treeBoundaryCrossingRules.ruleSetScopedBy(scopingNode);
424 unsigned boundaryBehavior = SelectorChecker::ScopeContainsLastMatchedElement;
425 bool isInnerTreeScope = element->treeScope().isInclusiveAncestorOf(scopingNode->treeScope());
427 // If a given scoping node is a shadow root and a given element is in a descendant tree of tree hosted by
428 // the scoping node's shadow host, we should use ScopeIsShadowHost.
429 if (scopingNode && scopingNode->isShadowRoot()) {
430 if (element->isInDescendantTreeOf(toShadowRoot(scopingNode)->host()))
431 boundaryBehavior |= SelectorChecker::ScopeIsShadowHost;
432 scopingNode = toShadowRoot(scopingNode)->host();
435 CascadeOrder cascadeOrder = isInnerTreeScope ? innerCascadeOrder : outerCascadeOrder;
437 collector.collectMatchingRules(MatchRequest(ruleSet, includeEmptyRules, scopingNode), ruleRange, static_cast<SelectorChecker::BehaviorAtBoundary>(boundaryBehavior), ignoreCascadeScope, cascadeOrder);
443 static inline bool applyAuthorStylesOf(const Element* element)
445 return element->treeScope().applyAuthorStyles() || (element->shadow() && element->shadow()->applyAuthorStyles());
448 void StyleResolver::matchAuthorRulesForShadowHost(Element* element, ElementRuleCollector& collector, bool includeEmptyRules, Vector<ScopedStyleResolver*, 8>& resolvers, Vector<ScopedStyleResolver*, 8>& resolversInShadowTree)
450 collector.clearMatchedRules();
451 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
453 CascadeScope cascadeScope = 0;
454 CascadeOrder cascadeOrder = 0;
455 bool applyAuthorStyles = applyAuthorStylesOf(element);
457 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j)
458 resolversInShadowTree.at(j)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope, cascadeOrder++);
460 if (resolvers.isEmpty() || resolvers.first()->treeScope() != element->treeScope())
462 cascadeOrder += resolvers.size();
463 for (unsigned i = 0; i < resolvers.size(); ++i)
464 resolvers.at(i)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, --cascadeOrder);
466 collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
467 collector.sortAndTransferMatchedRules();
470 void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules)
472 collector.clearMatchedRules();
473 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
475 bool applyAuthorStyles = applyAuthorStylesOf(element);
476 if (m_styleTree.hasOnlyScopedResolverForDocument()) {
477 m_styleTree.scopedStyleResolverForDocument()->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, ignoreCascadeScope);
478 collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
479 collector.sortAndTransferMatchedRules();
483 Vector<ScopedStyleResolver*, 8> resolvers;
484 m_styleTree.resolveScopedStyles(element, resolvers);
486 Vector<ScopedStyleResolver*, 8> resolversInShadowTree;
487 m_styleTree.collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree);
488 if (!resolversInShadowTree.isEmpty()) {
489 matchAuthorRulesForShadowHost(element, collector, includeEmptyRules, resolvers, resolversInShadowTree);
493 if (resolvers.isEmpty())
496 CascadeScope cascadeScope = 0;
497 CascadeOrder cascadeOrder = resolvers.size();
498 for (unsigned i = 0; i < resolvers.size(); ++i, --cascadeOrder) {
499 ScopedStyleResolver* resolver = resolvers.at(i);
500 // FIXME: Need to clarify how to treat style scoped.
501 resolver->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, resolver->treeScope() == element->treeScope() && resolver->scopingNode().isShadowRoot() ? 0 : cascadeOrder);
504 collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
505 collector.sortAndTransferMatchedRules();
508 void StyleResolver::matchWatchSelectorRules(ElementRuleCollector& collector)
510 if (!m_watchedSelectorsRules)
513 collector.clearMatchedRules();
514 collector.matchedResult().ranges.lastUserRule = collector.matchedResult().matchedProperties.size() - 1;
516 MatchRequest matchRequest(m_watchedSelectorsRules.get());
517 RuleRange ruleRange = collector.matchedResult().ranges.userRuleRange();
518 collector.collectMatchingRules(matchRequest, ruleRange);
520 collector.sortAndTransferMatchedRules();
523 void StyleResolver::matchUARules(ElementRuleCollector& collector)
525 collector.setMatchingUARules(true);
527 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
528 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
529 ? defaultStyleSheets.defaultPrintStyle() : defaultStyleSheets.defaultStyle();
530 matchUARules(collector, userAgentStyleSheet);
532 // In quirks mode, we match rules from the quirks user agent sheet.
533 if (document().inQuirksMode())
534 matchUARules(collector, defaultStyleSheets.defaultQuirksStyle());
536 // 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.
537 if (document().isViewSource())
538 matchUARules(collector, defaultStyleSheets.defaultViewSourceStyle());
540 collector.setMatchingUARules(false);
542 matchWatchSelectorRules(collector);
545 void StyleResolver::matchUARules(ElementRuleCollector& collector, RuleSet* rules)
547 collector.clearMatchedRules();
548 collector.matchedResult().ranges.lastUARule = collector.matchedResult().matchedProperties.size() - 1;
550 RuleRange ruleRange = collector.matchedResult().ranges.UARuleRange();
551 collector.collectMatchingRules(MatchRequest(rules), ruleRange);
553 collector.sortAndTransferMatchedRules();
556 void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollector& collector, bool includeSMILProperties)
558 matchUARules(collector);
560 // Now check author rules, beginning first with presentational attributes mapped from HTML.
561 if (state.element()->isStyledElement()) {
562 collector.addElementStyleProperties(state.element()->presentationAttributeStyle());
564 // Now we check additional mapped declarations.
565 // Tables and table cells share an additional mapped rule that must be applied
566 // after all attributes, since their mapped style depends on the values of multiple attributes.
567 collector.addElementStyleProperties(state.element()->additionalPresentationAttributeStyle());
569 if (state.element()->isHTMLElement()) {
571 TextDirection textDirection = toHTMLElement(state.element())->directionalityIfhasDirAutoAttribute(isAuto);
573 collector.matchedResult().addMatchedProperties(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
577 matchAuthorRules(state.element(), collector, false);
579 if (state.element()->isStyledElement()) {
580 if (state.element()->inlineStyle()) {
581 // Inline style is immutable as long as there is no CSSOM wrapper.
582 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMutable();
583 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable);
586 // Now check SMIL animation override style.
587 if (includeSMILProperties && state.element()->isSVGElement())
588 collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */);
592 PassRefPtr<RenderStyle> StyleResolver::styleForDocument(Document& document, CSSFontSelector* fontSelector)
594 const Frame* frame = document.frame();
596 RefPtr<RenderStyle> documentStyle = RenderStyle::create();
597 documentStyle->setDisplay(BLOCK);
598 documentStyle->setRTLOrdering(document.visuallyOrdered() ? VisualOrder : LogicalOrder);
599 documentStyle->setZoom(frame && !document.printing() ? frame->pageZoomFactor() : 1);
600 documentStyle->setLocale(document.contentLanguage());
602 // This overrides any -webkit-user-modify inherited from the parent iframe.
603 documentStyle->setUserModify(document.inDesignMode() ? READ_WRITE : READ_ONLY);
605 document.setupFontBuilder(documentStyle.get());
606 return documentStyle.release();
609 // FIXME: This is duplicated with StyleAdjuster.cpp
610 // Perhaps this should move onto ElementResolveContext or even Element?
611 static inline bool isAtShadowBoundary(const Element* element)
615 ContainerNode* parentNode = element->parentNode();
616 return parentNode && parentNode->isShadowRoot();
619 static inline void resetDirectionAndWritingModeOnDocument(Document& document)
621 document.setDirectionSetOnDocumentElement(false);
622 document.setWritingModeSetOnDocumentElement(false);
625 static void addContentAttrValuesToFeatures(const Vector<AtomicString>& contentAttrValues, RuleFeatureSet& features)
627 for (size_t i = 0; i < contentAttrValues.size(); ++i)
628 features.addAttributeInASelector(contentAttrValues[i]);
631 PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent, StyleSharingBehavior sharingBehavior,
632 RuleMatchingBehavior matchingBehavior)
634 ASSERT(document().frame());
635 ASSERT(documentSettings());
636 ASSERT(!hasPendingAuthorStyleSheets());
637 ASSERT(!m_needCollectFeatures);
639 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
640 // will vanish if a style recalc happens during loading.
641 if (sharingBehavior == AllowStyleSharing && !element->document().haveStylesheetsLoaded() && !element->renderer()) {
642 if (!s_styleNotYetAvailable) {
643 s_styleNotYetAvailable = RenderStyle::create().leakRef();
644 s_styleNotYetAvailable->setDisplay(NONE);
645 s_styleNotYetAvailable->font().update(document().styleEngine()->fontSelector());
647 element->document().setHasNodesWithPlaceholderStyle();
648 return s_styleNotYetAvailable;
653 if (element == document().documentElement())
654 resetDirectionAndWritingModeOnDocument(document());
655 StyleResolverState state(document(), element, defaultParent);
657 if (sharingBehavior == AllowStyleSharing && state.parentStyle()) {
658 SharedStyleFinder styleFinder(state.elementContext(), m_features, m_siblingRuleSet.get(), m_uncommonAttributeRuleSet.get(), *this);
659 if (RefPtr<RenderStyle> sharedStyle = styleFinder.findSharedStyle())
660 return sharedStyle.release();
663 if (state.parentStyle()) {
664 state.setStyle(RenderStyle::create());
665 state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
667 state.setStyle(defaultStyleForElement());
668 state.setParentStyle(RenderStyle::clone(state.style()));
670 // contenteditable attribute (implemented by -webkit-user-modify) should
671 // be propagated from shadow host to distributed node.
672 if (state.distributedToInsertionPoint()) {
673 if (Element* parent = element->parentElement()) {
674 if (RenderStyle* styleOfShadowHost = parent->renderStyle())
675 state.style()->setUserModify(styleOfShadowHost->userModify());
679 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules());
681 if (element->isLink()) {
682 state.style()->setIsLink(true);
683 EInsideLink linkState = state.elementLinkState();
684 if (linkState != NotInsideLink) {
685 bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited);
687 linkState = InsideVisitedLink;
689 state.style()->setInsideLink(linkState);
692 bool needsCollection = false;
693 CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection);
698 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
700 if (matchingBehavior == MatchOnlyUserAgentRules)
701 matchUARules(collector);
703 matchAllRules(state, collector, matchingBehavior != MatchAllRulesExcludingSMIL);
705 applyMatchedProperties(state, collector.matchedResult());
707 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
710 StyleAdjuster adjuster(state.cachedUAStyle(), m_document.inQuirksMode());
711 adjuster.adjustRenderStyle(state.style(), state.parentStyle(), element);
714 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
715 // important rules, but this currently happens here as we require adjustment to have happened
716 // before deciding which properties to transition.
717 applyAnimatedProperties(state, element);
719 // FIXME: Shouldn't this be on RenderBody::styleDidChange?
720 if (element->hasTagName(bodyTag))
721 document().textLinkColors().setTextColor(state.style()->color());
723 setAnimationUpdateIfNeeded(state, *element);
725 if (state.style()->hasViewportUnits())
726 document().setHasViewportUnits();
728 // Now return the style.
729 return state.takeStyle();
732 PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const RenderStyle& elementStyle, RenderStyle* parentStyle, const StyleKeyframe* keyframe, const AtomicString& animationName)
734 ASSERT(document().frame());
735 ASSERT(documentSettings());
736 ASSERT(!hasPendingAuthorStyleSheets());
738 if (element == document().documentElement())
739 resetDirectionAndWritingModeOnDocument(document());
740 StyleResolverState state(document(), element, parentStyle);
743 if (keyframe->properties())
744 result.addMatchedProperties(keyframe->properties());
746 ASSERT(!state.style());
749 state.setStyle(RenderStyle::clone(&elementStyle));
750 state.setLineHeightValue(0);
752 // Make sure that the CSSAnimationData for the animation to which this
753 // keyframe belongs is first in the list. This makes sure that if the
754 // animation-timing-function property is set for this keyframe, it will be
755 // applied to the correct CSSAnimationData object. Note that objects other
756 // than the first in the list are ignored when reading the timing function
757 // value. See KeyframeValue::timingFunction().
758 CSSAnimationDataList* animations = state.style()->accessAnimations();
759 ASSERT(animations && !animations->isEmpty());
760 while (animations->animation(0)->name() != animationName)
761 animations->remove(0);
762 ASSERT(!animations->isEmpty() && animations->animation(0)->name() == animationName);
764 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules());
766 // We don't need to bother with !important. Since there is only ever one
767 // decl, there's nothing to override. So just add the first properties.
768 bool inheritedOnly = false;
769 if (keyframe->properties()) {
770 applyMatchedProperties<AnimationProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
771 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
774 // If our font got dirtied, go ahead and update it now.
777 // Line-height is set when we are sure we decided on the font-size
778 if (state.lineHeightValue())
779 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
781 // Now do rest of the properties.
782 if (keyframe->properties())
783 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
785 // If our font got dirtied by one of the non-essential font props,
786 // go ahead and update it a second time.
789 // Start loading resources referenced by this style.
790 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources());
791 document().styleEngine()->fontSelector()->loadPendingFonts();
795 return state.takeStyle();
798 // This function is used by the WebAnimations JavaScript API method animate().
799 // FIXME: Remove this when animate() switches away from resolution-dependent parsing.
800 PassRefPtr<KeyframeEffectModel> StyleResolver::createKeyframeEffectModel(Element& element, const Vector<RefPtr<MutableStylePropertySet> >& propertySetVector, KeyframeEffectModel::KeyframeVector& keyframes)
802 ASSERT(propertySetVector.size() == keyframes.size());
804 StyleResolverState state(element.document(), &element);
805 state.setStyle(RenderStyle::create());
807 for (unsigned i = 0; i < propertySetVector.size(); ++i) {
808 for (unsigned j = 0; j < propertySetVector[i]->propertyCount(); ++j) {
809 CSSPropertyID id = propertySetVector[i]->propertyAt(j).id();
810 StyleBuilder::applyProperty(id, state, propertySetVector[i]->getPropertyCSSValue(id).get());
811 keyframes[i]->setPropertyValue(id, CSSAnimatableValueFactory::create(id, *state.style()).get());
814 return KeyframeEffectModel::create(keyframes);
817 PassRefPtr<PseudoElement> StyleResolver::createPseudoElementIfNeeded(Element& parent, PseudoId pseudoId)
819 RenderObject* parentRenderer = parent.renderer();
823 if (pseudoId < FIRST_INTERNAL_PSEUDOID && !parentRenderer->style()->hasPseudoStyle(pseudoId))
826 if (pseudoId == BACKDROP && !parent.isInTopLayer())
829 if (!parentRenderer->canHaveGeneratedChildren())
832 RenderStyle* parentStyle = parentRenderer->style();
833 StyleResolverState state(document(), &parent, parentStyle);
834 if (!pseudoStyleForElementInternal(parent, pseudoId, parentStyle, state))
836 RefPtr<RenderStyle> style = state.takeStyle();
839 if (!pseudoElementRendererIsNeeded(style.get()))
842 parentStyle->addCachedPseudoStyle(style.release());
843 RefPtr<PseudoElement> pseudo = PseudoElement::create(&parent, pseudoId);
845 setAnimationUpdateIfNeeded(state, *pseudo);
846 if (ActiveAnimations* activeAnimations = pseudo->activeAnimations())
847 activeAnimations->cssAnimations().maybeApplyPendingUpdate(pseudo.get());
848 return pseudo.release();
851 bool StyleResolver::pseudoStyleForElementInternal(Element& element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, StyleResolverState& state)
853 ASSERT(document().frame());
854 ASSERT(documentSettings());
855 ASSERT(pseudoStyleRequest.pseudoId != FIRST_LINE_INHERITED);
857 if (pseudoStyleRequest.allowsInheritance(state.parentStyle())) {
858 state.setStyle(RenderStyle::create());
859 state.style()->inheritFrom(state.parentStyle());
861 state.setStyle(defaultStyleForElement());
862 state.setParentStyle(RenderStyle::clone(state.style()));
865 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules());
867 // Since we don't use pseudo-elements in any of our quirk/print
868 // user agent rules, don't waste time walking those rules.
871 // Check UA, user and author rules.
872 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
873 collector.setPseudoStyleRequest(pseudoStyleRequest);
875 matchUARules(collector);
876 matchAuthorRules(state.element(), collector, false);
878 if (collector.matchedResult().matchedProperties.isEmpty())
881 state.style()->setStyleType(pseudoStyleRequest.pseudoId);
883 applyMatchedProperties(state, collector.matchedResult());
885 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
888 StyleAdjuster adjuster(state.cachedUAStyle(), m_document.inQuirksMode());
889 // FIXME: Passing 0 as the Element* introduces a lot of complexity
890 // in the adjustRenderStyle code.
891 adjuster.adjustRenderStyle(state.style(), state.parentStyle(), 0);
894 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
895 // important rules, but this currently happens here as we require adjustment to have happened
896 // before deciding which properties to transition.
897 applyAnimatedProperties(state, element.pseudoElement(pseudoStyleRequest.pseudoId));
901 if (state.style()->hasViewportUnits())
902 document().setHasViewportUnits();
907 PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle)
913 StyleResolverState state(document(), element, parentStyle);
914 if (!pseudoStyleForElementInternal(*element, pseudoStyleRequest, parentStyle, state))
917 if (PseudoElement* pseudoElement = element->pseudoElement(pseudoStyleRequest.pseudoId))
918 setAnimationUpdateIfNeeded(state, *pseudoElement);
920 // Now return the style.
921 return state.takeStyle();
924 PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
926 ASSERT(!hasPendingAuthorStyleSheets());
927 resetDirectionAndWritingModeOnDocument(document());
928 StyleResolverState state(document(), document().documentElement()); // m_rootElementStyle will be set to the document style.
930 state.setStyle(RenderStyle::create());
931 const RenderStyle* rootElementStyle = state.rootElementStyle() ? state.rootElementStyle() : document().renderStyle();
932 ASSERT(rootElementStyle);
933 state.style()->inheritFrom(rootElementStyle);
935 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules());
937 PageRuleCollector collector(rootElementStyle, pageIndex);
939 collector.matchPageRules(CSSDefaultStyleSheets::instance().defaultPrintStyle());
941 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
942 scopedResolver->matchPageRules(collector);
944 state.setLineHeightValue(0);
945 bool inheritedOnly = false;
947 MatchResult& result = collector.matchedResult();
948 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
950 // If our font got dirtied, go ahead and update it now.
953 // Line-height is set when we are sure we decided on the font-size.
954 if (state.lineHeightValue())
955 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
957 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
959 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
961 // Start loading resources referenced by this style.
962 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources());
963 document().styleEngine()->fontSelector()->loadPendingFonts();
967 // Now return the style.
968 return state.takeStyle();
971 void StyleResolver::collectViewportRules()
973 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
974 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultStyle(), ViewportStyleResolver::UserAgentOrigin);
976 if (!InspectorInstrumentation::applyViewportStyleOverride(&document(), this))
977 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultViewportStyle(), ViewportStyleResolver::UserAgentOrigin);
979 if (document().isMobileDocument())
980 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultXHTMLMobileProfileStyle(), ViewportStyleResolver::UserAgentOrigin);
982 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
983 scopedResolver->collectViewportRulesTo(this);
985 viewportStyleResolver()->resolve();
988 PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement()
990 StyleResolverState state(document(), 0);
991 state.setStyle(RenderStyle::create());
992 state.fontBuilder().initForStyleResolve(document(), state.style(), state.useSVGZoomRules());
993 state.style()->setLineHeight(RenderStyle::initialLineHeight());
994 state.setLineHeightValue(0);
995 state.fontBuilder().setInitial(state.style()->effectiveZoom());
996 state.style()->font().update(document().styleEngine()->fontSelector());
997 return state.takeStyle();
1000 PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode)
1004 NodeRenderingTraversal::ParentDetails parentDetails;
1005 Node* parentNode = NodeRenderingTraversal::parent(textNode, &parentDetails);
1006 if (!parentNode || !parentNode->renderStyle() || parentDetails.resetStyleInheritance())
1007 return defaultStyleForElement();
1008 return parentNode->renderStyle();
1011 void StyleResolver::updateFont(StyleResolverState& state)
1013 state.fontBuilder().createFont(document().styleEngine()->fontSelector(), state.parentStyle(), state.style());
1014 if (state.fontBuilder().fontSizeHasViewportUnits())
1015 state.style()->setHasViewportUnits();
1018 PassRefPtr<StyleRuleList> StyleResolver::styleRulesForElement(Element* element, unsigned rulesToInclude)
1021 StyleResolverState state(document(), element);
1022 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
1023 collector.setMode(SelectorChecker::CollectingStyleRules);
1024 collectPseudoRulesForElement(element, collector, NOPSEUDO, rulesToInclude);
1025 return collector.matchedStyleRuleList();
1028 PassRefPtr<CSSRuleList> StyleResolver::pseudoCSSRulesForElement(Element* element, PseudoId pseudoId, unsigned rulesToInclude)
1031 StyleResolverState state(document(), element);
1032 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
1033 collector.setMode(SelectorChecker::CollectingCSSRules);
1034 collectPseudoRulesForElement(element, collector, pseudoId, rulesToInclude);
1035 return collector.matchedCSSRuleList();
1038 PassRefPtr<CSSRuleList> StyleResolver::cssRulesForElement(Element* element, unsigned rulesToInclude)
1040 return pseudoCSSRulesForElement(element, NOPSEUDO, rulesToInclude);
1043 void StyleResolver::collectPseudoRulesForElement(Element* element, ElementRuleCollector& collector, PseudoId pseudoId, unsigned rulesToInclude)
1045 collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
1047 if (rulesToInclude & UAAndUserCSSRules)
1048 matchUARules(collector);
1050 if (rulesToInclude & AuthorCSSRules) {
1051 collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules));
1052 matchAuthorRules(element, collector, rulesToInclude & EmptyCSSRules);
1056 // -------------------------------------------------------------------------------------
1057 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1059 void StyleResolver::applyAnimatedProperties(StyleResolverState& state, Element* animatingElement)
1061 const Element* element = state.element();
1064 // The animating element may be this element, or its pseudo element. It is
1065 // null when calculating the style for a potential pseudo element that has
1066 // yet to be created.
1067 ASSERT(animatingElement == element || !animatingElement || animatingElement->parentOrShadowHostElement() == element);
1069 if (!(animatingElement && animatingElement->hasActiveAnimations())
1070 && !(state.style()->transitions() && !state.style()->transitions()->isEmpty())
1071 && !(state.style()->animations() && !state.style()->animations()->isEmpty()))
1074 state.setAnimationUpdate(CSSAnimations::calculateUpdate(animatingElement, *element, *state.style(), state.parentStyle(), this));
1075 if (!state.animationUpdate())
1078 const AnimationEffect::CompositableValueMap& compositableValuesForAnimations = state.animationUpdate()->compositableValuesForAnimations();
1079 const AnimationEffect::CompositableValueMap& compositableValuesForTransitions = state.animationUpdate()->compositableValuesForTransitions();
1080 applyAnimatedProperties<HighPriorityProperties>(state, compositableValuesForAnimations);
1081 applyAnimatedProperties<HighPriorityProperties>(state, compositableValuesForTransitions);
1082 applyAnimatedProperties<LowPriorityProperties>(state, compositableValuesForAnimations);
1083 applyAnimatedProperties<LowPriorityProperties>(state, compositableValuesForTransitions);
1085 // If the animations/transitions change opacity or transform, we need to update
1086 // the style to impose the stacking rules. Note that this is also
1087 // done in StyleResolver::adjustRenderStyle().
1088 RenderStyle* style = state.style();
1089 if (style->hasAutoZIndex() && (style->opacity() < 1.0f || style->hasTransform()))
1090 style->setZIndex(0);
1093 template <StyleResolver::StyleApplicationPass pass>
1094 void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const AnimationEffect::CompositableValueMap& compositableValues)
1096 ASSERT(pass != AnimationProperties);
1098 for (AnimationEffect::CompositableValueMap::const_iterator iter = compositableValues.begin(); iter != compositableValues.end(); ++iter) {
1099 CSSPropertyID property = iter->key;
1100 if (!isPropertyForPass<pass>(property))
1102 ASSERT_WITH_MESSAGE(!iter->value->dependsOnUnderlyingValue(), "Web Animations not yet implemented: An interface for compositing onto the underlying value.");
1103 RefPtr<AnimatableValue> animatableValue = iter->value->compositeOnto(0);
1104 AnimatedStyleBuilder::applyProperty(property, state, animatableValue.get());
1108 static inline bool isValidCueStyleProperty(CSSPropertyID id)
1111 case CSSPropertyBackground:
1112 case CSSPropertyBackgroundAttachment:
1113 case CSSPropertyBackgroundClip:
1114 case CSSPropertyBackgroundColor:
1115 case CSSPropertyBackgroundImage:
1116 case CSSPropertyBackgroundOrigin:
1117 case CSSPropertyBackgroundPosition:
1118 case CSSPropertyBackgroundPositionX:
1119 case CSSPropertyBackgroundPositionY:
1120 case CSSPropertyBackgroundRepeat:
1121 case CSSPropertyBackgroundRepeatX:
1122 case CSSPropertyBackgroundRepeatY:
1123 case CSSPropertyBackgroundSize:
1124 case CSSPropertyColor:
1125 case CSSPropertyFont:
1126 case CSSPropertyFontFamily:
1127 case CSSPropertyFontSize:
1128 case CSSPropertyFontStyle:
1129 case CSSPropertyFontVariant:
1130 case CSSPropertyFontWeight:
1131 case CSSPropertyLineHeight:
1132 case CSSPropertyOpacity:
1133 case CSSPropertyOutline:
1134 case CSSPropertyOutlineColor:
1135 case CSSPropertyOutlineOffset:
1136 case CSSPropertyOutlineStyle:
1137 case CSSPropertyOutlineWidth:
1138 case CSSPropertyVisibility:
1139 case CSSPropertyWhiteSpace:
1140 // FIXME: 'text-decoration' shorthand to be handled when available.
1141 // See https://chromiumcodereview.appspot.com/19516002 for details.
1142 case CSSPropertyTextDecoration:
1143 case CSSPropertyTextShadow:
1144 case CSSPropertyBorderStyle:
1146 case CSSPropertyTextDecorationLine:
1147 case CSSPropertyTextDecorationStyle:
1148 case CSSPropertyTextDecorationColor:
1149 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1156 template <StyleResolver::StyleApplicationPass pass>
1157 bool StyleResolver::isPropertyForPass(CSSPropertyID property)
1159 const CSSPropertyID firstAnimationProperty = CSSPropertyDisplay;
1160 const CSSPropertyID lastAnimationProperty = CSSPropertyTransitionTimingFunction;
1161 COMPILE_ASSERT(firstCSSProperty == firstAnimationProperty, CSS_first_animation_property_should_be_first_property);
1162 const CSSPropertyID firstHighPriorityProperty = CSSPropertyColor;
1163 const CSSPropertyID lastHighPriorityProperty = CSSPropertyLineHeight;
1164 COMPILE_ASSERT(lastAnimationProperty + 1 == firstHighPriorityProperty, CSS_color_is_first_high_priority_property);
1165 COMPILE_ASSERT(CSSPropertyLineHeight == firstHighPriorityProperty + 17, CSS_line_height_is_end_of_high_prioity_property_range);
1166 COMPILE_ASSERT(CSSPropertyZoom == lastHighPriorityProperty - 1, CSS_zoom_is_before_line_height);
1168 case AnimationProperties:
1169 return property >= firstAnimationProperty && property <= lastAnimationProperty;
1170 case HighPriorityProperties:
1171 return property >= firstHighPriorityProperty && property <= lastHighPriorityProperty;
1172 case LowPriorityProperties:
1173 return property > lastHighPriorityProperty;
1175 ASSERT_NOT_REACHED();
1179 template <StyleResolver::StyleApplicationPass pass>
1180 void StyleResolver::applyProperties(StyleResolverState& state, const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType)
1182 state.setCurrentRule(rule);
1184 unsigned propertyCount = properties->propertyCount();
1185 for (unsigned i = 0; i < propertyCount; ++i) {
1186 StylePropertySet::PropertyReference current = properties->propertyAt(i);
1187 if (isImportant != current.isImportant())
1189 if (inheritedOnly && !current.isInherited()) {
1190 // If the property value is explicitly inherited, we need to apply further non-inherited properties
1191 // as they might override the value inherited here. For this reason we don't allow declarations with
1192 // explicitly inherited properties to be cached.
1193 ASSERT(!current.value()->isInheritedValue());
1196 CSSPropertyID property = current.id();
1198 if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property))
1200 if (!isPropertyForPass<pass>(property))
1202 if (pass == HighPriorityProperties && property == CSSPropertyLineHeight)
1203 state.setLineHeightValue(current.value());
1205 StyleBuilder::applyProperty(current.id(), state, current.value());
1209 template <StyleResolver::StyleApplicationPass pass>
1210 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
1212 if (startIndex == -1)
1215 if (state.style()->insideLink() != NotInsideLink) {
1216 for (int i = startIndex; i <= endIndex; ++i) {
1217 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1218 unsigned linkMatchType = matchedProperties.linkMatchType;
1219 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
1220 state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink);
1221 state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited);
1223 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1225 state.setApplyPropertyToRegularStyle(true);
1226 state.setApplyPropertyToVisitedLinkStyle(false);
1229 for (int i = startIndex; i <= endIndex; ++i) {
1230 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1231 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1235 static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
1237 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
1240 void StyleResolver::invalidateMatchedPropertiesCache()
1242 m_matchedPropertiesCache.clear();
1245 void StyleResolver::notifyResizeForViewportUnits()
1247 collectViewportRules();
1248 m_matchedPropertiesCache.clearViewportDependent();
1251 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult)
1253 const Element* element = state.element();
1256 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply);
1258 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
1259 bool applyInheritedOnly = false;
1260 const CachedMatchedProperties* cachedMatchedProperties = 0;
1262 if (cacheHash && (cachedMatchedProperties = m_matchedPropertiesCache.find(cacheHash, state, matchResult))
1263 && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1264 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit);
1265 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
1266 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the
1267 // element context. This is fast and saves memory by reusing the style data structures.
1268 state.style()->copyNonInheritedFrom(cachedMatchedProperties->renderStyle.get());
1269 if (state.parentStyle()->inheritedDataShared(cachedMatchedProperties->parentRenderStyle.get()) && !isAtShadowBoundary(element)
1270 && (!state.distributedToInsertionPoint() || state.style()->userModify() == READ_ONLY)) {
1271 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheInheritedHit);
1273 EInsideLink linkStatus = state.style()->insideLink();
1274 // If the cache item parent style has identical inherited properties to the current parent style then the
1275 // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
1276 state.style()->inheritFrom(cachedMatchedProperties->renderStyle.get());
1278 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
1279 state.style()->setInsideLink(linkStatus);
1282 applyInheritedOnly = true;
1285 // Apply animation properties in order to apply animation results and trigger transitions below.
1286 applyMatchedProperties<AnimationProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1287 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1288 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1289 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1291 // Match transition-property / animation-name length by trimming and
1292 // lengthening other transition / animation property lists
1293 // FIXME: This is wrong because we shouldn't affect the computed values
1294 state.style()->adjustAnimations();
1295 state.style()->adjustTransitions();
1297 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
1298 // high-priority properties first, i.e., those properties that other properties depend on.
1299 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
1300 // and (4) normal important.
1301 state.setLineHeightValue(0);
1302 applyMatchedProperties<HighPriorityProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1303 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1304 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1305 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1307 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) {
1308 state.fontBuilder().setFontDirty(true);
1309 applyInheritedOnly = false;
1312 // If our font got dirtied, go ahead and update it now.
1315 // Line-height is set when we are sure we decided on the font-size.
1316 if (state.lineHeightValue())
1317 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
1319 // Many properties depend on the font. If it changes we just apply all properties.
1320 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription())
1321 applyInheritedOnly = false;
1323 // Now do the normal priority UA properties.
1324 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1326 // Cache the UA properties to pass them to RenderTheme in adjustRenderStyle.
1327 state.cacheUserAgentBorderAndBackground();
1329 // Now do the author and user normal priority properties and all the !important properties.
1330 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1331 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1332 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1333 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1335 // Start loading resources referenced by this style.
1336 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources());
1337 document().styleEngine()->fontSelector()->loadPendingFonts();
1339 if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1340 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded);
1341 m_matchedPropertiesCache.add(state.style(), state.parentStyle(), cacheHash, matchResult);
1344 ASSERT(!state.fontBuilder().fontDirty());
1347 CSSPropertyValue::CSSPropertyValue(CSSPropertyID id, const StylePropertySet& propertySet)
1348 : property(id), value(propertySet.getPropertyCSSValue(id).get())
1351 void StyleResolver::enableStats(StatsReportType reportType)
1353 if (m_styleResolverStats)
1355 m_styleResolverStats = StyleResolverStats::create();
1356 m_styleResolverStatsTotals = StyleResolverStats::create();
1357 if (reportType == ReportSlowStats) {
1358 m_styleResolverStats->printMissedCandidateCount = true;
1359 m_styleResolverStatsTotals->printMissedCandidateCount = true;
1363 void StyleResolver::disableStats()
1365 m_styleResolverStatsSequence = 0;
1366 m_styleResolverStats.clear();
1367 m_styleResolverStatsTotals.clear();
1370 void StyleResolver::printStats()
1372 if (!m_styleResolverStats)
1374 fprintf(stderr, "=== Style Resolver Stats (resolve #%u) (%s) ===\n", ++m_styleResolverStatsSequence, m_document.url().string().utf8().data());
1375 fprintf(stderr, "%s\n", m_styleResolverStats->report().utf8().data());
1376 fprintf(stderr, "== Totals ==\n");
1377 fprintf(stderr, "%s\n", m_styleResolverStatsTotals->report().utf8().data());
1380 void StyleResolver::applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle* style)
1382 StyleResolverState state(document(), document().documentElement(), style);
1383 state.setStyle(style);
1385 state.fontBuilder().initForStyleResolve(document(), style, state.useSVGZoomRules());
1387 for (size_t i = 0; i < count; ++i) {
1388 if (properties[i].value) {
1389 // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call,
1390 // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122).
1391 // The updateFont() call below updates the fontMetrics and ensure the proper setting of font-size and line-height.
1392 switch (properties[i].property) {
1393 case CSSPropertyFontSize:
1394 case CSSPropertyLineHeight:
1400 StyleBuilder::applyProperty(properties[i].property, state, properties[i].value);
1405 void StyleResolver::addMediaQueryResults(const MediaQueryResultList& list)
1407 for (size_t i = 0; i < list.size(); ++i)
1408 m_viewportDependentMediaQueryResults.append(list[i]);
1411 bool StyleResolver::mediaQueryAffectedByViewportChange() const
1413 for (unsigned i = 0; i < m_viewportDependentMediaQueryResults.size(); ++i) {
1414 if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result)
1420 } // namespace WebCore