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
87using namespace std;
88
89namespace {
90
91using namespace WebCore;
92
93void 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
103namespace WebCore {
104
105using namespace HTMLNames;
106
107RenderStyle* StyleResolver::s_styleNotYetAvailable;
108
109static 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
117static 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
125static 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
132StyleResolver::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
176void 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
185void 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
192void 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
198void 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
216void 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
226void 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
235void 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
247void 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
256void 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
264void 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
284void 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
302static 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
313void 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
337bool StyleResolver::hasRulesForId(const AtomicString& id) const
338{
339    return m_features.idsInRules.contains(id);
340}
341
342void 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
354void StyleResolver::clearStyleSharingList()
355{
356    m_styleSharingList.clear();
357}
358
359void StyleResolver::fontsNeedUpdate(FontSelector* fontSelector)
360{
361    invalidateMatchedPropertiesCache();
362    m_document.setNeedsStyleRecalc();
363}
364
365void 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
382void 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
392void StyleResolver::pushParentShadowRoot(const ShadowRoot& shadowRoot)
393{
394    ASSERT(shadowRoot.host());
395    m_styleTree.pushStyleCache(shadowRoot, shadowRoot.host());
396}
397
398void StyleResolver::popParentShadowRoot(const ShadowRoot& shadowRoot)
399{
400    ASSERT(shadowRoot.host());
401    m_styleTree.popStyleCache(shadowRoot);
402}
403
404StyleResolver::~StyleResolver()
405{
406    m_viewportStyleResolver->clearDocument();
407}
408
409inline 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
436static inline bool applyAuthorStylesOf(const Element* element)
437{
438    return element->treeScope().applyAuthorStyles() || (element->shadow() && element->shadow()->applyAuthorStyles());
439}
440
441void 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
463void 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
501void 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
517void 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
538void 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
549void 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
585PassRefPtr<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?
617static 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
625static inline void resetDirectionAndWritingModeOnDocument(Document& document)
626{
627    document.setDirectionSetOnDocumentElement(false);
628    document.setWritingModeSetOnDocumentElement(false);
629}
630
631static 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
637PassRefPtr<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
738PassRefPtr<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
805void 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.
868PassRefPtr<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
886PassRefPtr<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
914bool 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
967PassRefPtr<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
984PassRefPtr<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
1032void 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
1048PassRefPtr<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
1060PassRefPtr<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
1071bool 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
1082void StyleResolver::updateFont(StyleResolverState& state)
1083{
1084    state.fontBuilder().createFont(document().styleEngine()->fontSelector(), state.parentStyle(), state.style());
1085}
1086
1087PassRefPtr<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
1097PassRefPtr<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
1107PassRefPtr<CSSRuleList> StyleResolver::cssRulesForElement(Element* element, unsigned rulesToInclude, ShouldIncludeStyleSheetInCSSOMWrapper includeDocument)
1108{
1109    return pseudoCSSRulesForElement(element, NOPSEUDO, rulesToInclude, includeDocument);
1110}
1111
1112void 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
1128void 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
1165template <StyleResolver::StyleApplicationPass pass>
1166void 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.
1184static 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
1197static 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
1245template <StyleResolver::StyleApplicationPass pass>
1246bool 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
1271template <StyleResolver::StyleApplicationPass pass>
1272void 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
1304template <StyleResolver::StyleApplicationPass pass>
1305void 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
1330static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
1331{
1332    return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
1333}
1334
1335void StyleResolver::invalidateMatchedPropertiesCache()
1336{
1337    m_matchedPropertiesCache.clear();
1338}
1339
1340void 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
1441CSSPropertyValue::CSSPropertyValue(CSSPropertyID id, const StylePropertySet& propertySet)
1442    : property(id), value(propertySet.getPropertyCSSValue(id).get())
1443{ }
1444
1445void 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
1457void StyleResolver::disableStats()
1458{
1459    m_styleResolverStatsSequence = 0;
1460    m_styleResolverStats.clear();
1461    m_styleResolverStatsTotals.clear();
1462}
1463
1464void 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
1474void 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
1499void StyleResolver::addMediaQueryResults(const MediaQueryResultList& list)
1500{
1501    for (size_t i = 0; i < list.size(); ++i)
1502        m_viewportDependentMediaQueryResults.append(list[i]);
1503}
1504
1505bool 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