2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11 * Copyright (C) 2012 Google Inc. All rights reserved.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB. If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 #include "core/css/resolver/StyleResolver.h"
32 #include "CSSPropertyNames.h"
33 #include "HTMLNames.h"
34 #include "RuntimeEnabledFeatures.h"
35 #include "StylePropertyShorthand.h"
36 #include "core/animation/ActiveAnimations.h"
37 #include "core/animation/AnimatableValue.h"
38 #include "core/animation/Animation.h"
39 #include "core/animation/DocumentTimeline.h"
40 #include "core/animation/css/CSSAnimatableValueFactory.h"
41 #include "core/animation/css/CSSAnimations.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/parser/BisonCSSParser.h"
48 #include "core/css/CSSReflectValue.h"
49 #include "core/css/CSSRuleList.h"
50 #include "core/css/CSSSelector.h"
51 #include "core/css/CSSStyleRule.h"
52 #include "core/css/CSSValueList.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/resolver/AnimatedStyleBuilder.h"
61 #include "core/css/resolver/MatchResult.h"
62 #include "core/css/resolver/MediaQueryResult.h"
63 #include "core/css/resolver/SharedStyleFinder.h"
64 #include "core/css/resolver/StyleAdjuster.h"
65 #include "core/css/resolver/StyleResolverParentScope.h"
66 #include "core/css/resolver/StyleResolverStats.h"
67 #include "core/css/resolver/ViewportStyleResolver.h"
68 #include "core/dom/CSSSelectorWatch.h"
69 #include "core/dom/NodeRenderStyle.h"
70 #include "core/dom/StyleEngine.h"
71 #include "core/dom/Text.h"
72 #include "core/dom/shadow/ElementShadow.h"
73 #include "core/dom/shadow/ShadowRoot.h"
74 #include "core/frame/FrameView.h"
75 #include "core/frame/LocalFrame.h"
76 #include "core/html/HTMLIFrameElement.h"
77 #include "core/inspector/InspectorInstrumentation.h"
78 #include "core/rendering/RenderView.h"
79 #include "core/rendering/style/KeyframeList.h"
80 #include "core/svg/SVGDocumentExtensions.h"
81 #include "core/svg/SVGElement.h"
82 #include "core/svg/SVGFontFaceElement.h"
83 #include "wtf/StdLibExtras.h"
89 using namespace WebCore;
91 void setAnimationUpdateIfNeeded(StyleResolverState& state, Element& element)
93 // If any changes to CSS Animations were detected, stash the update away for application after the
94 // render object is updated if we're in the appropriate scope.
95 if (state.animationUpdate())
96 element.ensureActiveAnimations().cssAnimations().setPendingUpdate(state.takeAnimationUpdate());
103 using namespace HTMLNames;
105 RenderStyle* StyleResolver::s_styleNotYetAvailable;
107 static StylePropertySet* leftToRightDeclaration()
109 DEFINE_STATIC_REF(MutableStylePropertySet, leftToRightDecl, (MutableStylePropertySet::create()));
110 if (leftToRightDecl->isEmpty())
111 leftToRightDecl->setProperty(CSSPropertyDirection, CSSValueLtr);
112 return leftToRightDecl;
115 static StylePropertySet* rightToLeftDeclaration()
117 DEFINE_STATIC_REF(MutableStylePropertySet, rightToLeftDecl, (MutableStylePropertySet::create()));
118 if (rightToLeftDecl->isEmpty())
119 rightToLeftDecl->setProperty(CSSPropertyDirection, CSSValueRtl);
120 return rightToLeftDecl;
123 static void addFontFaceRule(Document* document, CSSFontSelector* cssFontSelector, const StyleRuleFontFace* fontFaceRule)
125 RefPtrWillBeRawPtr<FontFace> fontFace = FontFace::create(document, fontFaceRule);
127 cssFontSelector->fontFaceCache()->add(cssFontSelector, fontFaceRule, fontFace);
130 StyleResolver::StyleResolver(Document& document)
131 : m_document(document)
132 , m_viewportStyleResolver(ViewportStyleResolver::create(&document))
133 , m_needCollectFeatures(false)
134 , m_styleResourceLoader(document.fetcher())
135 , m_styleSharingDepth(0)
136 , m_styleResolverStatsSequence(0)
139 FrameView* view = document.view();
141 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), &view->frame()));
143 m_medium = adoptPtr(new MediaQueryEvaluator("all"));
147 initWatchedSelectorRules(CSSSelectorWatch::from(document).watchedCallbackSelectors());
149 #if ENABLE(SVG_FONTS)
150 if (document.svgExtensions()) {
151 const HashSet<SVGFontFaceElement*>& svgFontFaceElements = document.svgExtensions()->svgFontFaceElements();
152 HashSet<SVGFontFaceElement*>::const_iterator end = svgFontFaceElements.end();
153 for (HashSet<SVGFontFaceElement*>::const_iterator it = svgFontFaceElements.begin(); it != end; ++it)
154 addFontFaceRule(&document, document.styleEngine()->fontSelector(), (*it)->fontFaceRule());
159 void StyleResolver::initWatchedSelectorRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRule> >& watchedSelectors)
161 if (!watchedSelectors.size())
163 m_watchedSelectorsRules = RuleSet::create();
164 for (unsigned i = 0; i < watchedSelectors.size(); ++i)
165 m_watchedSelectorsRules->addStyleRule(watchedSelectors[i].get(), RuleHasNoSpecialState);
168 void StyleResolver::lazyAppendAuthorStyleSheets(unsigned firstNew, const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
170 unsigned size = styleSheets.size();
171 for (unsigned i = firstNew; i < size; ++i)
172 m_pendingStyleSheets.add(styleSheets[i].get());
175 void StyleResolver::removePendingAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
177 for (unsigned i = 0; i < styleSheets.size(); ++i)
178 m_pendingStyleSheets.remove(styleSheets[i].get());
181 void StyleResolver::appendCSSStyleSheet(CSSStyleSheet* cssSheet)
184 ASSERT(!cssSheet->disabled());
185 if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), &m_viewportDependentMediaQueryResults))
188 ContainerNode* scopingNode = ScopedStyleResolver::scopingNodeFor(document(), cssSheet);
192 ScopedStyleResolver* resolver = ensureScopedStyleResolver(scopingNode);
194 resolver->addRulesFromSheet(cssSheet, *m_medium, this);
197 void StyleResolver::appendPendingAuthorStyleSheets()
199 setBuildScopedStyleTreeInDocumentOrder(false);
200 for (WillBeHeapListHashSet<RawPtrWillBeMember<CSSStyleSheet>, 16>::iterator it = m_pendingStyleSheets.begin(); it != m_pendingStyleSheets.end(); ++it)
201 appendCSSStyleSheet(*it);
203 m_pendingStyleSheets.clear();
204 finishAppendAuthorStyleSheets();
207 void StyleResolver::appendAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
209 // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver
210 // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated.
211 unsigned size = styleSheets.size();
212 for (unsigned i = 0; i < size; ++i)
213 appendCSSStyleSheet(styleSheets[i].get());
216 void StyleResolver::finishAppendAuthorStyleSheets()
220 if (document().renderer() && document().renderer()->style())
221 document().renderer()->style()->font().update(document().styleEngine()->fontSelector());
223 collectViewportRules();
225 document().styleEngine()->resetCSSFeatureFlags(m_features);
228 void StyleResolver::resetRuleFeatures()
230 // Need to recreate RuleFeatureSet.
232 m_siblingRuleSet.clear();
233 m_uncommonAttributeRuleSet.clear();
234 m_needCollectFeatures = true;
237 void StyleResolver::processScopedRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, ContainerNode& scope)
239 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes> > keyframesRules = authorRules.keyframesRules();
240 for (unsigned i = 0; i < keyframesRules.size(); ++i)
241 ensureScopedStyleResolver(&scope)->addKeyframeStyle(keyframesRules[i]);
243 m_treeBoundaryCrossingRules.addTreeBoundaryCrossingRules(authorRules, scope, parentStyleSheet);
245 // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for the moment.
246 if (scope.isDocumentNode()) {
247 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace> > fontFaceRules = authorRules.fontFaceRules();
248 for (unsigned i = 0; i < fontFaceRules.size(); ++i)
249 addFontFaceRule(&m_document, document().styleEngine()->fontSelector(), fontFaceRules[i]);
250 if (fontFaceRules.size())
251 invalidateMatchedPropertiesCache();
255 void StyleResolver::resetAuthorStyle(const ContainerNode* scopingNode)
257 // FIXME: When chanking scoped attribute, scopingNode's hasScopedHTMLStyleChild has been already modified.
258 // So we cannot use hasScopedHTMLStyleChild flag here.
259 ScopedStyleResolver* resolver = scopingNode ? m_styleTree.lookupScopedStyleResolverFor(scopingNode) : m_styleTree.scopedStyleResolverForDocument();
263 m_treeBoundaryCrossingRules.reset(scopingNode);
265 resolver->resetAuthorStyle();
270 m_styleTree.remove(scopingNode);
273 static PassOwnPtrWillBeRawPtr<RuleSet> makeRuleSet(const Vector<RuleFeature>& rules)
275 size_t size = rules.size();
278 OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create();
279 for (size_t i = 0; i < size; ++i)
280 ruleSet->addRule(rules[i].rule, rules[i].selectorIndex, rules[i].hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState);
281 return ruleSet.release();
284 void StyleResolver::collectFeatures()
287 // Collect all ids and rules using sibling selectors (:first-child and similar)
288 // in the current set of stylesheets. Style sharing code uses this information to reject
289 // sharing candidates.
290 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
291 if (defaultStyleSheets.defaultStyle())
292 m_features.add(defaultStyleSheets.defaultStyle()->features());
294 if (document().isViewSource())
295 m_features.add(defaultStyleSheets.defaultViewSourceStyle()->features());
297 if (m_watchedSelectorsRules)
298 m_features.add(m_watchedSelectorsRules->features());
300 m_treeBoundaryCrossingRules.collectFeaturesTo(m_features);
302 m_styleTree.collectFeaturesTo(m_features);
304 m_siblingRuleSet = makeRuleSet(m_features.siblingRules);
305 m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules);
306 m_needCollectFeatures = false;
309 bool StyleResolver::hasRulesForId(const AtomicString& id) const
311 return m_features.hasSelectorForId(id);
314 void StyleResolver::addToStyleSharingList(Element& element)
316 // Never add elements to the style sharing list if we're not in a recalcStyle,
317 // otherwise we could leave stale pointers in there.
318 if (!document().inStyleRecalc())
320 INCREMENT_STYLE_STATS_COUNTER(*this, sharedStyleCandidates);
321 StyleSharingList& list = styleSharingList();
322 if (list.size() >= styleSharingListSize)
323 list.remove(--list.end());
324 list.prepend(&element);
327 StyleSharingList& StyleResolver::styleSharingList()
329 m_styleSharingLists.resize(styleSharingMaxDepth);
331 // We never put things at depth 0 into the list since that's only the <html> element
332 // and it has no siblings or cousins to share with.
333 unsigned depth = std::max(std::min(m_styleSharingDepth, styleSharingMaxDepth), 1u) - 1u;
336 if (!m_styleSharingLists[depth])
337 m_styleSharingLists[depth] = adoptPtr(new StyleSharingList);
338 return *m_styleSharingLists[depth];
341 void StyleResolver::clearStyleSharingList()
343 m_styleSharingLists.resize(0);
346 void StyleResolver::fontsNeedUpdate(CSSFontSelector* fontSelector)
348 invalidateMatchedPropertiesCache();
349 m_document.setNeedsStyleRecalc(SubtreeStyleChange);
352 void StyleResolver::pushParentElement(Element& parent)
354 const ContainerNode* parentsParent = parent.parentOrShadowHostElement();
356 // We are not always invoked consistently. For example, script execution can cause us to enter
357 // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree.
358 // Reset the stack in this case, or if we see a new root element.
359 // Otherwise just push the new parent.
360 if (!parentsParent || m_selectorFilter.parentStackIsEmpty())
361 m_selectorFilter.setupParentStack(parent);
363 m_selectorFilter.pushParent(parent);
365 // Note: We mustn't skip ShadowRoot nodes for the scope stack.
366 m_styleTree.pushStyleCache(parent, parent.parentOrShadowHostNode());
369 void StyleResolver::popParentElement(Element& parent)
371 // Note that we may get invoked for some random elements in some wacky cases during style resolve.
372 // Pause maintaining the stack in this case.
373 if (m_selectorFilter.parentStackIsConsistent(&parent))
374 m_selectorFilter.popParent();
376 m_styleTree.popStyleCache(parent);
379 void StyleResolver::pushParentShadowRoot(const ShadowRoot& shadowRoot)
381 ASSERT(shadowRoot.host());
382 m_styleTree.pushStyleCache(shadowRoot, shadowRoot.host());
385 void StyleResolver::popParentShadowRoot(const ShadowRoot& shadowRoot)
387 ASSERT(shadowRoot.host());
388 m_styleTree.popStyleCache(shadowRoot);
391 StyleResolver::~StyleResolver()
395 static inline bool applyAuthorStylesOf(const Element* element)
397 return element->treeScope().applyAuthorStyles();
400 void StyleResolver::matchAuthorRulesForShadowHost(Element* element, ElementRuleCollector& collector, bool includeEmptyRules, Vector<ScopedStyleResolver*, 8>& resolvers, Vector<ScopedStyleResolver*, 8>& resolversInShadowTree)
402 collector.clearMatchedRules();
403 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
405 CascadeScope cascadeScope = 0;
406 CascadeOrder cascadeOrder = 0;
407 bool applyAuthorStyles = applyAuthorStylesOf(element);
409 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j)
410 resolversInShadowTree.at(j)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope, cascadeOrder++);
412 if (resolvers.isEmpty() || resolvers.first()->treeScope() != element->treeScope())
414 cascadeOrder += resolvers.size();
415 for (unsigned i = 0; i < resolvers.size(); ++i)
416 resolvers.at(i)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, --cascadeOrder);
418 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
419 collector.sortAndTransferMatchedRules();
422 void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules)
424 collector.clearMatchedRules();
425 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
427 bool applyAuthorStyles = applyAuthorStylesOf(element);
428 if (m_styleTree.hasOnlyScopedResolverForDocument()) {
429 m_styleTree.scopedStyleResolverForDocument()->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, ignoreCascadeScope);
430 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
431 collector.sortAndTransferMatchedRules();
435 Vector<ScopedStyleResolver*, 8> resolvers;
436 m_styleTree.resolveScopedStyles(element, resolvers);
438 Vector<ScopedStyleResolver*, 8> resolversInShadowTree;
439 m_styleTree.collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree);
440 if (!resolversInShadowTree.isEmpty()) {
441 matchAuthorRulesForShadowHost(element, collector, includeEmptyRules, resolvers, resolversInShadowTree);
445 if (resolvers.isEmpty())
448 CascadeScope cascadeScope = 0;
449 CascadeOrder cascadeOrder = resolvers.size();
450 for (unsigned i = 0; i < resolvers.size(); ++i, --cascadeOrder) {
451 ScopedStyleResolver* resolver = resolvers.at(i);
452 // FIXME: Need to clarify how to treat style scoped.
453 resolver->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, resolver->treeScope() == element->treeScope() && resolver->scopingNode().isShadowRoot() ? 0 : cascadeOrder);
456 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
457 collector.sortAndTransferMatchedRules();
460 void StyleResolver::matchWatchSelectorRules(ElementRuleCollector& collector)
462 if (!m_watchedSelectorsRules)
465 collector.clearMatchedRules();
466 collector.matchedResult().ranges.lastUserRule = collector.matchedResult().matchedProperties.size() - 1;
468 MatchRequest matchRequest(m_watchedSelectorsRules.get());
469 RuleRange ruleRange = collector.matchedResult().ranges.userRuleRange();
470 collector.collectMatchingRules(matchRequest, ruleRange);
472 collector.sortAndTransferMatchedRules();
475 void StyleResolver::matchUARules(ElementRuleCollector& collector)
477 collector.setMatchingUARules(true);
479 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
480 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
481 ? defaultStyleSheets.defaultPrintStyle() : defaultStyleSheets.defaultStyle();
482 matchUARules(collector, userAgentStyleSheet);
484 // In quirks mode, we match rules from the quirks user agent sheet.
485 if (document().inQuirksMode())
486 matchUARules(collector, defaultStyleSheets.defaultQuirksStyle());
488 // 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.
489 if (document().isViewSource())
490 matchUARules(collector, defaultStyleSheets.defaultViewSourceStyle());
492 collector.setMatchingUARules(false);
494 matchWatchSelectorRules(collector);
497 void StyleResolver::matchUARules(ElementRuleCollector& collector, RuleSet* rules)
499 collector.clearMatchedRules();
500 collector.matchedResult().ranges.lastUARule = collector.matchedResult().matchedProperties.size() - 1;
502 RuleRange ruleRange = collector.matchedResult().ranges.UARuleRange();
503 collector.collectMatchingRules(MatchRequest(rules), ruleRange);
505 collector.sortAndTransferMatchedRules();
508 void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollector& collector, bool includeSMILProperties)
510 matchUARules(collector);
512 // Now check author rules, beginning first with presentational attributes mapped from HTML.
513 if (state.element()->isStyledElement()) {
514 collector.addElementStyleProperties(state.element()->presentationAttributeStyle());
516 // Now we check additional mapped declarations.
517 // Tables and table cells share an additional mapped rule that must be applied
518 // after all attributes, since their mapped style depends on the values of multiple attributes.
519 collector.addElementStyleProperties(state.element()->additionalPresentationAttributeStyle());
521 if (state.element()->isHTMLElement()) {
523 TextDirection textDirection = toHTMLElement(state.element())->directionalityIfhasDirAutoAttribute(isAuto);
525 collector.matchedResult().addMatchedProperties(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
529 matchAuthorRules(state.element(), collector, false);
531 if (state.element()->isStyledElement()) {
532 if (state.element()->inlineStyle()) {
533 // Inline style is immutable as long as there is no CSSOM wrapper.
534 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMutable();
535 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable);
538 // Now check SMIL animation override style.
539 if (includeSMILProperties && state.element()->isSVGElement())
540 collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */);
544 PassRefPtr<RenderStyle> StyleResolver::styleForDocument(Document& document)
546 const LocalFrame* frame = document.frame();
548 RefPtr<RenderStyle> documentStyle = RenderStyle::create();
549 documentStyle->setDisplay(BLOCK);
550 documentStyle->setRTLOrdering(document.visuallyOrdered() ? VisualOrder : LogicalOrder);
551 documentStyle->setZoom(frame && !document.printing() ? frame->pageZoomFactor() : 1);
552 documentStyle->setLocale(document.contentLanguage());
553 documentStyle->setZIndex(0);
554 documentStyle->setUserModify(document.inDesignMode() ? READ_WRITE : READ_ONLY);
556 document.setupFontBuilder(documentStyle.get());
558 return documentStyle.release();
561 // FIXME: This is duplicated with StyleAdjuster.cpp
562 // Perhaps this should move onto ElementResolveContext or even Element?
563 static inline bool isAtShadowBoundary(const Element* element)
567 ContainerNode* parentNode = element->parentNode();
568 return parentNode && parentNode->isShadowRoot();
571 static inline void resetDirectionAndWritingModeOnDocument(Document& document)
573 document.setDirectionSetOnDocumentElement(false);
574 document.setWritingModeSetOnDocumentElement(false);
577 static void addContentAttrValuesToFeatures(const Vector<AtomicString>& contentAttrValues, RuleFeatureSet& features)
579 for (size_t i = 0; i < contentAttrValues.size(); ++i)
580 features.addContentAttr(contentAttrValues[i]);
583 void StyleResolver::adjustRenderStyle(StyleResolverState& state, Element* element)
585 StyleAdjuster adjuster(state.cachedUAStyle(), m_document.inQuirksMode());
586 adjuster.adjustRenderStyle(state.style(), state.parentStyle(), element);
589 // Start loading resources referenced by this style.
590 void StyleResolver::loadPendingResources(StyleResolverState& state)
592 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources());
593 document().styleEngine()->fontSelector()->loadPendingFonts();
596 PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent, StyleSharingBehavior sharingBehavior,
597 RuleMatchingBehavior matchingBehavior)
599 ASSERT(document().frame());
600 ASSERT(documentSettings());
601 ASSERT(!hasPendingAuthorStyleSheets());
602 ASSERT(!m_needCollectFeatures);
604 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
605 // will vanish if a style recalc happens during loading.
606 if (sharingBehavior == AllowStyleSharing && !document().isRenderingReady() && !element->renderer()) {
607 if (!s_styleNotYetAvailable) {
608 s_styleNotYetAvailable = RenderStyle::create().leakRef();
609 s_styleNotYetAvailable->setDisplay(NONE);
610 s_styleNotYetAvailable->font().update(document().styleEngine()->fontSelector());
613 document().setHasNodesWithPlaceholderStyle();
614 return s_styleNotYetAvailable;
619 StyleResolverParentScope::ensureParentStackIsPushed();
621 if (element == document().documentElement())
622 resetDirectionAndWritingModeOnDocument(document());
623 StyleResolverState state(document(), element, defaultParent);
625 if (sharingBehavior == AllowStyleSharing && state.parentStyle()) {
626 SharedStyleFinder styleFinder(state.elementContext(), m_features, m_siblingRuleSet.get(), m_uncommonAttributeRuleSet.get(), *this);
627 if (RefPtr<RenderStyle> sharedStyle = styleFinder.findSharedStyle())
628 return sharedStyle.release();
631 if (state.parentStyle()) {
632 state.setStyle(RenderStyle::create());
633 state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
635 state.setStyle(defaultStyleForElement());
636 state.setParentStyle(RenderStyle::clone(state.style()));
638 // contenteditable attribute (implemented by -webkit-user-modify) should
639 // be propagated from shadow host to distributed node.
640 if (state.distributedToInsertionPoint()) {
641 if (Element* parent = element->parentElement()) {
642 if (RenderStyle* styleOfShadowHost = parent->renderStyle())
643 state.style()->setUserModify(styleOfShadowHost->userModify());
647 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules());
649 if (element->isLink()) {
650 state.style()->setIsLink(true);
651 EInsideLink linkState = state.elementLinkState();
652 if (linkState != NotInsideLink) {
653 bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited);
655 linkState = InsideVisitedLink;
657 state.style()->setInsideLink(linkState);
660 bool needsCollection = false;
661 CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection);
666 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
668 matchAllRules(state, collector, matchingBehavior != MatchAllRulesExcludingSMIL);
670 applyMatchedProperties(state, collector.matchedResult());
672 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
675 adjustRenderStyle(state, element);
677 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
678 // important rules, but this currently happens here as we require adjustment to have happened
679 // before deciding which properties to transition.
680 if (applyAnimatedProperties(state, element))
681 adjustRenderStyle(state, element);
683 // FIXME: Shouldn't this be on RenderBody::styleDidChange?
684 if (isHTMLBodyElement(*element))
685 document().textLinkColors().setTextColor(state.style()->color());
687 setAnimationUpdateIfNeeded(state, *element);
689 if (state.style()->hasViewportUnits())
690 document().setHasViewportUnits();
692 // Now return the style.
693 return state.takeStyle();
696 PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const RenderStyle& elementStyle, RenderStyle* parentStyle, const StyleKeyframe* keyframe, const AtomicString& animationName)
698 ASSERT(document().frame());
699 ASSERT(documentSettings());
700 ASSERT(!hasPendingAuthorStyleSheets());
702 if (element == document().documentElement())
703 resetDirectionAndWritingModeOnDocument(document());
704 StyleResolverState state(document(), element, parentStyle);
707 result.addMatchedProperties(&keyframe->properties());
709 ASSERT(!state.style());
712 state.setStyle(RenderStyle::clone(&elementStyle));
713 state.setLineHeightValue(0);
715 // Make sure that the CSSAnimationData for the animation to which this
716 // keyframe belongs is first in the list. This makes sure that if the
717 // animation-timing-function property is set for this keyframe, it will be
718 // applied to the correct CSSAnimationData object. Note that objects other
719 // than the first in the list are ignored when reading the timing function
720 // value. See KeyframeValue::timingFunction().
721 CSSAnimationDataList* animations = state.style()->accessAnimations();
722 ASSERT(animations && !animations->isEmpty());
723 while (animations->animation(0)->name() != animationName)
724 animations->remove(0);
725 ASSERT(!animations->isEmpty() && animations->animation(0)->name() == animationName);
727 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules());
729 // We don't need to bother with !important. Since there is only ever one
730 // decl, there's nothing to override. So just add the first properties.
731 bool inheritedOnly = false;
732 applyMatchedProperties<AnimationProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
733 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
735 // If our font got dirtied, go ahead and update it now.
738 // Line-height is set when we are sure we decided on the font-size
739 if (state.lineHeightValue())
740 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
742 // Now do rest of the properties.
743 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
745 // If our font got dirtied by one of the non-essential font props,
746 // go ahead and update it a second time.
749 loadPendingResources(state);
753 return state.takeStyle();
756 // This function is used by the WebAnimations JavaScript API method animate().
757 // FIXME: Remove this when animate() switches away from resolution-dependent parsing.
758 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(Element& element, CSSPropertyID property, CSSValue* value)
760 // We use a fresh RenderStyle here because certain values (eg. background-position) won't always completely replace the previously applied property.
761 RefPtr<RenderStyle> style = element.renderStyle() ? RenderStyle::clone(element.renderStyle()) : RenderStyle::create();
762 StyleResolverState state(element.document(), &element);
763 state.setStyle(style.get());
764 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules());
765 StyleBuilder::applyProperty(property, state, value);
766 return CSSAnimatableValueFactory::create(property, *style);
769 PassRefPtr<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 RefPtr<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(), state.useSVGZoomRules());
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 // FIXME: Passing 0 as the Element* introduces a lot of complexity
849 // in the adjustRenderStyle code.
850 adjustRenderStyle(state, 0);
852 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
853 // important rules, but this currently happens here as we require adjustment to have happened
854 // before deciding which properties to transition.
855 if (applyAnimatedProperties(state, element.pseudoElement(pseudoStyleRequest.pseudoId)))
856 adjustRenderStyle(state, 0);
860 if (state.style()->hasViewportUnits())
861 document().setHasViewportUnits();
866 PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle)
872 StyleResolverState state(document(), element, parentStyle);
873 if (!pseudoStyleForElementInternal(*element, pseudoStyleRequest, parentStyle, state))
876 if (PseudoElement* pseudoElement = element->pseudoElement(pseudoStyleRequest.pseudoId))
877 setAnimationUpdateIfNeeded(state, *pseudoElement);
879 // Now return the style.
880 return state.takeStyle();
883 PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
885 ASSERT(!hasPendingAuthorStyleSheets());
886 resetDirectionAndWritingModeOnDocument(document());
887 StyleResolverState state(document(), document().documentElement()); // m_rootElementStyle will be set to the document style.
889 state.setStyle(RenderStyle::create());
890 const RenderStyle* rootElementStyle = state.rootElementStyle() ? state.rootElementStyle() : document().renderStyle();
891 ASSERT(rootElementStyle);
892 state.style()->inheritFrom(rootElementStyle);
894 state.fontBuilder().initForStyleResolve(state.document(), state.style(), state.useSVGZoomRules());
896 PageRuleCollector collector(rootElementStyle, pageIndex);
898 collector.matchPageRules(CSSDefaultStyleSheets::instance().defaultPrintStyle());
900 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
901 scopedResolver->matchPageRules(collector);
903 state.setLineHeightValue(0);
904 bool inheritedOnly = false;
906 MatchResult& result = collector.matchedResult();
907 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
909 // If our font got dirtied, go ahead and update it now.
912 // Line-height is set when we are sure we decided on the font-size.
913 if (state.lineHeightValue())
914 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
916 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
918 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
920 loadPendingResources(state);
924 // Now return the style.
925 return state.takeStyle();
928 void StyleResolver::collectViewportRules()
930 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
931 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultStyle(), ViewportStyleResolver::UserAgentOrigin);
933 if (!InspectorInstrumentation::applyViewportStyleOverride(&document(), this))
934 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultViewportStyle(), ViewportStyleResolver::UserAgentOrigin);
936 if (document().isMobileDocument())
937 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultXHTMLMobileProfileStyle(), ViewportStyleResolver::UserAgentOrigin);
939 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
940 scopedResolver->collectViewportRulesTo(this);
942 viewportStyleResolver()->resolve();
945 PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement()
947 StyleResolverState state(document(), 0);
948 state.setStyle(RenderStyle::create());
949 state.fontBuilder().initForStyleResolve(document(), state.style(), state.useSVGZoomRules());
950 state.style()->setLineHeight(RenderStyle::initialLineHeight());
951 state.setLineHeightValue(0);
952 state.fontBuilder().setInitial(state.style()->effectiveZoom());
953 state.style()->font().update(document().styleEngine()->fontSelector());
954 return state.takeStyle();
957 PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode)
961 NodeRenderingTraversal::ParentDetails parentDetails;
962 Node* parentNode = NodeRenderingTraversal::parent(textNode, &parentDetails);
963 if (!parentNode || !parentNode->renderStyle())
964 return defaultStyleForElement();
965 return parentNode->renderStyle();
968 void StyleResolver::updateFont(StyleResolverState& state)
970 state.fontBuilder().createFont(document().styleEngine()->fontSelector(), state.parentStyle(), state.style());
971 if (state.fontBuilder().fontSizeHasViewportUnits())
972 state.style()->setHasViewportUnits();
975 PassRefPtrWillBeRawPtr<StyleRuleList> StyleResolver::styleRulesForElement(Element* element, unsigned rulesToInclude)
978 StyleResolverState state(document(), element);
979 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
980 collector.setMode(SelectorChecker::CollectingStyleRules);
981 collectPseudoRulesForElement(element, collector, NOPSEUDO, rulesToInclude);
982 return collector.matchedStyleRuleList();
985 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::pseudoCSSRulesForElement(Element* element, PseudoId pseudoId, unsigned rulesToInclude)
988 StyleResolverState state(document(), element);
989 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
990 collector.setMode(SelectorChecker::CollectingCSSRules);
991 collectPseudoRulesForElement(element, collector, pseudoId, rulesToInclude);
992 return collector.matchedCSSRuleList();
995 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::cssRulesForElement(Element* element, unsigned rulesToInclude)
997 return pseudoCSSRulesForElement(element, NOPSEUDO, rulesToInclude);
1000 void StyleResolver::collectPseudoRulesForElement(Element* element, ElementRuleCollector& collector, PseudoId pseudoId, unsigned rulesToInclude)
1002 collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
1004 if (rulesToInclude & UAAndUserCSSRules)
1005 matchUARules(collector);
1007 if (rulesToInclude & AuthorCSSRules) {
1008 collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules));
1009 matchAuthorRules(element, collector, rulesToInclude & EmptyCSSRules);
1013 // -------------------------------------------------------------------------------------
1014 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1016 bool StyleResolver::applyAnimatedProperties(StyleResolverState& state, Element* animatingElement)
1018 const Element* element = state.element();
1021 // The animating element may be this element, or its pseudo element. It is
1022 // null when calculating the style for a potential pseudo element that has
1023 // yet to be created.
1024 ASSERT(animatingElement == element || !animatingElement || animatingElement->parentOrShadowHostElement() == element);
1026 if (!(animatingElement && animatingElement->hasActiveAnimations())
1027 && !(state.style()->transitions() && !state.style()->transitions()->isEmpty())
1028 && !(state.style()->animations() && !state.style()->animations()->isEmpty()))
1031 state.setAnimationUpdate(CSSAnimations::calculateUpdate(animatingElement, *element, *state.style(), state.parentStyle(), this));
1032 if (!state.animationUpdate())
1035 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations = state.animationUpdate()->activeInterpolationsForAnimations();
1036 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForTransitions = state.animationUpdate()->activeInterpolationsForTransitions();
1037 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForAnimations);
1038 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForTransitions);
1039 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForAnimations);
1040 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForTransitions);
1042 // Start loading resources used by animations.
1043 loadPendingResources(state);
1048 template <StyleResolver::StyleApplicationPass pass>
1049 void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolations)
1051 ASSERT(pass != AnimationProperties);
1053 for (WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >::const_iterator iter = activeInterpolations.begin(); iter != activeInterpolations.end(); ++iter) {
1054 CSSPropertyID property = iter->key;
1055 if (!isPropertyForPass<pass>(property))
1057 const StyleInterpolation* interpolation = toStyleInterpolation(iter->value.get());
1058 interpolation->apply(state);
1062 static inline bool isValidCueStyleProperty(CSSPropertyID id)
1065 case CSSPropertyBackground:
1066 case CSSPropertyBackgroundAttachment:
1067 case CSSPropertyBackgroundClip:
1068 case CSSPropertyBackgroundColor:
1069 case CSSPropertyBackgroundImage:
1070 case CSSPropertyBackgroundOrigin:
1071 case CSSPropertyBackgroundPosition:
1072 case CSSPropertyBackgroundPositionX:
1073 case CSSPropertyBackgroundPositionY:
1074 case CSSPropertyBackgroundRepeat:
1075 case CSSPropertyBackgroundRepeatX:
1076 case CSSPropertyBackgroundRepeatY:
1077 case CSSPropertyBackgroundSize:
1078 case CSSPropertyColor:
1079 case CSSPropertyFont:
1080 case CSSPropertyFontFamily:
1081 case CSSPropertyFontSize:
1082 case CSSPropertyFontStyle:
1083 case CSSPropertyFontVariant:
1084 case CSSPropertyFontWeight:
1085 case CSSPropertyLineHeight:
1086 case CSSPropertyOpacity:
1087 case CSSPropertyOutline:
1088 case CSSPropertyOutlineColor:
1089 case CSSPropertyOutlineOffset:
1090 case CSSPropertyOutlineStyle:
1091 case CSSPropertyOutlineWidth:
1092 case CSSPropertyVisibility:
1093 case CSSPropertyWhiteSpace:
1094 // FIXME: 'text-decoration' shorthand to be handled when available.
1095 // See https://chromiumcodereview.appspot.com/19516002 for details.
1096 case CSSPropertyTextDecoration:
1097 case CSSPropertyTextShadow:
1098 case CSSPropertyBorderStyle:
1100 case CSSPropertyTextDecorationLine:
1101 case CSSPropertyTextDecorationStyle:
1102 case CSSPropertyTextDecorationColor:
1103 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1110 static inline bool isValidFirstLetterStyleProperty(CSSPropertyID id)
1113 // Valid ::first-letter properties listed in spec:
1114 // http://www.w3.org/TR/css3-selectors/#application-in-css
1115 case CSSPropertyBackgroundAttachment:
1116 case CSSPropertyBackgroundBlendMode:
1117 case CSSPropertyBackgroundClip:
1118 case CSSPropertyBackgroundColor:
1119 case CSSPropertyBackgroundImage:
1120 case CSSPropertyBackgroundOrigin:
1121 case CSSPropertyBackgroundPosition:
1122 case CSSPropertyBackgroundPositionX:
1123 case CSSPropertyBackgroundPositionY:
1124 case CSSPropertyBackgroundRepeat:
1125 case CSSPropertyBackgroundRepeatX:
1126 case CSSPropertyBackgroundRepeatY:
1127 case CSSPropertyBackgroundSize:
1128 case CSSPropertyBorderBottomColor:
1129 case CSSPropertyBorderBottomLeftRadius:
1130 case CSSPropertyBorderBottomRightRadius:
1131 case CSSPropertyBorderBottomStyle:
1132 case CSSPropertyBorderBottomWidth:
1133 case CSSPropertyBorderImageOutset:
1134 case CSSPropertyBorderImageRepeat:
1135 case CSSPropertyBorderImageSlice:
1136 case CSSPropertyBorderImageSource:
1137 case CSSPropertyBorderImageWidth:
1138 case CSSPropertyBorderLeftColor:
1139 case CSSPropertyBorderLeftStyle:
1140 case CSSPropertyBorderLeftWidth:
1141 case CSSPropertyBorderRightColor:
1142 case CSSPropertyBorderRightStyle:
1143 case CSSPropertyBorderRightWidth:
1144 case CSSPropertyBorderTopColor:
1145 case CSSPropertyBorderTopLeftRadius:
1146 case CSSPropertyBorderTopRightRadius:
1147 case CSSPropertyBorderTopStyle:
1148 case CSSPropertyBorderTopWidth:
1149 case CSSPropertyColor:
1150 case CSSPropertyFloat:
1151 case CSSPropertyFont:
1152 case CSSPropertyFontFamily:
1153 case CSSPropertyFontKerning:
1154 case CSSPropertyFontSize:
1155 case CSSPropertyFontStretch:
1156 case CSSPropertyFontStyle:
1157 case CSSPropertyFontVariant:
1158 case CSSPropertyFontVariantLigatures:
1159 case CSSPropertyFontWeight:
1160 case CSSPropertyLetterSpacing:
1161 case CSSPropertyLineHeight:
1162 case CSSPropertyMarginBottom:
1163 case CSSPropertyMarginLeft:
1164 case CSSPropertyMarginRight:
1165 case CSSPropertyMarginTop:
1166 case CSSPropertyPaddingBottom:
1167 case CSSPropertyPaddingLeft:
1168 case CSSPropertyPaddingRight:
1169 case CSSPropertyPaddingTop:
1170 case CSSPropertyTextTransform:
1171 case CSSPropertyVerticalAlign:
1172 case CSSPropertyWebkitBackgroundClip:
1173 case CSSPropertyWebkitBackgroundComposite:
1174 case CSSPropertyWebkitBackgroundOrigin:
1175 case CSSPropertyWebkitBackgroundSize:
1176 case CSSPropertyWebkitBorderAfter:
1177 case CSSPropertyWebkitBorderAfterColor:
1178 case CSSPropertyWebkitBorderAfterStyle:
1179 case CSSPropertyWebkitBorderAfterWidth:
1180 case CSSPropertyWebkitBorderBefore:
1181 case CSSPropertyWebkitBorderBeforeColor:
1182 case CSSPropertyWebkitBorderBeforeStyle:
1183 case CSSPropertyWebkitBorderBeforeWidth:
1184 case CSSPropertyWebkitBorderEnd:
1185 case CSSPropertyWebkitBorderEndColor:
1186 case CSSPropertyWebkitBorderEndStyle:
1187 case CSSPropertyWebkitBorderEndWidth:
1188 case CSSPropertyWebkitBorderFit:
1189 case CSSPropertyWebkitBorderHorizontalSpacing:
1190 case CSSPropertyWebkitBorderImage:
1191 case CSSPropertyWebkitBorderRadius:
1192 case CSSPropertyWebkitBorderStart:
1193 case CSSPropertyWebkitBorderStartColor:
1194 case CSSPropertyWebkitBorderStartStyle:
1195 case CSSPropertyWebkitBorderStartWidth:
1196 case CSSPropertyWebkitBorderVerticalSpacing:
1197 case CSSPropertyWebkitFontSmoothing:
1198 case CSSPropertyWebkitMarginAfter:
1199 case CSSPropertyWebkitMarginAfterCollapse:
1200 case CSSPropertyWebkitMarginBefore:
1201 case CSSPropertyWebkitMarginBeforeCollapse:
1202 case CSSPropertyWebkitMarginBottomCollapse:
1203 case CSSPropertyWebkitMarginCollapse:
1204 case CSSPropertyWebkitMarginEnd:
1205 case CSSPropertyWebkitMarginStart:
1206 case CSSPropertyWebkitMarginTopCollapse:
1207 case CSSPropertyWordSpacing:
1209 case CSSPropertyTextDecorationColor:
1210 case CSSPropertyTextDecorationLine:
1211 case CSSPropertyTextDecorationStyle:
1212 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1214 // text-shadow added in text decoration spec:
1215 // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property
1216 case CSSPropertyTextShadow:
1217 // box-shadox added in CSS3 backgrounds spec:
1218 // http://www.w3.org/TR/css3-background/#placement
1219 case CSSPropertyBoxShadow:
1220 case CSSPropertyWebkitBoxShadow:
1221 // Properties that we currently support outside of spec.
1222 case CSSPropertyWebkitLineBoxContain:
1223 case CSSPropertyVisibility:
1231 template <StyleResolver::StyleApplicationPass pass>
1232 bool StyleResolver::isPropertyForPass(CSSPropertyID property)
1234 const CSSPropertyID firstAnimationProperty = CSSPropertyDisplay;
1235 const CSSPropertyID lastAnimationProperty = CSSPropertyTransitionTimingFunction;
1236 COMPILE_ASSERT(firstCSSProperty == firstAnimationProperty, CSS_first_animation_property_should_be_first_property);
1237 const CSSPropertyID firstHighPriorityProperty = CSSPropertyColor;
1238 const CSSPropertyID lastHighPriorityProperty = CSSPropertyLineHeight;
1239 COMPILE_ASSERT(lastAnimationProperty + 1 == firstHighPriorityProperty, CSS_color_is_first_high_priority_property);
1240 COMPILE_ASSERT(CSSPropertyLineHeight == firstHighPriorityProperty + 17, CSS_line_height_is_end_of_high_prioity_property_range);
1241 COMPILE_ASSERT(CSSPropertyZoom == lastHighPriorityProperty - 1, CSS_zoom_is_before_line_height);
1243 case AnimationProperties:
1244 return property >= firstAnimationProperty && property <= lastAnimationProperty;
1245 case HighPriorityProperties:
1246 return property >= firstHighPriorityProperty && property <= lastHighPriorityProperty;
1247 case LowPriorityProperties:
1248 return property > lastHighPriorityProperty;
1250 ASSERT_NOT_REACHED();
1254 template <StyleResolver::StyleApplicationPass pass>
1255 void StyleResolver::applyProperties(StyleResolverState& state, const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType)
1257 state.setCurrentRule(rule);
1259 unsigned propertyCount = properties->propertyCount();
1260 for (unsigned i = 0; i < propertyCount; ++i) {
1261 StylePropertySet::PropertyReference current = properties->propertyAt(i);
1262 if (isImportant != current.isImportant())
1264 if (inheritedOnly && !current.isInherited()) {
1265 // If the property value is explicitly inherited, we need to apply further non-inherited properties
1266 // as they might override the value inherited here. For this reason we don't allow declarations with
1267 // explicitly inherited properties to be cached.
1268 ASSERT(!current.value()->isInheritedValue());
1271 CSSPropertyID property = current.id();
1273 if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property))
1275 if (propertyWhitelistType == PropertyWhitelistFirstLetter && !isValidFirstLetterStyleProperty(property))
1277 if (!isPropertyForPass<pass>(property))
1279 if (pass == HighPriorityProperties && property == CSSPropertyLineHeight)
1280 state.setLineHeightValue(current.value());
1282 StyleBuilder::applyProperty(current.id(), state, current.value());
1286 template <StyleResolver::StyleApplicationPass pass>
1287 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
1289 if (startIndex == -1)
1292 if (state.style()->insideLink() != NotInsideLink) {
1293 for (int i = startIndex; i <= endIndex; ++i) {
1294 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1295 unsigned linkMatchType = matchedProperties.linkMatchType;
1296 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
1297 state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink);
1298 state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited);
1300 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1302 state.setApplyPropertyToRegularStyle(true);
1303 state.setApplyPropertyToVisitedLinkStyle(false);
1306 for (int i = startIndex; i <= endIndex; ++i) {
1307 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1308 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1312 static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
1314 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
1317 void StyleResolver::invalidateMatchedPropertiesCache()
1319 m_matchedPropertiesCache.clear();
1322 void StyleResolver::notifyResizeForViewportUnits()
1324 collectViewportRules();
1325 m_matchedPropertiesCache.clearViewportDependent();
1328 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult)
1330 const Element* element = state.element();
1333 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply);
1335 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
1336 bool applyInheritedOnly = false;
1337 const CachedMatchedProperties* cachedMatchedProperties = 0;
1339 if (cacheHash && (cachedMatchedProperties = m_matchedPropertiesCache.find(cacheHash, state, matchResult))
1340 && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1341 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit);
1342 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
1343 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the
1344 // element context. This is fast and saves memory by reusing the style data structures.
1345 state.style()->copyNonInheritedFrom(cachedMatchedProperties->renderStyle.get());
1346 if (state.parentStyle()->inheritedDataShared(cachedMatchedProperties->parentRenderStyle.get()) && !isAtShadowBoundary(element)
1347 && (!state.distributedToInsertionPoint() || state.style()->userModify() == READ_ONLY)) {
1348 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheInheritedHit);
1350 EInsideLink linkStatus = state.style()->insideLink();
1351 // If the cache item parent style has identical inherited properties to the current parent style then the
1352 // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
1353 state.style()->inheritFrom(cachedMatchedProperties->renderStyle.get());
1355 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
1356 state.style()->setInsideLink(linkStatus);
1359 applyInheritedOnly = true;
1362 // Apply animation properties in order to apply animation results and trigger transitions below.
1363 applyMatchedProperties<AnimationProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1364 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1365 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1366 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1368 // Match transition-property / animation-name length by trimming and
1369 // lengthening other transition / animation property lists
1370 // FIXME: This is wrong because we shouldn't affect the computed values
1371 state.style()->adjustAnimations();
1372 state.style()->adjustTransitions();
1374 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
1375 // high-priority properties first, i.e., those properties that other properties depend on.
1376 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
1377 // and (4) normal important.
1378 state.setLineHeightValue(0);
1379 applyMatchedProperties<HighPriorityProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1380 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1381 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1382 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1384 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) {
1385 state.fontBuilder().setFontDirty(true);
1386 applyInheritedOnly = false;
1389 // If our font got dirtied, go ahead and update it now.
1392 // Line-height is set when we are sure we decided on the font-size.
1393 if (state.lineHeightValue())
1394 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
1396 // Many properties depend on the font. If it changes we just apply all properties.
1397 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription())
1398 applyInheritedOnly = false;
1400 // Now do the normal priority UA properties.
1401 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1403 // Cache the UA properties to pass them to RenderTheme in adjustRenderStyle.
1404 state.cacheUserAgentBorderAndBackground();
1406 // Now do the author and user normal priority properties and all the !important properties.
1407 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1408 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1409 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1410 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1412 loadPendingResources(state);
1414 if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1415 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded);
1416 m_matchedPropertiesCache.add(state.style(), state.parentStyle(), cacheHash, matchResult);
1419 ASSERT(!state.fontBuilder().fontDirty());
1422 CSSPropertyValue::CSSPropertyValue(CSSPropertyID id, const StylePropertySet& propertySet)
1423 : property(id), value(propertySet.getPropertyCSSValue(id).get())
1426 void StyleResolver::enableStats(StatsReportType reportType)
1428 if (m_styleResolverStats)
1430 m_styleResolverStats = StyleResolverStats::create();
1431 m_styleResolverStatsTotals = StyleResolverStats::create();
1432 if (reportType == ReportSlowStats) {
1433 m_styleResolverStats->printMissedCandidateCount = true;
1434 m_styleResolverStatsTotals->printMissedCandidateCount = true;
1438 void StyleResolver::disableStats()
1440 m_styleResolverStatsSequence = 0;
1441 m_styleResolverStats.clear();
1442 m_styleResolverStatsTotals.clear();
1445 void StyleResolver::printStats()
1447 if (!m_styleResolverStats)
1449 fprintf(stderr, "=== Style Resolver Stats (resolve #%u) (%s) ===\n", ++m_styleResolverStatsSequence, m_document.url().string().utf8().data());
1450 fprintf(stderr, "%s\n", m_styleResolverStats->report().utf8().data());
1451 fprintf(stderr, "== Totals ==\n");
1452 fprintf(stderr, "%s\n", m_styleResolverStatsTotals->report().utf8().data());
1455 void StyleResolver::applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle* style)
1457 StyleResolverState state(document(), document().documentElement(), style);
1458 state.setStyle(style);
1460 state.fontBuilder().initForStyleResolve(document(), style, state.useSVGZoomRules());
1462 for (size_t i = 0; i < count; ++i) {
1463 if (properties[i].value) {
1464 // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call,
1465 // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122).
1466 // The updateFont() call below updates the fontMetrics and ensure the proper setting of font-size and line-height.
1467 switch (properties[i].property) {
1468 case CSSPropertyFontSize:
1469 case CSSPropertyLineHeight:
1475 StyleBuilder::applyProperty(properties[i].property, state, properties[i].value);
1480 void StyleResolver::addMediaQueryResults(const MediaQueryResultList& list)
1482 for (size_t i = 0; i < list.size(); ++i)
1483 m_viewportDependentMediaQueryResults.append(list[i]);
1486 bool StyleResolver::mediaQueryAffectedByViewportChange() const
1488 for (unsigned i = 0; i < m_viewportDependentMediaQueryResults.size(); ++i) {
1489 if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result)
1495 void StyleResolver::trace(Visitor* visitor)
1497 visitor->trace(m_keyframesRuleMap);
1498 visitor->trace(m_viewportDependentMediaQueryResults);
1499 visitor->trace(m_viewportStyleResolver);
1500 visitor->trace(m_siblingRuleSet);
1501 visitor->trace(m_uncommonAttributeRuleSet);
1502 visitor->trace(m_watchedSelectorsRules);
1503 visitor->trace(m_treeBoundaryCrossingRules);
1504 visitor->trace(m_pendingStyleSheets);
1505 CSSFontSelectorClient::trace(visitor);
1508 } // namespace WebCore