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