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