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.
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.
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.
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.
30 #include "StyleResolver.h"
32 #include "Attribute.h"
33 #include "CSSBorderImage.h"
34 #include "CSSCalculationValue.h"
35 #include "CSSCursorImageValue.h"
36 #include "CSSDefaultStyleSheets.h"
37 #include "CSSFontFaceRule.h"
38 #include "CSSFontSelector.h"
39 #include "CSSLineBoxContainValue.h"
40 #include "CSSPageRule.h"
41 #include "CSSParser.h"
42 #include "CSSPrimitiveValueMappings.h"
43 #include "CSSPropertyNames.h"
44 #include "CSSReflectValue.h"
45 #include "CSSSelector.h"
46 #include "CSSSelectorList.h"
47 #include "CSSStyleRule.h"
48 #include "CSSSupportsRule.h"
49 #include "CSSTimingFunctionValue.h"
50 #include "CSSValueList.h"
51 #if ENABLE(CSS_VARIABLES)
52 #include "CSSVariableValue.h"
54 #include "CachedImage.h"
55 #include "CalculationValue.h"
56 #include "ContentData.h"
57 #include "ContextFeatures.h"
59 #include "CounterContent.h"
60 #include "CursorList.h"
61 #include "DocumentStyleSheetCollection.h"
62 #include "ElementShadow.h"
63 #include "FontFeatureValue.h"
64 #include "FontValue.h"
66 #include "FrameSelection.h"
67 #include "FrameView.h"
68 #include "HTMLDocument.h"
69 #include "HTMLIFrameElement.h"
70 #include "HTMLInputElement.h"
71 #include "HTMLNames.h"
72 #include "HTMLOptionElement.h"
73 #include "HTMLProgressElement.h"
74 #include "HTMLStyleElement.h"
75 #include "HTMLTextAreaElement.h"
76 #include "InsertionPoint.h"
77 #include "InspectorInstrumentation.h"
78 #include "KeyframeList.h"
80 #include "LocaleToScriptMapping.h"
81 #include "MathMLNames.h"
82 #include "Matrix3DTransformOperation.h"
83 #include "MatrixTransformOperation.h"
84 #include "MediaList.h"
85 #include "MediaQueryEvaluator.h"
86 #include "NodeRenderStyle.h"
87 #include "NodeRenderingContext.h"
90 #include "PerspectiveTransformOperation.h"
91 #include "QuotesData.h"
93 #include "RenderRegion.h"
94 #include "RenderScrollbar.h"
95 #include "RenderScrollbarTheme.h"
96 #include "RenderStyleConstants.h"
97 #include "RenderTheme.h"
98 #include "RenderView.h"
99 #include "RotateTransformOperation.h"
101 #include "SVGDocumentExtensions.h"
102 #include "SVGFontFaceElement.h"
103 #include "ScaleTransformOperation.h"
104 #include "SecurityOrigin.h"
105 #include "Settings.h"
106 #include "ShadowData.h"
107 #include "ShadowRoot.h"
108 #include "ShadowValue.h"
109 #include "SiblingTraversalStrategies.h"
110 #include "SkewTransformOperation.h"
111 #include "StyleBuilder.h"
112 #include "StyleCachedImage.h"
113 #include "StyleGeneratedImage.h"
114 #include "StylePendingImage.h"
115 #include "StyleRule.h"
116 #include "StyleRuleImport.h"
117 #include "StyleSheetContents.h"
118 #include "StyleSheetList.h"
120 #include "TransformationMatrix.h"
121 #include "TranslateTransformOperation.h"
122 #include "UserAgentStyleSheets.h"
123 #include "ViewportStyleResolver.h"
124 #include "VisitedLinkState.h"
125 #include "WebCoreMemoryInstrumentation.h"
126 #include "WebKitCSSKeyframeRule.h"
127 #include "WebKitCSSKeyframesRule.h"
128 #include "WebKitCSSRegionRule.h"
129 #include "WebKitCSSTransformValue.h"
130 #include "WebKitFontFamilyNames.h"
131 #include "XMLNames.h"
132 #include <wtf/MemoryInstrumentationHashMap.h>
133 #include <wtf/MemoryInstrumentationHashSet.h>
134 #include <wtf/MemoryInstrumentationVector.h>
135 #include <wtf/StdLibExtras.h>
136 #include <wtf/Vector.h>
138 #if ENABLE(CSS_FILTERS)
139 #include "FilterOperation.h"
140 #include "WebKitCSSFilterValue.h"
143 #if ENABLE(DASHBOARD_SUPPORT)
144 #include "DashboardRegion.h"
148 #include "CachedSVGDocument.h"
149 #include "CachedSVGDocumentReference.h"
150 #include "SVGDocument.h"
151 #include "SVGElement.h"
152 #include "SVGNames.h"
153 #include "SVGURIReference.h"
154 #include "WebKitCSSSVGDocumentValue.h"
157 #if ENABLE(CSS_SHADERS)
158 #include "CustomFilterArrayParameter.h"
159 #include "CustomFilterConstants.h"
160 #include "CustomFilterNumberParameter.h"
161 #include "CustomFilterOperation.h"
162 #include "CustomFilterParameter.h"
163 #include "CustomFilterTransformParameter.h"
164 #include "StyleCachedShader.h"
165 #include "StyleCustomFilterProgram.h"
166 #include "StylePendingShader.h"
167 #include "StyleShader.h"
168 #include "WebKitCSSMixFunctionValue.h"
169 #include "WebKitCSSShaderValue.h"
172 #if ENABLE(CSS_IMAGE_SET)
173 #include "CSSImageSetValue.h"
174 #include "StyleCachedImageSet.h"
177 #if ENABLE(VIDEO_TRACK)
178 #include "WebVTTElement.h"
185 template<> struct SequenceMemoryInstrumentationTraits<const WebCore::RuleData*> {
186 template <typename I> static void reportMemoryUsage(I, I, MemoryClassInfo&) { }
193 using namespace HTMLNames;
195 #define HANDLE_INHERIT(prop, Prop) \
197 m_state.style->set##Prop(m_state.parentStyle->prop()); \
201 #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
202 HANDLE_INHERIT(prop, Prop) \
204 m_state.style->set##Prop(RenderStyle::initial##Prop()); \
208 RenderStyle* StyleResolver::s_styleNotYetAvailable;
210 static StylePropertySet* leftToRightDeclaration()
212 DEFINE_STATIC_LOCAL(RefPtr<StylePropertySet>, leftToRightDecl, (StylePropertySet::create()));
213 if (leftToRightDecl->isEmpty())
214 leftToRightDecl->setProperty(CSSPropertyDirection, CSSValueLtr);
215 return leftToRightDecl.get();
218 static StylePropertySet* rightToLeftDeclaration()
220 DEFINE_STATIC_LOCAL(RefPtr<StylePropertySet>, rightToLeftDecl, (StylePropertySet::create()));
221 if (rightToLeftDecl->isEmpty())
222 rightToLeftDecl->setProperty(CSSPropertyDirection, CSSValueRtl);
223 return rightToLeftDecl.get();
227 StyleResolver::StyleResolver(Document* document, bool matchAuthorAndUserStyles)
228 : m_matchedPropertiesCacheAdditionsSinceLastSweep(0)
229 , m_matchedPropertiesCacheSweepTimer(this, &StyleResolver::sweepMatchedPropertiesCache)
230 , m_document(document)
231 , m_selectorChecker(document)
232 , m_matchAuthorAndUserStyles(matchAuthorAndUserStyles)
233 , m_fontSelector(CSSFontSelector::create(document))
234 #if ENABLE(CSS_DEVICE_ADAPTATION)
235 , m_viewportStyleResolver(ViewportStyleResolver::create(document))
237 , m_styleBuilder(StyleBuilder::sharedStyleBuilder())
240 Element* root = document->documentElement();
242 CSSDefaultStyleSheets::initDefaultStyle(root);
244 // construct document root element default style. this is needed
245 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
246 // This is here instead of constructor, because when constructor is run,
247 // document doesn't have documentElement
248 // NOTE: this assumes that element that gets passed to styleForElement -call
249 // is always from the document that owns the style selector
250 FrameView* view = document->view();
252 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType()));
254 m_medium = adoptPtr(new MediaQueryEvaluator("all"));
257 m_rootDefaultStyle = styleForElement(root, 0, DisallowStyleSharing, MatchOnlyUserAgentRules);
259 if (m_rootDefaultStyle && view)
260 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle.get()));
264 DocumentStyleSheetCollection* styleSheetCollection = document->styleSheetCollection();
265 OwnPtr<RuleSet> tempUserStyle = RuleSet::create();
266 if (CSSStyleSheet* pageUserSheet = styleSheetCollection->pageUserSheet())
267 tempUserStyle->addRulesFromSheet(pageUserSheet->contents(), *m_medium, this);
268 collectRulesFromUserStyleSheets(styleSheetCollection->injectedUserStyleSheets(), *tempUserStyle);
269 collectRulesFromUserStyleSheets(styleSheetCollection->documentUserStyleSheets(), *tempUserStyle);
270 if (tempUserStyle->m_ruleCount > 0 || tempUserStyle->m_pageRules.size() > 0)
271 m_userStyle = tempUserStyle.release();
273 #if ENABLE(SVG_FONTS)
274 if (document->svgExtensions()) {
275 const HashSet<SVGFontFaceElement*>& svgFontFaceElements = document->svgExtensions()->svgFontFaceElements();
276 HashSet<SVGFontFaceElement*>::const_iterator end = svgFontFaceElements.end();
277 for (HashSet<SVGFontFaceElement*>::const_iterator it = svgFontFaceElements.begin(); it != end; ++it)
278 fontSelector()->addFontFaceRule((*it)->fontFaceRule());
282 appendAuthorStyleSheets(0, styleSheetCollection->activeAuthorStyleSheets());
285 void StyleResolver::collectRulesFromUserStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& userSheets, RuleSet& userStyle)
287 for (unsigned i = 0; i < userSheets.size(); ++i) {
288 ASSERT(userSheets[i]->contents()->isUserStyleSheet());
289 userStyle.addRulesFromSheet(userSheets[i]->contents(), *m_medium, this);
293 static PassOwnPtr<RuleSet> makeRuleSet(const Vector<RuleFeature>& rules)
295 size_t size = rules.size();
298 OwnPtr<RuleSet> ruleSet = RuleSet::create();
299 for (size_t i = 0; i < size; ++i)
300 ruleSet->addRule(rules[i].rule, rules[i].selectorIndex, rules[i].hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState);
301 ruleSet->shrinkToFit();
302 return ruleSet.release();
305 void StyleResolver::resetAuthorStyle()
307 m_authorStyle = RuleSet::create();
308 m_authorStyle->disableAutoShrinkToFit();
311 void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets)
313 // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver
314 // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated.
315 unsigned size = styleSheets.size();
316 for (unsigned i = firstNew; i < size; ++i) {
317 CSSStyleSheet* cssSheet = styleSheets[i].get();
318 ASSERT(!cssSheet->disabled());
319 if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), this))
321 StyleSheetContents* sheet = cssSheet->contents();
322 #if ENABLE(STYLE_SCOPED) || ENABLE(SHADOW_DOM)
323 if (const ContainerNode* scope = StyleScopeResolver::scopeFor(cssSheet)) {
324 ensureScopeResolver()->ensureRuleSetFor(scope)->addRulesFromSheet(sheet, *m_medium, this, scope);
329 m_authorStyle->addRulesFromSheet(sheet, *m_medium, this);
330 m_inspectorCSSOMWrappers.collectFromStyleSheetIfNeeded(cssSheet);
332 m_authorStyle->shrinkToFit();
335 if (document()->renderer() && document()->renderer()->style())
336 document()->renderer()->style()->font().update(fontSelector());
338 #if ENABLE(CSS_DEVICE_ADAPTATION)
339 viewportStyleResolver()->resolve();
343 void StyleResolver::pushParentElement(Element* parent)
345 const ContainerNode* parentsParent = parent->parentOrShadowHostElement();
347 // We are not always invoked consistently. For example, script execution can cause us to enter
348 // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree.
349 // Reset the stack in this case, or if we see a new root element.
350 // Otherwise just push the new parent.
351 if (!parentsParent || m_selectorFilter.parentStackIsEmpty())
352 m_selectorFilter.setupParentStack(parent);
354 m_selectorFilter.pushParent(parent);
356 // Note: We mustn't skip ShadowRoot nodes for the scope stack.
358 m_scopeResolver->push(parent, parent->parentOrShadowHostNode());
361 void StyleResolver::popParentElement(Element* parent)
363 // Note that we may get invoked for some random elements in some wacky cases during style resolve.
364 // Pause maintaining the stack in this case.
365 if (m_selectorFilter.parentStackIsConsistent(parent))
366 m_selectorFilter.popParent();
368 m_scopeResolver->pop(parent);
371 void StyleResolver::pushParentShadowRoot(const ShadowRoot* shadowRoot)
373 ASSERT(shadowRoot->host());
375 m_scopeResolver->push(shadowRoot, shadowRoot->host());
378 void StyleResolver::popParentShadowRoot(const ShadowRoot* shadowRoot)
380 ASSERT(shadowRoot->host());
382 m_scopeResolver->pop(shadowRoot);
385 // This is a simplified style setting function for keyframe styles
386 void StyleResolver::addKeyframeStyle(PassRefPtr<StyleRuleKeyframes> rule)
388 AtomicString s(rule->name());
389 m_keyframesRuleMap.set(s.impl(), rule);
392 StyleResolver::~StyleResolver()
394 m_fontSelector->clearDocument();
396 #if ENABLE(CSS_DEVICE_ADAPTATION)
397 m_viewportStyleResolver->clearDocument();
401 void StyleResolver::sweepMatchedPropertiesCache(Timer<StyleResolver>*)
403 // Look for cache entries containing a style declaration with a single ref and remove them.
404 // This may happen when an element attribute mutation causes it to generate a new inlineStyle()
405 // or presentationAttributeStyle(), potentially leaving this cache with the last ref on the old one.
406 Vector<unsigned, 16> toRemove;
407 MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.begin();
408 MatchedPropertiesCache::iterator end = m_matchedPropertiesCache.end();
409 for (; it != end; ++it) {
410 Vector<MatchedProperties>& matchedProperties = it->value.matchedProperties;
411 for (size_t i = 0; i < matchedProperties.size(); ++i) {
412 if (matchedProperties[i].properties->hasOneRef()) {
413 toRemove.append(it->key);
418 for (size_t i = 0; i < toRemove.size(); ++i)
419 m_matchedPropertiesCache.remove(toRemove[i]);
421 m_matchedPropertiesCacheAdditionsSinceLastSweep = 0;
424 void StyleResolver::addMatchedProperties(MatchResult& matchResult, const StylePropertySet* properties, StyleRule* rule, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType)
426 matchResult.matchedProperties.grow(matchResult.matchedProperties.size() + 1);
427 MatchedProperties& newProperties = matchResult.matchedProperties.last();
428 newProperties.properties = const_cast<StylePropertySet*>(properties);
429 newProperties.linkMatchType = linkMatchType;
430 newProperties.whitelistType = propertyWhitelistType;
431 matchResult.matchedRules.append(rule);
434 inline void StyleResolver::addElementStyleProperties(MatchResult& result, const StylePropertySet* propertySet, bool isCacheable)
438 result.ranges.lastAuthorRule = result.matchedProperties.size();
439 if (result.ranges.firstAuthorRule == -1)
440 result.ranges.firstAuthorRule = result.ranges.lastAuthorRule;
441 addMatchedProperties(result, propertySet);
443 result.isCacheable = false;
446 class MatchingUARulesScope {
448 MatchingUARulesScope();
449 ~MatchingUARulesScope();
451 static bool isMatchingUARules();
454 static bool m_matchingUARules;
457 MatchingUARulesScope::MatchingUARulesScope()
459 ASSERT(!m_matchingUARules);
460 m_matchingUARules = true;
463 MatchingUARulesScope::~MatchingUARulesScope()
465 m_matchingUARules = false;
468 inline bool MatchingUARulesScope::isMatchingUARules()
470 return m_matchingUARules;
473 bool MatchingUARulesScope::m_matchingUARules = false;
475 void StyleResolver::collectMatchingRules(const MatchRequest& matchRequest, RuleRange& ruleRange)
477 ASSERT(matchRequest.ruleSet);
478 ASSERT(m_state.element);
480 State& state = m_state;
481 Element* element = state.element;
482 StyledElement* styledElement = state.styledElement;
483 const AtomicString& pseudoId = element->shadowPseudoId();
484 if (!pseudoId.isEmpty()) {
485 ASSERT(styledElement);
486 collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange);
489 #if ENABLE(VIDEO_TRACK)
490 if (element->isWebVTTElement())
491 collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), matchRequest, ruleRange);
493 // Check whether other types of rules are applicable in the current tree scope. Criteria for this:
495 // b) the tree scope allows author rules
496 // c) the rules comes from a scoped style sheet within the same tree scope
497 TreeScope* treeScope = element->treeScope();
498 if (!MatchingUARulesScope::isMatchingUARules()
499 && !treeScope->applyAuthorStyles()
500 && (!matchRequest.scope || matchRequest.scope->treeScope() != treeScope))
503 // We need to collect the rules for id, class, tag, and everything else into a buffer and
504 // then sort the buffer.
505 if (element->hasID())
506 collectMatchingRulesForList(matchRequest.ruleSet->idRules(element->idForStyleResolution().impl()), matchRequest, ruleRange);
507 if (styledElement && styledElement->hasClass()) {
508 for (size_t i = 0; i < styledElement->classNames().size(); ++i)
509 collectMatchingRulesForList(matchRequest.ruleSet->classRules(styledElement->classNames()[i].impl()), matchRequest, ruleRange);
512 if (element->isLink())
513 collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), matchRequest, ruleRange);
514 if (m_selectorChecker.matchesFocusPseudoClass(element))
515 collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), matchRequest, ruleRange);
516 collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element->localName().impl()), matchRequest, ruleRange);
517 collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), matchRequest, ruleRange);
520 void StyleResolver::collectMatchingRulesForRegion(const MatchRequest& matchRequest, RuleRange& ruleRange)
522 if (!m_state.regionForStyling)
525 unsigned size = matchRequest.ruleSet->m_regionSelectorsAndRuleSets.size();
526 for (unsigned i = 0; i < size; ++i) {
527 const CSSSelector* regionSelector = matchRequest.ruleSet->m_regionSelectorsAndRuleSets.at(i).selector;
528 if (checkRegionSelector(regionSelector, static_cast<Element*>(m_state.regionForStyling->node()))) {
529 RuleSet* regionRules = matchRequest.ruleSet->m_regionSelectorsAndRuleSets.at(i).ruleSet.get();
531 collectMatchingRules(MatchRequest(regionRules, matchRequest.includeEmptyRules, matchRequest.scope), ruleRange);
536 void StyleResolver::sortAndTransferMatchedRules(MatchResult& result)
538 State& state = m_state;
539 if (state.matchedRules.isEmpty())
544 if (m_selectorChecker.mode() == SelectorChecker::CollectingRules) {
546 state.ruleList = StaticCSSRuleList::create();
547 for (unsigned i = 0; i < state.matchedRules.size(); ++i)
548 state.ruleList->rules().append(state.matchedRules[i]->rule()->createCSSOMWrapper());
552 // Now transfer the set of matched rules over to our list of declarations.
553 for (unsigned i = 0; i < state.matchedRules.size(); i++) {
554 if (state.style && state.matchedRules[i]->containsUncommonAttributeSelector())
555 state.style->setUnique();
556 addMatchedProperties(result, state.matchedRules[i]->rule()->properties(), state.matchedRules[i]->rule(), state.matchedRules[i]->linkMatchType(), state.matchedRules[i]->propertyWhitelistType());
560 void StyleResolver::matchScopedAuthorRules(MatchResult& result, bool includeEmptyRules)
562 #if ENABLE(STYLE_SCOPED) || ENABLE(SHADOW_DOM)
563 if (!m_scopeResolver)
566 // Match scoped author rules by traversing the scoped element stack (rebuild it if it got inconsistent).
567 if (m_scopeResolver->hasScopedStyles() && m_scopeResolver->ensureStackConsistency(m_state.element)) {
568 bool applyAuthorStyles = m_state.element->treeScope()->applyAuthorStyles();
569 bool documentScope = true;
570 unsigned scopeSize = m_scopeResolver->stackSize();
571 for (unsigned i = 0; i < scopeSize; ++i) {
572 m_state.matchedRules.clear();
573 result.ranges.lastAuthorRule = result.matchedProperties.size() - 1;
575 const StyleScopeResolver::StackFrame& frame = m_scopeResolver->stackFrameAt(i);
576 documentScope = documentScope && !frame.m_scope->isInShadowTree();
578 if (!applyAuthorStyles)
581 if (!m_scopeResolver->matchesStyleBounds(frame))
585 MatchRequest matchRequest(frame.m_ruleSet, includeEmptyRules, frame.m_scope);
586 RuleRange ruleRange = result.ranges.authorRuleRange();
587 collectMatchingRules(matchRequest, ruleRange);
588 collectMatchingRulesForRegion(matchRequest, ruleRange);
589 sortAndTransferMatchedRules(result);
593 matchHostRules(result, includeEmptyRules);
595 UNUSED_PARAM(result);
596 UNUSED_PARAM(includeEmptyRules);
600 inline bool StyleResolver::styleSharingCandidateMatchesHostRules()
602 #if ENABLE(SHADOW_DOM)
603 return m_scopeResolver && m_scopeResolver->styleSharingCandidateMatchesHostRules(m_state.element);
609 void StyleResolver::matchHostRules(MatchResult& result, bool includeEmptyRules)
611 #if ENABLE(SHADOW_DOM)
612 ASSERT(m_scopeResolver);
614 m_state.matchedRules.clear();
615 result.ranges.lastAuthorRule = result.matchedProperties.size() - 1;
617 Vector<RuleSet*> matchedRules;
618 m_scopeResolver->matchHostRules(m_state.element, matchedRules);
619 if (matchedRules.isEmpty())
622 for (unsigned i = matchedRules.size(); i > 0; --i) {
623 RuleRange ruleRange = result.ranges.authorRuleRange();
624 collectMatchingRules(MatchRequest(matchedRules.at(i-1), includeEmptyRules, m_state.element), ruleRange);
626 sortAndTransferMatchedRules(result);
628 UNUSED_PARAM(result);
629 UNUSED_PARAM(includeEmptyRules);
633 void StyleResolver::matchAuthorRules(MatchResult& result, bool includeEmptyRules)
635 m_state.matchedRules.clear();
636 result.ranges.lastAuthorRule = result.matchedProperties.size() - 1;
638 if (!m_state.element)
641 // Match global author rules.
642 MatchRequest matchRequest(m_authorStyle.get(), includeEmptyRules);
643 RuleRange ruleRange = result.ranges.authorRuleRange();
644 collectMatchingRules(matchRequest, ruleRange);
645 collectMatchingRulesForRegion(matchRequest, ruleRange);
646 sortAndTransferMatchedRules(result);
648 matchScopedAuthorRules(result, includeEmptyRules);
651 void StyleResolver::matchUserRules(MatchResult& result, bool includeEmptyRules)
656 m_state.matchedRules.clear();
658 result.ranges.lastUserRule = result.matchedProperties.size() - 1;
659 MatchRequest matchRequest(m_userStyle.get(), includeEmptyRules);
660 RuleRange ruleRange = result.ranges.userRuleRange();
661 collectMatchingRules(matchRequest, ruleRange);
662 collectMatchingRulesForRegion(matchRequest, ruleRange);
664 sortAndTransferMatchedRules(result);
667 void StyleResolver::matchUARules(MatchResult& result, RuleSet* rules)
669 m_state.matchedRules.clear();
671 result.ranges.lastUARule = result.matchedProperties.size() - 1;
672 RuleRange ruleRange = result.ranges.UARuleRange();
673 collectMatchingRules(MatchRequest(rules), ruleRange);
675 sortAndTransferMatchedRules(result);
678 void StyleResolver::collectMatchingRulesForList(const Vector<RuleData>* rules, const MatchRequest& matchRequest, RuleRange& ruleRange)
683 State& state = m_state;
684 // In some cases we may end up looking up style for random elements in the middle of a recursive tree resolve.
685 // Ancestor identifier filter won't be up-to-date in that case and we can't use the fast path.
686 bool canUseFastReject = m_selectorFilter.parentStackIsConsistent(state.parentNode);
688 unsigned size = rules->size();
689 for (unsigned i = 0; i < size; ++i) {
690 const RuleData& ruleData = rules->at(i);
691 if (canUseFastReject && m_selectorFilter.fastRejectSelector<RuleData::maximumIdentifierCount>(ruleData.descendantSelectorIdentifierHashes()))
694 StyleRule* rule = ruleData.rule();
695 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willMatchRule(document(), rule, this);
696 if (ruleMatches(ruleData, matchRequest.scope)) {
697 // If the rule has no properties to apply, then ignore it in the non-debug mode.
698 const StylePropertySet* properties = rule->properties();
699 if (!properties || (properties->isEmpty() && !matchRequest.includeEmptyRules)) {
700 InspectorInstrumentation::didMatchRule(cookie, false);
703 // FIXME: Exposing the non-standard getMatchedCSSRules API to web is the only reason this is needed.
704 if (state.sameOriginOnly && !ruleData.hasDocumentSecurityOrigin()) {
705 InspectorInstrumentation::didMatchRule(cookie, false);
708 // If we're matching normal rules, set a pseudo bit if
709 // we really just matched a pseudo-element.
710 if (state.dynamicPseudo != NOPSEUDO && state.pseudoStyle == NOPSEUDO) {
711 if (m_selectorChecker.mode() == SelectorChecker::CollectingRules) {
712 InspectorInstrumentation::didMatchRule(cookie, false);
715 if (state.dynamicPseudo < FIRST_INTERNAL_PSEUDOID)
716 state.style->setHasPseudoStyle(state.dynamicPseudo);
718 // Update our first/last rule indices in the matched rules array.
719 ++ruleRange.lastRuleIndex;
720 if (ruleRange.firstRuleIndex == -1)
721 ruleRange.firstRuleIndex = ruleRange.lastRuleIndex;
723 // Add this rule to our list of matched rules.
724 addMatchedRule(&ruleData);
725 InspectorInstrumentation::didMatchRule(cookie, true);
729 InspectorInstrumentation::didMatchRule(cookie, false);
733 static inline bool compareRules(const RuleData* r1, const RuleData* r2)
735 unsigned specificity1 = r1->specificity();
736 unsigned specificity2 = r2->specificity();
737 return (specificity1 == specificity2) ? r1->position() < r2->position() : specificity1 < specificity2;
740 void StyleResolver::sortMatchedRules()
742 std::sort(m_state.matchedRules.begin(), m_state.matchedRules.end(), compareRules);
745 void StyleResolver::matchAllRules(MatchResult& result, bool includeSMILProperties)
747 matchUARules(result);
749 // Now we check user sheet rules.
750 if (m_matchAuthorAndUserStyles)
751 matchUserRules(result, false);
753 // Now check author rules, beginning first with presentational attributes mapped from HTML.
754 if (m_state.styledElement) {
755 addElementStyleProperties(result, m_state.styledElement->presentationAttributeStyle());
757 // Now we check additional mapped declarations.
758 // Tables and table cells share an additional mapped rule that must be applied
759 // after all attributes, since their mapped style depends on the values of multiple attributes.
760 addElementStyleProperties(result, m_state.styledElement->additionalPresentationAttributeStyle());
762 if (m_state.styledElement->isHTMLElement()) {
764 TextDirection textDirection = toHTMLElement(m_state.styledElement)->directionalityIfhasDirAutoAttribute(isAuto);
766 addMatchedProperties(result, textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
770 // Check the rules in author sheets next.
771 if (m_matchAuthorAndUserStyles)
772 matchAuthorRules(result, false);
774 // Now check our inline style attribute.
775 if (m_matchAuthorAndUserStyles && m_state.styledElement && m_state.styledElement->inlineStyle()) {
776 // Inline style is immutable as long as there is no CSSOM wrapper.
777 // FIXME: Media control shadow trees seem to have problems with caching.
778 bool isInlineStyleCacheable = !m_state.styledElement->inlineStyle()->isMutable() && !m_state.styledElement->isInShadowTree();
780 addElementStyleProperties(result, m_state.styledElement->inlineStyle(), isInlineStyleCacheable);
784 // Now check SMIL animation override style.
785 if (includeSMILProperties && m_matchAuthorAndUserStyles && m_state.styledElement && m_state.styledElement->isSVGElement())
786 addElementStyleProperties(result, static_cast<SVGElement*>(m_state.styledElement)->animatedSMILStyleProperties(), false /* isCacheable */);
788 UNUSED_PARAM(includeSMILProperties);
792 bool StyleResolver::classNamesAffectedByRules(const SpaceSplitString& classNames) const
794 for (unsigned i = 0; i < classNames.size(); ++i) {
795 if (m_features.classesInRules.contains(classNames[i].impl()))
801 inline void StyleResolver::initElement(Element* e)
803 if (m_state.element != e) {
805 m_state.styledElement = m_state.element && m_state.element->isStyledElement() ? static_cast<StyledElement*>(m_state.element) : 0;
806 m_state.elementLinkState = document()->visitedLinkState()->determineLinkState(e);
807 if (e && e == e->document()->documentElement()) {
808 e->document()->setDirectionSetOnDocumentElement(false);
809 e->document()->setWritingModeSetOnDocumentElement(false);
814 inline void StyleResolver::initForStyleResolve(Element* e, RenderStyle* parentStyle, PseudoId pseudoID)
816 State& state = m_state;
817 state.pseudoStyle = pseudoID;
820 NodeRenderingContext context(e);
821 state.parentNode = context.parentNodeForRenderingAndStyle();
822 state.parentStyle = context.resetStyleInheritance() ? 0 :
823 parentStyle ? parentStyle :
824 state.parentNode ? state.parentNode->renderStyle() : 0;
825 state.distributedToInsertionPoint = context.insertionPoint();
827 state.parentNode = 0;
828 state.parentStyle = parentStyle;
829 state.distributedToInsertionPoint = false;
832 Node* docElement = e ? e->document()->documentElement() : 0;
833 RenderStyle* docStyle = document()->renderStyle();
834 state.rootElementStyle = docElement && e != docElement ? docElement->renderStyle() : docStyle;
838 state.pendingImageProperties.clear();
842 state.fontDirty = false;
845 static const unsigned cStyleSearchThreshold = 10;
846 static const unsigned cStyleSearchLevelThreshold = 10;
848 static inline bool parentElementPreventsSharing(const Element* parentElement)
852 return parentElement->hasFlagsSetDuringStylingOfChildren();
855 Node* StyleResolver::locateCousinList(Element* parent, unsigned& visitedNodeCount) const
857 if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold)
859 if (!parent || !parent->isStyledElement())
861 if (parent->hasScopedHTMLStyleChild())
863 StyledElement* p = static_cast<StyledElement*>(parent);
864 if (p->inlineStyle())
867 if (p->isSVGElement() && static_cast<SVGElement*>(p)->animatedSMILStyleProperties())
870 if (p->hasID() && m_features.idsInRules.contains(p->idForStyleResolution().impl()))
873 RenderStyle* parentStyle = p->renderStyle();
874 unsigned subcount = 0;
875 Node* thisCousin = p;
876 Node* currentNode = p->previousSibling();
878 // Reserve the tries for this level. This effectively makes sure that the algorithm
879 // will never go deeper than cStyleSearchLevelThreshold levels into recursion.
880 visitedNodeCount += cStyleSearchThreshold;
882 while (currentNode) {
884 if (currentNode->renderStyle() == parentStyle && currentNode->lastChild()
885 && currentNode->isElementNode() && !parentElementPreventsSharing(toElement(currentNode))) {
886 // Adjust for unused reserved tries.
887 visitedNodeCount -= cStyleSearchThreshold - subcount;
888 return currentNode->lastChild();
890 if (subcount >= cStyleSearchThreshold)
892 currentNode = currentNode->previousSibling();
894 currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount);
895 thisCousin = currentNode;
901 bool StyleResolver::styleSharingCandidateMatchesRuleSet(RuleSet* ruleSet)
905 m_state.matchedRules.clear();
907 m_selectorChecker.setMode(SelectorChecker::SharingRules);
908 int firstRuleIndex = -1, lastRuleIndex = -1;
909 RuleRange ruleRange(firstRuleIndex, lastRuleIndex);
910 collectMatchingRules(MatchRequest(ruleSet), ruleRange);
911 m_selectorChecker.setMode(SelectorChecker::ResolvingStyle);
912 if (m_state.matchedRules.isEmpty())
914 m_state.matchedRules.clear();
918 bool StyleResolver::canShareStyleWithControl(StyledElement* element) const
920 const State& state = m_state;
921 HTMLInputElement* thisInputElement = element->toInputElement();
922 HTMLInputElement* otherInputElement = state.element->toInputElement();
924 if (!thisInputElement || !otherInputElement)
927 if (thisInputElement->attributeData() != otherInputElement->attributeData()) {
928 if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->fastGetAttribute(typeAttr))
930 if (thisInputElement->fastGetAttribute(readonlyAttr) != otherInputElement->fastGetAttribute(readonlyAttr))
934 if (thisInputElement->isAutofilled() != otherInputElement->isAutofilled())
936 if (thisInputElement->shouldAppearChecked() != otherInputElement->shouldAppearChecked())
938 if (thisInputElement->isIndeterminate() != otherInputElement->isIndeterminate())
940 if (thisInputElement->isRequired() != otherInputElement->isRequired())
943 if (element->isEnabledFormControl() != state.element->isEnabledFormControl())
946 if (element->isDefaultButtonForForm() != state.element->isDefaultButtonForForm())
949 if (state.element->document()->containsValidityStyleRules()) {
950 bool willValidate = element->willValidate();
952 if (willValidate != state.element->willValidate())
955 if (willValidate && (element->isValidFormControlElement() != state.element->isValidFormControlElement()))
958 if (element->isInRange() != state.element->isInRange())
961 if (element->isOutOfRange() != state.element->isOutOfRange())
968 static inline bool elementHasDirectionAuto(Element* element)
970 // FIXME: This line is surprisingly hot, we may wish to inline hasDirectionAuto into StyleResolver.
971 return element->isHTMLElement() && toHTMLElement(element)->hasDirectionAuto();
974 bool StyleResolver::sharingCandidateHasIdenticalStyleAffectingAttributes(StyledElement* sharingCandidate) const
976 const State& state = m_state;
977 if (state.element->attributeData() == sharingCandidate->attributeData())
979 if (state.element->fastGetAttribute(XMLNames::langAttr) != sharingCandidate->fastGetAttribute(XMLNames::langAttr))
981 if (state.element->fastGetAttribute(langAttr) != sharingCandidate->fastGetAttribute(langAttr))
984 if (!state.elementAffectedByClassRules) {
985 if (sharingCandidate->hasClass() && classNamesAffectedByRules(sharingCandidate->classNames()))
987 } else if (sharingCandidate->hasClass()) {
989 // SVG elements require a (slow!) getAttribute comparision because "class" is an animatable attribute for SVG.
990 if (state.element->isSVGElement()) {
991 if (state.element->getAttribute(classAttr) != sharingCandidate->getAttribute(classAttr))
995 if (state.element->classNames() != sharingCandidate->classNames())
1003 if (state.styledElement->presentationAttributeStyle() != sharingCandidate->presentationAttributeStyle())
1006 #if ENABLE(PROGRESS_ELEMENT)
1007 if (state.element->hasTagName(progressTag)) {
1008 if (static_cast<HTMLProgressElement*>(state.element)->isDeterminate() != static_cast<HTMLProgressElement*>(sharingCandidate)->isDeterminate())
1016 bool StyleResolver::canShareStyleWithElement(StyledElement* element) const
1018 RenderStyle* style = element->renderStyle();
1019 const State& state = m_state;
1023 if (style->unique())
1025 if (element->tagQName() != state.element->tagQName())
1027 if (element->inlineStyle())
1029 if (element->needsStyleRecalc())
1032 if (element->isSVGElement() && static_cast<SVGElement*>(element)->animatedSMILStyleProperties())
1035 if (element->isLink() != state.element->isLink())
1037 if (element->hovered() != state.element->hovered())
1039 if (element->active() != state.element->active())
1041 if (element->focused() != state.element->focused())
1043 if (element->shadowPseudoId() != state.element->shadowPseudoId())
1045 if (element == element->document()->cssTarget())
1047 if (!sharingCandidateHasIdenticalStyleAffectingAttributes(element))
1049 if (element->additionalPresentationAttributeStyle() != state.styledElement->additionalPresentationAttributeStyle())
1052 if (element->hasID() && m_features.idsInRules.contains(element->idForStyleResolution().impl()))
1054 if (element->hasScopedHTMLStyleChild())
1057 // FIXME: We should share style for option and optgroup whenever possible.
1058 // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
1059 // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
1060 if (element->hasTagName(optionTag) || element->hasTagName(optgroupTag))
1063 bool isControl = element->isFormControlElement();
1065 if (isControl != state.element->isFormControlElement())
1068 if (isControl && !canShareStyleWithControl(element))
1071 if (style->transitions() || style->animations())
1074 #if USE(ACCELERATED_COMPOSITING)
1075 // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
1076 // See comments in RenderObject::setStyle().
1077 if (element->hasTagName(iframeTag) || element->hasTagName(frameTag) || element->hasTagName(embedTag) || element->hasTagName(objectTag) || element->hasTagName(appletTag) || element->hasTagName(canvasTag)
1078 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1079 // With proxying, the media elements are backed by a RenderEmbeddedObject.
1080 || element->hasTagName(videoTag) || element->hasTagName(audioTag)
1086 if (elementHasDirectionAuto(element))
1089 if (element->isLink() && state.elementLinkState != style->insideLink())
1092 #if ENABLE(VIDEO_TRACK)
1093 // Deny sharing styles between WebVTT and non-WebVTT nodes.
1094 if (element->isWebVTTElement() != state.element->isWebVTTElement())
1097 if (element->isWebVTTElement() && state.element->isWebVTTElement() && toWebVTTElement(element)->isPastNode() != toWebVTTElement(state.element)->isPastNode())
1101 #if ENABLE(FULLSCREEN_API)
1102 if (element == element->document()->webkitCurrentFullScreenElement() || state.element == state.element->document()->webkitCurrentFullScreenElement())
1108 inline StyledElement* StyleResolver::findSiblingForStyleSharing(Node* node, unsigned& count) const
1110 for (; node; node = node->previousSibling()) {
1111 if (!node->isStyledElement())
1113 if (canShareStyleWithElement(static_cast<StyledElement*>(node)))
1115 if (count++ == cStyleSearchThreshold)
1118 return static_cast<StyledElement*>(node);
1121 RenderStyle* StyleResolver::locateSharedStyle()
1123 State& state = m_state;
1124 if (!state.styledElement || !state.parentStyle)
1127 // If the element has inline style it is probably unique.
1128 if (state.styledElement->inlineStyle())
1131 if (state.styledElement->isSVGElement() && static_cast<SVGElement*>(state.styledElement)->animatedSMILStyleProperties())
1134 // Ids stop style sharing if they show up in the stylesheets.
1135 if (state.styledElement->hasID() && m_features.idsInRules.contains(state.styledElement->idForStyleResolution().impl()))
1137 if (parentElementPreventsSharing(state.element->parentElement()))
1139 if (state.styledElement->hasScopedHTMLStyleChild())
1141 if (state.element == state.element->document()->cssTarget())
1143 if (elementHasDirectionAuto(state.element))
1146 // Cache whether state.element is affected by any known class selectors.
1147 // FIXME: This shouldn't be a member variable. The style sharing code could be factored out of StyleResolver.
1148 state.elementAffectedByClassRules = state.element && state.element->hasClass() && classNamesAffectedByRules(state.element->classNames());
1150 // Check previous siblings and their cousins.
1152 unsigned visitedNodeCount = 0;
1153 StyledElement* shareElement = 0;
1154 Node* cousinList = state.styledElement->previousSibling();
1155 while (cousinList) {
1156 shareElement = findSiblingForStyleSharing(cousinList, count);
1159 cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount);
1162 // If we have exhausted all our budget or our cousins.
1166 // Can't share if sibling rules apply. This is checked at the end as it should rarely fail.
1167 if (styleSharingCandidateMatchesRuleSet(m_siblingRuleSet.get()))
1169 // Can't share if attribute rules apply.
1170 if (styleSharingCandidateMatchesRuleSet(m_uncommonAttributeRuleSet.get()))
1172 // Can't share if @host @-rules apply.
1173 if (styleSharingCandidateMatchesHostRules())
1175 // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
1176 if (parentElementPreventsSharing(state.element->parentElement()))
1178 return shareElement->renderStyle();
1181 void StyleResolver::matchUARules(MatchResult& result)
1183 MatchingUARulesScope scope;
1185 // First we match rules from the user agent sheet.
1186 if (CSSDefaultStyleSheets::simpleDefaultStyleSheet)
1187 result.isCacheable = false;
1188 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
1189 ? CSSDefaultStyleSheets::defaultPrintStyle : CSSDefaultStyleSheets::defaultStyle;
1190 matchUARules(result, userAgentStyleSheet);
1192 // In quirks mode, we match rules from the quirks user agent sheet.
1193 if (!m_selectorChecker.strictParsing())
1194 matchUARules(result, CSSDefaultStyleSheets::defaultQuirksStyle);
1196 // 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.
1197 if (document()->isViewSource())
1198 matchUARules(result, CSSDefaultStyleSheets::viewSourceStyle());
1201 static void setStylesForPaginationMode(Pagination::Mode paginationMode, RenderStyle* style)
1203 if (paginationMode == Pagination::Unpaginated)
1206 switch (paginationMode) {
1207 case Pagination::LeftToRightPaginated:
1208 style->setColumnAxis(HorizontalColumnAxis);
1209 if (style->isHorizontalWritingMode())
1210 style->setColumnProgression(style->isLeftToRightDirection() ? NormalColumnProgression : ReverseColumnProgression);
1212 style->setColumnProgression(style->isFlippedBlocksWritingMode() ? ReverseColumnProgression : NormalColumnProgression);
1214 case Pagination::RightToLeftPaginated:
1215 style->setColumnAxis(HorizontalColumnAxis);
1216 if (style->isHorizontalWritingMode())
1217 style->setColumnProgression(style->isLeftToRightDirection() ? ReverseColumnProgression : NormalColumnProgression);
1219 style->setColumnProgression(style->isFlippedBlocksWritingMode() ? NormalColumnProgression : ReverseColumnProgression);
1221 case Pagination::TopToBottomPaginated:
1222 style->setColumnAxis(VerticalColumnAxis);
1223 if (style->isHorizontalWritingMode())
1224 style->setColumnProgression(style->isFlippedBlocksWritingMode() ? ReverseColumnProgression : NormalColumnProgression);
1226 style->setColumnProgression(style->isLeftToRightDirection() ? NormalColumnProgression : ReverseColumnProgression);
1228 case Pagination::BottomToTopPaginated:
1229 style->setColumnAxis(VerticalColumnAxis);
1230 if (style->isHorizontalWritingMode())
1231 style->setColumnProgression(style->isFlippedBlocksWritingMode() ? NormalColumnProgression : ReverseColumnProgression);
1233 style->setColumnProgression(style->isLeftToRightDirection() ? ReverseColumnProgression : NormalColumnProgression);
1235 case Pagination::Unpaginated:
1236 ASSERT_NOT_REACHED();
1241 static void getFontAndGlyphOrientation(const RenderStyle* style, FontOrientation& fontOrientation, NonCJKGlyphOrientation& glyphOrientation)
1243 if (style->isHorizontalWritingMode()) {
1244 fontOrientation = Horizontal;
1245 glyphOrientation = NonCJKGlyphOrientationVerticalRight;
1249 switch (style->textOrientation()) {
1250 case TextOrientationVerticalRight:
1251 fontOrientation = Vertical;
1252 glyphOrientation = NonCJKGlyphOrientationVerticalRight;
1254 case TextOrientationUpright:
1255 fontOrientation = Vertical;
1256 glyphOrientation = NonCJKGlyphOrientationUpright;
1258 case TextOrientationSideways:
1259 if (style->writingMode() == LeftToRightWritingMode) {
1260 // FIXME: This should map to sideways-left, which is not supported yet.
1261 fontOrientation = Vertical;
1262 glyphOrientation = NonCJKGlyphOrientationVerticalRight;
1265 fontOrientation = Horizontal;
1266 glyphOrientation = NonCJKGlyphOrientationVerticalRight;
1268 case TextOrientationSidewaysRight:
1269 fontOrientation = Horizontal;
1270 glyphOrientation = NonCJKGlyphOrientationVerticalRight;
1273 ASSERT_NOT_REACHED();
1274 fontOrientation = Horizontal;
1275 glyphOrientation = NonCJKGlyphOrientationVerticalRight;
1280 PassRefPtr<RenderStyle> StyleResolver::styleForDocument(Document* document, CSSFontSelector* fontSelector)
1282 Frame* frame = document->frame();
1284 // HTML5 states that seamless iframes should replace default CSS values
1285 // with values inherited from the containing iframe element. However,
1286 // some values (such as the case of designMode = "on") still need to
1287 // be set by this "document style".
1288 RefPtr<RenderStyle> documentStyle = RenderStyle::create();
1289 bool seamlessWithParent = document->shouldDisplaySeamlesslyWithParent();
1290 if (seamlessWithParent) {
1291 RenderStyle* iframeStyle = document->seamlessParentIFrame()->renderStyle();
1293 documentStyle->inheritFrom(iframeStyle);
1296 // FIXME: It's not clear which values below we want to override in the seamless case!
1297 documentStyle->setDisplay(BLOCK);
1298 if (!seamlessWithParent) {
1299 documentStyle->setRTLOrdering(document->visuallyOrdered() ? VisualOrder : LogicalOrder);
1300 documentStyle->setZoom(frame && !document->printing() ? frame->pageZoomFactor() : 1);
1301 documentStyle->setPageScaleTransform(frame ? frame->frameScaleFactor() : 1);
1302 documentStyle->setLocale(document->contentLanguage());
1304 // This overrides any -webkit-user-modify inherited from the parent iframe.
1305 documentStyle->setUserModify(document->inDesignMode() ? READ_WRITE : READ_ONLY);
1307 Element* docElement = document->documentElement();
1308 RenderObject* docElementRenderer = docElement ? docElement->renderer() : 0;
1309 if (docElementRenderer) {
1310 // Use the direction and writing-mode of the body to set the
1311 // viewport's direction and writing-mode unless the property is set on the document element.
1312 // If there is no body, then use the document element.
1313 RenderObject* bodyRenderer = document->body() ? document->body()->renderer() : 0;
1314 if (bodyRenderer && !document->writingModeSetOnDocumentElement())
1315 documentStyle->setWritingMode(bodyRenderer->style()->writingMode());
1317 documentStyle->setWritingMode(docElementRenderer->style()->writingMode());
1318 if (bodyRenderer && !document->directionSetOnDocumentElement())
1319 documentStyle->setDirection(bodyRenderer->style()->direction());
1321 documentStyle->setDirection(docElementRenderer->style()->direction());
1325 if (FrameView* frameView = frame->view()) {
1326 const Pagination& pagination = frameView->pagination();
1327 if (pagination.mode != Pagination::Unpaginated) {
1328 setStylesForPaginationMode(pagination.mode, documentStyle.get());
1329 documentStyle->setColumnGap(pagination.gap);
1330 if (RenderView* view = document->renderView()) {
1331 if (view->hasColumns())
1332 view->updateColumnInfoFromStyle(documentStyle.get());
1338 // Seamless iframes want to inherit their font from their parent iframe, so early return before setting the font.
1339 if (seamlessWithParent)
1340 return documentStyle.release();
1342 FontDescription fontDescription;
1343 fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle->locale()));
1344 if (Settings* settings = document->settings()) {
1345 fontDescription.setUsePrinterFont(document->printing() || !settings->screenFontSubstitutionEnabled());
1346 fontDescription.setRenderingMode(settings->fontRenderingMode());
1347 const AtomicString& standardFont = settings->standardFontFamily(fontDescription.script());
1348 if (!standardFont.isEmpty()) {
1349 fontDescription.setGenericFamily(FontDescription::StandardFamily);
1350 fontDescription.firstFamily().setFamily(standardFont);
1351 fontDescription.firstFamily().appendFamily(0);
1353 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
1354 int size = StyleResolver::fontSizeForKeyword(document, CSSValueMedium, false);
1355 fontDescription.setSpecifiedSize(size);
1356 bool useSVGZoomRules = document->isSVGDocument();
1357 fontDescription.setComputedSize(StyleResolver::getComputedSizeFromSpecifiedSize(document, documentStyle.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules));
1359 fontDescription.setUsePrinterFont(document->printing());
1361 FontOrientation fontOrientation;
1362 NonCJKGlyphOrientation glyphOrientation;
1363 getFontAndGlyphOrientation(documentStyle.get(), fontOrientation, glyphOrientation);
1364 fontDescription.setOrientation(fontOrientation);
1365 fontDescription.setNonCJKGlyphOrientation(glyphOrientation);
1367 documentStyle->setFontDescription(fontDescription);
1368 documentStyle->font().update(fontSelector);
1370 return documentStyle.release();
1373 static inline bool isAtShadowBoundary(const Element* element)
1377 ContainerNode* parentNode = element->parentNode();
1378 return parentNode && parentNode->isShadowRoot();
1381 PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent,
1382 StyleSharingBehavior sharingBehavior, RuleMatchingBehavior matchingBehavior, RenderRegion* regionForStyling)
1384 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
1385 // will vanish if a style recalc happens during loading.
1386 if (sharingBehavior == AllowStyleSharing && !element->document()->haveStylesheetsLoaded() && !element->renderer()) {
1387 if (!s_styleNotYetAvailable) {
1388 s_styleNotYetAvailable = RenderStyle::create().leakRef();
1389 s_styleNotYetAvailable->setDisplay(NONE);
1390 s_styleNotYetAvailable->font().update(m_fontSelector);
1392 element->document()->setHasNodesWithPlaceholderStyle();
1393 return s_styleNotYetAvailable;
1396 State& state = m_state;
1397 initElement(element);
1398 initForStyleResolve(element, defaultParent);
1399 state.regionForStyling = regionForStyling;
1400 if (sharingBehavior == AllowStyleSharing && !state.distributedToInsertionPoint) {
1401 RenderStyle* sharedStyle = locateSharedStyle();
1406 RefPtr<RenderStyle> cloneForParent;
1408 if (state.parentStyle) {
1409 state.style = RenderStyle::create();
1410 state.style->inheritFrom(state.parentStyle, isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
1412 state.style = defaultStyleForElement();
1413 cloneForParent = RenderStyle::clone(state.style.get());
1414 state.parentStyle = cloneForParent.get();
1416 // contenteditable attribute (implemented by -webkit-user-modify) should
1417 // be propagated from shadow host to distributed node.
1418 if (state.distributedToInsertionPoint) {
1419 if (Element* parent = element->parentElement()) {
1420 if (RenderStyle* styleOfShadowHost = parent->renderStyle())
1421 state.style->setUserModify(styleOfShadowHost->userModify());
1425 if (element->isLink()) {
1426 state.style->setIsLink(true);
1427 EInsideLink linkState = state.elementLinkState;
1428 if (linkState != NotInsideLink) {
1429 bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited);
1431 linkState = InsideVisitedLink;
1433 state.style->setInsideLink(linkState);
1436 bool needsCollection = false;
1437 CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(element, needsCollection);
1438 if (needsCollection)
1441 MatchResult matchResult;
1442 if (matchingBehavior == MatchOnlyUserAgentRules)
1443 matchUARules(matchResult);
1445 matchAllRules(matchResult, matchingBehavior != MatchAllRulesExcludingSMIL);
1447 applyMatchedProperties(matchResult, element);
1449 // Clean up our style object's display and text decorations (among other fixups).
1450 adjustRenderStyle(state.style.get(), state.parentStyle, element);
1452 initElement(0); // Clear out for the next resolve.
1455 state.parentStyle = 0;
1457 document()->didAccessStyleResolver();
1459 // Now return the style.
1460 return state.style.release();
1463 PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementStyle, const StyleKeyframe* keyframe, KeyframeValue& keyframeValue)
1466 if (keyframe->properties())
1467 addMatchedProperties(result, keyframe->properties());
1469 ASSERT(!m_state.style);
1471 State& state = m_state;
1474 state.style = RenderStyle::clone(elementStyle);
1476 state.lineHeightValue = 0;
1478 // We don't need to bother with !important. Since there is only ever one
1479 // decl, there's nothing to override. So just add the first properties.
1480 bool inheritedOnly = false;
1481 if (keyframe->properties())
1482 applyMatchedProperties<HighPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1484 // If our font got dirtied, go ahead and update it now.
1487 // Line-height is set when we are sure we decided on the font-size
1488 if (state.lineHeightValue)
1489 applyProperty(CSSPropertyLineHeight, state.lineHeightValue);
1491 // Now do rest of the properties.
1492 if (keyframe->properties())
1493 applyMatchedProperties<LowPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1495 // If our font got dirtied by one of the non-essential font props,
1496 // go ahead and update it a second time.
1499 // Start loading resources referenced by this style.
1500 loadPendingResources();
1502 // Add all the animating properties to the keyframe.
1503 if (const StylePropertySet* styleDeclaration = keyframe->properties()) {
1504 unsigned propertyCount = styleDeclaration->propertyCount();
1505 for (unsigned i = 0; i < propertyCount; ++i) {
1506 CSSPropertyID property = styleDeclaration->propertyAt(i).id();
1507 // Timing-function within keyframes is special, because it is not animated; it just
1508 // describes the timing function between this keyframe and the next.
1509 if (property != CSSPropertyWebkitAnimationTimingFunction)
1510 keyframeValue.addProperty(property);
1514 document()->didAccessStyleResolver();
1516 return state.style.release();
1519 void StyleResolver::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list)
1523 // Get the keyframesRule for this name
1524 if (!e || list.animationName().isEmpty())
1527 m_keyframesRuleMap.checkConsistency();
1529 KeyframesRuleMap::iterator it = m_keyframesRuleMap.find(list.animationName().impl());
1530 if (it == m_keyframesRuleMap.end())
1533 const StyleRuleKeyframes* keyframesRule = it->value.get();
1535 // Construct and populate the style for each keyframe
1536 const Vector<RefPtr<StyleKeyframe> >& keyframes = keyframesRule->keyframes();
1537 for (unsigned i = 0; i < keyframes.size(); ++i) {
1538 // Apply the declaration to the style. This is a simplified version of the logic in styleForElement
1540 initForStyleResolve(e);
1542 const StyleKeyframe* keyframe = keyframes[i].get();
1544 KeyframeValue keyframeValue(0, 0);
1545 keyframeValue.setStyle(styleForKeyframe(elementStyle, keyframe, keyframeValue));
1547 // Add this keyframe style to all the indicated key times
1549 keyframe->getKeys(keys);
1550 for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) {
1551 keyframeValue.setKey(keys[keyIndex]);
1552 list.insert(keyframeValue);
1556 // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe)
1557 int initialListSize = list.size();
1558 if (initialListSize > 0 && list[0].key()) {
1559 static StyleKeyframe* zeroPercentKeyframe;
1560 if (!zeroPercentKeyframe) {
1561 zeroPercentKeyframe = StyleKeyframe::create().leakRef();
1562 zeroPercentKeyframe->setKeyText("0%");
1564 KeyframeValue keyframeValue(0, 0);
1565 keyframeValue.setStyle(styleForKeyframe(elementStyle, zeroPercentKeyframe, keyframeValue));
1566 list.insert(keyframeValue);
1569 // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe)
1570 if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) {
1571 static StyleKeyframe* hundredPercentKeyframe;
1572 if (!hundredPercentKeyframe) {
1573 hundredPercentKeyframe = StyleKeyframe::create().leakRef();
1574 hundredPercentKeyframe->setKeyText("100%");
1576 KeyframeValue keyframeValue(1, 0);
1577 keyframeValue.setStyle(styleForKeyframe(elementStyle, hundredPercentKeyframe, keyframeValue));
1578 list.insert(keyframeValue);
1582 PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(PseudoId pseudo, Element* e, RenderStyle* parentStyle)
1584 ASSERT(m_state.parentStyle);
1588 State& state = m_state;
1592 initForStyleResolve(e, parentStyle, pseudo);
1593 state.style = RenderStyle::create();
1594 state.style->inheritFrom(m_state.parentStyle);
1596 // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
1599 // Check UA, user and author rules.
1600 MatchResult matchResult;
1601 matchUARules(matchResult);
1603 if (m_matchAuthorAndUserStyles) {
1604 matchUserRules(matchResult, false);
1605 matchAuthorRules(matchResult, false);
1608 if (matchResult.matchedProperties.isEmpty())
1611 state.style->setStyleType(pseudo);
1613 applyMatchedProperties(matchResult, e);
1615 // Clean up our style object's display and text decorations (among other fixups).
1616 adjustRenderStyle(state.style.get(), m_state.parentStyle, 0);
1618 // Start loading resources referenced by this style.
1619 loadPendingResources();
1621 document()->didAccessStyleResolver();
1623 // Now return the style.
1624 return state.style.release();
1627 PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
1629 initForStyleResolve(document()->documentElement()); // m_rootElementStyle will be set to the document style.
1631 m_state.style = RenderStyle::create();
1632 m_state.style->inheritFrom(m_state.rootElementStyle);
1634 const bool isLeft = isLeftPage(pageIndex);
1635 const bool isFirst = isFirstPage(pageIndex);
1636 const String page = pageName(pageIndex);
1639 matchPageRules(result, CSSDefaultStyleSheets::defaultPrintStyle, isLeft, isFirst, page);
1640 matchPageRules(result, m_userStyle.get(), isLeft, isFirst, page);
1641 // Only consider the global author RuleSet for @page rules, as per the HTML5 spec.
1642 matchPageRules(result, m_authorStyle.get(), isLeft, isFirst, page);
1643 m_state.lineHeightValue = 0;
1644 bool inheritedOnly = false;
1645 #if ENABLE(CSS_VARIABLES)
1646 applyMatchedProperties<VariableDefinitions>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1648 applyMatchedProperties<HighPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1650 // If our font got dirtied, go ahead and update it now.
1653 // Line-height is set when we are sure we decided on the font-size.
1654 if (m_state.lineHeightValue)
1655 applyProperty(CSSPropertyLineHeight, m_state.lineHeightValue);
1657 applyMatchedProperties<LowPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1659 // Start loading resources referenced by this style.
1660 loadPendingResources();
1662 document()->didAccessStyleResolver();
1664 // Now return the style.
1665 return m_state.style.release();
1668 PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement()
1670 m_state.style = RenderStyle::create();
1671 // Make sure our fonts are initialized if we don't inherit them from our parent style.
1672 if (Settings* settings = documentSettings()) {
1673 initializeFontStyle(settings);
1674 m_state.style->font().update(fontSelector());
1676 m_state.style->font().update(0);
1678 return m_state.style.release();
1681 PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode)
1685 NodeRenderingContext context(textNode);
1686 Node* parentNode = context.parentNodeForRenderingAndStyle();
1687 return context.resetStyleInheritance() || !parentNode ?
1688 defaultStyleForElement() : parentNode->renderStyle();
1691 static void addIntrinsicMargins(RenderStyle* style)
1693 // Intrinsic margin value.
1694 const int intrinsicMargin = 2 * style->effectiveZoom();
1696 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
1697 // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame.
1698 if (style->width().isIntrinsicOrAuto()) {
1699 if (style->marginLeft().quirk())
1700 style->setMarginLeft(Length(intrinsicMargin, Fixed));
1701 if (style->marginRight().quirk())
1702 style->setMarginRight(Length(intrinsicMargin, Fixed));
1705 if (style->height().isAuto()) {
1706 if (style->marginTop().quirk())
1707 style->setMarginTop(Length(intrinsicMargin, Fixed));
1708 if (style->marginBottom().quirk())
1709 style->setMarginBottom(Length(intrinsicMargin, Fixed));
1713 static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool strictParsing)
1724 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, but only in quirks mode.
1725 if (!strictParsing && isFloating)
1741 case TABLE_ROW_GROUP:
1742 case TABLE_HEADER_GROUP:
1743 case TABLE_FOOTER_GROUP:
1745 case TABLE_COLUMN_GROUP:
1751 ASSERT_NOT_REACHED();
1754 ASSERT_NOT_REACHED();
1758 // CSS requires text-decoration to be reset at each DOM element for tables,
1759 // inline blocks, inline tables, run-ins, shadow DOM crossings, floating elements,
1760 // and absolute or relatively positioned elements.
1761 static bool doesNotInheritTextDecoration(RenderStyle* style, Element* e)
1763 return style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
1764 || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX || isAtShadowBoundary(e)
1765 || style->isFloating() || style->hasOutOfFlowPosition();
1768 static bool isDisplayFlexibleBox(EDisplay display)
1770 return display == FLEX || display == INLINE_FLEX;
1773 void StyleResolver::adjustRenderStyle(RenderStyle* style, RenderStyle* parentStyle, Element *e)
1775 ASSERT(parentStyle);
1777 // Cache our original display.
1778 style->setOriginalDisplay(style->display());
1780 if (style->display() != NONE) {
1781 // If we have a <td> that specifies a float property, in quirks mode we just drop the float
1783 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
1784 // these tags to retain their display types.
1785 if (!m_selectorChecker.strictParsing() && e) {
1786 if (e->hasTagName(tdTag)) {
1787 style->setDisplay(TABLE_CELL);
1788 style->setFloating(NoFloat);
1789 } else if (e->hasTagName(tableTag))
1790 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
1793 if (e && (e->hasTagName(tdTag) || e->hasTagName(thTag))) {
1794 if (style->whiteSpace() == KHTML_NOWRAP) {
1795 // Figure out if we are really nowrapping or if we should just
1796 // use normal instead. If the width of the cell is fixed, then
1797 // we don't actually use NOWRAP.
1798 if (style->width().isFixed())
1799 style->setWhiteSpace(NORMAL);
1801 style->setWhiteSpace(NOWRAP);
1805 // Tables never support the -webkit-* values for text-align and will reset back to the default.
1806 if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT))
1807 style->setTextAlign(TASTART);
1809 // Frames and framesets never honor position:relative or position:absolute. This is necessary to
1810 // fix a crash where a site tries to position these objects. They also never honor display.
1811 if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) {
1812 style->setPosition(StaticPosition);
1813 style->setDisplay(BLOCK);
1816 // Ruby text does not support float or position. This might change with evolution of the specification.
1817 if (e && e->hasTagName(rtTag)) {
1818 style->setPosition(StaticPosition);
1819 style->setFloating(NoFloat);
1822 // FIXME: We shouldn't be overriding start/-webkit-auto like this. Do it in html.css instead.
1823 // Table headers with a text-align of -webkit-auto will change the text-align to center.
1824 if (e && e->hasTagName(thTag) && style->textAlign() == TASTART)
1825 style->setTextAlign(CENTER);
1827 if (e && e->hasTagName(legendTag))
1828 style->setDisplay(BLOCK);
1830 // Absolute/fixed positioned elements, floating elements and the document element need block-like outside display.
1831 if (style->hasOutOfFlowPosition() || style->isFloating() || (e && e->document()->documentElement() == e))
1832 style->setDisplay(equivalentBlockDisplay(style->display(), style->isFloating(), m_selectorChecker.strictParsing()));
1834 // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely
1835 // clear how that should work.
1836 if (style->display() == INLINE && style->styleType() == NOPSEUDO && style->writingMode() != parentStyle->writingMode())
1837 style->setDisplay(INLINE_BLOCK);
1839 // After performing the display mutation, check table rows. We do not honor position:relative or position:sticky on
1840 // table rows or cells. This has been established for position:relative in CSS2.1 (and caused a crash in containingBlock()
1842 if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP
1843 || style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW)
1844 && style->hasInFlowPosition())
1845 style->setPosition(StaticPosition);
1847 // writing-mode does not apply to table row groups, table column groups, table rows, and table columns.
1848 // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though.
1849 if (style->display() == TABLE_COLUMN || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_FOOTER_GROUP
1850 || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_ROW_GROUP
1851 || style->display() == TABLE_CELL)
1852 style->setWritingMode(parentStyle->writingMode());
1854 // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting
1855 // of block-flow to anything other than TopToBottomWritingMode.
1856 // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support.
1857 if (style->writingMode() != TopToBottomWritingMode && (style->display() == BOX || style->display() == INLINE_BOX))
1858 style->setWritingMode(TopToBottomWritingMode);
1860 if (isDisplayFlexibleBox(parentStyle->display())) {
1861 style->setFloating(NoFloat);
1862 style->setDisplay(equivalentBlockDisplay(style->display(), style->isFloating(), m_selectorChecker.strictParsing()));
1865 #if ENABLE(DIALOG_ELEMENT)
1866 // Per the spec, position 'static' and 'relative' in the top layer compute to 'absolute'.
1867 if (e && e->isInTopLayer() && (style->position() == StaticPosition || style->position() == RelativePosition)) {
1868 style->setPosition(AbsolutePosition);
1869 style->setDisplay(BLOCK);
1874 // Make sure our z-index value is only applied if the object is positioned.
1875 if (style->position() == StaticPosition && !isDisplayFlexibleBox(parentStyle->display()))
1876 style->setHasAutoZIndex();
1878 // Auto z-index becomes 0 for the root element and transparent objects. This prevents
1879 // cases where objects that should be blended as a single unit end up with a non-transparent
1880 // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections.
1881 if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e)
1882 || style->opacity() < 1.0f
1883 || style->hasTransformRelatedProperty()
1885 || style->clipPath()
1886 || style->boxReflect()
1887 || style->hasFilter()
1888 || style->hasBlendMode()
1889 || style->position() == StickyPosition
1890 || (style->position() == FixedPosition && e && e->document()->page() && e->document()->page()->settings()->fixedPositionCreatesStackingContext())
1891 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
1892 // Touch overflow scrolling creates a stacking context.
1893 || ((style->overflowX() != OHIDDEN || style->overflowY() != OHIDDEN) && style->useTouchOverflowScrolling())
1895 #if ENABLE(DIALOG_ELEMENT)
1896 || (e && e->isInTopLayer())
1899 style->setZIndex(0);
1901 // Textarea considers overflow visible as auto.
1902 if (e && e->hasTagName(textareaTag)) {
1903 style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX());
1904 style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY());
1907 if (doesNotInheritTextDecoration(style, e))
1908 style->setTextDecorationsInEffect(style->textDecoration());
1910 style->addToTextDecorationsInEffect(style->textDecoration());
1912 // If either overflow value is not visible, change to auto.
1913 if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE)
1914 style->setOverflowY(OMARQUEE);
1915 else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE)
1916 style->setOverflowX(OMARQUEE);
1917 else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE) {
1918 // FIXME: Once we implement pagination controls, overflow-x should default to hidden
1919 // if overflow-y is set to -webkit-paged-x or -webkit-page-y. For now, we'll let it
1920 // default to auto so we can at least scroll through the pages.
1921 style->setOverflowX(OAUTO);
1922 } else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE)
1923 style->setOverflowY(OAUTO);
1925 // Call setStylesForPaginationMode() if a pagination mode is set for any non-root elements. If these
1926 // styles are specified on a root element, then they will be incorporated in
1927 // StyleResolver::styleForDocument().
1928 if ((style->overflowY() == OPAGEDX || style->overflowY() == OPAGEDY) && !(e && (e->hasTagName(htmlTag) || e->hasTagName(bodyTag))))
1929 setStylesForPaginationMode(WebCore::paginationModeForRenderStyle(style), style);
1931 // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
1932 // FIXME: Eventually table sections will support auto and scroll.
1933 if (style->display() == TABLE || style->display() == INLINE_TABLE
1934 || style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
1935 if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN)
1936 style->setOverflowX(OVISIBLE);
1937 if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN)
1938 style->setOverflowY(OVISIBLE);
1941 // Menulists should have visible overflow
1942 if (style->appearance() == MenulistPart) {
1943 style->setOverflowX(OVISIBLE);
1944 style->setOverflowY(OVISIBLE);
1947 // Cull out any useless layers and also repeat patterns into additional layers.
1948 style->adjustBackgroundLayers();
1949 style->adjustMaskLayers();
1951 // Do the same for animations and transitions.
1952 style->adjustAnimations();
1953 style->adjustTransitions();
1955 // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will
1956 // alter fonts and heights/widths.
1957 if (e && e->isFormControlElement() && style->fontSize() >= 11) {
1958 // Don't apply intrinsic margins to image buttons. The designer knows how big the images are,
1959 // so we have to treat all image buttons as though they were explicitly sized.
1960 if (!e->hasTagName(inputTag) || !static_cast<HTMLInputElement*>(e)->isImageButton())
1961 addIntrinsicMargins(style);
1964 // Let the theme also have a crack at adjusting the style.
1965 if (style->hasAppearance())
1966 RenderTheme::defaultTheme()->adjustStyle(this, style, e, m_state.hasUAAppearance, m_state.borderData, m_state.backgroundData, m_state.backgroundColor);
1968 // If we have first-letter pseudo style, do not share this style.
1969 if (style->hasPseudoStyle(FIRST_LETTER))
1972 // FIXME: when dropping the -webkit prefix on transform-style, we should also have opacity < 1 cause flattening.
1973 if (style->preserves3D() && (style->overflowX() != OVISIBLE
1974 || style->overflowY() != OVISIBLE
1975 || style->hasFilter()))
1976 style->setTransformStyle3D(TransformStyle3DFlat);
1978 // Seamless iframes behave like blocks. Map their display to inline-block when marked inline.
1979 if (e && e->hasTagName(iframeTag) && style->display() == INLINE && static_cast<HTMLIFrameElement*>(e)->shouldDisplaySeamlessly())
1980 style->setDisplay(INLINE_BLOCK);
1983 if (e && e->isSVGElement()) {
1984 // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty
1985 if (style->overflowY() == OSCROLL)
1986 style->setOverflowY(OHIDDEN);
1987 else if (style->overflowY() == OAUTO)
1988 style->setOverflowY(OVISIBLE);
1990 if (style->overflowX() == OSCROLL)
1991 style->setOverflowX(OHIDDEN);
1992 else if (style->overflowX() == OAUTO)
1993 style->setOverflowX(OVISIBLE);
1995 // Only the root <svg> element in an SVG document fragment tree honors css position
1996 if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement()))
1997 style->setPosition(RenderStyle::initialPosition());
1999 // RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should
2000 // not be scaled again.
2001 if (e->hasTagName(SVGNames::foreignObjectTag))
2002 style->setEffectiveZoom(RenderStyle::initialZoom());
2007 bool StyleResolver::checkRegionStyle(Element* regionElement)
2009 // FIXME (BUG 72472): We don't add @-webkit-region rules of scoped style sheets for the moment,
2010 // so all region rules are global by default. Verify whether that can stand or needs changing.
2012 unsigned rulesSize = m_authorStyle->m_regionSelectorsAndRuleSets.size();
2013 for (unsigned i = 0; i < rulesSize; ++i) {
2014 ASSERT(m_authorStyle->m_regionSelectorsAndRuleSets.at(i).ruleSet.get());
2015 if (checkRegionSelector(m_authorStyle->m_regionSelectorsAndRuleSets.at(i).selector, regionElement))
2020 rulesSize = m_userStyle->m_regionSelectorsAndRuleSets.size();
2021 for (unsigned i = 0; i < rulesSize; ++i) {
2022 ASSERT(m_userStyle->m_regionSelectorsAndRuleSets.at(i).ruleSet.get());
2023 if (checkRegionSelector(m_userStyle->m_regionSelectorsAndRuleSets.at(i).selector, regionElement))
2031 static void checkForOrientationChange(RenderStyle* style)
2033 FontOrientation fontOrientation;
2034 NonCJKGlyphOrientation glyphOrientation;
2035 getFontAndGlyphOrientation(style, fontOrientation, glyphOrientation);
2037 const FontDescription& fontDescription = style->fontDescription();
2038 if (fontDescription.orientation() == fontOrientation && fontDescription.nonCJKGlyphOrientation() == glyphOrientation)
2041 FontDescription newFontDescription(fontDescription);
2042 newFontDescription.setNonCJKGlyphOrientation(glyphOrientation);
2043 newFontDescription.setOrientation(fontOrientation);
2044 style->setFontDescription(newFontDescription);
2047 void StyleResolver::updateFont()
2049 if (!m_state.fontDirty)
2052 checkForTextSizeAdjust();
2053 RenderStyle* style = m_state.style.get();
2054 checkForGenericFamilyChange(style, m_state.parentStyle);
2055 checkForZoomChange(style, m_state.parentStyle);
2056 checkForOrientationChange(style);
2057 m_state.style->font().update(m_fontSelector);
2058 m_state.fontDirty = false;
2061 void StyleResolver::cacheBorderAndBackground()
2063 m_state.hasUAAppearance = m_state.style->hasAppearance();
2064 if (m_state.hasUAAppearance) {
2065 m_state.borderData = m_state.style->border();
2066 m_state.backgroundData = *m_state.style->backgroundLayers();
2067 m_state.backgroundColor = m_state.style->backgroundColor();
2071 PassRefPtr<CSSRuleList> StyleResolver::styleRulesForElement(Element* e, unsigned rulesToInclude)
2073 return pseudoStyleRulesForElement(e, NOPSEUDO, rulesToInclude);
2076 PassRefPtr<CSSRuleList> StyleResolver::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, unsigned rulesToInclude)
2078 if (!e || !e->document()->haveStylesheetsLoaded())
2081 m_selectorChecker.setMode(SelectorChecker::CollectingRules);
2084 initForStyleResolve(e, 0, pseudoId);
2087 if (rulesToInclude & UAAndUserCSSRules) {
2088 // First we match rules from the user agent sheet.
2089 matchUARules(dummy);
2091 // Now we check user sheet rules.
2092 if (m_matchAuthorAndUserStyles)
2093 matchUserRules(dummy, rulesToInclude & EmptyCSSRules);
2096 if (m_matchAuthorAndUserStyles && (rulesToInclude & AuthorCSSRules)) {
2097 m_state.sameOriginOnly = !(rulesToInclude & CrossOriginCSSRules);
2099 // Check the rules in author sheets.
2100 matchAuthorRules(dummy, rulesToInclude & EmptyCSSRules);
2102 m_state.sameOriginOnly = false;
2105 m_selectorChecker.setMode(SelectorChecker::ResolvingStyle);
2107 return m_state.ruleList.release();
2110 inline bool StyleResolver::ruleMatches(const RuleData& ruleData, const ContainerNode* scope)
2112 State& state = m_state;
2113 state.dynamicPseudo = NOPSEUDO;
2115 if (ruleData.hasFastCheckableSelector()) {
2116 // We know this selector does not include any pseudo elements.
2117 if (state.pseudoStyle != NOPSEUDO)
2119 // We know a sufficiently simple single part selector matches simply because we found it from the rule hash.
2120 // This is limited to HTML only so we don't need to check the namespace.
2121 if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && state.element->isHTMLElement()) {
2122 if (!ruleData.hasMultipartSelector())
2125 if (ruleData.selector()->m_match == CSSSelector::Tag && !SelectorChecker::tagMatches(state.element, ruleData.selector()->tagQName()))
2127 if (!SelectorChecker::fastCheckRightmostAttributeSelector(state.element, ruleData.selector()))
2130 return m_selectorChecker.fastCheck(ruleData.selector(), state.element);
2134 SelectorChecker::SelectorCheckingContext context(ruleData.selector(), state.element, SelectorChecker::VisitedMatchEnabled);
2135 context.elementStyle = state.style.get();
2136 context.scope = scope;
2137 context.pseudoStyle = state.pseudoStyle;
2138 SelectorChecker::Match match = m_selectorChecker.match(context, state.dynamicPseudo, DOMSiblingTraversalStrategy());
2139 if (match != SelectorChecker::SelectorMatches)
2141 if (state.pseudoStyle != NOPSEUDO && state.pseudoStyle != state.dynamicPseudo)
2146 bool StyleResolver::checkRegionSelector(const CSSSelector* regionSelector, Element* regionElement)
2148 if (!regionSelector || !regionElement)
2151 m_state.pseudoStyle = NOPSEUDO;
2153 for (const CSSSelector* s = regionSelector; s; s = CSSSelectorList::next(s))
2154 if (m_selectorChecker.matches(s, regionElement))
2160 // -------------------------------------------------------------------------------------
2161 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
2163 Length StyleResolver::convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier)
2165 return primitiveValue ? primitiveValue->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined);
2168 Length StyleResolver::convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier)
2170 return primitiveValue ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined);
2173 template <StyleResolver::StyleApplicationPass pass>
2174 void StyleResolver::applyProperties(const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType)
2176 ASSERT((propertyWhitelistType != PropertyWhitelistRegion) || m_state.regionForStyling);
2177 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willProcessRule(document(), rule, this);
2179 unsigned propertyCount = properties->propertyCount();
2180 for (unsigned i = 0; i < propertyCount; ++i) {
2181 StylePropertySet::PropertyReference current = properties->propertyAt(i);
2182 if (isImportant != current.isImportant())
2184 if (inheritedOnly && !current.isInherited()) {
2185 // If the property value is explicitly inherited, we need to apply further non-inherited properties
2186 // as they might override the value inherited here. For this reason we don't allow declarations with
2187 // explicitly inherited properties to be cached.
2188 ASSERT(!current.value()->isInheritedValue());
2191 CSSPropertyID property = current.id();
2193 if (propertyWhitelistType == PropertyWhitelistRegion && !StyleResolver::isValidRegionStyleProperty(property))
2195 #if ENABLE(VIDEO_TRACK)
2196 if (propertyWhitelistType == PropertyWhitelistCue && !StyleResolver::isValidCueStyleProperty(property))
2200 #if ENABLE(CSS_VARIABLES)
2201 case VariableDefinitions:
2202 COMPILE_ASSERT(CSSPropertyVariable < firstCSSProperty, CSS_variable_is_before_first_property);
2203 if (property == CSSPropertyVariable)
2204 applyProperty(current.id(), current.value());
2207 case HighPriorityProperties:
2208 COMPILE_ASSERT(firstCSSProperty == CSSPropertyColor, CSS_color_is_first_property);
2209 COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyColor + 18, CSS_zoom_is_end_of_first_prop_range);
2210 COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyZoom + 1, CSS_line_height_is_after_zoom);
2211 #if ENABLE(CSS_VARIABLES)
2212 if (property == CSSPropertyVariable)
2215 // give special priority to font-xxx, color properties, etc
2216 if (property < CSSPropertyLineHeight)
2217 applyProperty(current.id(), current.value());
2218 // we apply line-height later
2219 else if (property == CSSPropertyLineHeight)
2220 m_state.lineHeightValue = current.value();
2222 case LowPriorityProperties:
2223 if (property > CSSPropertyLineHeight)
2224 applyProperty(current.id(), current.value());
2227 InspectorInstrumentation::didProcessRule(cookie);
2230 template <StyleResolver::StyleApplicationPass pass>
2231 void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
2233 if (startIndex == -1)
2236 State& state = m_state;
2237 if (state.style->insideLink() != NotInsideLink) {
2238 for (int i = startIndex; i <= endIndex; ++i) {
2239 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
2240 unsigned linkMatchType = matchedProperties.linkMatchType;
2241 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
2242 state.applyPropertyToRegularStyle = linkMatchType & SelectorChecker::MatchLink;
2243 state.applyPropertyToVisitedLinkStyle = linkMatchType & SelectorChecker::MatchVisited;
2245 applyProperties<pass>(matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
2247 state.applyPropertyToRegularStyle = true;
2248 state.applyPropertyToVisitedLinkStyle = false;
2251 for (int i = startIndex; i <= endIndex; ++i) {
2252 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
2253 applyProperties<pass>(matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
2257 unsigned StyleResolver::computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
2260 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
2263 bool operator==(const StyleResolver::MatchRanges& a, const StyleResolver::MatchRanges& b)
2265 return a.firstUARule == b.firstUARule
2266 && a.lastUARule == b.lastUARule
2267 && a.firstAuthorRule == b.firstAuthorRule
2268 && a.lastAuthorRule == b.lastAuthorRule
2269 && a.firstUserRule == b.firstUserRule
2270 && a.lastUserRule == b.lastUserRule;
2273 bool operator!=(const StyleResolver::MatchRanges& a, const StyleResolver::MatchRanges& b)
2278 bool operator==(const StyleResolver::MatchedProperties& a, const StyleResolver::MatchedProperties& b)
2280 return a.properties == b.properties && a.linkMatchType == b.linkMatchType;
2283 bool operator!=(const StyleResolver::MatchedProperties& a, const StyleResolver::MatchedProperties& b)
2288 const StyleResolver::MatchedPropertiesCacheItem* StyleResolver::findFromMatchedPropertiesCache(unsigned hash, const MatchResult& matchResult)
2292 MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.find(hash);
2293 if (it == m_matchedPropertiesCache.end())
2295 MatchedPropertiesCacheItem& cacheItem = it->value;
2297 size_t size = matchResult.matchedProperties.size();
2298 if (size != cacheItem.matchedProperties.size())
2300 for (size_t i = 0; i < size; ++i) {
2301 if (matchResult.matchedProperties[i] != cacheItem.matchedProperties[i])
2304 if (cacheItem.ranges != matchResult.ranges)
2309 void StyleResolver::addToMatchedPropertiesCache(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult)
2311 static const unsigned matchedDeclarationCacheAdditionsBetweenSweeps = 100;
2312 if (++m_matchedPropertiesCacheAdditionsSinceLastSweep >= matchedDeclarationCacheAdditionsBetweenSweeps
2313 && !m_matchedPropertiesCacheSweepTimer.isActive()) {
2314 static const unsigned matchedDeclarationCacheSweepTimeInSeconds = 60;
2315 m_matchedPropertiesCacheSweepTimer.startOneShot(matchedDeclarationCacheSweepTimeInSeconds);
2319 MatchedPropertiesCacheItem cacheItem;
2320 cacheItem.matchedProperties.append(matchResult.matchedProperties);
2321 cacheItem.ranges = matchResult.ranges;
2322 // Note that we don't cache the original RenderStyle instance. It may be further modified.
2323 // The RenderStyle in the cache is really just a holder for the substructures and never used as-is.
2324 cacheItem.renderStyle = RenderStyle::clone(style);
2325 cacheItem.parentRenderStyle = RenderStyle::clone(parentStyle);
2326 m_matchedPropertiesCache.add(hash, cacheItem);
2329 void StyleResolver::invalidateMatchedPropertiesCache()
2331 m_matchedPropertiesCache.clear();
2334 static bool isCacheableInMatchedPropertiesCache(const Element* element, const RenderStyle* style, const RenderStyle* parentStyle)
2336 // FIXME: CSSPropertyWebkitWritingMode modifies state when applying to document element. We can't skip the applying by caching.
2337 if (element == element->document()->documentElement() && element->document()->writingModeSetOnDocumentElement())
2339 if (style->unique() || (style->styleType() != NOPSEUDO && parentStyle->unique()))
2341 if (style->hasAppearance())
2343 if (style->zoom() != RenderStyle::initialZoom())
2345 if (style->writingMode() != RenderStyle::initialWritingMode())
2347 // The cache assumes static knowledge about which properties are inherited.
2348 if (parentStyle->hasExplicitlyInheritedProperties())
2353 void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const Element* element)
2356 State& state = m_state;
2357 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
2358 bool applyInheritedOnly = false;
2359 const MatchedPropertiesCacheItem* cacheItem = 0;
2360 if (cacheHash && (cacheItem = findFromMatchedPropertiesCache(cacheHash, matchResult))) {
2361 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
2362 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the
2363 // element context. This is fast and saves memory by reusing the style data structures.
2364 state.style->copyNonInheritedFrom(cacheItem->renderStyle.get());
2365 if (state.parentStyle->inheritedDataShared(cacheItem->parentRenderStyle.get()) && !isAtShadowBoundary(element)) {
2366 EInsideLink linkStatus = state.style->insideLink();
2367 // If the cache item parent style has identical inherited properties to the current parent style then the
2368 // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
2369 state.style->inheritFrom(cacheItem->renderStyle.get());
2371 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
2372 state.style->setInsideLink(linkStatus);
2375 applyInheritedOnly = true;
2378 #if ENABLE(CSS_VARIABLES)
2379 // First apply all variable definitions, as they may be used during application of later properties.
2380 applyMatchedProperties<VariableDefinitions>(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
2381 applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
2382 applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
2383 applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
2386 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
2387 // high-priority properties first, i.e., those properties that other properties depend on.
2388 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
2389 // and (4) normal important.
2390 state.lineHeightValue = 0;
2391 applyMatchedProperties<HighPriorityProperties>(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
2392 applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
2393 applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
2394 applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
2396 if (cacheItem && cacheItem->renderStyle->effectiveZoom() != state.style->effectiveZoom()) {
2397 state.fontDirty = true;
2398 applyInheritedOnly = false;
2401 // If our font got dirtied, go ahead and update it now.
2404 // Line-height is set when we are sure we decided on the font-size.
2405 if (state.lineHeightValue)
2406 applyProperty(CSSPropertyLineHeight, state.lineHeightValue);
2408 // Many properties depend on the font. If it changes we just apply all properties.
2409 if (cacheItem && cacheItem->renderStyle->fontDescription() != state.style->fontDescription())
2410 applyInheritedOnly = false;
2412 // Now do the normal priority UA properties.
2413 applyMatchedProperties<LowPriorityProperties>(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
2415 // Cache our border and background so that we can examine them later.
2416 cacheBorderAndBackground();
2418 // Now do the author and user normal priority properties and all the !important properties.
2419 applyMatchedProperties<LowPriorityProperties>(matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
2420 applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
2421 applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
2422 applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
2424 // Start loading resources referenced by this style.
2425 loadPendingResources();
2427 ASSERT(!state.fontDirty);
2429 if (cacheItem || !cacheHash)
2431 if (!isCacheableInMatchedPropertiesCache(state.element, state.style.get(), state.parentStyle))
2433 addToMatchedPropertiesCache(state.style.get(), state.parentStyle, cacheHash, matchResult);
2436 static inline bool comparePageRules(const StyleRulePage* r1, const StyleRulePage* r2)
2438 return r1->selector()->specificity() < r2->selector()->specificity();
2441 void StyleResolver::matchPageRules(MatchResult& result, RuleSet* rules, bool isLeftPage, bool isFirstPage, const String& pageName)
2446 Vector<StyleRulePage*> matchedPageRules;
2447 matchPageRulesForList(matchedPageRules, rules->pageRules(), isLeftPage, isFirstPage, pageName);
2448 if (matchedPageRules.isEmpty())
2451 std::stable_sort(matchedPageRules.begin(), matchedPageRules.end(), comparePageRules);
2453 for (unsigned i = 0; i < matchedPageRules.size(); i++)
2454 addMatchedProperties(result, matchedPageRules[i]->properties());
2457 static bool checkPageSelectorComponents(const CSSSelector* selector, bool isLeftPage, bool isFirstPage, const String& pageName)
2459 for (const CSSSelector* component = selector; component; component = component->tagHistory()) {
2460 if (component->m_match == CSSSelector::Tag) {
2461 const AtomicString& localName = component->tagQName().localName();
2462 if (localName != starAtom && localName != pageName)
2466 CSSSelector::PseudoType pseudoType = component->pseudoType();
2467 if ((pseudoType == CSSSelector::PseudoLeftPage && !isLeftPage)
2468 || (pseudoType == CSSSelector::PseudoRightPage && isLeftPage)
2469 || (pseudoType == CSSSelector::PseudoFirstPage && !isFirstPage))
2477 void StyleResolver::matchPageRulesForList(Vector<StyleRulePage*>& matchedRules, const Vector<StyleRulePage*>& rules, bool isLeftPage, bool isFirstPage, const String& pageName)
2479 for (unsigned i = 0; i < rules.size(); ++i) {
2480 StyleRulePage* rule = rules[i];
2482 if (!checkPageSelectorComponents(rule->selector(), isLeftPage, isFirstPage, pageName))
2485 // If the rule has no properties to apply, then ignore it.
2486 const StylePropertySet* properties = rule->properties();
2487 if (!properties || properties->isEmpty())
2490 // Add this rule to our list of matched rules.
2491 matchedRules.append(rule);
2495 bool StyleResolver::isLeftPage(int pageIndex) const
2497 bool isFirstPageLeft = false;
2498 if (!m_state.rootElementStyle->isLeftToRightDirection())
2499 isFirstPageLeft = true;
2501 return (pageIndex + (isFirstPageLeft ? 1 : 0)) % 2;
2504 bool StyleResolver::isFirstPage(int pageIndex) const
2506 // FIXME: In case of forced left/right page, page at index 1 (not 0) can be the first page.
2507 return (!pageIndex);
2510 String StyleResolver::pageName(int /* pageIndex */) const
2512 // FIXME: Implement page index to page name mapping.
2516 void StyleResolver::applyPropertyToStyle(CSSPropertyID id, CSSValue* value, RenderStyle* style)
2519 initForStyleResolve(0, style);
2520 m_state.style = style;
2521 applyPropertyToCurrentStyle(id, value);
2524 void StyleResolver::applyPropertyToCurrentStyle(CSSPropertyID id, CSSValue* value)
2527 applyProperty(id, value);
2530 inline bool isValidVisitedLinkProperty(CSSPropertyID id)
2533 case CSSPropertyBackgroundColor:
2534 case CSSPropertyBorderLeftColor:
2535 case CSSPropertyBorderRightColor:
2536 case CSSPropertyBorderTopColor:
2537 case CSSPropertyBorderBottomColor:
2538 case CSSPropertyColor:
2539 case CSSPropertyOutlineColor:
2540 case CSSPropertyWebkitColumnRuleColor:
2541 case CSSPropertyWebkitTextEmphasisColor:
2542 case CSSPropertyWebkitTextFillColor:
2543 case CSSPropertyWebkitTextStrokeColor:
2544 // Also allow shorthands so that inherit/initial still work.
2545 case CSSPropertyBackground:
2546 case CSSPropertyBorderLeft:
2547 case CSSPropertyBorderRight:
2548 case CSSPropertyBorderTop:
2549 case CSSPropertyBorderBottom:
2550 case CSSPropertyOutline:
2551 case CSSPropertyWebkitColumnRule:
2553 case CSSPropertyFill:
2554 case CSSPropertyStroke:
2564 // http://dev.w3.org/csswg/css3-regions/#the-at-region-style-rule
2565 // FIXME: add incremental support for other region styling properties.
2566 inline bool StyleResolver::isValidRegionStyleProperty(CSSPropertyID id)
2569 case CSSPropertyBackgroundColor:
2570 case CSSPropertyColor:
2579 #if ENABLE(VIDEO_TRACK)
2580 inline bool StyleResolver::isValidCueStyleProperty(CSSPropertyID id)
2583 case CSSPropertyBackground:
2584 case CSSPropertyBackgroundAttachment:
2585 case CSSPropertyBackgroundClip:
2586 case CSSPropertyBackgroundColor:
2587 case CSSPropertyBackgroundImage:
2588 case CSSPropertyBackgroundOrigin:
2589 case CSSPropertyBackgroundPosition:
2590 case CSSPropertyBackgroundPositionX:
2591 case CSSPropertyBackgroundPositionY:
2592 case CSSPropertyBackgroundRepeat:
2593 case CSSPropertyBackgroundRepeatX:
2594 case CSSPropertyBackgroundRepeatY:
2595 case CSSPropertyBackgroundSize:
2596 case CSSPropertyColor:
2597 case CSSPropertyFont:
2598 case CSSPropertyFontFamily:
2599 case CSSPropertyFontSize:
2600 case CSSPropertyFontStyle:
2601 case CSSPropertyFontVariant:
2602 case CSSPropertyFontWeight:
2603 case CSSPropertyLineHeight:
2604 case CSSPropertyOpacity:
2605 case CSSPropertyOutline:
2606 case CSSPropertyOutlineColor:
2607 case CSSPropertyOutlineOffset:
2608 case CSSPropertyOutlineStyle:
2609 case CSSPropertyOutlineWidth:
2610 case CSSPropertyVisibility:
2611 case CSSPropertyWhiteSpace:
2612 case CSSPropertyTextDecoration:
2613 case CSSPropertyTextShadow:
2614 case CSSPropertyBorderStyle:
2622 // SVG handles zooming in a different way compared to CSS. The whole document is scaled instead
2623 // of each individual length value in the render style / tree. CSSPrimitiveValue::computeLength*()
2624 // multiplies each resolved length with the zoom multiplier - so for SVG we need to disable that.
2625 // Though all CSS values that can be applied to outermost <svg> elements (width/height/border/padding...)
2626 // need to respect the scaling. RenderBox (the parent class of RenderSVGRoot) grabs values like
2627 // width/height/border/padding/... from the RenderStyle -> for SVG these values would never scale,
2628 // if we'd pass a 1.0 zoom factor everyhwere. So we only pass a zoom factor of 1.0 for specific
2629 // properties that are NOT allowed to scale within a zoomed SVG document (letter/word-spacing/font-size).
2630 bool StyleResolver::useSVGZoomRules()
2632 return m_state.element && m_state.element->isSVGElement();
2635 static bool createGridTrackBreadth(CSSPrimitiveValue* primitiveValue, const StyleResolver::State& state, Length& workingLength)
2637 if (primitiveValue->getIdent() == CSSValueWebkitMinContent) {
2638 workingLength = Length(MinContent);
2642 if (primitiveValue->getIdent() == CSSValueWebkitMaxContent) {
2643 workingLength = Length(MaxContent);
2647 workingLength = primitiveValue->convertToLength<FixedIntegerConversion | PercentConversion | ViewportPercentageConversion | AutoConversion>(state.style.get(), state.rootElementStyle, state.style->effectiveZoom());
2648 if (workingLength.isUndefined())
2651 if (primitiveValue->isLength())
2652 workingLength.setQuirk(primitiveValue->isQuirkValue());
2657 static bool createGridTrackMinMax(CSSPrimitiveValue* primitiveValue, const StyleResolver::State& state, GridTrackSize& trackSize)
2659 Pair* minMaxTrackBreadth = primitiveValue->getPairValue();
2660 if (!minMaxTrackBreadth) {
2661 Length workingLength;
2662 if (!createGridTrackBreadth(primitiveValue, state, workingLength))
2665 trackSize.setLength(workingLength);
2669 Length minTrackBreadth;
2670 Length maxTrackBreadth;
2671 if (!createGridTrackBreadth(minMaxTrackBreadth->first(), state, minTrackBreadth) || !createGridTrackBreadth(minMaxTrackBreadth->second(), state, maxTrackBreadth))
2674 trackSize.setMinMax(minTrackBreadth, maxTrackBreadth);
2678 static bool createGridTrackGroup(CSSValue* value, const StyleResolver::State& state, Vector<GridTrackSize>& trackSizes)
2680 if (!value->isValueList())
2683 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
2684 CSSValue* currValue = i.value();
2685 if (!currValue->isPrimitiveValue())
2688 GridTrackSize trackSize;
2689 if (!createGridTrackMinMax(static_cast<CSSPrimitiveValue*>(currValue), state, trackSize))
2692 trackSizes.append(trackSize);
2697 static bool createGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, const StyleResolver::State& state)
2700 if (value->isPrimitiveValue()) {
2701 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
2702 return primitiveValue->getIdent() == CSSValueNone;
2705 return createGridTrackGroup(value, state, trackSizes);
2709 static bool createGridPosition(CSSValue* value, GridPosition& position)
2711 // For now, we only accept: <integer> | 'auto'
2712 if (!value->isPrimitiveValue())
2715 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
2716 if (primitiveValue->getIdent() == CSSValueAuto)
2719 ASSERT_WITH_SECURITY_IMPLICATION(primitiveValue->isNumber());
2720 position.setIntegerPosition(primitiveValue->getIntValue());
2724 #if ENABLE(CSS_VARIABLES)
2725 static bool hasVariableReference(CSSValue* value)
2727 if (value->isPrimitiveValue()) {
2728 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
2729 return primitiveValue->hasVariableReference();
2732 if (value->isCalculationValue())
2733 return static_cast<CSSCalcValue*>(value)->hasVariableReference();
2735 if (value->isReflectValue()) {
2736 CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value);
2737 CSSPrimitiveValue* direction = reflectValue->direction();
2738 CSSPrimitiveValue* offset = reflectValue->offset();
2739 CSSValue* mask = reflectValue->mask();
2740 return (direction && hasVariableReference(direction)) || (offset && hasVariableReference(offset)) || (mask && hasVariableReference(mask));
2743 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
2744 if (hasVariableReference(i.value()))
2751 void StyleResolver::resolveVariables(CSSPropertyID id, CSSValue* value, Vector<std::pair<CSSPropertyID, String> >& knownExpressions)
2753 std::pair<CSSPropertyID, String> expression(id, value->serializeResolvingVariables(*m_state.style->variables()));
2755 if (knownExpressions.contains(expression))
2756 return; // cycle detected.
2758 knownExpressions.append(expression);
2760 // FIXME: It would be faster not to re-parse from strings, but for now CSS property validation lives inside the parser so we do it there.
2761 RefPtr<StylePropertySet> resultSet = StylePropertySet::create();
2762 if (!CSSParser::parseValue(resultSet.get(), id, expression.second, false, document()))
2763 return; // expression failed to parse.
2765 for (unsigned i = 0; i < resultSet->propertyCount(); i++) {
2766 StylePropertySet::PropertyReference property = resultSet->propertyAt(i);
2767 if (property.id() != CSSPropertyVariable && hasVariableReference(property.value()))
2768 resolveVariables(property.id(), property.value(), knownExpressions);
2770 applyProperty(property.id(), property.value());
2775 void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
2777 #if ENABLE(CSS_VARIABLES)
2778 if (id != CSSPropertyVariable && hasVariableReference(value)) {
2779 Vector<std::pair<CSSPropertyID, String> > knownExpressions;
2780 resolveVariables(id, value, knownExpressions);
2785 State& state = m_state;
2786 bool isInherit = state.parentNode && value->isInheritedValue();
2787 bool isInitial = value->isInitialValue() || (!state.parentNode && value->isInheritedValue());
2789 ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit
2790 ASSERT(!isInherit || (state.parentNode && state.parentStyle)); // isInherit -> (state.parentNode && state.parentStyle)
2792 if (!state.applyPropertyToRegularStyle && (!state.applyPropertyToVisitedLinkStyle || !isValidVisitedLinkProperty(id))) {
2793 // Limit the properties that can be applied to only the ones honored by :visited.
2797 if (isInherit && !state.parentStyle->hasExplicitlyInheritedProperties() && !CSSProperty::isInheritedProperty(id))
2798 state.parentStyle->setHasExplicitlyInheritedProperties();
2800 #if ENABLE(CSS_VARIABLES)
2801 if (id == CSSPropertyVariable) {
2802 ASSERT_WITH_SECURITY_IMPLICATION(value->isVariableValue());
2803 CSSVariableValue* variable = static_cast<CSSVariableValue*>(value);
2804 ASSERT(!variable->name().isEmpty());
2805 ASSERT(!variable->value().isEmpty());
2806 state.style->setVariable(variable->name(), variable->value());
2811 // Check lookup table for implementations and use when available.
2812 const PropertyHandler& handler = m_styleBuilder.propertyHandler(id);
2813 if (handler.isValid()) {
2815 handler.applyInheritValue(id, this);
2817 handler.applyInitialValue(id, this);
2819 handler.applyValue(id, this, value);
2823 CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? static_cast<CSSPrimitiveValue*>(value) : 0;
2825 float zoomFactor = state.style->effectiveZoom();
2827 // What follows is a list that maps the CSS properties into their corresponding front-end
2828 // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and
2829 // are only hit when mapping "inherit" or "initial" into front-end values.
2832 case CSSPropertyContent:
2833 // list of string, uri, counter, attr, i
2835 // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
2836 // note is a reminder that eventually "inherit" needs to be supported.
2839 state.style->clearContent();
2843 if (!value->isValueList())
2846 bool didSet = false;
2847 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
2848 CSSValue* item = i.value();
2849 if (item->isImageGeneratorValue()) {
2850 if (item->isGradientValue())
2851 state.style->setContent(StyleGeneratedImage::create(static_cast<CSSGradientValue*>(item)->gradientWithStylesResolved(this).get()), didSet);
2853 state.style->setContent(StyleGeneratedImage::create(static_cast<CSSImageGeneratorValue*>(item)), didSet);
2855 #if ENABLE(CSS_IMAGE_SET)
2856 } else if (item->isImageSetValue()) {
2857 state.style->setContent(setOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageSetValue*>(item)), didSet);
2862 if (item->isImageValue()) {
2863 state.style->setContent(cachedOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageValue*>(item)), didSet);
2868 if (!item->isPrimitiveValue())
2871 CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item);
2873 if (contentValue->isString()) {
2874 state.style->setContent(contentValue->getStringValue().impl(), didSet);
2876 } else if (contentValue->isAttr()) {
2877 // FIXME: Can a namespace be specified for an attr(foo)?
2878 if (state.style->styleType() == NOPSEUDO)
2879 state.style->setUnique();
2881 state.parentStyle->setUnique();
2882 QualifiedName attr(nullAtom, contentValue->getStringValue().impl(), nullAtom);
2883 const AtomicString& value = state.element->getAttribute(attr);
2884 state.style->setContent(value.isNull() ? emptyAtom : value.impl(), didSet);
2886 // register the fact that the attribute value affects the style
2887 m_features.attrsInRules.add(attr.localName().impl());
2888 } else if (contentValue->isCounter()) {
2889 Counter* counterValue = contentValue->getCounterValue();
2890 EListStyleType listStyleType = NoneListStyle;
2891 int listStyleIdent = counterValue->listStyleIdent();
2892 if (listStyleIdent != CSSValueNone)
2893 listStyleType = static_cast<EListStyleType>(listStyleIdent - CSSValueDisc);
2894 OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(counterValue->identifier(), listStyleType, counterValue->separator()));
2895 state.style->setContent(counter.release(), didSet);
2898 switch (contentValue->getIdent()) {
2899 case CSSValueOpenQuote:
2900 state.style->setContent(OPEN_QUOTE, didSet);
2903 case CSSValueCloseQuote:
2904 state.style->setContent(CLOSE_QUOTE, didSet);
2907 case CSSValueNoOpenQuote:
2908 state.style->setContent(NO_OPEN_QUOTE, didSet);
2911 case CSSValueNoCloseQuote:
2912 state.style->setContent(NO_CLOSE_QUOTE, didSet);
2916 // normal and none do not have any effect.
2922 state.style->clearContent();
2925 case CSSPropertyQuotes:
2927 state.style->setQuotes(state.parentStyle->quotes());
2931 state.style->setQuotes(0);
2934 if (value->isValueList()) {
2935 CSSValueList* list = static_cast<CSSValueList*>(value);
2936 RefPtr<QuotesData> quotes = QuotesData::create();
2937 for (size_t i = 0; i < list->length(); i += 2) {
2938 CSSValue* first = list->itemWithoutBoundsCheck(i);
2939 // item() returns null if out of bounds so this is safe.
2940 CSSValue* second = list->item(i + 1);
2943 ASSERT_WITH_SECURITY_IMPLICATION(first->isPrimitiveValue());
2944 ASSERT_WITH_SECURITY_IMPLICATION(second->isPrimitiveValue());
2945 String startQuote = static_cast<CSSPrimitiveValue*>(first)->getStringValue();
2946 String endQuote = static_cast<CSSPrimitiveValue*>(second)->getStringValue();
2947 quotes->addPair(std::make_pair(startQuote, endQuote));
2949 state.style->setQuotes(quotes);
2952 if (primitiveValue) {
2953 if (primitiveValue->getIdent() == CSSValueNone)
2954 state.style->setQuotes(QuotesData::create());
2957 case CSSPropertyFontFamily: {
2958 // list of strings and ids
2960 FontDescription parentFontDescription = state.parentStyle->fontDescription();
2961 FontDescription fontDescription = state.style->fontDescription();
2962 fontDescription.setGenericFamily(parentFontDescription.genericFamily());
2963 fontDescription.setFamily(parentFontDescription.firstFamily());
2964 fontDescription.setIsSpecifiedFont(parentFontDescription.isSpecifiedFont());
2965 setFontDescription(fontDescription);
2970 FontDescription initialDesc = FontDescription();
2971 FontDescription fontDescription = state.style->fontDescription();
2972 // We need to adjust the size to account for the generic family change from monospace
2973 // to non-monospace.
2974 if (fontDescription.keywordSize() && fontDescription.useFixedDefaultSize())
2975 setFontSize(fontDescription, fontSizeForKeyword(document(), CSSValueXxSmall + fontDescription.keywordSize() - 1, false));
2976 fontDescription.setGenericFamily(initialDesc.genericFamily());
2977 if (!initialDesc.firstFamily().familyIsEmpty())
2978 fontDescription.setFamily(initialDesc.firstFamily());
2979 setFontDescription(fontDescription);
2983 if (!value->isValueList())
2985 FontDescription fontDescription = state.style->fontDescription();
2986 FontFamily& firstFamily = fontDescription.firstFamily();
2987 FontFamily* currFamily = 0;
2989 // Before mapping in a new font-family property, we should reset the generic family.
2990 bool oldFamilyUsedFixedDefaultSize = fontDescription.useFixedDefaultSize();
2991 fontDescription.setGenericFamily(FontDescription::NoFamily);
2993 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
2994 CSSValue* item = i.value();
2995 if (!item->isPrimitiveValue())
2997 CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item);
2999 Settings* settings = documentSettings();
3000 if (contentValue->isString())
3001 face = contentValue->getStringValue();
3002 else if (settings) {
3003 switch (contentValue->getIdent()) {
3004 case CSSValueWebkitBody:
3005 face = settings->standardFontFamily();
3009 fontDescription.setGenericFamily(FontDescription::SerifFamily);
3011 case CSSValueSansSerif:
3012 face = sansSerifFamily;
3013 fontDescription.setGenericFamily(FontDescription::SansSerifFamily);
3015 case CSSValueCursive:
3016 face = cursiveFamily;
3017 fontDescription.setGenericFamily(FontDescription::CursiveFamily);
3019 case CSSValueFantasy:
3020 face = fantasyFamily;
3021 fontDescription.setGenericFamily(FontDescription::FantasyFamily);
3023 case CSSValueMonospace:
3024 face = monospaceFamily;
3025 fontDescription.setGenericFamily(FontDescription::MonospaceFamily);
3027 case CSSValueWebkitPictograph:
3028 face = pictographFamily;
3029 fontDescription.setGenericFamily(FontDescription::PictographFamily);
3034 if (!face.isEmpty()) {
3036 // Filling in the first family.
3037 firstFamily.setFamily(face);
3038 firstFamily.appendFamily(0); // Remove any inherited family-fallback list.
3039 currFamily = &firstFamily;
3040 fontDescription.setIsSpecifiedFont(fontDescription.genericFamily() == FontDescription::NoFamily);
3042 RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create();
3043 newFamily->setFamily(face);
3044 currFamily->appendFamily(newFamily);
3045 currFamily = newFamily.get();
3050 // We can't call useFixedDefaultSize() until all new font families have been added
3051 // If currFamily is non-zero then we set at least one family on this description.
3053 if (fontDescription.keywordSize() && fontDescription.useFixedDefaultSize() != oldFamilyUsedFixedDefaultSize)
3054 setFontSize(fontDescription, fontSizeForKeyword(document(), CSSValueXxSmall + fontDescription.keywordSize() - 1, !oldFamilyUsedFixedDefaultSize));
3056 setFontDescription(fontDescription);
3060 // shorthand properties
3061 case CSSPropertyBackground:
3063 state.style->clearBackgroundLayers();
3064 state.style->setBackgroundColor(Color());
3065 } else if (isInherit) {
3066 state.style->inheritBackgroundLayers(*state.parentStyle->backgroundLayers());
3067 state.style->setBackgroundColor(state.parentStyle->backgroundColor());
3070 case CSSPropertyWebkitMask:
3072 state.style->clearMaskLayers();
3074 state.style->inheritMaskLayers(*state.parentStyle->maskLayers());
3076 case CSSPropertyFont:
3078 FontDescription fontDescription = state.parentStyle->fontDescription();
3079 state.style->setLineHeight(state.parentStyle->specifiedLineHeight());
3080 state.lineHeightValue = 0;
3081 setFontDescription(fontDescription);
3082 } else if (isInitial) {
3083 Settings* settings = documentSettings();
3084 ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
3087 initializeFontStyle(settings);
3088 } else if (primitiveValue) {
3089 state.style->setLineHeight(RenderStyle::initialLineHeight());
3090 state.lineHeightValue = 0;
3092 FontDescription fontDescription;
3093 RenderTheme::defaultTheme()->systemFont(primitiveValue->getIdent(), fontDescription);
3095 // Double-check and see if the theme did anything. If not, don't bother updating the font.
3096 if (fontDescription.isAbsoluteSize()) {
3097 // Make sure the rendering mode and printer font settings are updated.
3098 Settings* settings = documentSettings();
3099 ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
3102 fontDescription.setRenderingMode(settings->fontRenderingMode());
3103 fontDescription.setUsePrinterFont(document()->printing() || !settings->screenFontSubstitutionEnabled());
3105 // Handle the zoom factor.
3106 fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(document(), state.style.get(), fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), useSVGZoomRules()));
3107 setFontDescription(fontDescription);
3109 } else if (value->isFontValue()) {
3110 FontValue* font = static_cast<FontValue*>(value);
3111 if (!font->style || !font->variant || !font->weight
3112 || !font->size || !font->lineHeight || !font->family)
3114 applyProperty(CSSPropertyFontStyle, font->style.get());
3115 applyProperty(CSSPropertyFontVariant, font->variant.get());
3116 applyProperty(CSSPropertyFontWeight, font->weight.get());
3117 // The previous properties can dirty our font but they don't try to read the font's
3118 // properties back, which is safe. However if font-size is using the 'ex' unit, it will
3119 // need query the dirtied font's x-height to get the computed size. To be safe in this
3120 // case, let's just update the font now.
3122 applyProperty(CSSPropertyFontSize, font->size.get());
3124 state.lineHeightValue = font->lineHeight.get();
3126 applyProperty(CSSPropertyFontFamily, font->family.get());
3131 case CSSPropertyTextShadow:
3132 case CSSPropertyBoxShadow:
3133 case CSSPropertyWebkitBoxShadow: {
3135 if (id == CSSPropertyTextShadow)
3136 return state.style->setTextShadow(state.parentStyle->textShadow() ? adoptPtr(new ShadowData(*state.parentStyle->textShadow())) : nullptr);
3137 return state.style->setBoxShadow(state.parentStyle->boxShadow() ? adoptPtr(new ShadowData(*state.parentStyle->boxShadow())) : nullptr);
3139 if (isInitial || primitiveValue) // initial | none
3140 return id == CSSPropertyTextShadow ? state.style->setTextShadow(nullptr) : state.style->setBoxShadow(nullptr);
3142 if (!value->isValueList())
3145 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
3146 CSSValue* currValue = i.value();
3147 if (!currValue->isShadowValue())
3149 ShadowValue* item = static_cast<ShadowValue*>(currValue);
3150 int x = item->x->computeLength<int>(state.style.get(), state.rootElementStyle, zoomFactor);
3151 int y = item->y->computeLength<int>(state.style.get(), state.rootElementStyle, zoomFactor);
3152 int blur = item->blur ? item->blur->computeLength<int>(state.style.get(), state.rootElementStyle, zoomFactor) : 0;
3153 int spread = item->spread ? item->spread->computeLength<int>(state.style.get(), state.rootElementStyle, zoomFactor) : 0;
3154 ShadowStyle shadowStyle = item->style && item->style->getIdent() == CSSValueInset ? Inset : Normal;
3157 color = colorFromPrimitiveValue(item->color.get());
3158 else if (state.style)
3159 color = state.style->color();
3161 OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(IntPoint(x, y), blur, spread, shadowStyle, id == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent));
3162 if (id == CSSPropertyTextShadow)
3163 state.style->setTextShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry
3165 state.style->setBoxShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry
3169 case CSSPropertyWebkitBoxReflect: {
3170 HANDLE_INHERIT_AND_INITIAL(boxReflect, BoxReflect)
3171 if (primitiveValue) {
3172 state.style->setBoxReflect(RenderStyle::initialBoxReflect());
3176 if (!value->isReflectValue())
3179 CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value);
3180 RefPtr<StyleReflection> reflection = StyleReflection::create();
3181 reflection->setDirection(*reflectValue->direction());
3182 if (reflectValue->offset())
3183 reflection->setOffset(reflectValue->offset()->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(state.style.get(), state.rootElementStyle, zoomFactor));
3184 NinePieceImage mask;
3185 mask.setMaskDefaults();
3186 m_styleMap.mapNinePieceImage(id, reflectValue->mask(), mask);
3187 reflection->setMask(mask);
3189 state.style->setBoxReflect(reflection.release());
3192 case CSSPropertySrc: // Only used in @font-face rules.
3194 case CSSPropertyUnicodeRange: // Only used in @font-face rules.
3196 case CSSPropertyWebkitColumnRule:
3198 state.style->setColumnRuleColor(state.parentStyle->columnRuleColor().isValid() ? state.parentStyle->columnRuleColor() : state.parentStyle->color());
3199 state.style->setColumnRuleStyle(state.parentStyle->columnRuleStyle());
3200 state.style->setColumnRuleWidth(state.parentStyle->columnRuleWidth());
3201 } else if (isInitial)
3202 state.style->resetColumnRule();
3204 case CSSPropertyWebkitMarquee:
3207 state.style->setMarqueeDirection(state.parentStyle->marqueeDirection());
3208 state.style->setMarqueeIncrement(state.parentStyle->marqueeIncrement());
3209 state.style->setMarqueeSpeed(state.parentStyle->marqueeSpeed());
3210 state.style->setMarqueeLoopCount(state.parentStyle->marqueeLoopCount());
3211 state.style->setMarqueeBehavior(state.parentStyle->marqueeBehavior());
3213 case CSSPropertyWebkitMarqueeRepetition: {
3214 HANDLE_INHERIT_AND_INITIAL(marqueeLoopCount, MarqueeLoopCount)
3215 if (!primitiveValue)
3217 if (primitiveValue->getIdent() == CSSValueInfinite)
3218 state.style->setMarqueeLoopCount(-1); // -1 means repeat forever.
3219 else if (primitiveValue->isNumber())
3220 state.style->setMarqueeLoopCount(primitiveValue->getIntValue());
3223 case CSSPropertyWebkitMarqueeSpeed: {
3224 HANDLE_INHERIT_AND_INITIAL(marqueeSpeed, MarqueeSpeed)
3225 if (!primitiveValue)
3227 if (int ident = primitiveValue->getIdent()) {
3230 state.style->setMarqueeSpeed(500); // 500 msec.
3232 case CSSValueNormal:
3233 state.style->setMarqueeSpeed(85); // 85msec. The WinIE default.
3236 state.style->setMarqueeSpeed(10); // 10msec. Super fast.
3239 } else if (primitiveValue->isTime())
3240 state.style->setMarqueeSpeed(primitiveValue->computeTime<int, CSSPrimitiveValue::Milliseconds>());
3241 else if (primitiveValue->isNumber()) // For scrollamount support.
3242 state.style->setMarqueeSpeed(primitiveValue->getIntValue());
3245 case CSSPropertyWebkitMarqueeIncrement: {
3246 HANDLE_INHERIT_AND_INITIAL(marqueeIncrement, MarqueeIncrement)
3247 if (!primitiveValue)
3249 if (primitiveValue->getIdent()) {
3250 switch (primitiveValue->getIdent()) {
3252 state.style->setMarqueeIncrement(Length(1, Fixed)); // 1px.
3254 case CSSValueNormal:
3255 state.style->setMarqueeIncrement(Length(6, Fixed)); // 6px. The WinIE default.
3258 state.style->setMarqueeIncrement(Length(36, Fixed)); // 36px.
3262 Length marqueeLength = convertToIntLength(primitiveValue, state.style.get(), state.rootElementStyle);
3263 if (!marqueeLength.isUndefined())
3264 state.style->setMarqueeIncrement(marqueeLength);
3268 case CSSPropertyWebkitLocale: {
3269 HANDLE_INHERIT_AND_INITIAL(locale, Locale);
3270 if (!primitiveValue)
3272 if (primitiveValue->getIdent() == CSSValueAuto)
3273 state.style->setLocale(nullAtom);
3275 state.style->setLocale(primitiveValue->getStringValue());
3276 FontDescription fontDescription = state.style->fontDescription();
3277 fontDescription.setScript(localeToScriptCodeForFontSelection(state.style->locale()));
3278 setFontDescription(fontDescription);
3281 case CSSPropertyWebkitTextSizeAdjust: {
3282 HANDLE_INHERIT_AND_INITIAL(textSizeAdjust, TextSizeAdjust)
3283 if (!primitiveValue || !primitiveValue->getIdent())
3285 setTextSizeAdjust(primitiveValue->getIdent() == CSSValueAuto);
3288 #if ENABLE(DASHBOARD_SUPPORT)
3289 case CSSPropertyWebkitDashboardRegion:
3291 HANDLE_INHERIT_AND_INITIAL(dashboardRegions, DashboardRegions)
3292 if (!primitiveValue)
3295 if (primitiveValue->getIdent() == CSSValueNone) {
3296 state.style->setDashboardRegions(RenderStyle::noneDashboardRegions());
3300 DashboardRegion* region = primitiveValue->getDashboardRegionValue();
3304 DashboardRegion* first = region;
3306 Length top = convertToIntLength(region->top(), state.style.get(), state.rootElementStyle);
3307 Length right = convertToIntLength(region->right(), state.style.get(), state.rootElementStyle);
3308 Length bottom = convertToIntLength(region->bottom(), state.style.get(), state.rootElementStyle);
3309 Length left = convertToIntLength(region->left(), state.style.get(), state.rootElementStyle);
3311 if (top.isUndefined())
3313 if (right.isUndefined())
3315 if (bottom.isUndefined())
3317 if (left.isUndefined())
3320 if (region->m_isCircle)
3321 state.style->setDashboardRegion(StyleDashboardRegion::Circle, region->m_label, top, right, bottom, left, region == first ? false : true);
3322 else if (region->m_isRectangle)
3323 state.style->setDashboardRegion(StyleDashboardRegion::Rectangle, region->m_label, top, right, bottom, left, region == first ? false : true);
3324 region = region->m_next.get();
3327 state.element->document()->setHasAnnotatedRegions(true);
3332 #if ENABLE(DRAGGABLE_REGION)
3333 case CSSPropertyWebkitAppRegion: {
3334 if (!primitiveValue || !primitiveValue->getIdent())
3336 state.style->setDraggableRegionMode(primitiveValue->getIdent() == CSSValueDrag ? DraggableRegionDrag : DraggableRegionNoDrag);
3337 state.element->document()->setHasAnnotatedRegions(true);
3341 case CSSPropertyWebkitTextStrokeWidth: {
3342 HANDLE_INHERIT_AND_INITIAL(textStrokeWidth, TextStrokeWidth)
3344 switch (primitiveValue->getIdent()) {
3346 case CSSValueMedium:
3347 case CSSValueThick: {
3348 double result = 1.0 / 48;
3349 if (primitiveValue->getIdent() == CSSValueMedium)
3351 else if (primitiveValue->getIdent() == CSSValueThick)
3353 width = CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS)->computeLength<float>(state.style.get(), state.rootElementStyle, zoomFactor);
3357 width = primitiveValue->computeLength<float>(state.style.get(), state.rootElementStyle, zoomFactor);
3360 state.style->setTextStrokeWidth(width);
3363 case CSSPropertyWebkitTransform: {
3364 HANDLE_INHERIT_AND_INITIAL(transform, Transform);
3365 TransformOperations operations;
3366 createTransformOperations(value, state.style.get(