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