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 "core/CSSPropertyNames.h"
33 #include "core/HTMLNames.h"
34 #include "core/StylePropertyShorthand.h"
35 #include "core/animation/ActiveAnimations.h"
36 #include "core/animation/AnimatableValue.h"
37 #include "core/animation/Animation.h"
38 #include "core/animation/AnimationTimeline.h"
39 #include "core/animation/css/CSSAnimatableValueFactory.h"
40 #include "core/animation/css/CSSAnimations.h"
41 #include "core/animation/interpolation/StyleInterpolation.h"
42 #include "core/css/CSSCalculationValue.h"
43 #include "core/css/CSSDefaultStyleSheets.h"
44 #include "core/css/CSSFontSelector.h"
45 #include "core/css/CSSKeyframeRule.h"
46 #include "core/css/CSSKeyframesRule.h"
47 #include "core/css/CSSReflectValue.h"
48 #include "core/css/CSSRuleList.h"
49 #include "core/css/CSSSelector.h"
50 #include "core/css/CSSStyleRule.h"
51 #include "core/css/CSSValueList.h"
52 #include "core/css/CSSValuePool.h"
53 #include "core/css/ElementRuleCollector.h"
54 #include "core/css/FontFace.h"
55 #include "core/css/MediaQueryEvaluator.h"
56 #include "core/css/PageRuleCollector.h"
57 #include "core/css/StylePropertySet.h"
58 #include "core/css/StyleRuleImport.h"
59 #include "core/css/StyleSheetContents.h"
60 #include "core/css/parser/BisonCSSParser.h"
61 #include "core/css/resolver/AnimatedStyleBuilder.h"
62 #include "core/css/resolver/MatchResult.h"
63 #include "core/css/resolver/MediaQueryResult.h"
64 #include "core/css/resolver/SharedStyleFinder.h"
65 #include "core/css/resolver/StyleAdjuster.h"
66 #include "core/css/resolver/StyleResolverParentScope.h"
67 #include "core/css/resolver/StyleResolverState.h"
68 #include "core/css/resolver/StyleResolverStats.h"
69 #include "core/css/resolver/ViewportStyleResolver.h"
70 #include "core/dom/CSSSelectorWatch.h"
71 #include "core/dom/NodeRenderStyle.h"
72 #include "core/dom/StyleEngine.h"
73 #include "core/dom/Text.h"
74 #include "core/dom/shadow/ElementShadow.h"
75 #include "core/dom/shadow/ShadowRoot.h"
76 #include "core/frame/FrameView.h"
77 #include "core/frame/LocalFrame.h"
78 #include "core/html/HTMLIFrameElement.h"
79 #include "core/inspector/InspectorInstrumentation.h"
80 #include "core/rendering/RenderView.h"
81 #include "core/rendering/style/KeyframeList.h"
82 #include "core/svg/SVGDocumentExtensions.h"
83 #include "core/svg/SVGElement.h"
84 #include "core/svg/SVGFontFaceElement.h"
85 #include "platform/RuntimeEnabledFeatures.h"
86 #include "wtf/StdLibExtras.h"
87
88 namespace {
89
90 using namespace WebCore;
91
setAnimationUpdateIfNeeded(StyleResolverState & state,Element & element)92 void setAnimationUpdateIfNeeded(StyleResolverState& state, Element& element)
93 {
94 // If any changes to CSS Animations were detected, stash the update away for application after the
95 // render object is updated if we're in the appropriate scope.
96 if (state.animationUpdate())
97 element.ensureActiveAnimations().cssAnimations().setPendingUpdate(state.takeAnimationUpdate());
98 }
99
100 } // namespace
101
102 namespace WebCore {
103
104 using namespace HTMLNames;
105
106 RenderStyle* StyleResolver::s_styleNotYetAvailable;
107
leftToRightDeclaration()108 static StylePropertySet* leftToRightDeclaration()
109 {
110 DEFINE_STATIC_REF(MutableStylePropertySet, leftToRightDecl, (MutableStylePropertySet::create()));
111 if (leftToRightDecl->isEmpty())
112 leftToRightDecl->setProperty(CSSPropertyDirection, CSSValueLtr);
113 return leftToRightDecl;
114 }
115
rightToLeftDeclaration()116 static StylePropertySet* rightToLeftDeclaration()
117 {
118 DEFINE_STATIC_REF(MutableStylePropertySet, rightToLeftDecl, (MutableStylePropertySet::create()));
119 if (rightToLeftDecl->isEmpty())
120 rightToLeftDecl->setProperty(CSSPropertyDirection, CSSValueRtl);
121 return rightToLeftDecl;
122 }
123
addFontFaceRule(Document * document,CSSFontSelector * cssFontSelector,const StyleRuleFontFace * fontFaceRule)124 static void addFontFaceRule(Document* document, CSSFontSelector* cssFontSelector, const StyleRuleFontFace* fontFaceRule)
125 {
126 RefPtrWillBeRawPtr<FontFace> fontFace = FontFace::create(document, fontFaceRule);
127 if (fontFace)
128 cssFontSelector->fontFaceCache()->add(cssFontSelector, fontFaceRule, fontFace);
129 }
130
StyleResolver(Document & document)131 StyleResolver::StyleResolver(Document& document)
132 : m_document(document)
133 , m_viewportStyleResolver(ViewportStyleResolver::create(&document))
134 , m_needCollectFeatures(false)
135 , m_styleResourceLoader(document.fetcher())
136 , m_styleSharingDepth(0)
137 , m_styleResolverStatsSequence(0)
138 , m_accessCount(0)
139 {
140 FrameView* view = document.view();
141 if (view)
142 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), &view->frame()));
143 else
144 m_medium = adoptPtr(new MediaQueryEvaluator("all"));
145
146 m_styleTree.clear();
147
148 initWatchedSelectorRules(CSSSelectorWatch::from(document).watchedCallbackSelectors());
149
150 #if ENABLE(SVG_FONTS)
151 if (document.svgExtensions()) {
152 const WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >& svgFontFaceElements = document.svgExtensions()->svgFontFaceElements();
153 WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >::const_iterator end = svgFontFaceElements.end();
154 for (WillBeHeapHashSet<RawPtrWillBeMember<SVGFontFaceElement> >::const_iterator it = svgFontFaceElements.begin(); it != end; ++it)
155 addFontFaceRule(&document, document.styleEngine()->fontSelector(), (*it)->fontFaceRule());
156 }
157 #endif
158 }
159
initWatchedSelectorRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRule>> & watchedSelectors)160 void StyleResolver::initWatchedSelectorRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRule> >& watchedSelectors)
161 {
162 if (!watchedSelectors.size())
163 return;
164 m_watchedSelectorsRules = RuleSet::create();
165 for (unsigned i = 0; i < watchedSelectors.size(); ++i)
166 m_watchedSelectorsRules->addStyleRule(watchedSelectors[i].get(), RuleHasNoSpecialState);
167 }
168
lazyAppendAuthorStyleSheets(unsigned firstNew,const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>> & styleSheets)169 void StyleResolver::lazyAppendAuthorStyleSheets(unsigned firstNew, const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
170 {
171 unsigned size = styleSheets.size();
172 for (unsigned i = firstNew; i < size; ++i)
173 m_pendingStyleSheets.add(styleSheets[i].get());
174 }
175
removePendingAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>> & styleSheets)176 void StyleResolver::removePendingAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
177 {
178 for (unsigned i = 0; i < styleSheets.size(); ++i)
179 m_pendingStyleSheets.remove(styleSheets[i].get());
180 }
181
appendCSSStyleSheet(CSSStyleSheet * cssSheet)182 void StyleResolver::appendCSSStyleSheet(CSSStyleSheet* cssSheet)
183 {
184 ASSERT(cssSheet);
185 ASSERT(!cssSheet->disabled());
186 if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), &m_viewportDependentMediaQueryResults))
187 return;
188
189 ContainerNode* scopingNode = ScopedStyleResolver::scopingNodeFor(document(), cssSheet);
190 if (!scopingNode)
191 return;
192
193 ScopedStyleResolver* resolver = ensureScopedStyleResolver(scopingNode);
194 ASSERT(resolver);
195 resolver->addRulesFromSheet(cssSheet, *m_medium, this);
196 }
197
appendPendingAuthorStyleSheets()198 void StyleResolver::appendPendingAuthorStyleSheets()
199 {
200 setBuildScopedStyleTreeInDocumentOrder(false);
201 for (WillBeHeapListHashSet<RawPtrWillBeMember<CSSStyleSheet>, 16>::iterator it = m_pendingStyleSheets.begin(); it != m_pendingStyleSheets.end(); ++it)
202 appendCSSStyleSheet(*it);
203
204 m_pendingStyleSheets.clear();
205 finishAppendAuthorStyleSheets();
206 }
207
appendAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>> & styleSheets)208 void StyleResolver::appendAuthorStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& styleSheets)
209 {
210 // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver
211 // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated.
212 unsigned size = styleSheets.size();
213 for (unsigned i = 0; i < size; ++i)
214 appendCSSStyleSheet(styleSheets[i].get());
215 }
216
finishAppendAuthorStyleSheets()217 void StyleResolver::finishAppendAuthorStyleSheets()
218 {
219 collectFeatures();
220
221 if (document().renderView() && document().renderView()->style())
222 document().renderView()->style()->font().update(document().styleEngine()->fontSelector());
223
224 collectViewportRules();
225
226 document().styleEngine()->resetCSSFeatureFlags(m_features);
227 }
228
resetRuleFeatures()229 void StyleResolver::resetRuleFeatures()
230 {
231 // Need to recreate RuleFeatureSet.
232 m_features.clear();
233 m_siblingRuleSet.clear();
234 m_uncommonAttributeRuleSet.clear();
235 m_needCollectFeatures = true;
236 }
237
processScopedRules(const RuleSet & authorRules,CSSStyleSheet * parentStyleSheet,ContainerNode & scope)238 void StyleResolver::processScopedRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, ContainerNode& scope)
239 {
240 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes> > keyframesRules = authorRules.keyframesRules();
241 for (unsigned i = 0; i < keyframesRules.size(); ++i)
242 ensureScopedStyleResolver(&scope)->addKeyframeStyle(keyframesRules[i]);
243
244 m_treeBoundaryCrossingRules.addTreeBoundaryCrossingRules(authorRules, scope, parentStyleSheet);
245
246 // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for the moment.
247 if (scope.isDocumentNode()) {
248 const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace> > fontFaceRules = authorRules.fontFaceRules();
249 for (unsigned i = 0; i < fontFaceRules.size(); ++i)
250 addFontFaceRule(&m_document, document().styleEngine()->fontSelector(), fontFaceRules[i]);
251 if (fontFaceRules.size())
252 invalidateMatchedPropertiesCache();
253 }
254 }
255
resetAuthorStyle(const ContainerNode * scopingNode)256 void StyleResolver::resetAuthorStyle(const ContainerNode* scopingNode)
257 {
258 ScopedStyleResolver* resolver = scopingNode ? m_styleTree.lookupScopedStyleResolverFor(scopingNode) : m_styleTree.scopedStyleResolverForDocument();
259 if (!resolver)
260 return;
261
262 m_treeBoundaryCrossingRules.reset(scopingNode);
263
264 resolver->resetAuthorStyle();
265 resetRuleFeatures();
266 if (!scopingNode)
267 return;
268
269 m_styleTree.remove(scopingNode);
270 }
271
makeRuleSet(const WillBeHeapVector<RuleFeature> & rules)272 static PassOwnPtrWillBeRawPtr<RuleSet> makeRuleSet(const WillBeHeapVector<RuleFeature>& rules)
273 {
274 size_t size = rules.size();
275 if (!size)
276 return nullptr;
277 OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create();
278 for (size_t i = 0; i < size; ++i)
279 ruleSet->addRule(rules[i].rule, rules[i].selectorIndex, rules[i].hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState);
280 return ruleSet.release();
281 }
282
collectFeatures()283 void StyleResolver::collectFeatures()
284 {
285 m_features.clear();
286 // Collect all ids and rules using sibling selectors (:first-child and similar)
287 // in the current set of stylesheets. Style sharing code uses this information to reject
288 // sharing candidates.
289 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
290 if (defaultStyleSheets.defaultStyle())
291 m_features.add(defaultStyleSheets.defaultStyle()->features());
292
293 if (document().isViewSource())
294 m_features.add(defaultStyleSheets.defaultViewSourceStyle()->features());
295
296 if (document().isTransitionDocument())
297 m_features.add(defaultStyleSheets.defaultTransitionStyle()->features());
298
299 if (m_watchedSelectorsRules)
300 m_features.add(m_watchedSelectorsRules->features());
301
302 m_treeBoundaryCrossingRules.collectFeaturesTo(m_features);
303
304 m_styleTree.collectFeaturesTo(m_features);
305
306 m_siblingRuleSet = makeRuleSet(m_features.siblingRules);
307 m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules);
308 m_needCollectFeatures = false;
309 }
310
hasRulesForId(const AtomicString & id) const311 bool StyleResolver::hasRulesForId(const AtomicString& id) const
312 {
313 return m_features.hasSelectorForId(id);
314 }
315
addToStyleSharingList(Element & element)316 void StyleResolver::addToStyleSharingList(Element& element)
317 {
318 // Never add elements to the style sharing list if we're not in a recalcStyle,
319 // otherwise we could leave stale pointers in there.
320 if (!document().inStyleRecalc())
321 return;
322 INCREMENT_STYLE_STATS_COUNTER(*this, sharedStyleCandidates);
323 StyleSharingList& list = styleSharingList();
324 if (list.size() >= styleSharingListSize)
325 list.remove(--list.end());
326 list.prepend(&element);
327 }
328
styleSharingList()329 StyleSharingList& StyleResolver::styleSharingList()
330 {
331 m_styleSharingLists.resize(styleSharingMaxDepth);
332
333 // We never put things at depth 0 into the list since that's only the <html> element
334 // and it has no siblings or cousins to share with.
335 unsigned depth = std::max(std::min(m_styleSharingDepth, styleSharingMaxDepth), 1u) - 1u;
336 ASSERT(depth >= 0);
337
338 if (!m_styleSharingLists[depth])
339 m_styleSharingLists[depth] = adoptPtr(new StyleSharingList);
340 return *m_styleSharingLists[depth];
341 }
342
clearStyleSharingList()343 void StyleResolver::clearStyleSharingList()
344 {
345 m_styleSharingLists.resize(0);
346 }
347
pushParentElement(Element & parent)348 void StyleResolver::pushParentElement(Element& parent)
349 {
350 const ContainerNode* parentsParent = parent.parentOrShadowHostElement();
351
352 // We are not always invoked consistently. For example, script execution can cause us to enter
353 // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree.
354 // Reset the stack in this case, or if we see a new root element.
355 // Otherwise just push the new parent.
356 if (!parentsParent || m_selectorFilter.parentStackIsEmpty())
357 m_selectorFilter.setupParentStack(parent);
358 else
359 m_selectorFilter.pushParent(parent);
360
361 // Note: We mustn't skip ShadowRoot nodes for the scope stack.
362 m_styleTree.pushStyleCache(parent, parent.parentOrShadowHostNode());
363 }
364
popParentElement(Element & parent)365 void StyleResolver::popParentElement(Element& parent)
366 {
367 // Note that we may get invoked for some random elements in some wacky cases during style resolve.
368 // Pause maintaining the stack in this case.
369 if (m_selectorFilter.parentStackIsConsistent(&parent))
370 m_selectorFilter.popParent();
371
372 m_styleTree.popStyleCache(parent);
373 }
374
pushParentShadowRoot(const ShadowRoot & shadowRoot)375 void StyleResolver::pushParentShadowRoot(const ShadowRoot& shadowRoot)
376 {
377 ASSERT(shadowRoot.host());
378 m_styleTree.pushStyleCache(shadowRoot, shadowRoot.host());
379 }
380
popParentShadowRoot(const ShadowRoot & shadowRoot)381 void StyleResolver::popParentShadowRoot(const ShadowRoot& shadowRoot)
382 {
383 ASSERT(shadowRoot.host());
384 m_styleTree.popStyleCache(shadowRoot);
385 }
386
~StyleResolver()387 StyleResolver::~StyleResolver()
388 {
389 }
390
applyAuthorStylesOf(const Element * element)391 static inline bool applyAuthorStylesOf(const Element* element)
392 {
393 return element->treeScope().applyAuthorStyles();
394 }
395
matchAuthorRulesForShadowHost(Element * element,ElementRuleCollector & collector,bool includeEmptyRules,Vector<ScopedStyleResolver *,8> & resolvers,Vector<ScopedStyleResolver *,8> & resolversInShadowTree)396 void StyleResolver::matchAuthorRulesForShadowHost(Element* element, ElementRuleCollector& collector, bool includeEmptyRules, Vector<ScopedStyleResolver*, 8>& resolvers, Vector<ScopedStyleResolver*, 8>& resolversInShadowTree)
397 {
398 collector.clearMatchedRules();
399 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
400
401 CascadeScope cascadeScope = 0;
402 CascadeOrder cascadeOrder = 0;
403 bool applyAuthorStyles = applyAuthorStylesOf(element);
404
405 for (int j = resolversInShadowTree.size() - 1; j >= 0; --j)
406 resolversInShadowTree.at(j)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope, cascadeOrder++);
407
408 if (resolvers.isEmpty() || resolvers.first()->treeScope() != element->treeScope())
409 ++cascadeScope;
410 cascadeOrder += resolvers.size();
411 for (unsigned i = 0; i < resolvers.size(); ++i)
412 resolvers.at(i)->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, --cascadeOrder);
413
414 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
415 collector.sortAndTransferMatchedRules();
416 }
417
matchAuthorRules(Element * element,ElementRuleCollector & collector,bool includeEmptyRules)418 void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules)
419 {
420 collector.clearMatchedRules();
421 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
422
423 bool applyAuthorStyles = applyAuthorStylesOf(element);
424 if (m_styleTree.hasOnlyScopedResolverForDocument()) {
425 m_styleTree.scopedStyleResolverForDocument()->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, ignoreCascadeScope);
426 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
427 collector.sortAndTransferMatchedRules();
428 return;
429 }
430
431 Vector<ScopedStyleResolver*, 8> resolvers;
432 m_styleTree.resolveScopedStyles(element, resolvers);
433
434 Vector<ScopedStyleResolver*, 8> resolversInShadowTree;
435 m_styleTree.collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree);
436 if (!resolversInShadowTree.isEmpty()) {
437 matchAuthorRulesForShadowHost(element, collector, includeEmptyRules, resolvers, resolversInShadowTree);
438 return;
439 }
440
441 if (resolvers.isEmpty())
442 return;
443
444 CascadeScope cascadeScope = 0;
445 CascadeOrder cascadeOrder = resolvers.size();
446 for (unsigned i = 0; i < resolvers.size(); ++i, --cascadeOrder) {
447 ScopedStyleResolver* resolver = resolvers.at(i);
448 // FIXME: Need to clarify how to treat style scoped.
449 resolver->collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, cascadeScope++, resolver->treeScope() == element->treeScope() && resolver->scopingNode().isShadowRoot() ? 0 : cascadeOrder);
450 }
451
452 m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
453 collector.sortAndTransferMatchedRules();
454 }
455
matchWatchSelectorRules(ElementRuleCollector & collector)456 void StyleResolver::matchWatchSelectorRules(ElementRuleCollector& collector)
457 {
458 if (!m_watchedSelectorsRules)
459 return;
460
461 collector.clearMatchedRules();
462 collector.matchedResult().ranges.lastUserRule = collector.matchedResult().matchedProperties.size() - 1;
463
464 MatchRequest matchRequest(m_watchedSelectorsRules.get());
465 RuleRange ruleRange = collector.matchedResult().ranges.userRuleRange();
466 collector.collectMatchingRules(matchRequest, ruleRange);
467
468 collector.sortAndTransferMatchedRules();
469 }
470
matchUARules(ElementRuleCollector & collector)471 void StyleResolver::matchUARules(ElementRuleCollector& collector)
472 {
473 collector.setMatchingUARules(true);
474
475 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
476 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
477 ? defaultStyleSheets.defaultPrintStyle() : defaultStyleSheets.defaultStyle();
478 matchUARules(collector, userAgentStyleSheet);
479
480 // In quirks mode, we match rules from the quirks user agent sheet.
481 if (document().inQuirksMode())
482 matchUARules(collector, defaultStyleSheets.defaultQuirksStyle());
483
484 // If document uses view source styles (in view source mode or in xml viewer mode), then we match rules from the view source style sheet.
485 if (document().isViewSource())
486 matchUARules(collector, defaultStyleSheets.defaultViewSourceStyle());
487
488 if (document().isTransitionDocument())
489 matchUARules(collector, defaultStyleSheets.defaultTransitionStyle());
490
491 collector.setMatchingUARules(false);
492
493 matchWatchSelectorRules(collector);
494 }
495
matchUARules(ElementRuleCollector & collector,RuleSet * rules)496 void StyleResolver::matchUARules(ElementRuleCollector& collector, RuleSet* rules)
497 {
498 collector.clearMatchedRules();
499 collector.matchedResult().ranges.lastUARule = collector.matchedResult().matchedProperties.size() - 1;
500
501 RuleRange ruleRange = collector.matchedResult().ranges.UARuleRange();
502 collector.collectMatchingRules(MatchRequest(rules), ruleRange);
503
504 collector.sortAndTransferMatchedRules();
505 }
506
matchAllRules(StyleResolverState & state,ElementRuleCollector & collector,bool includeSMILProperties)507 void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollector& collector, bool includeSMILProperties)
508 {
509 matchUARules(collector);
510
511 // Now check author rules, beginning first with presentational attributes mapped from HTML.
512 if (state.element()->isStyledElement()) {
513 collector.addElementStyleProperties(state.element()->presentationAttributeStyle());
514
515 // Now we check additional mapped declarations.
516 // Tables and table cells share an additional mapped rule that must be applied
517 // after all attributes, since their mapped style depends on the values of multiple attributes.
518 collector.addElementStyleProperties(state.element()->additionalPresentationAttributeStyle());
519
520 if (state.element()->isHTMLElement()) {
521 bool isAuto;
522 TextDirection textDirection = toHTMLElement(state.element())->directionalityIfhasDirAutoAttribute(isAuto);
523 if (isAuto)
524 collector.matchedResult().addMatchedProperties(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
525 }
526 }
527
528 matchAuthorRules(state.element(), collector, false);
529
530 if (state.element()->isStyledElement()) {
531 if (state.element()->inlineStyle()) {
532 // Inline style is immutable as long as there is no CSSOM wrapper.
533 bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMutable();
534 collector.addElementStyleProperties(state.element()->inlineStyle(), isInlineStyleCacheable);
535 }
536
537 // Now check SMIL animation override style.
538 if (includeSMILProperties && state.element()->isSVGElement())
539 collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */);
540 }
541 }
542
styleForDocument(Document & document)543 PassRefPtr<RenderStyle> StyleResolver::styleForDocument(Document& document)
544 {
545 const LocalFrame* frame = document.frame();
546
547 RefPtr<RenderStyle> documentStyle = RenderStyle::create();
548 documentStyle->setDisplay(BLOCK);
549 documentStyle->setRTLOrdering(document.visuallyOrdered() ? VisualOrder : LogicalOrder);
550 documentStyle->setZoom(frame && !document.printing() ? frame->pageZoomFactor() : 1);
551 documentStyle->setLocale(document.contentLanguage());
552 documentStyle->setZIndex(0);
553 documentStyle->setUserModify(document.inDesignMode() ? READ_WRITE : READ_ONLY);
554
555 document.setupFontBuilder(documentStyle.get());
556
557 return documentStyle.release();
558 }
559
560 // FIXME: This is duplicated with StyleAdjuster.cpp
561 // Perhaps this should move onto ElementResolveContext or even Element?
isAtShadowBoundary(const Element * element)562 static inline bool isAtShadowBoundary(const Element* element)
563 {
564 if (!element)
565 return false;
566 ContainerNode* parentNode = element->parentNode();
567 return parentNode && parentNode->isShadowRoot();
568 }
569
resetDirectionAndWritingModeOnDocument(Document & document)570 static inline void resetDirectionAndWritingModeOnDocument(Document& document)
571 {
572 document.setDirectionSetOnDocumentElement(false);
573 document.setWritingModeSetOnDocumentElement(false);
574 }
575
addContentAttrValuesToFeatures(const Vector<AtomicString> & contentAttrValues,RuleFeatureSet & features)576 static void addContentAttrValuesToFeatures(const Vector<AtomicString>& contentAttrValues, RuleFeatureSet& features)
577 {
578 for (size_t i = 0; i < contentAttrValues.size(); ++i)
579 features.addContentAttr(contentAttrValues[i]);
580 }
581
adjustRenderStyle(StyleResolverState & state,Element * element)582 void StyleResolver::adjustRenderStyle(StyleResolverState& state, Element* element)
583 {
584 StyleAdjuster adjuster(m_document.inQuirksMode());
585 adjuster.adjustRenderStyle(state.style(), state.parentStyle(), element, state.cachedUAStyle());
586 }
587
588 // Start loading resources referenced by this style.
loadPendingResources(StyleResolverState & state)589 void StyleResolver::loadPendingResources(StyleResolverState& state)
590 {
591 m_styleResourceLoader.loadPendingResources(state.style(), state.elementStyleResources());
592 document().styleEngine()->fontSelector()->fontLoader()->loadPendingFonts();
593 }
594
styleForElement(Element * element,RenderStyle * defaultParent,StyleSharingBehavior sharingBehavior,RuleMatchingBehavior matchingBehavior)595 PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent, StyleSharingBehavior sharingBehavior,
596 RuleMatchingBehavior matchingBehavior)
597 {
598 ASSERT(document().frame());
599 ASSERT(documentSettings());
600 ASSERT(!hasPendingAuthorStyleSheets());
601 ASSERT(!m_needCollectFeatures);
602
603 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
604 // will vanish if a style recalc happens during loading.
605 if (sharingBehavior == AllowStyleSharing && !document().isRenderingReady() && !element->renderer()) {
606 if (!s_styleNotYetAvailable) {
607 s_styleNotYetAvailable = RenderStyle::create().leakRef();
608 s_styleNotYetAvailable->setDisplay(NONE);
609 s_styleNotYetAvailable->font().update(document().styleEngine()->fontSelector());
610 }
611
612 document().setHasNodesWithPlaceholderStyle();
613 return s_styleNotYetAvailable;
614 }
615
616 didAccess();
617
618 StyleResolverParentScope::ensureParentStackIsPushed();
619
620 if (element == document().documentElement())
621 resetDirectionAndWritingModeOnDocument(document());
622 StyleResolverState state(document(), element, defaultParent);
623
624 if (sharingBehavior == AllowStyleSharing && state.parentStyle()) {
625 SharedStyleFinder styleFinder(state.elementContext(), m_features, m_siblingRuleSet.get(), m_uncommonAttributeRuleSet.get(), *this);
626 if (RefPtr<RenderStyle> sharedStyle = styleFinder.findSharedStyle())
627 return sharedStyle.release();
628 }
629
630 if (state.parentStyle()) {
631 state.setStyle(RenderStyle::create());
632 state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
633 } else {
634 state.setStyle(defaultStyleForElement());
635 state.setParentStyle(RenderStyle::clone(state.style()));
636 }
637 // contenteditable attribute (implemented by -webkit-user-modify) should
638 // be propagated from shadow host to distributed node.
639 if (state.distributedToInsertionPoint()) {
640 if (Element* parent = element->parentElement()) {
641 if (RenderStyle* styleOfShadowHost = parent->renderStyle())
642 state.style()->setUserModify(styleOfShadowHost->userModify());
643 }
644 }
645
646 state.fontBuilder().initForStyleResolve(state.document(), state.style());
647
648 if (element->isLink()) {
649 state.style()->setIsLink(true);
650 EInsideLink linkState = state.elementLinkState();
651 if (linkState != NotInsideLink) {
652 bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited);
653 if (forceVisited)
654 linkState = InsideVisitedLink;
655 }
656 state.style()->setInsideLink(linkState);
657 }
658
659 bool needsCollection = false;
660 CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection);
661 if (needsCollection)
662 collectFeatures();
663
664 {
665 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
666
667 matchAllRules(state, collector, matchingBehavior != MatchAllRulesExcludingSMIL);
668
669 applyMatchedProperties(state, collector.matchedResult());
670
671 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
672 }
673
674 // Cache our original display.
675 state.style()->setOriginalDisplay(state.style()->display());
676
677 adjustRenderStyle(state, element);
678
679 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
680 // important rules, but this currently happens here as we require adjustment to have happened
681 // before deciding which properties to transition.
682 if (applyAnimatedProperties(state, element))
683 adjustRenderStyle(state, element);
684
685 // FIXME: Shouldn't this be on RenderBody::styleDidChange?
686 if (isHTMLBodyElement(*element))
687 document().textLinkColors().setTextColor(state.style()->color());
688
689 setAnimationUpdateIfNeeded(state, *element);
690
691 if (state.style()->hasViewportUnits())
692 document().setHasViewportUnits();
693
694 // Now return the style.
695 return state.takeStyle();
696 }
697
styleForKeyframe(Element * element,const RenderStyle & elementStyle,RenderStyle * parentStyle,const StyleKeyframe * keyframe,const AtomicString & animationName)698 PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const RenderStyle& elementStyle, RenderStyle* parentStyle, const StyleKeyframe* keyframe, const AtomicString& animationName)
699 {
700 ASSERT(document().frame());
701 ASSERT(documentSettings());
702 ASSERT(!hasPendingAuthorStyleSheets());
703
704 if (element == document().documentElement())
705 resetDirectionAndWritingModeOnDocument(document());
706 StyleResolverState state(document(), element, parentStyle);
707
708 MatchResult result;
709 result.addMatchedProperties(&keyframe->properties());
710
711 ASSERT(!state.style());
712
713 // Create the style
714 state.setStyle(RenderStyle::clone(&elementStyle));
715 state.setLineHeightValue(0);
716
717 state.fontBuilder().initForStyleResolve(state.document(), state.style());
718
719 // We don't need to bother with !important. Since there is only ever one
720 // decl, there's nothing to override. So just add the first properties.
721 // We also don't need to bother with animation properties since the only
722 // relevant one is animation-timing-function and we special-case that in
723 // CSSAnimations.cpp
724 bool inheritedOnly = false;
725 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
726
727 // If our font got dirtied, go ahead and update it now.
728 updateFont(state);
729
730 // Line-height is set when we are sure we decided on the font-size
731 if (state.lineHeightValue())
732 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
733
734 // Now do rest of the properties.
735 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
736
737 // If our font got dirtied by one of the non-essential font props,
738 // go ahead and update it a second time.
739 updateFont(state);
740
741 loadPendingResources(state);
742
743 didAccess();
744
745 return state.takeStyle();
746 }
747
748 // This function is used by the WebAnimations JavaScript API method animate().
749 // FIXME: Remove this when animate() switches away from resolution-dependent parsing.
createAnimatableValueSnapshot(Element & element,CSSPropertyID property,CSSValue & value)750 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(Element& element, CSSPropertyID property, CSSValue& value)
751 {
752 RefPtr<RenderStyle> style;
753 if (element.renderStyle())
754 style = RenderStyle::clone(element.renderStyle());
755 else
756 style = RenderStyle::create();
757 StyleResolverState state(element.document(), &element);
758 state.setStyle(style);
759 state.fontBuilder().initForStyleResolve(state.document(), state.style());
760 return createAnimatableValueSnapshot(state, property, value);
761 }
762
createAnimatableValueSnapshot(StyleResolverState & state,CSSPropertyID property,CSSValue & value)763 PassRefPtrWillBeRawPtr<AnimatableValue> StyleResolver::createAnimatableValueSnapshot(StyleResolverState& state, CSSPropertyID property, CSSValue& value)
764 {
765 StyleBuilder::applyProperty(property, state, &value);
766 return CSSAnimatableValueFactory::create(property, *state.style());
767 }
768
createPseudoElementIfNeeded(Element & parent,PseudoId pseudoId)769 PassRefPtrWillBeRawPtr<PseudoElement> StyleResolver::createPseudoElementIfNeeded(Element& parent, PseudoId pseudoId)
770 {
771 RenderObject* parentRenderer = parent.renderer();
772 if (!parentRenderer)
773 return nullptr;
774
775 if (pseudoId < FIRST_INTERNAL_PSEUDOID && !parentRenderer->style()->hasPseudoStyle(pseudoId))
776 return nullptr;
777
778 if (pseudoId == BACKDROP && !parent.isInTopLayer())
779 return nullptr;
780
781 if (!parentRenderer->canHaveGeneratedChildren())
782 return nullptr;
783
784 RenderStyle* parentStyle = parentRenderer->style();
785 if (RenderStyle* cachedStyle = parentStyle->getCachedPseudoStyle(pseudoId)) {
786 if (!pseudoElementRendererIsNeeded(cachedStyle))
787 return nullptr;
788 return PseudoElement::create(&parent, pseudoId);
789 }
790
791 StyleResolverState state(document(), &parent, parentStyle);
792 if (!pseudoStyleForElementInternal(parent, pseudoId, parentStyle, state))
793 return nullptr;
794 RefPtr<RenderStyle> style = state.takeStyle();
795 ASSERT(style);
796 parentStyle->addCachedPseudoStyle(style);
797
798 if (!pseudoElementRendererIsNeeded(style.get()))
799 return nullptr;
800
801 RefPtrWillBeRawPtr<PseudoElement> pseudo = PseudoElement::create(&parent, pseudoId);
802
803 setAnimationUpdateIfNeeded(state, *pseudo);
804 if (ActiveAnimations* activeAnimations = pseudo->activeAnimations())
805 activeAnimations->cssAnimations().maybeApplyPendingUpdate(pseudo.get());
806 return pseudo.release();
807 }
808
pseudoStyleForElementInternal(Element & element,const PseudoStyleRequest & pseudoStyleRequest,RenderStyle * parentStyle,StyleResolverState & state)809 bool StyleResolver::pseudoStyleForElementInternal(Element& element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, StyleResolverState& state)
810 {
811 ASSERT(document().frame());
812 ASSERT(documentSettings());
813 ASSERT(pseudoStyleRequest.pseudoId != FIRST_LINE_INHERITED);
814
815 StyleResolverParentScope::ensureParentStackIsPushed();
816
817 if (pseudoStyleRequest.allowsInheritance(state.parentStyle())) {
818 state.setStyle(RenderStyle::create());
819 state.style()->inheritFrom(state.parentStyle());
820 } else {
821 state.setStyle(defaultStyleForElement());
822 state.setParentStyle(RenderStyle::clone(state.style()));
823 }
824
825 state.fontBuilder().initForStyleResolve(state.document(), state.style());
826
827 // Since we don't use pseudo-elements in any of our quirk/print
828 // user agent rules, don't waste time walking those rules.
829
830 {
831 // Check UA, user and author rules.
832 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
833 collector.setPseudoStyleRequest(pseudoStyleRequest);
834
835 matchUARules(collector);
836 matchAuthorRules(state.element(), collector, false);
837
838 if (collector.matchedResult().matchedProperties.isEmpty())
839 return false;
840
841 state.style()->setStyleType(pseudoStyleRequest.pseudoId);
842
843 applyMatchedProperties(state, collector.matchedResult());
844
845 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
846 }
847
848 // Cache our original display.
849 state.style()->setOriginalDisplay(state.style()->display());
850
851 // FIXME: Passing 0 as the Element* introduces a lot of complexity
852 // in the adjustRenderStyle code.
853 adjustRenderStyle(state, 0);
854
855 // FIXME: The CSSWG wants to specify that the effects of animations are applied before
856 // important rules, but this currently happens here as we require adjustment to have happened
857 // before deciding which properties to transition.
858 if (applyAnimatedProperties(state, element.pseudoElement(pseudoStyleRequest.pseudoId)))
859 adjustRenderStyle(state, 0);
860
861 didAccess();
862
863 if (state.style()->hasViewportUnits())
864 document().setHasViewportUnits();
865
866 return true;
867 }
868
pseudoStyleForElement(Element * element,const PseudoStyleRequest & pseudoStyleRequest,RenderStyle * parentStyle)869 PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* element, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle)
870 {
871 ASSERT(parentStyle);
872 if (!element)
873 return nullptr;
874
875 StyleResolverState state(document(), element, parentStyle);
876 if (!pseudoStyleForElementInternal(*element, pseudoStyleRequest, parentStyle, state))
877 return nullptr;
878
879 if (PseudoElement* pseudoElement = element->pseudoElement(pseudoStyleRequest.pseudoId))
880 setAnimationUpdateIfNeeded(state, *pseudoElement);
881
882 // Now return the style.
883 return state.takeStyle();
884 }
885
styleForPage(int pageIndex)886 PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
887 {
888 ASSERT(!hasPendingAuthorStyleSheets());
889 resetDirectionAndWritingModeOnDocument(document());
890 StyleResolverState state(document(), document().documentElement()); // m_rootElementStyle will be set to the document style.
891
892 state.setStyle(RenderStyle::create());
893 const RenderStyle* rootElementStyle = state.rootElementStyle() ? state.rootElementStyle() : document().renderStyle();
894 ASSERT(rootElementStyle);
895 state.style()->inheritFrom(rootElementStyle);
896
897 state.fontBuilder().initForStyleResolve(state.document(), state.style());
898
899 PageRuleCollector collector(rootElementStyle, pageIndex);
900
901 collector.matchPageRules(CSSDefaultStyleSheets::instance().defaultPrintStyle());
902
903 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
904 scopedResolver->matchPageRules(collector);
905
906 state.setLineHeightValue(0);
907 bool inheritedOnly = false;
908
909 MatchResult& result = collector.matchedResult();
910 applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
911
912 // If our font got dirtied, go ahead and update it now.
913 updateFont(state);
914
915 // Line-height is set when we are sure we decided on the font-size.
916 if (state.lineHeightValue())
917 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
918
919 applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
920
921 addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
922
923 loadPendingResources(state);
924
925 didAccess();
926
927 // Now return the style.
928 return state.takeStyle();
929 }
930
collectViewportRules()931 void StyleResolver::collectViewportRules()
932 {
933 CSSDefaultStyleSheets& defaultStyleSheets = CSSDefaultStyleSheets::instance();
934 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultStyle(), ViewportStyleResolver::UserAgentOrigin);
935
936 if (!InspectorInstrumentation::applyViewportStyleOverride(&document(), this))
937 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultViewportStyle(), ViewportStyleResolver::UserAgentOrigin);
938
939 if (document().isMobileDocument())
940 viewportStyleResolver()->collectViewportRules(defaultStyleSheets.defaultXHTMLMobileProfileStyle(), ViewportStyleResolver::UserAgentOrigin);
941
942 if (ScopedStyleResolver* scopedResolver = m_styleTree.scopedStyleResolverForDocument())
943 scopedResolver->collectViewportRulesTo(this);
944
945 viewportStyleResolver()->resolve();
946 }
947
defaultStyleForElement()948 PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement()
949 {
950 StyleResolverState state(document(), 0);
951 state.setStyle(RenderStyle::create());
952 state.fontBuilder().initForStyleResolve(document(), state.style());
953 state.style()->setLineHeight(RenderStyle::initialLineHeight());
954 state.setLineHeightValue(0);
955 state.fontBuilder().setInitial(state.style()->effectiveZoom());
956 state.style()->font().update(document().styleEngine()->fontSelector());
957 return state.takeStyle();
958 }
959
styleForText(Text * textNode)960 PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode)
961 {
962 ASSERT(textNode);
963
964 NodeRenderingTraversal::ParentDetails parentDetails;
965 Node* parentNode = NodeRenderingTraversal::parent(textNode, &parentDetails);
966 if (!parentNode || !parentNode->renderStyle())
967 return defaultStyleForElement();
968 return parentNode->renderStyle();
969 }
970
updateFont(StyleResolverState & state)971 void StyleResolver::updateFont(StyleResolverState& state)
972 {
973 state.fontBuilder().createFont(document().styleEngine()->fontSelector(), state.parentStyle(), state.style());
974 if (state.fontBuilder().fontSizeHasViewportUnits())
975 state.style()->setHasViewportUnits();
976 }
977
styleRulesForElement(Element * element,unsigned rulesToInclude)978 PassRefPtrWillBeRawPtr<StyleRuleList> StyleResolver::styleRulesForElement(Element* element, unsigned rulesToInclude)
979 {
980 ASSERT(element);
981 StyleResolverState state(document(), element);
982 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
983 collector.setMode(SelectorChecker::CollectingStyleRules);
984 collectPseudoRulesForElement(element, collector, NOPSEUDO, rulesToInclude);
985 return collector.matchedStyleRuleList();
986 }
987
pseudoCSSRulesForElement(Element * element,PseudoId pseudoId,unsigned rulesToInclude)988 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::pseudoCSSRulesForElement(Element* element, PseudoId pseudoId, unsigned rulesToInclude)
989 {
990 ASSERT(element);
991 StyleResolverState state(document(), element);
992 ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
993 collector.setMode(SelectorChecker::CollectingCSSRules);
994 collectPseudoRulesForElement(element, collector, pseudoId, rulesToInclude);
995 return collector.matchedCSSRuleList();
996 }
997
cssRulesForElement(Element * element,unsigned rulesToInclude)998 PassRefPtrWillBeRawPtr<CSSRuleList> StyleResolver::cssRulesForElement(Element* element, unsigned rulesToInclude)
999 {
1000 return pseudoCSSRulesForElement(element, NOPSEUDO, rulesToInclude);
1001 }
1002
collectPseudoRulesForElement(Element * element,ElementRuleCollector & collector,PseudoId pseudoId,unsigned rulesToInclude)1003 void StyleResolver::collectPseudoRulesForElement(Element* element, ElementRuleCollector& collector, PseudoId pseudoId, unsigned rulesToInclude)
1004 {
1005 collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
1006
1007 if (rulesToInclude & UAAndUserCSSRules)
1008 matchUARules(collector);
1009
1010 if (rulesToInclude & AuthorCSSRules) {
1011 collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules));
1012 matchAuthorRules(element, collector, rulesToInclude & EmptyCSSRules);
1013 }
1014 }
1015
1016 // -------------------------------------------------------------------------------------
1017 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1018
applyAnimatedProperties(StyleResolverState & state,Element * animatingElement)1019 bool StyleResolver::applyAnimatedProperties(StyleResolverState& state, Element* animatingElement)
1020 {
1021 const Element* element = state.element();
1022 ASSERT(element);
1023
1024 // The animating element may be this element, or its pseudo element. It is
1025 // null when calculating the style for a potential pseudo element that has
1026 // yet to be created.
1027 ASSERT(animatingElement == element || !animatingElement || animatingElement->parentOrShadowHostElement() == element);
1028
1029 if (!(animatingElement && animatingElement->hasActiveAnimations())
1030 && !state.style()->transitions() && !state.style()->animations())
1031 return false;
1032
1033 state.setAnimationUpdate(CSSAnimations::calculateUpdate(animatingElement, *element, *state.style(), state.parentStyle(), this));
1034 if (!state.animationUpdate())
1035 return false;
1036
1037 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations = state.animationUpdate()->activeInterpolationsForAnimations();
1038 const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForTransitions = state.animationUpdate()->activeInterpolationsForTransitions();
1039 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForAnimations);
1040 applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForTransitions);
1041
1042 updateFont(state);
1043
1044 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForAnimations);
1045 applyAnimatedProperties<LowPriorityProperties>(state, activeInterpolationsForTransitions);
1046
1047 // Start loading resources used by animations.
1048 loadPendingResources(state);
1049
1050 ASSERT(!state.fontBuilder().fontDirty());
1051
1052 return true;
1053 }
1054
1055 template <StyleResolver::StyleApplicationPass pass>
applyAnimatedProperties(StyleResolverState & state,const WillBeHeapHashMap<CSSPropertyID,RefPtrWillBeMember<Interpolation>> & activeInterpolations)1056 void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolations)
1057 {
1058 ASSERT(pass != AnimationProperties);
1059
1060 for (WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >::const_iterator iter = activeInterpolations.begin(); iter != activeInterpolations.end(); ++iter) {
1061 CSSPropertyID property = iter->key;
1062 if (!isPropertyForPass<pass>(property))
1063 continue;
1064 const StyleInterpolation* interpolation = toStyleInterpolation(iter->value.get());
1065 interpolation->apply(state);
1066 }
1067 }
1068
isValidCueStyleProperty(CSSPropertyID id)1069 static inline bool isValidCueStyleProperty(CSSPropertyID id)
1070 {
1071 switch (id) {
1072 case CSSPropertyBackground:
1073 case CSSPropertyBackgroundAttachment:
1074 case CSSPropertyBackgroundClip:
1075 case CSSPropertyBackgroundColor:
1076 case CSSPropertyBackgroundImage:
1077 case CSSPropertyBackgroundOrigin:
1078 case CSSPropertyBackgroundPosition:
1079 case CSSPropertyBackgroundPositionX:
1080 case CSSPropertyBackgroundPositionY:
1081 case CSSPropertyBackgroundRepeat:
1082 case CSSPropertyBackgroundRepeatX:
1083 case CSSPropertyBackgroundRepeatY:
1084 case CSSPropertyBackgroundSize:
1085 case CSSPropertyColor:
1086 case CSSPropertyFont:
1087 case CSSPropertyFontFamily:
1088 case CSSPropertyFontSize:
1089 case CSSPropertyFontStyle:
1090 case CSSPropertyFontVariant:
1091 case CSSPropertyFontWeight:
1092 case CSSPropertyLineHeight:
1093 case CSSPropertyOpacity:
1094 case CSSPropertyOutline:
1095 case CSSPropertyOutlineColor:
1096 case CSSPropertyOutlineOffset:
1097 case CSSPropertyOutlineStyle:
1098 case CSSPropertyOutlineWidth:
1099 case CSSPropertyVisibility:
1100 case CSSPropertyWhiteSpace:
1101 // FIXME: 'text-decoration' shorthand to be handled when available.
1102 // See https://chromiumcodereview.appspot.com/19516002 for details.
1103 case CSSPropertyTextDecoration:
1104 case CSSPropertyTextShadow:
1105 case CSSPropertyBorderStyle:
1106 return true;
1107 case CSSPropertyTextDecorationLine:
1108 case CSSPropertyTextDecorationStyle:
1109 case CSSPropertyTextDecorationColor:
1110 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1111 default:
1112 break;
1113 }
1114 return false;
1115 }
1116
isValidFirstLetterStyleProperty(CSSPropertyID id)1117 static inline bool isValidFirstLetterStyleProperty(CSSPropertyID id)
1118 {
1119 switch (id) {
1120 // Valid ::first-letter properties listed in spec:
1121 // http://www.w3.org/TR/css3-selectors/#application-in-css
1122 case CSSPropertyBackgroundAttachment:
1123 case CSSPropertyBackgroundBlendMode:
1124 case CSSPropertyBackgroundClip:
1125 case CSSPropertyBackgroundColor:
1126 case CSSPropertyBackgroundImage:
1127 case CSSPropertyBackgroundOrigin:
1128 case CSSPropertyBackgroundPosition:
1129 case CSSPropertyBackgroundPositionX:
1130 case CSSPropertyBackgroundPositionY:
1131 case CSSPropertyBackgroundRepeat:
1132 case CSSPropertyBackgroundRepeatX:
1133 case CSSPropertyBackgroundRepeatY:
1134 case CSSPropertyBackgroundSize:
1135 case CSSPropertyBorderBottomColor:
1136 case CSSPropertyBorderBottomLeftRadius:
1137 case CSSPropertyBorderBottomRightRadius:
1138 case CSSPropertyBorderBottomStyle:
1139 case CSSPropertyBorderBottomWidth:
1140 case CSSPropertyBorderImageOutset:
1141 case CSSPropertyBorderImageRepeat:
1142 case CSSPropertyBorderImageSlice:
1143 case CSSPropertyBorderImageSource:
1144 case CSSPropertyBorderImageWidth:
1145 case CSSPropertyBorderLeftColor:
1146 case CSSPropertyBorderLeftStyle:
1147 case CSSPropertyBorderLeftWidth:
1148 case CSSPropertyBorderRightColor:
1149 case CSSPropertyBorderRightStyle:
1150 case CSSPropertyBorderRightWidth:
1151 case CSSPropertyBorderTopColor:
1152 case CSSPropertyBorderTopLeftRadius:
1153 case CSSPropertyBorderTopRightRadius:
1154 case CSSPropertyBorderTopStyle:
1155 case CSSPropertyBorderTopWidth:
1156 case CSSPropertyColor:
1157 case CSSPropertyFloat:
1158 case CSSPropertyFont:
1159 case CSSPropertyFontFamily:
1160 case CSSPropertyFontKerning:
1161 case CSSPropertyFontSize:
1162 case CSSPropertyFontStretch:
1163 case CSSPropertyFontStyle:
1164 case CSSPropertyFontVariant:
1165 case CSSPropertyFontVariantLigatures:
1166 case CSSPropertyFontWeight:
1167 case CSSPropertyLetterSpacing:
1168 case CSSPropertyLineHeight:
1169 case CSSPropertyMarginBottom:
1170 case CSSPropertyMarginLeft:
1171 case CSSPropertyMarginRight:
1172 case CSSPropertyMarginTop:
1173 case CSSPropertyPaddingBottom:
1174 case CSSPropertyPaddingLeft:
1175 case CSSPropertyPaddingRight:
1176 case CSSPropertyPaddingTop:
1177 case CSSPropertyTextTransform:
1178 case CSSPropertyVerticalAlign:
1179 case CSSPropertyWebkitBackgroundClip:
1180 case CSSPropertyWebkitBackgroundComposite:
1181 case CSSPropertyWebkitBackgroundOrigin:
1182 case CSSPropertyWebkitBackgroundSize:
1183 case CSSPropertyWebkitBorderAfter:
1184 case CSSPropertyWebkitBorderAfterColor:
1185 case CSSPropertyWebkitBorderAfterStyle:
1186 case CSSPropertyWebkitBorderAfterWidth:
1187 case CSSPropertyWebkitBorderBefore:
1188 case CSSPropertyWebkitBorderBeforeColor:
1189 case CSSPropertyWebkitBorderBeforeStyle:
1190 case CSSPropertyWebkitBorderBeforeWidth:
1191 case CSSPropertyWebkitBorderEnd:
1192 case CSSPropertyWebkitBorderEndColor:
1193 case CSSPropertyWebkitBorderEndStyle:
1194 case CSSPropertyWebkitBorderEndWidth:
1195 case CSSPropertyWebkitBorderFit:
1196 case CSSPropertyWebkitBorderHorizontalSpacing:
1197 case CSSPropertyWebkitBorderImage:
1198 case CSSPropertyWebkitBorderRadius:
1199 case CSSPropertyWebkitBorderStart:
1200 case CSSPropertyWebkitBorderStartColor:
1201 case CSSPropertyWebkitBorderStartStyle:
1202 case CSSPropertyWebkitBorderStartWidth:
1203 case CSSPropertyWebkitBorderVerticalSpacing:
1204 case CSSPropertyWebkitFontSmoothing:
1205 case CSSPropertyWebkitMarginAfter:
1206 case CSSPropertyWebkitMarginAfterCollapse:
1207 case CSSPropertyWebkitMarginBefore:
1208 case CSSPropertyWebkitMarginBeforeCollapse:
1209 case CSSPropertyWebkitMarginBottomCollapse:
1210 case CSSPropertyWebkitMarginCollapse:
1211 case CSSPropertyWebkitMarginEnd:
1212 case CSSPropertyWebkitMarginStart:
1213 case CSSPropertyWebkitMarginTopCollapse:
1214 case CSSPropertyWordSpacing:
1215 return true;
1216 case CSSPropertyTextDecorationColor:
1217 case CSSPropertyTextDecorationLine:
1218 case CSSPropertyTextDecorationStyle:
1219 return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
1220
1221 // text-shadow added in text decoration spec:
1222 // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property
1223 case CSSPropertyTextShadow:
1224 // box-shadox added in CSS3 backgrounds spec:
1225 // http://www.w3.org/TR/css3-background/#placement
1226 case CSSPropertyBoxShadow:
1227 case CSSPropertyWebkitBoxShadow:
1228 // Properties that we currently support outside of spec.
1229 case CSSPropertyWebkitLineBoxContain:
1230 case CSSPropertyVisibility:
1231 return true;
1232
1233 default:
1234 return false;
1235 }
1236 }
1237
1238 // FIXME: Consider refactoring to create a new class which owns the following
1239 // first/last/range properties.
1240 // This method returns the first CSSPropertyId of properties which generate
1241 // animations. All animation properties are obtained by using
1242 // firstCSSPropertyId<AnimationProperties> and
1243 // lastCSSPropertyId<AnimationProperties>.
1244 // c.f. //src/third_party/WebKit/Source/core/css/CSSPropertyNames.in.
firstCSSPropertyId()1245 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::AnimationProperties>()
1246 {
1247 COMPILE_ASSERT(firstCSSProperty == CSSPropertyDisplay, CSS_first_animation_property_should_be_first_property);
1248 return CSSPropertyDisplay;
1249 }
1250
1251 // This method returns the first CSSPropertyId of properties which generate
1252 // animations.
lastCSSPropertyId()1253 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::AnimationProperties>()
1254 {
1255 COMPILE_ASSERT(CSSPropertyTransitionTimingFunction == CSSPropertyColor - 1, CSS_transition_timing_is_last_animation_property);
1256 return CSSPropertyTransitionTimingFunction;
1257 }
1258
1259 // This method returns the first CSSPropertyId of high priority properties.
1260 // Other properties can depend on high priority properties. For example,
1261 // border-color property with currentColor value depends on color property.
1262 // All high priority properties are obtained by using
1263 // firstCSSPropertyId<HighPriorityProperties> and
1264 // lastCSSPropertyId<HighPriorityProperties>.
firstCSSPropertyId()1265 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::HighPriorityProperties>()
1266 {
1267 COMPILE_ASSERT(CSSPropertyTransitionTimingFunction + 1 == CSSPropertyColor, CSS_color_is_first_high_priority_property);
1268 return CSSPropertyColor;
1269 }
1270
1271 // This method returns the last CSSPropertyId of high priority properties.
lastCSSPropertyId()1272 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::HighPriorityProperties>()
1273 {
1274 COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyColor + 17, CSS_line_height_is_end_of_high_prioity_property_range);
1275 COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyLineHeight - 1, CSS_zoom_is_before_line_height);
1276 return CSSPropertyLineHeight;
1277 }
1278
1279 // This method returns the first CSSPropertyId of remaining properties,
1280 // i.e. low priority properties. No properties depend on low priority
1281 // properties. So we don't need to resolve such properties quickly.
1282 // All low priority properties are obtained by using
1283 // firstCSSPropertyId<LowPriorityProperties> and
1284 // lastCSSPropertyId<LowPriorityProperties>.
firstCSSPropertyId()1285 template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::LowPriorityProperties>()
1286 {
1287 COMPILE_ASSERT(CSSPropertyBackground == CSSPropertyLineHeight + 1, CSS_background_is_first_low_priority_property);
1288 return CSSPropertyBackground;
1289 }
1290
1291 // This method returns the last CSSPropertyId of low priority properties.
lastCSSPropertyId()1292 template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::LowPriorityProperties>()
1293 {
1294 return static_cast<CSSPropertyID>(lastCSSProperty);
1295 }
1296
1297 template <StyleResolver::StyleApplicationPass pass>
isPropertyForPass(CSSPropertyID property)1298 bool StyleResolver::isPropertyForPass(CSSPropertyID property)
1299 {
1300 return firstCSSPropertyId<pass>() <= property && property <= lastCSSPropertyId<pass>();
1301 }
1302
1303 // This method expands all shorthand property to longhand properties
1304 // considering StyleApplicationPass, and apply each expanded longhand property.
1305 // For example, if StyleApplicationPass is AnimationProperties, all shorthand
1306 // is expaneded to display, -webkit-animation, -webkit-animation-delay, ...,
1307 // transition-timing-function. So each property's value will be applied
1308 // according to all's value (initial, inherit or unset).
1309 template <StyleResolver::StyleApplicationPass pass>
applyAllProperty(StyleResolverState & state,CSSValue * allValue)1310 void StyleResolver::applyAllProperty(StyleResolverState& state, CSSValue* allValue)
1311 {
1312 bool isUnsetValue = !allValue->isInitialValue() && !allValue->isInheritedValue();
1313 unsigned startCSSProperty = firstCSSPropertyId<pass>();
1314 unsigned endCSSProperty = lastCSSPropertyId<pass>();
1315
1316 for (unsigned i = startCSSProperty; i <= endCSSProperty; ++i) {
1317 CSSPropertyID propertyId = static_cast<CSSPropertyID>(i);
1318
1319 // StyleBuilder does not allow any expanded shorthands.
1320 if (isExpandedShorthandForAll(propertyId))
1321 continue;
1322
1323 // all shorthand spec says:
1324 // The all property is a shorthand that resets all CSS properties
1325 // except direction and unicode-bidi.
1326 // c.f. http://dev.w3.org/csswg/css-cascade/#all-shorthand
1327 // We skip applyProperty when a given property is unicode-bidi or
1328 // direction.
1329 if (!CSSProperty::isAffectedByAllProperty(propertyId))
1330 continue;
1331
1332 CSSValue* value;
1333 if (!isUnsetValue) {
1334 value = allValue;
1335 } else {
1336 if (CSSProperty::isInheritedProperty(propertyId))
1337 value = cssValuePool().createInheritedValue().get();
1338 else
1339 value = cssValuePool().createExplicitInitialValue().get();
1340 }
1341 StyleBuilder::applyProperty(propertyId, state, value);
1342 }
1343 }
1344
1345 template <StyleResolver::StyleApplicationPass pass>
applyProperties(StyleResolverState & state,const StylePropertySet * properties,StyleRule * rule,bool isImportant,bool inheritedOnly,PropertyWhitelistType propertyWhitelistType)1346 void StyleResolver::applyProperties(StyleResolverState& state, const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType)
1347 {
1348 state.setCurrentRule(rule);
1349
1350 unsigned propertyCount = properties->propertyCount();
1351 for (unsigned i = 0; i < propertyCount; ++i) {
1352 StylePropertySet::PropertyReference current = properties->propertyAt(i);
1353 if (isImportant != current.isImportant())
1354 continue;
1355
1356 CSSPropertyID property = current.id();
1357 if (property == CSSPropertyAll) {
1358 applyAllProperty<pass>(state, current.value());
1359 continue;
1360 }
1361
1362 if (inheritedOnly && !current.isInherited()) {
1363 // If the property value is explicitly inherited, we need to apply further non-inherited properties
1364 // as they might override the value inherited here. For this reason we don't allow declarations with
1365 // explicitly inherited properties to be cached.
1366 ASSERT(!current.value()->isInheritedValue());
1367 continue;
1368 }
1369
1370 if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property))
1371 continue;
1372 if (propertyWhitelistType == PropertyWhitelistFirstLetter && !isValidFirstLetterStyleProperty(property))
1373 continue;
1374 if (!isPropertyForPass<pass>(property))
1375 continue;
1376 if (pass == HighPriorityProperties && property == CSSPropertyLineHeight)
1377 state.setLineHeightValue(current.value());
1378 else
1379 StyleBuilder::applyProperty(current.id(), state, current.value());
1380 }
1381 }
1382
1383 template <StyleResolver::StyleApplicationPass pass>
applyMatchedProperties(StyleResolverState & state,const MatchResult & matchResult,bool isImportant,int startIndex,int endIndex,bool inheritedOnly)1384 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
1385 {
1386 if (startIndex == -1)
1387 return;
1388
1389 if (state.style()->insideLink() != NotInsideLink) {
1390 for (int i = startIndex; i <= endIndex; ++i) {
1391 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1392 unsigned linkMatchType = matchedProperties.linkMatchType;
1393 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
1394 state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink);
1395 state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited);
1396
1397 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1398 }
1399 state.setApplyPropertyToRegularStyle(true);
1400 state.setApplyPropertyToVisitedLinkStyle(false);
1401 return;
1402 }
1403 for (int i = startIndex; i <= endIndex; ++i) {
1404 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1405 applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1406 }
1407 }
1408
computeMatchedPropertiesHash(const MatchedProperties * properties,unsigned size)1409 static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
1410 {
1411 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
1412 }
1413
invalidateMatchedPropertiesCache()1414 void StyleResolver::invalidateMatchedPropertiesCache()
1415 {
1416 m_matchedPropertiesCache.clear();
1417 }
1418
notifyResizeForViewportUnits()1419 void StyleResolver::notifyResizeForViewportUnits()
1420 {
1421 collectViewportRules();
1422 m_matchedPropertiesCache.clearViewportDependent();
1423 }
1424
applyMatchedProperties(StyleResolverState & state,const MatchResult & matchResult)1425 void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult)
1426 {
1427 const Element* element = state.element();
1428 ASSERT(element);
1429
1430 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply);
1431
1432 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
1433 bool applyInheritedOnly = false;
1434 const CachedMatchedProperties* cachedMatchedProperties = 0;
1435
1436 if (cacheHash && (cachedMatchedProperties = m_matchedPropertiesCache.find(cacheHash, state, matchResult))
1437 && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1438 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit);
1439 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
1440 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the
1441 // element context. This is fast and saves memory by reusing the style data structures.
1442 state.style()->copyNonInheritedFrom(cachedMatchedProperties->renderStyle.get());
1443 if (state.parentStyle()->inheritedDataShared(cachedMatchedProperties->parentRenderStyle.get()) && !isAtShadowBoundary(element)
1444 && (!state.distributedToInsertionPoint() || state.style()->userModify() == READ_ONLY)) {
1445 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheInheritedHit);
1446
1447 EInsideLink linkStatus = state.style()->insideLink();
1448 // If the cache item parent style has identical inherited properties to the current parent style then the
1449 // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
1450 state.style()->inheritFrom(cachedMatchedProperties->renderStyle.get());
1451
1452 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
1453 state.style()->setInsideLink(linkStatus);
1454 return;
1455 }
1456 applyInheritedOnly = true;
1457 }
1458
1459 // Apply animation properties in order to apply animation results and trigger transitions below.
1460 applyMatchedProperties<AnimationProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1461 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1462 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1463 applyMatchedProperties<AnimationProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1464
1465 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
1466 // high-priority properties first, i.e., those properties that other properties depend on.
1467 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
1468 // and (4) normal important.
1469 state.setLineHeightValue(0);
1470 applyMatchedProperties<HighPriorityProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1471 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1472 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1473 applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1474
1475 if (UNLIKELY(isSVGForeignObjectElement(element))) {
1476 // RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should not be scaled again.
1477 //
1478 // FIXME: The following hijacks the zoom property for foreignObject so that children of foreignObject get the
1479 // correct font-size in case of zooming. 'zoom' is part of HighPriorityProperties, along with other font-related
1480 // properties used as input to the FontBuilder, so resetting it here may cause the FontBuilder to recompute the
1481 // font used as inheritable font for foreignObject content. If we want to support zoom on foreignObject we'll
1482 // need to find another way of handling the SVG zoom model.
1483 state.setEffectiveZoom(RenderStyle::initialZoom());
1484 }
1485
1486 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) {
1487 state.fontBuilder().setFontDirty(true);
1488 applyInheritedOnly = false;
1489 }
1490
1491 // If our font got dirtied, go ahead and update it now.
1492 updateFont(state);
1493
1494 // Line-height is set when we are sure we decided on the font-size.
1495 if (state.lineHeightValue())
1496 StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
1497
1498 // Many properties depend on the font. If it changes we just apply all properties.
1499 if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription())
1500 applyInheritedOnly = false;
1501
1502 // Now do the normal priority UA properties.
1503 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1504
1505 // Cache the UA properties to pass them to RenderTheme in adjustRenderStyle.
1506 state.cacheUserAgentBorderAndBackground();
1507
1508 // Now do the author and user normal priority properties and all the !important properties.
1509 applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1510 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1511 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1512 applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1513
1514 loadPendingResources(state);
1515
1516 if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) {
1517 INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded);
1518 m_matchedPropertiesCache.add(state.style(), state.parentStyle(), cacheHash, matchResult);
1519 }
1520
1521 ASSERT(!state.fontBuilder().fontDirty());
1522 }
1523
CSSPropertyValue(CSSPropertyID id,const StylePropertySet & propertySet)1524 CSSPropertyValue::CSSPropertyValue(CSSPropertyID id, const StylePropertySet& propertySet)
1525 : property(id), value(propertySet.getPropertyCSSValue(id).get())
1526 { }
1527
enableStats(StatsReportType reportType)1528 void StyleResolver::enableStats(StatsReportType reportType)
1529 {
1530 if (m_styleResolverStats)
1531 return;
1532 m_styleResolverStats = StyleResolverStats::create();
1533 m_styleResolverStatsTotals = StyleResolverStats::create();
1534 if (reportType == ReportSlowStats) {
1535 m_styleResolverStats->printMissedCandidateCount = true;
1536 m_styleResolverStatsTotals->printMissedCandidateCount = true;
1537 }
1538 }
1539
disableStats()1540 void StyleResolver::disableStats()
1541 {
1542 m_styleResolverStatsSequence = 0;
1543 m_styleResolverStats.clear();
1544 m_styleResolverStatsTotals.clear();
1545 }
1546
printStats()1547 void StyleResolver::printStats()
1548 {
1549 if (!m_styleResolverStats)
1550 return;
1551 fprintf(stderr, "=== Style Resolver Stats (resolve #%u) (%s) ===\n", ++m_styleResolverStatsSequence, m_document.url().string().utf8().data());
1552 fprintf(stderr, "%s\n", m_styleResolverStats->report().utf8().data());
1553 fprintf(stderr, "== Totals ==\n");
1554 fprintf(stderr, "%s\n", m_styleResolverStatsTotals->report().utf8().data());
1555 }
1556
applyPropertiesToStyle(const CSSPropertyValue * properties,size_t count,RenderStyle * style)1557 void StyleResolver::applyPropertiesToStyle(const CSSPropertyValue* properties, size_t count, RenderStyle* style)
1558 {
1559 StyleResolverState state(document(), document().documentElement(), style);
1560 state.setStyle(style);
1561
1562 state.fontBuilder().initForStyleResolve(document(), style);
1563
1564 for (size_t i = 0; i < count; ++i) {
1565 if (properties[i].value) {
1566 // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call,
1567 // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122).
1568 // The updateFont() call below updates the fontMetrics and ensure the proper setting of font-size and line-height.
1569 switch (properties[i].property) {
1570 case CSSPropertyFontSize:
1571 case CSSPropertyLineHeight:
1572 updateFont(state);
1573 break;
1574 default:
1575 break;
1576 }
1577 StyleBuilder::applyProperty(properties[i].property, state, properties[i].value);
1578 }
1579 }
1580 }
1581
addMediaQueryResults(const MediaQueryResultList & list)1582 void StyleResolver::addMediaQueryResults(const MediaQueryResultList& list)
1583 {
1584 for (size_t i = 0; i < list.size(); ++i)
1585 m_viewportDependentMediaQueryResults.append(list[i]);
1586 }
1587
mediaQueryAffectedByViewportChange() const1588 bool StyleResolver::mediaQueryAffectedByViewportChange() const
1589 {
1590 for (unsigned i = 0; i < m_viewportDependentMediaQueryResults.size(); ++i) {
1591 if (m_medium->eval(m_viewportDependentMediaQueryResults[i]->expression()) != m_viewportDependentMediaQueryResults[i]->result())
1592 return true;
1593 }
1594 return false;
1595 }
1596
trace(Visitor * visitor)1597 void StyleResolver::trace(Visitor* visitor)
1598 {
1599 visitor->trace(m_keyframesRuleMap);
1600 visitor->trace(m_viewportDependentMediaQueryResults);
1601 visitor->trace(m_viewportStyleResolver);
1602 visitor->trace(m_features);
1603 visitor->trace(m_siblingRuleSet);
1604 visitor->trace(m_uncommonAttributeRuleSet);
1605 visitor->trace(m_watchedSelectorsRules);
1606 visitor->trace(m_treeBoundaryCrossingRules);
1607 visitor->trace(m_pendingStyleSheets);
1608 }
1609
1610 } // namespace WebCore
1611