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 "core/CSSPropertyNames.h"
33 #include "core/HTMLNames.h"
34 #include "core/StylePropertyShorthand.h"
35 #include "core/animation/ActiveAnimations.h"
36 #include "core/animation/AnimatableValue.h"
37 #include "core/animation/Animation.h"
38 #include "core/animation/AnimationTimeline.h"
39 #include "core/animation/css/CSSAnimatableValueFactory.h"
40 #include "core/animation/css/CSSAnimations.h"
41 #include "core/animation/interpolation/StyleInterpolation.h"
42 #include "core/css/CSSCalculationValue.h"
43 #include "core/css/CSSDefaultStyleSheets.h"
44 #include "core/css/CSSFontSelector.h"
45 #include "core/css/CSSKeyframeRule.h"
46 #include "core/css/CSSKeyframesRule.h"
47 #include "core/css/CSSReflectValue.h"
48 #include "core/css/CSSRuleList.h"
49 #include "core/css/CSSSelector.h"
50 #include "core/css/CSSStyleRule.h"
51 #include "core/css/CSSValueList.h"
52 #include "core/css/CSSValuePool.h"
53 #include "core/css/ElementRuleCollector.h"
54 #include "core/css/FontFace.h"
55 #include "core/css/MediaQueryEvaluator.h"
56 #include "core/css/PageRuleCollector.h"
57 #include "core/css/StylePropertySet.h"
58 #include "core/css/StyleRuleImport.h"
59 #include "core/css/StyleSheetContents.h"
60 #include "core/css/parser/BisonCSSParser.h"
61 #include "core/css/resolver/AnimatedStyleBuilder.h"
62 #include "core/css/resolver/MatchResult.h"
63 #include "core/css/resolver/MediaQueryResult.h"
64 #include "core/css/resolver/SharedStyleFinder.h"
65 #include "core/css/resolver/StyleAdjuster.h"
66 #include "core/css/resolver/StyleResolverParentScope.h"
67 #include "core/css/resolver/StyleResolverState.h"
68 #include "core/css/resolver/StyleResolverStats.h"
69 #include "core/css/resolver/ViewportStyleResolver.h"
70 #include "core/dom/CSSSelectorWatch.h"
71 #include "core/dom/NodeRenderStyle.h"
72 #include "core/dom/StyleEngine.h"
73 #include "core/dom/Text.h"
74 #include "core/dom/shadow/ElementShadow.h"
75 #include "core/dom/shadow/ShadowRoot.h"
76 #include "core/frame/FrameView.h"
77 #include "core/frame/LocalFrame.h"
78 #include "core/html/HTMLIFrameElement.h"
79 #include "core/inspector/InspectorInstrumentation.h"
80 #include "core/rendering/RenderView.h"
81 #include "core/rendering/style/KeyframeList.h"
82 #include "core/svg/SVGDocumentExtensions.h"
83 #include "core/svg/SVGElement.h"
84 #include "core/svg/SVGFontFaceElement.h"
85 #include "platform/RuntimeEnabledFeatures.h"
86 #include "wtf/StdLibExtras.h"
90 using namespace WebCore;
92 void setAnimationUpdateIfNeeded(StyleResolverState& state, Element& element)
94 // If any changes to CSS Animations were detected, stash the update away for application after the
95 // render object is updated if we're in the appropriate scope.
96 if (state.animationUpdate())
97 element.ensureActiveAnimations().cssAnimations().setPendingUpdate(state.takeAnimationUpdate());
104 using namespace HTMLNames;
106 RenderStyle* StyleResolver::s_styleNotYetAvailable;
108 static StylePropertySet* leftToRightDeclaration()
110 DEFINE_STATIC_REF(MutableStylePropertySet, leftToRightDecl, (MutableStylePropertySet::create()));
111 if (leftToRightDecl->isEmpty())
112 leftToRightDecl->setProperty(CSSPropertyDirection, CSSValueLtr);
113 return leftToRightDecl;
116 static StylePropertySet* rightToLeftDeclaration()
118 DEFINE_STATIC_REF(MutableStylePropertySet, rightToLeftDecl, (MutableStylePropertySet::create()));
119 if (rightToLeftDecl->isEmpty())
120 rightToLeftDecl->setProperty(CSSPropertyDirection, CSSValueRtl);
121 return rightToLeftDecl;
124 static void addFontFaceRule(Document* document, CSSFontSelector* cssFontSelector, const StyleRuleFontFace* fontFaceRule)
126 RefPtrWillBeRawPtr<FontFace> fontFace = FontFace::create(document, fontFaceRule);
128 cssFontSelector->fontFaceCache()->add(cssFontSelector, fontFaceRule, fontFace);
131 StyleResolver::StyleResolver(Document& document)
132 : m_document(document)
133 , m_viewportStyleResolver(ViewportStyleResolver::create(&document))
134 , m_needCollectFeatures(false)
135 , m_styleResourceLoader(document.fetcher())
136 , m_styleSharingDepth(0)
137 , m_styleResolverStatsSequence(0)
140 FrameView* view = document.view();
142 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), &view->frame()));
144 m_medium = adoptPtr(new MediaQueryEvaluator("all"));
148 initWatchedSelectorRules(CSSSelectorWatch::from(document).watchedCallbackSelectors());
150 #if ENABLE(SVG_FONTS)
151 if (document.svgExtensions()) {
152 const WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >& svgFontFaceElements = document.svgExtensions()->svgFontFaceElements();
153 WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >::const_iterator end = svgFontFaceElements.end();
154 for (WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >::const_iterator it = svgFontFaceElements.begin(); it != end; ++it)
155 addFontFaceRule(&document, document.styleEngine()->fontSelector(), (*it)->fontFaceRule());
160 void StyleResolver::initWatchedSelectorRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRule> >& watchedSelectors)
162 if (!watchedSelectors.size())
164 m_watchedSelectorsRules = RuleSet::create();
165 for (unsigned i = 0; i < watchedSelectors.size(); ++i)
166 m_watchedSelectorsRules->addStyleRule(watchedSelectors[i].get(), RuleHasNoSpecialState);
169 void StyleResolver::lazyAppendAuthorStyleSheets(unsigned firstNew, const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
171 unsigned size = styleSheets.size();
172 for (unsigned i = firstNew; i < size; ++i)
173 m_pendingStyleSheets.add(styleSheets[i].get());
176 void StyleResolver::removePendingAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
178 for (unsigned i = 0; i < styleSheets.size(); ++i)
179 m_pendingStyleSheets.remove(styleSheets[i].get());
182 void StyleResolver::appendCSSStyleSheet(CSSStyleSheet* cssSheet)
185 ASSERT(!cssSheet->disabled());
186 if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), &m_viewportDependentMediaQueryResults))
189 ContainerNode* scopingNode = ScopedStyleResolver::scopingNodeFor(document(), cssSheet);
193 ScopedStyleResolver* resolver = ensureScopedStyleResolver(scopingNode);
195 resolver->addRulesFromSheet(cssSheet, *m_medium, this);
198 void StyleResolver::appendPendingAuthorStyleSheets()
200 setBuildScopedStyleTreeInDocumentOrder(false);
201 for (WillBeHeapListHashSet<RawPtrWillBeMember<CSSStyleSheet>, 16>::iterator it = m_pendingStyleSheets.begin(); it != m_pendingStyleSheets.end(); ++it)
202 appendCSSStyleSheet(*it);
204 m_pendingStyleSheets.clear();
205 finishAppendAuthorStyleSheets();
208 void StyleResolver::appendAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
210 // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver
211 // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated.
212 unsigned size = styleSheets.size();
213 for (unsigned i = 0; i < size; ++i)
214 appendCSSStyleSheet(styleSheets[i].get());
217 void StyleResolver::finishAppendAuthorStyleSheets()
221 if (document().renderView() && document().renderView()->style())
222 document().renderView()->style()->font().update(document().styleEngine()->fontSelector());
224 collectViewportRules();
226 document().styleEngine()->resetCSSFeatureFlags(m_features);
229 void StyleResolver::resetRuleFeatures()
231 // Need to recreate RuleFeatureSet.
233 m_siblingRuleSet.clear();
234 m_uncommonAttributeRuleSet.clear();
235 m_needCollectFeatures = true;
238 void StyleResolver::processScopedRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, ContainerNode& scope)
240 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes> > keyframesRules = authorRules.keyframesRules();
241 for (unsigned i = 0; i < keyframesRules.size(); ++i)
242 ensureScopedStyleResolver(&scope)->addKeyframeStyle(keyframesRules[i]);
244 m_treeBoundaryCrossingRules.addTreeBoundaryCrossingRules(authorRules, scope, parentStyleSheet);
246 // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for the moment.
247 if (scope.isDocumentNode()) {
248 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace> > fontFaceRules = authorRules.fontFaceRules();
249 for (unsigned i = 0; i < fontFaceRules.size(); ++i)
250 addFontFaceRule(&m_document, document().styleEngine()->fontSelector(), fontFaceRules[i]);
251 if (fontFaceRules.size())
252 invalidateMatchedPropertiesCache();
256 void StyleResolver::resetAuthorStyle(const ContainerNode* scopingNode)
258 ScopedStyleResolver* resolver = scopingNode ? m_styleTree.lookupScopedStyleResolverFor(scopingNode) : m_styleTree.scopedStyleResolverForDocument();
262 m_treeBoundaryCrossingRules.reset(scopingNode);
264 resolver->resetAuthorStyle();
269 m_styleTree.remove(scopingNode);
272 static PassOwnPtrWillBeRawPtr<RuleSet> makeRuleSet(const WillBeHeapVector<RuleFeature>& rules)
274 size_t size = rules.size();
277 OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create();
278 for (size_t i = 0; i < size; ++i)
279 ruleSet->addRule(rules[i].rule, rules[i].selectorIndex, rules[i].hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState);
280 return ruleSet.release();
283 void StyleResolver::collectFeatures()
286 // Collect all ids and rules using sibling selectors (:first-child and similar)
287 // in the current set of stylesheets. Style sharing code uses this information to reject
288 // sharing candidates.
289 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
290 if (defaultStyleSheets.defaultStyle())
291 m_features.add(defaultStyleSheets.defaultStyle()->features());
293 if (document().isViewSource())
294 m_features.add(defaultStyleSheets.defaultViewSourceStyle()->features());
296 if (document().isTransitionDocument())
297 m_features.add(defaultStyleSheets.defaultTransitionStyle()->features());
299 if (m_watchedSelectorsRules)
300 m_features.add(m_watchedSelectorsRules->features());
302 m_treeBoundaryCrossingRules.collectFeaturesTo(m_features);
304 m_styleTree.collectFeaturesTo(m_features);
306 m_siblingRuleSet = makeRuleSet(m_features.siblingRules);
307 m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules);
308 m_needCollectFeatures = false;
311 bool StyleResolver::hasRulesForId(const AtomicString& id) const
313 return m_features.hasSelectorForId(id);
316 void StyleResolver::addToStyleSharingList(Element& element)
318 // Never add elements to the style sharing list if we're not in a recalcStyle,
319 // otherwise we could leave stale pointers in there.
320 if (!document().inStyleRecalc())
322 INCREMENT_STYLE_STATS_COUNTER(*this, sharedStyleCandidates);
323 StyleSharingList& list = styleSharingList();
324 if (list.size() >= styleSharingListSize)
325 list.remove(--list.end());
326 list.prepend(&element);
329 StyleSharingList& StyleResolver::styleSharingList()
331 m_styleSharingLists.resize(styleSharingMaxDepth);
333 // We never put things at depth 0 into the list since that's only the <html> element
334 // and it has no siblings or cousins to share with.
335 unsigned depth = std::max(std::min(m_styleSharingDepth, styleSharingMaxDepth), 1u) - 1u;
338 if (!m_styleSharingLists[depth])
339 m_styleSharingLists[depth] = adoptPtr(new StyleSharingList);
340 return *m_styleSharingLists[depth];
343 void StyleResolver::clearStyleSharingList()
345 m_styleSharingLists.resize(0);
348 void StyleResolver::pushParentElement(Element& parent)
350 const ContainerNode* parentsParent = parent.parentOrShadowHostElement();
352 // We are not always invoked consistently. For example, script execution can cause us to enter
353 // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree.
354 // Reset the stack in this case, or if we see a new root element.
355 // Otherwise just push the new parent.
356 if (!parentsParent || m_selectorFilter.parentStackIsEmpty())
357 m_selectorFilter.setupParentStack(parent);
359 m_selectorFilter.pushParent(parent);
361 // Note: We mustn't skip ShadowRoot nodes for the scope stack.
362 m_styleTree.pushStyleCache(parent, parent.parentOrShadowHostNode());
365 void StyleResolver::popParentElement(Element& parent)
367 // Note that we may get invoked for some random elements in some wacky cases during style resolve.
368 // Pause maintaining the stack in this case.
369 if (m_selectorFilter.parentStackIsConsistent(&parent))
370 m_selectorFilter.popParent();
372 m_styleTree.popStyleCache(parent);
375 void StyleResolver::pushParentShadowRoot(const ShadowRoot& shadowRoot)
377 ASSERT(shadowRoot.host());
378 m_styleTree.pushStyleCache(shadowRoot, shadowRoot.host());
381 void StyleResolver::popParentShadowRoot(const ShadowRoot& shadowRoot)
383 ASSERT(shadowRoot.host());
384 m_styleTree.popStyleCache(shadowRoot);
387 StyleResolver::~StyleResolver()
391 static inline bool applyAuthorStylesOf(const Element* element)
393 return element->treeScope().applyAuthorStyles();
396 void StyleResolver::matchAuthorRulesForShadowHost(Element* element, ElementRuleCollector& collector, bool includeEmptyRules, Vector<ScopedStyleResolver*, 8>& resolvers, Vector<ScopedStyleResolver*, 8>& resolversInShadowTree)
398 collector.clearMatchedRules();
399 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
401 CascadeScope cascadeScope = 0;
402 CascadeOrder cascadeOrder = 0;
403 bool applyAuthorStyles = applyAuthorStylesOf(element);
405 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j)
406 resolversInShadowTree.at(j)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope, cascadeOrder++);
408 if (resolvers.isEmpty() || resolvers.first()->treeScope() != element->treeScope())
410 cascadeOrder += resolvers.size();
411 for (unsigned i = 0; i < resolvers.size(); ++i)
412 resolvers.at(i)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, --cascadeOrder);
414 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
415 collector.sortAndTransferMatchedRules();
418 void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules)
420 collector.clearMatchedRules();
421 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
423 bool applyAuthorStyles = applyAuthorStylesOf(element);
424 if (m_styleTree.hasOnlyScopedResolverForDocument()) {
425 m_styleTree.scopedStyleResolverForDocument()->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, ignoreCascadeScope);
426 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
427 collector.sortAndTransferMatchedRules();
431 Vector<ScopedStyleResolver*, 8> resolvers;
432 m_styleTree.resolveScopedStyles(element, resolvers);
434 Vector<ScopedStyleResolver*, 8> resolversInShadowTree;
435 m_styleTree.collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree);
436 if (!resolversInShadowTree.isEmpty()) {
437 matchAuthorRulesForShadowHost(element, collector, includeEmptyRules, resolvers, resolversInShadowTree);
441 if (resolvers.isEmpty())
444 CascadeScope cascadeScope = 0;
445 CascadeOrder cascadeOrder = resolvers.size();
446 for (unsigned i = 0; i < resolvers.size(); ++i, --cascadeOrder) {
447 ScopedStyleResolver* resolver = resolvers.at(i);
448 // FIXME: Need to clarify how to treat style scoped.
449 resolver->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, resolver->treeScope() == element->treeScope() && resolver->scopingNode().isShadowRoot() ? 0 : cascadeOrder);
452 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
453 collector.sortAndTransferMatchedRules();
456 void StyleResolver::matchWatchSelectorRules(ElementRuleCollector& collector)
458 if (!m_watchedSelectorsRules)
461 collector.clearMatchedRules();
462 collector.matchedResult().ranges.lastUserRule = collector.matchedResult().matchedProperties.size() - 1;
464 MatchRequest matchRequest(m_watchedSelectorsRules.get());
465 RuleRange ruleRange = collector.matchedResult().ranges.userRuleRange();
466 collector.collectMatchingRules(matchRequest, ruleRange);
468 collector.sortAndTransferMatchedRules();
471 void StyleResolver::matchUARules(ElementRuleCollector& collector)
473 collector.setMatchingUARules(true);
475 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
476 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
477 ? defaultStyleSheets.defaultPrintStyle() : defaultStyleSheets.defaultStyle();
478 matchUARules(collector, userAgentStyleSheet);
480 // In quirks mode, we match rules from the quirks user agent sheet.
481 if (document().inQuirksMode())
482 matchUARules(collector, defaultStyleSheets.defaultQuirksStyle());
484 // If document uses view source styles (in view source mode or in xml viewer mode), then we match rules from the view source style sheet.
485 if (document().isViewSource())
486 matchUARules(collector, defaultStyleSheets.defaultViewSourceStyle());
488 if (document().isTransitionDocument())
489 matchUARules(collector, defaultStyleSheets.defaultTransitionStyle());
491 collector.setMatchingUARules(false);
493 matchWatchSelectorRules(collector);
496 void StyleResolver::matchUARules(ElementRuleCollector& collector, RuleSet* rules)
498 collector.clearMatchedRules();
499 collector.matchedResult().ranges.lastUARule = collector.matchedResult().matchedProperties.size() - 1;
501 RuleRange ruleRange = collector.matchedResult().ranges.UARuleRange();
502 collector.collectMatchingRules(MatchRequest(rules), ruleRange);
504 collector.sortAndTransferMatchedRules();
507 void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollector& collector, bool includeSMILProperties)
509 matchUARules(collector);
511 // Now check author rules, beginning first with presentational attributes mapped from HTML.
512 if (state.element()->isStyledElement()) {
513 collector.addElementStyleProperties(state.element()->presentationAttributeStyle());
515 // Now we check additional mapped declarations.
516 // Tables and table cells share an additional mapped rule that must be applied
517 // after all attributes, since their mapped style depends on the values of multiple attributes.
518 collector.addElementStyleProperties(state.element()->additionalPresentationAttributeStyle());
520 if (state.element()->isHTMLElement()) {
522 TextDirection textDirection = toHTMLElement(state.element())->directionalityIfhasDirAutoAttribute(isAuto);
524 collector.matchedResult().addMatchedProperties(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
528 matchAuthorRules(state.element(), collector, false);
530 if (state.element()->isStyledElement()) {
531 if (state.element()->inlineStyle()) {
532 // Inline style is immutable as long as there is no CSSOM wrapper.
533 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMutable();
534 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable);
537 // Now check SMIL animation override style.
538 if (includeSMILProperties && state.element()->isSVGElement())
539 collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */);
543 PassRefPtr<RenderStyle> StyleResolver::styleForDocument(Document& document)
545 const LocalFrame* frame = document.frame();
547 RefPtr<RenderStyle> documentStyle = RenderStyle::create();
548 documentStyle->setDisplay(BLOCK);
549 documentStyle->setRTLOrdering(document.visuallyOrdered() ? VisualOrder : LogicalOrder);
550 documentStyle->setZoom(frame && !document.printing() ? frame->pageZoomFactor() : 1);
551 documentStyle->setLocale(document.contentLanguage());
552 documentStyle->setZIndex(0);
553 documentStyle->setUserModify(document.inDesignMode() ? READ_WRITE : READ_ONLY);
555 document.setupFontBuilder(documentStyle.get());
557 return documentStyle.release();
560 // FIXME: This is duplicated with StyleAdjuster.cpp
561 // Perhaps this should move onto ElementResolveContext or even Element?
562 static inline bool isAtShadowBoundary(const Element* element)
566 ContainerNode* parentNode = element->parentNode();
567 return parentNode && parentNode->isShadowRoot();
570 static inline void resetDirectionAndWritingModeOnDocument(Document& document)
572 document.setDirectionSetOnDocumentElement(false);
573 document.setWritingModeSetOnDocumentElement(false);
576 static void addContentAttrValuesToFeatures(const Vector<AtomicString>& contentAttrValues, RuleFeatureSet& features)
578 for (size_t i = 0; i < contentAttrValues.size(); ++i)
579 features.addContentAttr(contentAttrValues[i]);
582 void StyleResolver::adjustRenderStyle(StyleResolverState& state, Element* element)
584 StyleAdjuster adjuster(m_document.inQuirksMode());
585 adjuster.adjustRenderStyle(state.style(), state.parentStyle(), element, state.cachedUAStyle());
588 // Start loading resources referenced by this style.
589 void StyleResolver::loadPendingResources(StyleResolverState& state)
591 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources());
592 document().styleEngine()->fontSelector()->fontLoader()->loadPendingFonts();
595 PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent, StyleSharingBehavior sharingBehavior,
596 RuleMatchingBehavior matchingBehavior)
598 ASSERT(document().frame());
599 ASSERT(documentSettings());
600 ASSERT(!hasPendingAuthorStyleSheets());
601 ASSERT(!m_needCollectFeatures);
603 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
604 // will vanish if a style recalc happens during loading.
605 if (sharingBehavior == AllowStyleSharing && !document().isRenderingReady() && !element->renderer()) {
606 if (!s_styleNotYetAvailable) {
607 s_styleNotYetAvailable = RenderStyle::create().leakRef();
608 s_styleNotYetAvailable->setDisplay(NONE);
609 s_styleNotYetAvailable->font().update(document().styleEngine()->fontSelector());
612 document().setHasNodesWithPlaceholderStyle();
613 return s_styleNotYetAvailable;
618 StyleResolverParentScope::ensureParentStackIsPushed();
620 if (element == document().documentElement())
621 resetDirectionAndWritingModeOnDocument(document());
622 StyleResolverState state(document(), element, defaultParent);
624 if (sharingBehavior == AllowStyleSharing && state.parentStyle()) {
625 SharedStyleFinder styleFinder(state.elementContext(), m_features, m_siblingRuleSet.get(), m_uncommonAttributeRuleSet.get(), *this);
626 if (RefPtr<RenderStyle> sharedStyle = styleFinder.findSharedStyle())
627 return sharedStyle.release();
630 if (state.parentStyle()) {
631 state.setStyle(RenderStyle::create());
632 state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
634 state.setStyle(defaultStyleForElement());
635 state.setParentStyle(RenderStyle::clone(state.style()));
637 // contenteditable attribute (implemented by -webkit-user-modify) should
638 // be propagated from shadow host to distributed node.
639 if (state.distributedToInsertionPoint()) {
640 if (Element* parent = element->parentElement()) {
641 if (RenderStyle* styleOfShadowHost = parent->renderStyle())
642 state.style()->setUserModify(styleOfShadowHost->userModify());
646 state.fontBuilder().initForStyleResolve(state.document(), state.style());
648 if (element->isLink()) {
649 state.style()->setIsLink(true);
650 EInsideLink linkState = state.elementLinkState();
651 if (linkState != NotInsideLink) {
652 bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited);
654 linkState = InsideVisitedLink;
656 state.style()->setInsideLink(linkState);
659 bool needsCollection = false;
660 CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection);
665 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
667 matchAllRules(state, collector, matchingBehavior != MatchAllRulesExcludingSMIL);
669 applyMatchedProperties(state, collector.matchedResult());
671 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
674 // Cache our original display.
675 state.style()->setOriginalDisplay(state.style()->display());
677 adjustRenderStyle(state, element);
679 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
680 // important rules, but this currently happens here as we require adjustment to have happened
681 // before deciding which properties to transition.
682 if (applyAnimatedProperties(state, element))
683 adjustRenderStyle(state, element);
685 // FIXME: Shouldn't this be on RenderBody::styleDidChange?
686 if (isHTMLBodyElement(*element))
687 document().textLinkColors().setTextColor(state.style()->color());
689 setAnimationUpdateIfNeeded(state, *element);
691 if (state.style()->hasViewportUnits())
692 document().setHasViewportUnits();
694 // Now return the style.
695 return state.takeStyle();
698 PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const RenderStyle& elementStyle, RenderStyle* parentStyle, const StyleKeyframe* keyframe, const AtomicString& animationName)
700 ASSERT(document().frame());
701 ASSERT(documentSettings());
702 ASSERT(!hasPendingAuthorStyleSheets());
704 if (element == document().documentElement())
705 resetDirectionAndWritingModeOnDocument(document());
706 StyleResolverState state(document(), element, parentStyle);
709 result.addMatchedProperties(&keyframe->properties());
711 ASSERT(!state.style());
714 state.setStyle(RenderStyle::clone(&elementStyle));
715 state.setLineHeightValue(0);
717 state.fontBuilder().initForStyleResolve(state.document(), state.style());
719 // We don't need to bother with !important. Since there is only ever one
720 // decl, there's nothing to override. So just add the first properties.
721 // We also don't need to bother with animation properties since the only
722 // relevant one is animation-timing-function and we special-case that in
724 bool inheritedOnly = false;
725 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
727 // If our font got dirtied, go ahead and update it now.
730 // Line-height is set when we are sure we decided on the font-size
731 if (state.lineHeightValue())
732 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
734 // Now do rest of the properties.
735 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
737 // If our font got dirtied by one of the non-essential font props,
738 // go ahead and update it a second time.
741 loadPendingResources(state);
745 return state.takeStyle();
748 // This function is used by the WebAnimations JavaScript API method animate().
749 // FIXME: Remove this when animate() switches away from resolution-dependent parsing.
750 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(Element& element, CSSPropertyID property, CSSValue& value)
752 RefPtr<RenderStyle> style;
753 if (element.renderStyle())
754 style = RenderStyle::clone(element.renderStyle());
756 style = RenderStyle::create();
757 StyleResolverState state(element.document(), &element);
758 state.setStyle(style);
759 state.fontBuilder().initForStyleResolve(state.document(), state.style());
760 return createAnimatableValueSnapshot(state, property, value);
763 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(StyleResolverState& state, CSSPropertyID property, CSSValue& value)
765 StyleBuilder::applyProperty(property, state, &value);
766 return CSSAnimatableValueFactory::create(property, *state.style());
769 PassRefPtrWillBeRawPtr<PseudoElement> StyleResolver::createPseudoElementIfNeeded(Element& parent, PseudoId pseudoId)
771 RenderObject* parentRenderer = parent.renderer();
775 if (pseudoId < FIRST_INTERNAL_PSEUDOID && !parentRenderer->style()->hasPseudoStyle(pseudoId))
778 if (pseudoId == BACKDROP && !parent.isInTopLayer())
781 if (!parentRenderer->canHaveGeneratedChildren())
784 RenderStyle* parentStyle = parentRenderer->style();
785 if (RenderStyle* cachedStyle = parentStyle->getCachedPseudoStyle(pseudoId)) {
786 if (!pseudoElementRendererIsNeeded(cachedStyle))
788 return PseudoElement::create(&parent, pseudoId);
791 StyleResolverState state(document(), &parent, parentStyle);
792 if (!pseudoStyleForElementInternal(parent, pseudoId, parentStyle, state))
794 RefPtr<RenderStyle> style = state.takeStyle();
796 parentStyle->addCachedPseudoStyle(style);
798 if (!pseudoElementRendererIsNeeded(style.get()))
801 RefPtrWillBeRawPtr<PseudoElement> pseudo = PseudoElement::create(&parent, pseudoId);
803 setAnimationUpdateIfNeeded(state, *pseudo);
804 if (ActiveAnimations* activeAnimations = pseudo->activeAnimations())
805 activeAnimations->cssAnimations().maybeApplyPendingUpdate(pseudo.get());
806 return pseudo.release();
809 bool StyleResolver::pseudoStyleForElementInternal(Element& element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, StyleResolverState& state)
811 ASSERT(document().frame());
812 ASSERT(documentSettings());
813 ASSERT(pseudoStyleRequest.pseudoId != FIRST_LINE_INHERITED);
815 StyleResolverParentScope::ensureParentStackIsPushed();
817 if (pseudoStyleRequest.allowsInheritance(state.parentStyle())) {
818 state.setStyle(RenderStyle::create());
819 state.style()->inheritFrom(state.parentStyle());
821 state.setStyle(defaultStyleForElement());
822 state.setParentStyle(RenderStyle::clone(state.style()));
825 state.fontBuilder().initForStyleResolve(state.document(), state.style());
827 // Since we don't use pseudo-elements in any of our quirk/print
828 // user agent rules, don't waste time walking those rules.
831 // Check UA, user and author rules.
832 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
833 collector.setPseudoStyleRequest(pseudoStyleRequest);
835 matchUARules(collector);
836 matchAuthorRules(state.element(), collector, false);
838 if (collector.matchedResult().matchedProperties.isEmpty())
841 state.style()->setStyleType(pseudoStyleRequest.pseudoId);
843 applyMatchedProperties(state, collector.matchedResult());
845 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
848 // Cache our original display.
849 state.style()->setOriginalDisplay(state.style()->display());
851 // FIXME: Passing 0 as the Element* introduces a lot of complexity
852 // in the adjustRenderStyle code.
853 adjustRenderStyle(state, 0);
855 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
856 // important rules, but this currently happens here as we require adjustment to have happened
857 // before deciding which properties to transition.
858 if (applyAnimatedProperties(state, element.pseudoElement(pseudoStyleRequest.pseudoId)))
859 adjustRenderStyle(state, 0);
863 if (state.style()->hasViewportUnits())
864 document().setHasViewportUnits();
869 PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle)
875 StyleResolverState state(document(), element, parentStyle);
876 if (!pseudoStyleForElementInternal(*element, pseudoStyleRequest, parentStyle, state))
879 if (PseudoElement* pseudoElement = element->pseudoElement(pseudoStyleRequest.pseudoId))
880 setAnimationUpdateIfNeeded(state, *pseudoElement);
882 // Now return the style.
883 return state.takeStyle();
886 PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
888 ASSERT(!hasPendingAuthorStyleSheets());
889 resetDirectionAndWritingModeOnDocument(document());
890 StyleResolverState state(document(), document().documentElement()); // m_rootElementStyle will be set to the document style.
892 state.setStyle(RenderStyle::create());
893 const RenderStyle* rootElementStyle = state.rootElementStyle() ? state.rootElementStyle() : document().renderStyle();
894 ASSERT(rootElementStyle);
895 state.style()->inheritFrom(rootElementStyle);
897 state.fontBuilder().initForStyleResolve(state.document(), state.style());
899 PageRuleCollector collector(rootElementStyle, pageIndex);
901 collector.matchPageRules(CSSDefaultStyleSheets::instance().defaultPrintStyle());
903 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
904 scopedResolver->matchPageRules(collector);
906 state.setLineHeightValue(0);
907 bool inheritedOnly = false;
909 MatchResult& result = collector.matchedResult();
910 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
912 // If our font got dirtied, go ahead and update it now.
915 // Line-height is set when we are sure we decided on the font-size.
916 if (state.lineHeightValue())
917 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
919 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
921 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
923 loadPendingResources(state);
927 // Now return the style.
928 return state.takeStyle();
931 void StyleResolver::collectViewportRules()
933 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
934 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultStyle(), ViewportStyleResolver::UserAgentOrigin);
936 if (!InspectorInstrumentation::applyViewportStyleOverride(&document(), this))
937 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultViewportStyle(), ViewportStyleResolver::UserAgentOrigin);
939 if (document().isMobileDocument())
940 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultXHTMLMobileProfileStyle(), ViewportStyleResolver::UserAgentOrigin);
942 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
943 scopedResolver->collectViewportRulesTo(this);
945 viewportStyleResolver()->resolve();
948 PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement()
950 StyleResolverState state(document(), 0);
951 state.setStyle(RenderStyle::create());
952 state.fontBuilder().initForStyleResolve(document(), state.style());
953 state.style()->setLineHeight(RenderStyle::initialLineHeight());
954 state.setLineHeightValue(0);
955 state.fontBuilder().setInitial(state.style()->effectiveZoom());
956 state.style()->font().update(document().styleEngine()->fontSelector());
957 return state.takeStyle();
960 PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode)
964 NodeRenderingTraversal::ParentDetails parentDetails;
965 Node* parentNode = NodeRenderingTraversal::parent(textNode, &parentDetails);
966 if (!parentNode || !parentNode->renderStyle())
967 return defaultStyleForElement();
968 return parentNode->renderStyle();
971 void StyleResolver::updateFont(StyleResolverState& state)
973 state.fontBuilder().createFont(document().styleEngine()->fontSelector(), state.parentStyle(), state.style());
974 if (state.fontBuilder().fontSizeHasViewportUnits())
975 state.style()->setHasViewportUnits();
978 PassRefPtrWillBeRawPtr<StyleRuleList> StyleResolver::styleRulesForElement(Element* element, unsigned rulesToInclude)
981 StyleResolverState state(document(), element);
982 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
983 collector.setMode(SelectorChecker::CollectingStyleRules);
984 collectPseudoRulesForElement(element, collector, NOPSEUDO, rulesToInclude);
985 return collector.matchedStyleRuleList();
988 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::pseudoCSSRulesForElement(Element* element, PseudoId pseudoId, unsigned rulesToInclude)
991 StyleResolverState state(document(), element);
992 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
993 collector.setMode(SelectorChecker::CollectingCSSRules);
994 collectPseudoRulesForElement(element, collector, pseudoId, rulesToInclude);
995 return collector.matchedCSSRuleList();
998 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::cssRulesForElement(Element* element, unsigned rulesToInclude)
1000 return pseudoCSSRulesForElement(element, NOPSEUDO, rulesToInclude);
1003 void StyleResolver::collectPseudoRulesForElement(Element* element, ElementRuleCollector& collector, PseudoId pseudoId, unsigned rulesToInclude)
1005 collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
1007 if (rulesToInclude & UAAndUserCSSRules)
1008 matchUARules(collector);
1010 if (rulesToInclude & AuthorCSSRules) {
1011 collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules));
1012 matchAuthorRules(element, collector, rulesToInclude & EmptyCSSRules);
1016 // -------------------------------------------------------------------------------------
1017 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1019 bool StyleResolver::applyAnimatedProperties(StyleResolverState& state, Element* animatingElement)
1021 const Element* element = state.element();
1024 // The animating element may be this element, or its pseudo element. It is
1025 // null when calculating the style for a potential pseudo element that has
1026 // yet to be created.
1027 ASSERT(animatingElement == element || !animatingElement || animatingElement->parentOrShadowHostElement() == element);
1029 if (!(animatingElement && animatingElement->hasActiveAnimations())
1030 && !state.style()->transitions() && !state.style()->animations())
1033 state.setAnimationUpdate(CSSAnimations::calculateUpdate(animatingElement, *element, *state.style(), state.parentStyle(), this));
1034 if (!state.animationUpdate())
1037 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations = state.animationUpdate()->activeInterpolationsForAnimations();
1038 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForTransitions = state.animationUpdate()->activeInterpolationsForTransitions();
1039 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForAnimations);
1040 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForTransitions);
1044 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForAnimations);
1045 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForTransitions);
1047 // Start loading resources used by animations.
1048 loadPendingResources(state);
1050 ASSERT(!state.fontBuilder().fontDirty());
1055 template <StyleResolver::StyleApplicationPass pass>
1056 void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolations)
1058 ASSERT(pass != AnimationProperties);
1060 for (WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >::const_iterator iter = activeInterpolations.begin(); iter != activeInterpolations.end(); ++iter) {
1061 CSSPropertyID property = iter->key;
1062 if (!isPropertyForPass<pass>(property))
1064 const StyleInterpolation* interpolation = toStyleInterpolation(iter->value.get());
1065 interpolation->apply(state);
1069 static inline bool isValidCueStyleProperty(CSSPropertyID id)
1072 case CSSPropertyBackground:
1073 case CSSPropertyBackgroundAttachment:
1074 case CSSPropertyBackgroundClip:
1075 case CSSPropertyBackgroundColor:
1076 case CSSPropertyBackgroundImage:
1077 case CSSPropertyBackgroundOrigin:
1078 case CSSPropertyBackgroundPosition:
1079 case CSSPropertyBackgroundPositionX:
1080 case CSSPropertyBackgroundPositionY:
1081 case CSSPropertyBackgroundRepeat:
1082 case CSSPropertyBackgroundRepeatX:
1083 case CSSPropertyBackgroundRepeatY:
1084 case CSSPropertyBackgroundSize:
1085 case CSSPropertyColor:
1086 case CSSPropertyFont:
1087 case CSSPropertyFontFamily:
1088 case CSSPropertyFontSize:
1089 case CSSPropertyFontStyle:
1090 case CSSPropertyFontVariant:
1091 case CSSPropertyFontWeight:
1092 case CSSPropertyLineHeight:
1093 case CSSPropertyOpacity:
1094 case CSSPropertyOutline:
1095 case CSSPropertyOutlineColor:
1096 case CSSPropertyOutlineOffset:
1097 case CSSPropertyOutlineStyle:
1098 case CSSPropertyOutlineWidth:
1099 case CSSPropertyVisibility:
1100 case CSSPropertyWhiteSpace:
1101 // FIXME: 'text-decoration' shorthand to be handled when available.
1102 // See https://chromiumcodereview.appspot.com/19516002 for details.
1103 case CSSPropertyTextDecoration:
1104 case CSSPropertyTextShadow:
1105 case CSSPropertyBorderStyle:
1107 case CSSPropertyTextDecorationLine:
1108 case CSSPropertyTextDecorationStyle:
1109 case CSSPropertyTextDecorationColor:
1110 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1117 static inline bool isValidFirstLetterStyleProperty(CSSPropertyID id)
1120 // Valid ::first-letter properties listed in spec:
1121 // http://www.w3.org/TR/css3-selectors/#application-in-css
1122 case CSSPropertyBackgroundAttachment:
1123 case CSSPropertyBackgroundBlendMode:
1124 case CSSPropertyBackgroundClip:
1125 case CSSPropertyBackgroundColor:
1126 case CSSPropertyBackgroundImage:
1127 case CSSPropertyBackgroundOrigin:
1128 case CSSPropertyBackgroundPosition:
1129 case CSSPropertyBackgroundPositionX:
1130 case CSSPropertyBackgroundPositionY:
1131 case CSSPropertyBackgroundRepeat:
1132 case CSSPropertyBackgroundRepeatX:
1133 case CSSPropertyBackgroundRepeatY:
1134 case CSSPropertyBackgroundSize:
1135 case CSSPropertyBorderBottomColor:
1136 case CSSPropertyBorderBottomLeftRadius:
1137 case CSSPropertyBorderBottomRightRadius:
1138 case CSSPropertyBorderBottomStyle:
1139 case CSSPropertyBorderBottomWidth:
1140 case CSSPropertyBorderImageOutset:
1141 case CSSPropertyBorderImageRepeat:
1142 case CSSPropertyBorderImageSlice:
1143 case CSSPropertyBorderImageSource:
1144 case CSSPropertyBorderImageWidth:
1145 case CSSPropertyBorderLeftColor:
1146 case CSSPropertyBorderLeftStyle:
1147 case CSSPropertyBorderLeftWidth:
1148 case CSSPropertyBorderRightColor:
1149 case CSSPropertyBorderRightStyle:
1150 case CSSPropertyBorderRightWidth:
1151 case CSSPropertyBorderTopColor:
1152 case CSSPropertyBorderTopLeftRadius:
1153 case CSSPropertyBorderTopRightRadius:
1154 case CSSPropertyBorderTopStyle:
1155 case CSSPropertyBorderTopWidth:
1156 case CSSPropertyColor:
1157 case CSSPropertyFloat:
1158 case CSSPropertyFont:
1159 case CSSPropertyFontFamily:
1160 case CSSPropertyFontKerning:
1161 case CSSPropertyFontSize:
1162 case CSSPropertyFontStretch:
1163 case CSSPropertyFontStyle:
1164 case CSSPropertyFontVariant:
1165 case CSSPropertyFontVariantLigatures:
1166 case CSSPropertyFontWeight:
1167 case CSSPropertyLetterSpacing:
1168 case CSSPropertyLineHeight:
1169 case CSSPropertyMarginBottom:
1170 case CSSPropertyMarginLeft:
1171 case CSSPropertyMarginRight:
1172 case CSSPropertyMarginTop:
1173 case CSSPropertyPaddingBottom:
1174 case CSSPropertyPaddingLeft:
1175 case CSSPropertyPaddingRight:
1176 case CSSPropertyPaddingTop:
1177 case CSSPropertyTextTransform:
1178 case CSSPropertyVerticalAlign:
1179 case CSSPropertyWebkitBackgroundClip:
1180 case CSSPropertyWebkitBackgroundComposite:
1181 case CSSPropertyWebkitBackgroundOrigin:
1182 case CSSPropertyWebkitBackgroundSize:
1183 case CSSPropertyWebkitBorderAfter:
1184 case CSSPropertyWebkitBorderAfterColor:
1185 case CSSPropertyWebkitBorderAfterStyle:
1186 case CSSPropertyWebkitBorderAfterWidth:
1187 case CSSPropertyWebkitBorderBefore:
1188 case CSSPropertyWebkitBorderBeforeColor:
1189 case CSSPropertyWebkitBorderBeforeStyle:
1190 case CSSPropertyWebkitBorderBeforeWidth:
1191 case CSSPropertyWebkitBorderEnd:
1192 case CSSPropertyWebkitBorderEndColor:
1193 case CSSPropertyWebkitBorderEndStyle:
1194 case CSSPropertyWebkitBorderEndWidth:
1195 case CSSPropertyWebkitBorderFit:
1196 case CSSPropertyWebkitBorderHorizontalSpacing:
1197 case CSSPropertyWebkitBorderImage:
1198 case CSSPropertyWebkitBorderRadius:
1199 case CSSPropertyWebkitBorderStart:
1200 case CSSPropertyWebkitBorderStartColor:
1201 case CSSPropertyWebkitBorderStartStyle:
1202 case CSSPropertyWebkitBorderStartWidth:
1203 case CSSPropertyWebkitBorderVerticalSpacing:
1204 case CSSPropertyWebkitFontSmoothing:
1205 case CSSPropertyWebkitMarginAfter:
1206 case CSSPropertyWebkitMarginAfterCollapse:
1207 case CSSPropertyWebkitMarginBefore:
1208 case CSSPropertyWebkitMarginBeforeCollapse:
1209 case CSSPropertyWebkitMarginBottomCollapse:
1210 case CSSPropertyWebkitMarginCollapse:
1211 case CSSPropertyWebkitMarginEnd:
1212 case CSSPropertyWebkitMarginStart:
1213 case CSSPropertyWebkitMarginTopCollapse:
1214 case CSSPropertyWordSpacing:
1216 case CSSPropertyTextDecorationColor:
1217 case CSSPropertyTextDecorationLine:
1218 case CSSPropertyTextDecorationStyle:
1219 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1221 // text-shadow added in text decoration spec:
1222 // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property
1223 case CSSPropertyTextShadow:
1224 // box-shadox added in CSS3 backgrounds spec:
1225 // http://www.w3.org/TR/css3-background/#placement
1226 case CSSPropertyBoxShadow:
1227 case CSSPropertyWebkitBoxShadow:
1228 // Properties that we currently support outside of spec.
1229 case CSSPropertyWebkitLineBoxContain:
1230 case CSSPropertyVisibility:
1238 // FIXME: Consider refactoring to create a new class which owns the following
1239 // first/last/range properties.
1240 // This method returns the first CSSPropertyId of properties which generate
1241 // animations. All animation properties are obtained by using
1242 // firstCSSPropertyId<AnimationProperties> and
1243 // lastCSSPropertyId<AnimationProperties>.
1244 // c.f. //src/third_party/WebKit/Source/core/css/CSSPropertyNames.in.
1245 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::AnimationProperties>()
1247 COMPILE_ASSERT(firstCSSProperty == CSSPropertyDisplay, CSS_first_animation_property_should_be_first_property);
1248 return CSSPropertyDisplay;
1251 // This method returns the first CSSPropertyId of properties which generate
1253 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::AnimationProperties>()
1255 COMPILE_ASSERT(CSSPropertyTransitionTimingFunction == CSSPropertyColor - 1, CSS_transition_timing_is_last_animation_property);
1256 return CSSPropertyTransitionTimingFunction;
1259 // This method returns the first CSSPropertyId of high priority properties.
1260 // Other properties can depend on high priority properties. For example,
1261 // border-color property with currentColor value depends on color property.
1262 // All high priority properties are obtained by using
1263 // firstCSSPropertyId<HighPriorityProperties> and
1264 // lastCSSPropertyId<HighPriorityProperties>.
1265 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::HighPriorityProperties>()
1267 COMPILE_ASSERT(CSSPropertyTransitionTimingFunction + 1 == CSSPropertyColor, CSS_color_is_first_high_priority_property);
1268 return CSSPropertyColor;
1271 // This method returns the last CSSPropertyId of high priority properties.
1272 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::HighPriorityProperties>()
1274 COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyColor + 17, CSS_line_height_is_end_of_high_prioity_property_range);
1275 COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyLineHeight - 1, CSS_zoom_is_before_line_height);
1276 return CSSPropertyLineHeight;
1279 // This method returns the first CSSPropertyId of remaining properties,
1280 // i.e. low priority properties. No properties depend on low priority
1281 // properties. So we don't need to resolve such properties quickly.
1282 // All low priority properties are obtained by using
1283 // firstCSSPropertyId<LowPriorityProperties> and
1284 // lastCSSPropertyId<LowPriorityProperties>.
1285 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::LowPriorityProperties>()
1287 COMPILE_ASSERT(CSSPropertyBackground == CSSPropertyLineHeight + 1, CSS_background_is_first_low_priority_property);
1288 return CSSPropertyBackground;
1291 // This method returns the last CSSPropertyId of low priority properties.
1292 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::LowPriorityProperties>()
1294 return static_cast<CSSPropertyID>(lastCSSProperty);
1297 template <StyleResolver::StyleApplicationPass pass>
1298 bool StyleResolver::isPropertyForPass(CSSPropertyID property)
1300 return firstCSSPropertyId<pass>() <= property && property <= lastCSSPropertyId<pass>();
1303 // This method expands all shorthand property to longhand properties
1304 // considering StyleApplicationPass, and apply each expanded longhand property.
1305 // For example, if StyleApplicationPass is AnimationProperties, all shorthand
1306 // is expaneded to display, -webkit-animation, -webkit-animation-delay, ...,
1307 // transition-timing-function. So each property's value will be applied
1308 // according to all's value (initial, inherit or unset).
1309 template <StyleResolver::StyleApplicationPass pass>
1310 void StyleResolver::applyAllProperty(StyleResolverState& state, CSSValue* allValue)
1312 bool isUnsetValue = !allValue->isInitialValue() && !allValue->isInheritedValue();
1313 unsigned startCSSProperty = firstCSSPropertyId<pass>();
1314 unsigned endCSSProperty = lastCSSPropertyId<pass>();
1316 for (unsigned i = startCSSProperty; i <= endCSSProperty; ++i) {
1317 CSSPropertyID propertyId = static_cast<CSSPropertyID>(i);
1319 // StyleBuilder does not allow any expanded shorthands.
1320 if (isExpandedShorthandForAll(propertyId))
1323 // all shorthand spec says:
1324 // The all property is a shorthand that resets all CSS properties
1325 // except direction and unicode-bidi.
1326 // c.f. http://dev.w3.org/csswg/css-cascade/#all-shorthand
1327 // We skip applyProperty when a given property is unicode-bidi or
1329 if (!CSSProperty::isAffectedByAllProperty(propertyId))
1333 if (!isUnsetValue) {
1336 if (CSSProperty::isInheritedProperty(propertyId))
1337 value = cssValuePool().createInheritedValue().get();
1339 value = cssValuePool().createExplicitInitialValue().get();
1341 StyleBuilder::applyProperty(propertyId, state, value);
1345 template <StyleResolver::StyleApplicationPass pass>
1346 void StyleResolver::applyProperties(StyleResolverState& state, const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType)
1348 state.setCurrentRule(rule);
1350 unsigned propertyCount = properties->propertyCount();
1351 for (unsigned i = 0; i < propertyCount; ++i) {
1352 StylePropertySet::PropertyReference current = properties->propertyAt(i);
1353 if (isImportant != current.isImportant())
1356 CSSPropertyID property = current.id();
1357 if (property == CSSPropertyAll) {
1358 applyAllProperty<pass>(state, current.value());
1362 if (inheritedOnly && !current.isInherited()) {
1363 // If the property value is explicitly inherited, we need to apply further non-inherited properties
1364 // as they might override the value inherited here. For this reason we don't allow declarations with
1365 // explicitly inherited properties to be cached.
1366 ASSERT(!current.value()->isInheritedValue());
1370 if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property))
1372 if (propertyWhitelistType == PropertyWhitelistFirstLetter && !isValidFirstLetterStyleProperty(property))
1374 if (!isPropertyForPass<pass>(property))
1376 if (pass == HighPriorityProperties && property == CSSPropertyLineHeight)
1377 state.setLineHeightValue(current.value());
1379 StyleBuilder::applyProperty(current.id(), state, current.value());
1383 template <StyleResolver::StyleApplicationPass pass>
1384 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
1386 if (startIndex == -1)
1389 if (state.style()->insideLink() != NotInsideLink) {
1390 for (int i = startIndex; i <= endIndex; ++i) {
1391 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1392 unsigned linkMatchType = matchedProperties.linkMatchType;
1393 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
1394 state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink);
1395 state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited);
1397 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1399 state.setApplyPropertyToRegularStyle(true);
1400 state.setApplyPropertyToVisitedLinkStyle(false);
1403 for (int i = startIndex; i <= endIndex; ++i) {
1404 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1405 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1409 static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
1411 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
1414 void StyleResolver::invalidateMatchedPropertiesCache()
1416 m_matchedPropertiesCache.clear();
1419 void StyleResolver::notifyResizeForViewportUnits()
1421 collectViewportRules();
1422 m_matchedPropertiesCache.clearViewportDependent();
1425 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult)
1427 const Element* element = state.element();
1430 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply);
1432 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
1433 bool applyInheritedOnly = false;
1434 const CachedMatchedProperties* cachedMatchedProperties = 0;
1436 if (cacheHash && (cachedMatchedProperties = m_matchedPropertiesCache.find(cacheHash, state, matchResult))
1437 && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1438 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit);
1439 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
1440 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the
1441 // element context. This is fast and saves memory by reusing the style data structures.
1442 state.style()->copyNonInheritedFrom(cachedMatchedProperties->renderStyle.get());
1443 if (state.parentStyle()->inheritedDataShared(cachedMatchedProperties->parentRenderStyle.get()) && !isAtShadowBoundary(element)
1444 && (!state.distributedToInsertionPoint() || state.style()->userModify() == READ_ONLY)) {
1445 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheInheritedHit);
1447 EInsideLink linkStatus = state.style()->insideLink();
1448 // If the cache item parent style has identical inherited properties to the current parent style then the
1449 // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
1450 state.style()->inheritFrom(cachedMatchedProperties->renderStyle.get());
1452 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
1453 state.style()->setInsideLink(linkStatus);
1456 applyInheritedOnly = true;
1459 // Apply animation properties in order to apply animation results and trigger transitions below.
1460 applyMatchedProperties<AnimationProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1461 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1462 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1463 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1465 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
1466 // high-priority properties first, i.e., those properties that other properties depend on.
1467 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
1468 // and (4) normal important.
1469 state.setLineHeightValue(0);
1470 applyMatchedProperties<HighPriorityProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1471 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1472 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1473 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1475 if (UNLIKELY(isSVGForeignObjectElement(element))) {
1476 // RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should not be scaled again.
1478 // FIXME: The following hijacks the zoom property for foreignObject so that children of foreignObject get the
1479 // correct font-size in case of zooming. 'zoom' is part of HighPriorityProperties, along with other font-related
1480 // properties used as input to the FontBuilder, so resetting it here may cause the FontBuilder to recompute the
1481 // font used as inheritable font for foreignObject content. If we want to support zoom on foreignObject we'll
1482 // need to find another way of handling the SVG zoom model.
1483 state.setEffectiveZoom(RenderStyle::initialZoom());
1486 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) {
1487 state.fontBuilder().setFontDirty(true);
1488 applyInheritedOnly = false;
1491 // If our font got dirtied, go ahead and update it now.
1494 // Line-height is set when we are sure we decided on the font-size.
1495 if (state.lineHeightValue())
1496 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
1498 // Many properties depend on the font. If it changes we just apply all properties.
1499 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription())
1500 applyInheritedOnly = false;
1502 // Now do the normal priority UA properties.
1503 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1505 // Cache the UA properties to pass them to RenderTheme in adjustRenderStyle.
1506 state.cacheUserAgentBorderAndBackground();
1508 // Now do the author and user normal priority properties and all the !important properties.
1509 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1510 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1511 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1512 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1514 loadPendingResources(state);
1516 if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1517 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded);
1518 m_matchedPropertiesCache.add(state.style(), state.parentStyle(), cacheHash, matchResult);
1521 ASSERT(!state.fontBuilder().fontDirty());
1524 CSSPropertyValue::CSSPropertyValue(CSSPropertyID id, const StylePropertySet& propertySet)
1525 : property(id), value(propertySet.getPropertyCSSValue(id).get())
1528 void StyleResolver::enableStats(StatsReportType reportType)
1530 if (m_styleResolverStats)
1532 m_styleResolverStats = StyleResolverStats::create();
1533 m_styleResolverStatsTotals = StyleResolverStats::create();
1534 if (reportType == ReportSlowStats) {
1535 m_styleResolverStats->printMissedCandidateCount = true;
1536 m_styleResolverStatsTotals->printMissedCandidateCount = true;
1540 void StyleResolver::disableStats()
1542 m_styleResolverStatsSequence = 0;
1543 m_styleResolverStats.clear();
1544 m_styleResolverStatsTotals.clear();
1547 void StyleResolver::printStats()
1549 if (!m_styleResolverStats)
1551 fprintf(stderr, "=== Style Resolver Stats (resolve #%u) (%s) ===\n", ++m_styleResolverStatsSequence, m_document.url().string().utf8().data());
1552 fprintf(stderr, "%s\n", m_styleResolverStats->report().utf8().data());
1553 fprintf(stderr, "== Totals ==\n");
1554 fprintf(stderr, "%s\n", m_styleResolverStatsTotals->report().utf8().data());
1557 void StyleResolver::applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle* style)
1559 StyleResolverState state(document(), document().documentElement(), style);
1560 state.setStyle(style);
1562 state.fontBuilder().initForStyleResolve(document(), style);
1564 for (size_t i = 0; i < count; ++i) {
1565 if (properties[i].value) {
1566 // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call,
1567 // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122).
1568 // The updateFont() call below updates the fontMetrics and ensure the proper setting of font-size and line-height.
1569 switch (properties[i].property) {
1570 case CSSPropertyFontSize:
1571 case CSSPropertyLineHeight:
1577 StyleBuilder::applyProperty(properties[i].property, state, properties[i].value);
1582 void StyleResolver::addMediaQueryResults(const MediaQueryResultList& list)
1584 for (size_t i = 0; i < list.size(); ++i)
1585 m_viewportDependentMediaQueryResults.append(list[i]);
1588 bool StyleResolver::mediaQueryAffectedByViewportChange() const
1590 for (unsigned i = 0; i < m_viewportDependentMediaQueryResults.size(); ++i) {
1591 if (m_medium->eval(m_viewportDependentMediaQueryResults[i]->expression()) != m_viewportDependentMediaQueryResults[i]->result())
1597 void StyleResolver::trace(Visitor* visitor)
1599 visitor->trace(m_keyframesRuleMap);
1600 visitor->trace(m_viewportDependentMediaQueryResults);
1601 visitor->trace(m_viewportStyleResolver);
1602 visitor->trace(m_features);
1603 visitor->trace(m_siblingRuleSet);
1604 visitor->trace(m_uncommonAttributeRuleSet);
1605 visitor->trace(m_watchedSelectorsRules);
1606 visitor->trace(m_treeBoundaryCrossingRules);
1607 visitor->trace(m_pendingStyleSheets);
1610 } // namespace WebCore