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 adjustRenderStyle(state, element);
676 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
677 // important rules, but this currently happens here as we require adjustment to have happened
678 // before deciding which properties to transition.
679 if (applyAnimatedProperties(state, element))
680 adjustRenderStyle(state, element);
682 // FIXME: Shouldn't this be on RenderBody::styleDidChange?
683 if (isHTMLBodyElement(*element))
684 document().textLinkColors().setTextColor(state.style()->color());
686 setAnimationUpdateIfNeeded(state, *element);
688 if (state.style()->hasViewportUnits())
689 document().setHasViewportUnits();
691 // Now return the style.
692 return state.takeStyle();
695 PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const RenderStyle& elementStyle, RenderStyle* parentStyle, const StyleKeyframe* keyframe, const AtomicString& animationName)
697 ASSERT(document().frame());
698 ASSERT(documentSettings());
699 ASSERT(!hasPendingAuthorStyleSheets());
701 if (element == document().documentElement())
702 resetDirectionAndWritingModeOnDocument(document());
703 StyleResolverState state(document(), element, parentStyle);
706 result.addMatchedProperties(&keyframe->properties());
708 ASSERT(!state.style());
711 state.setStyle(RenderStyle::clone(&elementStyle));
712 state.setLineHeightValue(0);
714 state.fontBuilder().initForStyleResolve(state.document(), state.style());
716 // We don't need to bother with !important. Since there is only ever one
717 // decl, there's nothing to override. So just add the first properties.
718 // We also don't need to bother with animation properties since the only
719 // relevant one is animation-timing-function and we special-case that in
721 bool inheritedOnly = false;
722 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
724 // If our font got dirtied, go ahead and update it now.
727 // Line-height is set when we are sure we decided on the font-size
728 if (state.lineHeightValue())
729 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
731 // Now do rest of the properties.
732 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
734 // If our font got dirtied by one of the non-essential font props,
735 // go ahead and update it a second time.
738 loadPendingResources(state);
742 return state.takeStyle();
745 // This function is used by the WebAnimations JavaScript API method animate().
746 // FIXME: Remove this when animate() switches away from resolution-dependent parsing.
747 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(Element& element, CSSPropertyID property, CSSValue& value)
749 RefPtr<RenderStyle> style;
750 if (element.renderStyle())
751 style = RenderStyle::clone(element.renderStyle());
753 style = RenderStyle::create();
754 return createAnimatableValueSnapshot(element, property, value, *style);
757 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(Element& element, CSSPropertyID property, CSSValue& value, RenderStyle& style)
759 StyleResolverState state(element.document(), &element);
760 state.setStyle(&style);
761 state.fontBuilder().initForStyleResolve(state.document(), state.style());
762 StyleBuilder::applyProperty(property, state, &value);
763 return CSSAnimatableValueFactory::create(property, style);
766 PassRefPtrWillBeRawPtr<PseudoElement> StyleResolver::createPseudoElementIfNeeded(Element& parent, PseudoId pseudoId)
768 RenderObject* parentRenderer = parent.renderer();
772 if (pseudoId < FIRST_INTERNAL_PSEUDOID && !parentRenderer->style()->hasPseudoStyle(pseudoId))
775 if (pseudoId == BACKDROP && !parent.isInTopLayer())
778 if (!parentRenderer->canHaveGeneratedChildren())
781 RenderStyle* parentStyle = parentRenderer->style();
782 if (RenderStyle* cachedStyle = parentStyle->getCachedPseudoStyle(pseudoId)) {
783 if (!pseudoElementRendererIsNeeded(cachedStyle))
785 return PseudoElement::create(&parent, pseudoId);
788 StyleResolverState state(document(), &parent, parentStyle);
789 if (!pseudoStyleForElementInternal(parent, pseudoId, parentStyle, state))
791 RefPtr<RenderStyle> style = state.takeStyle();
793 parentStyle->addCachedPseudoStyle(style);
795 if (!pseudoElementRendererIsNeeded(style.get()))
798 RefPtrWillBeRawPtr<PseudoElement> pseudo = PseudoElement::create(&parent, pseudoId);
800 setAnimationUpdateIfNeeded(state, *pseudo);
801 if (ActiveAnimations* activeAnimations = pseudo->activeAnimations())
802 activeAnimations->cssAnimations().maybeApplyPendingUpdate(pseudo.get());
803 return pseudo.release();
806 bool StyleResolver::pseudoStyleForElementInternal(Element& element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, StyleResolverState& state)
808 ASSERT(document().frame());
809 ASSERT(documentSettings());
810 ASSERT(pseudoStyleRequest.pseudoId != FIRST_LINE_INHERITED);
812 StyleResolverParentScope::ensureParentStackIsPushed();
814 if (pseudoStyleRequest.allowsInheritance(state.parentStyle())) {
815 state.setStyle(RenderStyle::create());
816 state.style()->inheritFrom(state.parentStyle());
818 state.setStyle(defaultStyleForElement());
819 state.setParentStyle(RenderStyle::clone(state.style()));
822 state.fontBuilder().initForStyleResolve(state.document(), state.style());
824 // Since we don't use pseudo-elements in any of our quirk/print
825 // user agent rules, don't waste time walking those rules.
828 // Check UA, user and author rules.
829 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
830 collector.setPseudoStyleRequest(pseudoStyleRequest);
832 matchUARules(collector);
833 matchAuthorRules(state.element(), collector, false);
835 if (collector.matchedResult().matchedProperties.isEmpty())
838 state.style()->setStyleType(pseudoStyleRequest.pseudoId);
840 applyMatchedProperties(state, collector.matchedResult());
842 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
845 // FIXME: Passing 0 as the Element* introduces a lot of complexity
846 // in the adjustRenderStyle code.
847 adjustRenderStyle(state, 0);
849 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
850 // important rules, but this currently happens here as we require adjustment to have happened
851 // before deciding which properties to transition.
852 if (applyAnimatedProperties(state, element.pseudoElement(pseudoStyleRequest.pseudoId)))
853 adjustRenderStyle(state, 0);
857 if (state.style()->hasViewportUnits())
858 document().setHasViewportUnits();
863 PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle)
869 StyleResolverState state(document(), element, parentStyle);
870 if (!pseudoStyleForElementInternal(*element, pseudoStyleRequest, parentStyle, state))
873 if (PseudoElement* pseudoElement = element->pseudoElement(pseudoStyleRequest.pseudoId))
874 setAnimationUpdateIfNeeded(state, *pseudoElement);
876 // Now return the style.
877 return state.takeStyle();
880 PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
882 ASSERT(!hasPendingAuthorStyleSheets());
883 resetDirectionAndWritingModeOnDocument(document());
884 StyleResolverState state(document(), document().documentElement()); // m_rootElementStyle will be set to the document style.
886 state.setStyle(RenderStyle::create());
887 const RenderStyle* rootElementStyle = state.rootElementStyle() ? state.rootElementStyle() : document().renderStyle();
888 ASSERT(rootElementStyle);
889 state.style()->inheritFrom(rootElementStyle);
891 state.fontBuilder().initForStyleResolve(state.document(), state.style());
893 PageRuleCollector collector(rootElementStyle, pageIndex);
895 collector.matchPageRules(CSSDefaultStyleSheets::instance().defaultPrintStyle());
897 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
898 scopedResolver->matchPageRules(collector);
900 state.setLineHeightValue(0);
901 bool inheritedOnly = false;
903 MatchResult& result = collector.matchedResult();
904 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
906 // If our font got dirtied, go ahead and update it now.
909 // Line-height is set when we are sure we decided on the font-size.
910 if (state.lineHeightValue())
911 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
913 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
915 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
917 loadPendingResources(state);
921 // Now return the style.
922 return state.takeStyle();
925 void StyleResolver::collectViewportRules()
927 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
928 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultStyle(), ViewportStyleResolver::UserAgentOrigin);
930 if (!InspectorInstrumentation::applyViewportStyleOverride(&document(), this))
931 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultViewportStyle(), ViewportStyleResolver::UserAgentOrigin);
933 if (document().isMobileDocument())
934 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultXHTMLMobileProfileStyle(), ViewportStyleResolver::UserAgentOrigin);
936 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
937 scopedResolver->collectViewportRulesTo(this);
939 viewportStyleResolver()->resolve();
942 PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement()
944 StyleResolverState state(document(), 0);
945 state.setStyle(RenderStyle::create());
946 state.fontBuilder().initForStyleResolve(document(), state.style());
947 state.style()->setLineHeight(RenderStyle::initialLineHeight());
948 state.setLineHeightValue(0);
949 state.fontBuilder().setInitial(state.style()->effectiveZoom());
950 state.style()->font().update(document().styleEngine()->fontSelector());
951 return state.takeStyle();
954 PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode)
958 NodeRenderingTraversal::ParentDetails parentDetails;
959 Node* parentNode = NodeRenderingTraversal::parent(textNode, &parentDetails);
960 if (!parentNode || !parentNode->renderStyle())
961 return defaultStyleForElement();
962 return parentNode->renderStyle();
965 void StyleResolver::updateFont(StyleResolverState& state)
967 state.fontBuilder().createFont(document().styleEngine()->fontSelector(), state.parentStyle(), state.style());
968 if (state.fontBuilder().fontSizeHasViewportUnits())
969 state.style()->setHasViewportUnits();
972 PassRefPtrWillBeRawPtr<StyleRuleList> StyleResolver::styleRulesForElement(Element* element, unsigned rulesToInclude)
975 StyleResolverState state(document(), element);
976 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
977 collector.setMode(SelectorChecker::CollectingStyleRules);
978 collectPseudoRulesForElement(element, collector, NOPSEUDO, rulesToInclude);
979 return collector.matchedStyleRuleList();
982 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::pseudoCSSRulesForElement(Element* element, PseudoId pseudoId, unsigned rulesToInclude)
985 StyleResolverState state(document(), element);
986 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
987 collector.setMode(SelectorChecker::CollectingCSSRules);
988 collectPseudoRulesForElement(element, collector, pseudoId, rulesToInclude);
989 return collector.matchedCSSRuleList();
992 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::cssRulesForElement(Element* element, unsigned rulesToInclude)
994 return pseudoCSSRulesForElement(element, NOPSEUDO, rulesToInclude);
997 void StyleResolver::collectPseudoRulesForElement(Element* element, ElementRuleCollector& collector, PseudoId pseudoId, unsigned rulesToInclude)
999 collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
1001 if (rulesToInclude & UAAndUserCSSRules)
1002 matchUARules(collector);
1004 if (rulesToInclude & AuthorCSSRules) {
1005 collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules));
1006 matchAuthorRules(element, collector, rulesToInclude & EmptyCSSRules);
1010 // -------------------------------------------------------------------------------------
1011 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1013 bool StyleResolver::applyAnimatedProperties(StyleResolverState& state, Element* animatingElement)
1015 const Element* element = state.element();
1018 // The animating element may be this element, or its pseudo element. It is
1019 // null when calculating the style for a potential pseudo element that has
1020 // yet to be created.
1021 ASSERT(animatingElement == element || !animatingElement || animatingElement->parentOrShadowHostElement() == element);
1023 if (!(animatingElement && animatingElement->hasActiveAnimations())
1024 && !state.style()->transitions() && !state.style()->animations())
1027 state.setAnimationUpdate(CSSAnimations::calculateUpdate(animatingElement, *element, *state.style(), state.parentStyle(), this));
1028 if (!state.animationUpdate())
1031 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations = state.animationUpdate()->activeInterpolationsForAnimations();
1032 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForTransitions = state.animationUpdate()->activeInterpolationsForTransitions();
1033 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForAnimations);
1034 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForTransitions);
1038 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForAnimations);
1039 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForTransitions);
1041 // Start loading resources used by animations.
1042 loadPendingResources(state);
1044 ASSERT(!state.fontBuilder().fontDirty());
1049 template <StyleResolver::StyleApplicationPass pass>
1050 void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolations)
1052 ASSERT(pass != AnimationProperties);
1054 for (WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >::const_iterator iter = activeInterpolations.begin(); iter != activeInterpolations.end(); ++iter) {
1055 CSSPropertyID property = iter->key;
1056 if (!isPropertyForPass<pass>(property))
1058 const StyleInterpolation* interpolation = toStyleInterpolation(iter->value.get());
1059 interpolation->apply(state);
1063 static inline bool isValidCueStyleProperty(CSSPropertyID id)
1066 case CSSPropertyBackground:
1067 case CSSPropertyBackgroundAttachment:
1068 case CSSPropertyBackgroundClip:
1069 case CSSPropertyBackgroundColor:
1070 case CSSPropertyBackgroundImage:
1071 case CSSPropertyBackgroundOrigin:
1072 case CSSPropertyBackgroundPosition:
1073 case CSSPropertyBackgroundPositionX:
1074 case CSSPropertyBackgroundPositionY:
1075 case CSSPropertyBackgroundRepeat:
1076 case CSSPropertyBackgroundRepeatX:
1077 case CSSPropertyBackgroundRepeatY:
1078 case CSSPropertyBackgroundSize:
1079 case CSSPropertyColor:
1080 case CSSPropertyFont:
1081 case CSSPropertyFontFamily:
1082 case CSSPropertyFontSize:
1083 case CSSPropertyFontStyle:
1084 case CSSPropertyFontVariant:
1085 case CSSPropertyFontWeight:
1086 case CSSPropertyLineHeight:
1087 case CSSPropertyOpacity:
1088 case CSSPropertyOutline:
1089 case CSSPropertyOutlineColor:
1090 case CSSPropertyOutlineOffset:
1091 case CSSPropertyOutlineStyle:
1092 case CSSPropertyOutlineWidth:
1093 case CSSPropertyVisibility:
1094 case CSSPropertyWhiteSpace:
1095 // FIXME: 'text-decoration' shorthand to be handled when available.
1096 // See https://chromiumcodereview.appspot.com/19516002 for details.
1097 case CSSPropertyTextDecoration:
1098 case CSSPropertyTextShadow:
1099 case CSSPropertyBorderStyle:
1101 case CSSPropertyTextDecorationLine:
1102 case CSSPropertyTextDecorationStyle:
1103 case CSSPropertyTextDecorationColor:
1104 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1111 static inline bool isValidFirstLetterStyleProperty(CSSPropertyID id)
1114 // Valid ::first-letter properties listed in spec:
1115 // http://www.w3.org/TR/css3-selectors/#application-in-css
1116 case CSSPropertyBackgroundAttachment:
1117 case CSSPropertyBackgroundBlendMode:
1118 case CSSPropertyBackgroundClip:
1119 case CSSPropertyBackgroundColor:
1120 case CSSPropertyBackgroundImage:
1121 case CSSPropertyBackgroundOrigin:
1122 case CSSPropertyBackgroundPosition:
1123 case CSSPropertyBackgroundPositionX:
1124 case CSSPropertyBackgroundPositionY:
1125 case CSSPropertyBackgroundRepeat:
1126 case CSSPropertyBackgroundRepeatX:
1127 case CSSPropertyBackgroundRepeatY:
1128 case CSSPropertyBackgroundSize:
1129 case CSSPropertyBorderBottomColor:
1130 case CSSPropertyBorderBottomLeftRadius:
1131 case CSSPropertyBorderBottomRightRadius:
1132 case CSSPropertyBorderBottomStyle:
1133 case CSSPropertyBorderBottomWidth:
1134 case CSSPropertyBorderImageOutset:
1135 case CSSPropertyBorderImageRepeat:
1136 case CSSPropertyBorderImageSlice:
1137 case CSSPropertyBorderImageSource:
1138 case CSSPropertyBorderImageWidth:
1139 case CSSPropertyBorderLeftColor:
1140 case CSSPropertyBorderLeftStyle:
1141 case CSSPropertyBorderLeftWidth:
1142 case CSSPropertyBorderRightColor:
1143 case CSSPropertyBorderRightStyle:
1144 case CSSPropertyBorderRightWidth:
1145 case CSSPropertyBorderTopColor:
1146 case CSSPropertyBorderTopLeftRadius:
1147 case CSSPropertyBorderTopRightRadius:
1148 case CSSPropertyBorderTopStyle:
1149 case CSSPropertyBorderTopWidth:
1150 case CSSPropertyColor:
1151 case CSSPropertyFloat:
1152 case CSSPropertyFont:
1153 case CSSPropertyFontFamily:
1154 case CSSPropertyFontKerning:
1155 case CSSPropertyFontSize:
1156 case CSSPropertyFontStretch:
1157 case CSSPropertyFontStyle:
1158 case CSSPropertyFontVariant:
1159 case CSSPropertyFontVariantLigatures:
1160 case CSSPropertyFontWeight:
1161 case CSSPropertyLetterSpacing:
1162 case CSSPropertyLineHeight:
1163 case CSSPropertyMarginBottom:
1164 case CSSPropertyMarginLeft:
1165 case CSSPropertyMarginRight:
1166 case CSSPropertyMarginTop:
1167 case CSSPropertyPaddingBottom:
1168 case CSSPropertyPaddingLeft:
1169 case CSSPropertyPaddingRight:
1170 case CSSPropertyPaddingTop:
1171 case CSSPropertyTextTransform:
1172 case CSSPropertyVerticalAlign:
1173 case CSSPropertyWebkitBackgroundClip:
1174 case CSSPropertyWebkitBackgroundComposite:
1175 case CSSPropertyWebkitBackgroundOrigin:
1176 case CSSPropertyWebkitBackgroundSize:
1177 case CSSPropertyWebkitBorderAfter:
1178 case CSSPropertyWebkitBorderAfterColor:
1179 case CSSPropertyWebkitBorderAfterStyle:
1180 case CSSPropertyWebkitBorderAfterWidth:
1181 case CSSPropertyWebkitBorderBefore:
1182 case CSSPropertyWebkitBorderBeforeColor:
1183 case CSSPropertyWebkitBorderBeforeStyle:
1184 case CSSPropertyWebkitBorderBeforeWidth:
1185 case CSSPropertyWebkitBorderEnd:
1186 case CSSPropertyWebkitBorderEndColor:
1187 case CSSPropertyWebkitBorderEndStyle:
1188 case CSSPropertyWebkitBorderEndWidth:
1189 case CSSPropertyWebkitBorderFit:
1190 case CSSPropertyWebkitBorderHorizontalSpacing:
1191 case CSSPropertyWebkitBorderImage:
1192 case CSSPropertyWebkitBorderRadius:
1193 case CSSPropertyWebkitBorderStart:
1194 case CSSPropertyWebkitBorderStartColor:
1195 case CSSPropertyWebkitBorderStartStyle:
1196 case CSSPropertyWebkitBorderStartWidth:
1197 case CSSPropertyWebkitBorderVerticalSpacing:
1198 case CSSPropertyWebkitFontSmoothing:
1199 case CSSPropertyWebkitMarginAfter:
1200 case CSSPropertyWebkitMarginAfterCollapse:
1201 case CSSPropertyWebkitMarginBefore:
1202 case CSSPropertyWebkitMarginBeforeCollapse:
1203 case CSSPropertyWebkitMarginBottomCollapse:
1204 case CSSPropertyWebkitMarginCollapse:
1205 case CSSPropertyWebkitMarginEnd:
1206 case CSSPropertyWebkitMarginStart:
1207 case CSSPropertyWebkitMarginTopCollapse:
1208 case CSSPropertyWordSpacing:
1210 case CSSPropertyTextDecorationColor:
1211 case CSSPropertyTextDecorationLine:
1212 case CSSPropertyTextDecorationStyle:
1213 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1215 // text-shadow added in text decoration spec:
1216 // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property
1217 case CSSPropertyTextShadow:
1218 // box-shadox added in CSS3 backgrounds spec:
1219 // http://www.w3.org/TR/css3-background/#placement
1220 case CSSPropertyBoxShadow:
1221 case CSSPropertyWebkitBoxShadow:
1222 // Properties that we currently support outside of spec.
1223 case CSSPropertyWebkitLineBoxContain:
1224 case CSSPropertyVisibility:
1232 // FIXME: Consider refactoring to create a new class which owns the following
1233 // first/last/range properties.
1234 // This method returns the first CSSPropertyId of properties which generate
1235 // animations. All animation properties are obtained by using
1236 // firstCSSPropertyId<AnimationProperties> and
1237 // lastCSSPropertyId<AnimationProperties>.
1238 // c.f. //src/third_party/WebKit/Source/core/css/CSSPropertyNames.in.
1239 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::AnimationProperties>()
1241 COMPILE_ASSERT(firstCSSProperty == CSSPropertyDisplay, CSS_first_animation_property_should_be_first_property);
1242 return CSSPropertyDisplay;
1245 // This method returns the first CSSPropertyId of properties which generate
1247 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::AnimationProperties>()
1249 COMPILE_ASSERT(CSSPropertyTransitionTimingFunction == CSSPropertyColor - 1, CSS_transition_timing_is_last_animation_property);
1250 return CSSPropertyTransitionTimingFunction;
1253 // This method returns the first CSSPropertyId of high priority properties.
1254 // Other properties can depend on high priority properties. For example,
1255 // border-color property with currentColor value depends on color property.
1256 // All high priority properties are obtained by using
1257 // firstCSSPropertyId<HighPriorityProperties> and
1258 // lastCSSPropertyId<HighPriorityProperties>.
1259 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::HighPriorityProperties>()
1261 COMPILE_ASSERT(CSSPropertyTransitionTimingFunction + 1 == CSSPropertyColor, CSS_color_is_first_high_priority_property);
1262 return CSSPropertyColor;
1265 // This method returns the last CSSPropertyId of high priority properties.
1266 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::HighPriorityProperties>()
1268 COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyColor + 17, CSS_line_height_is_end_of_high_prioity_property_range);
1269 COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyLineHeight - 1, CSS_zoom_is_before_line_height);
1270 return CSSPropertyLineHeight;
1273 // This method returns the first CSSPropertyId of remaining properties,
1274 // i.e. low priority properties. No properties depend on low priority
1275 // properties. So we don't need to resolve such properties quickly.
1276 // All low priority properties are obtained by using
1277 // firstCSSPropertyId<LowPriorityProperties> and
1278 // lastCSSPropertyId<LowPriorityProperties>.
1279 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::LowPriorityProperties>()
1281 COMPILE_ASSERT(CSSPropertyBackground == CSSPropertyLineHeight + 1, CSS_background_is_first_low_priority_property);
1282 return CSSPropertyBackground;
1285 // This method returns the last CSSPropertyId of low priority properties.
1286 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::LowPriorityProperties>()
1288 return static_cast<CSSPropertyID>(lastCSSProperty);
1291 template <StyleResolver::StyleApplicationPass pass>
1292 bool StyleResolver::isPropertyForPass(CSSPropertyID property)
1294 return firstCSSPropertyId<pass>() <= property && property <= lastCSSPropertyId<pass>();
1297 // This method expands all shorthand property to longhand properties
1298 // considering StyleApplicationPass, and apply each expanded longhand property.
1299 // For example, if StyleApplicationPass is AnimationProperties, all shorthand
1300 // is expaneded to display, -webkit-animation, -webkit-animation-delay, ...,
1301 // transition-timing-function. So each property's value will be applied
1302 // according to all's value (initial, inherit or unset).
1303 template <StyleResolver::StyleApplicationPass pass>
1304 void StyleResolver::applyAllProperty(StyleResolverState& state, CSSValue* allValue)
1306 bool isUnsetValue = !allValue->isInitialValue() && !allValue->isInheritedValue();
1307 unsigned startCSSProperty = firstCSSPropertyId<pass>();
1308 unsigned endCSSProperty = lastCSSPropertyId<pass>();
1310 for (unsigned i = startCSSProperty; i <= endCSSProperty; ++i) {
1311 CSSPropertyID propertyId = static_cast<CSSPropertyID>(i);
1313 // StyleBuilder does not allow any expanded shorthands.
1314 if (isExpandedShorthandForAll(propertyId))
1317 // all shorthand spec says:
1318 // The all property is a shorthand that resets all CSS properties
1319 // except direction and unicode-bidi.
1320 // c.f. http://dev.w3.org/csswg/css-cascade/#all-shorthand
1321 // We skip applyProperty when a given property is unicode-bidi or
1323 if (!CSSProperty::isAffectedByAllProperty(propertyId))
1327 if (!isUnsetValue) {
1330 if (CSSProperty::isInheritedProperty(propertyId))
1331 value = cssValuePool().createInheritedValue().get();
1333 value = cssValuePool().createExplicitInitialValue().get();
1335 StyleBuilder::applyProperty(propertyId, state, value);
1339 template <StyleResolver::StyleApplicationPass pass>
1340 void StyleResolver::applyProperties(StyleResolverState& state, const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType)
1342 state.setCurrentRule(rule);
1344 unsigned propertyCount = properties->propertyCount();
1345 for (unsigned i = 0; i < propertyCount; ++i) {
1346 StylePropertySet::PropertyReference current = properties->propertyAt(i);
1347 if (isImportant != current.isImportant())
1350 CSSPropertyID property = current.id();
1351 if (property == CSSPropertyAll) {
1352 applyAllProperty<pass>(state, current.value());
1356 if (inheritedOnly && !current.isInherited()) {
1357 // If the property value is explicitly inherited, we need to apply further non-inherited properties
1358 // as they might override the value inherited here. For this reason we don't allow declarations with
1359 // explicitly inherited properties to be cached.
1360 ASSERT(!current.value()->isInheritedValue());
1364 if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property))
1366 if (propertyWhitelistType == PropertyWhitelistFirstLetter && !isValidFirstLetterStyleProperty(property))
1368 if (!isPropertyForPass<pass>(property))
1370 if (pass == HighPriorityProperties && property == CSSPropertyLineHeight)
1371 state.setLineHeightValue(current.value());
1373 StyleBuilder::applyProperty(current.id(), state, current.value());
1377 template <StyleResolver::StyleApplicationPass pass>
1378 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
1380 if (startIndex == -1)
1383 if (state.style()->insideLink() != NotInsideLink) {
1384 for (int i = startIndex; i <= endIndex; ++i) {
1385 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1386 unsigned linkMatchType = matchedProperties.linkMatchType;
1387 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
1388 state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink);
1389 state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited);
1391 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1393 state.setApplyPropertyToRegularStyle(true);
1394 state.setApplyPropertyToVisitedLinkStyle(false);
1397 for (int i = startIndex; i <= endIndex; ++i) {
1398 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1399 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1403 static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
1405 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
1408 void StyleResolver::invalidateMatchedPropertiesCache()
1410 m_matchedPropertiesCache.clear();
1413 void StyleResolver::notifyResizeForViewportUnits()
1415 collectViewportRules();
1416 m_matchedPropertiesCache.clearViewportDependent();
1419 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult)
1421 const Element* element = state.element();
1424 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply);
1426 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
1427 bool applyInheritedOnly = false;
1428 const CachedMatchedProperties* cachedMatchedProperties = 0;
1430 if (cacheHash && (cachedMatchedProperties = m_matchedPropertiesCache.find(cacheHash, state, matchResult))
1431 && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1432 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit);
1433 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
1434 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the
1435 // element context. This is fast and saves memory by reusing the style data structures.
1436 state.style()->copyNonInheritedFrom(cachedMatchedProperties->renderStyle.get());
1437 if (state.parentStyle()->inheritedDataShared(cachedMatchedProperties->parentRenderStyle.get()) && !isAtShadowBoundary(element)
1438 && (!state.distributedToInsertionPoint() || state.style()->userModify() == READ_ONLY)) {
1439 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheInheritedHit);
1441 EInsideLink linkStatus = state.style()->insideLink();
1442 // If the cache item parent style has identical inherited properties to the current parent style then the
1443 // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
1444 state.style()->inheritFrom(cachedMatchedProperties->renderStyle.get());
1446 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
1447 state.style()->setInsideLink(linkStatus);
1450 applyInheritedOnly = true;
1453 // Apply animation properties in order to apply animation results and trigger transitions below.
1454 applyMatchedProperties<AnimationProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1455 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1456 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1457 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1459 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
1460 // high-priority properties first, i.e., those properties that other properties depend on.
1461 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
1462 // and (4) normal important.
1463 state.setLineHeightValue(0);
1464 applyMatchedProperties<HighPriorityProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1465 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1466 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1467 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1469 if (UNLIKELY(isSVGForeignObjectElement(element))) {
1470 // RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should not be scaled again.
1472 // FIXME: The following hijacks the zoom property for foreignObject so that children of foreignObject get the
1473 // correct font-size in case of zooming. 'zoom' is part of HighPriorityProperties, along with other font-related
1474 // properties used as input to the FontBuilder, so resetting it here may cause the FontBuilder to recompute the
1475 // font used as inheritable font for foreignObject content. If we want to support zoom on foreignObject we'll
1476 // need to find another way of handling the SVG zoom model.
1477 state.setEffectiveZoom(RenderStyle::initialZoom());
1480 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) {
1481 state.fontBuilder().setFontDirty(true);
1482 applyInheritedOnly = false;
1485 // If our font got dirtied, go ahead and update it now.
1488 // Line-height is set when we are sure we decided on the font-size.
1489 if (state.lineHeightValue())
1490 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
1492 // Many properties depend on the font. If it changes we just apply all properties.
1493 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription())
1494 applyInheritedOnly = false;
1496 // Now do the normal priority UA properties.
1497 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1499 // Cache the UA properties to pass them to RenderTheme in adjustRenderStyle.
1500 state.cacheUserAgentBorderAndBackground();
1502 // Now do the author and user normal priority properties and all the !important properties.
1503 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1504 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1505 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1506 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1508 loadPendingResources(state);
1510 if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1511 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded);
1512 m_matchedPropertiesCache.add(state.style(), state.parentStyle(), cacheHash, matchResult);
1515 ASSERT(!state.fontBuilder().fontDirty());
1518 CSSPropertyValue::CSSPropertyValue(CSSPropertyID id, const StylePropertySet& propertySet)
1519 : property(id), value(propertySet.getPropertyCSSValue(id).get())
1522 void StyleResolver::enableStats(StatsReportType reportType)
1524 if (m_styleResolverStats)
1526 m_styleResolverStats = StyleResolverStats::create();
1527 m_styleResolverStatsTotals = StyleResolverStats::create();
1528 if (reportType == ReportSlowStats) {
1529 m_styleResolverStats->printMissedCandidateCount = true;
1530 m_styleResolverStatsTotals->printMissedCandidateCount = true;
1534 void StyleResolver::disableStats()
1536 m_styleResolverStatsSequence = 0;
1537 m_styleResolverStats.clear();
1538 m_styleResolverStatsTotals.clear();
1541 void StyleResolver::printStats()
1543 if (!m_styleResolverStats)
1545 fprintf(stderr, "=== Style Resolver Stats (resolve #%u) (%s) ===\n", ++m_styleResolverStatsSequence, m_document.url().string().utf8().data());
1546 fprintf(stderr, "%s\n", m_styleResolverStats->report().utf8().data());
1547 fprintf(stderr, "== Totals ==\n");
1548 fprintf(stderr, "%s\n", m_styleResolverStatsTotals->report().utf8().data());
1551 void StyleResolver::applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle* style)
1553 StyleResolverState state(document(), document().documentElement(), style);
1554 state.setStyle(style);
1556 state.fontBuilder().initForStyleResolve(document(), style);
1558 for (size_t i = 0; i < count; ++i) {
1559 if (properties[i].value) {
1560 // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call,
1561 // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122).
1562 // The updateFont() call below updates the fontMetrics and ensure the proper setting of font-size and line-height.
1563 switch (properties[i].property) {
1564 case CSSPropertyFontSize:
1565 case CSSPropertyLineHeight:
1571 StyleBuilder::applyProperty(properties[i].property, state, properties[i].value);
1576 void StyleResolver::addMediaQueryResults(const MediaQueryResultList& list)
1578 for (size_t i = 0; i < list.size(); ++i)
1579 m_viewportDependentMediaQueryResults.append(list[i]);
1582 bool StyleResolver::mediaQueryAffectedByViewportChange() const
1584 for (unsigned i = 0; i < m_viewportDependentMediaQueryResults.size(); ++i) {
1585 if (m_medium->eval(m_viewportDependentMediaQueryResults[i]->expression()) != m_viewportDependentMediaQueryResults[i]->result())
1591 void StyleResolver::trace(Visitor* visitor)
1593 visitor->trace(m_keyframesRuleMap);
1594 visitor->trace(m_viewportDependentMediaQueryResults);
1595 visitor->trace(m_viewportStyleResolver);
1596 visitor->trace(m_features);
1597 visitor->trace(m_siblingRuleSet);
1598 visitor->trace(m_uncommonAttributeRuleSet);
1599 visitor->trace(m_watchedSelectorsRules);
1600 visitor->trace(m_treeBoundaryCrossingRules);
1601 visitor->trace(m_pendingStyleSheets);
1604 } // namespace WebCore