summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/StyleResolver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/css/StyleResolver.cpp')
-rw-r--r--Source/WebCore/css/StyleResolver.cpp3457
1 files changed, 910 insertions, 2547 deletions
diff --git a/Source/WebCore/css/StyleResolver.cpp b/Source/WebCore/css/StyleResolver.cpp
index 827388f29..719ff295c 100644
--- a/Source/WebCore/css/StyleResolver.cpp
+++ b/Source/WebCore/css/StyleResolver.cpp
@@ -1,14 +1,15 @@
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
- * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2014 Apple Inc. All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (C) Research In Motion Limited 2011. All rights reserved.
- * Copyright (C) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -29,10 +30,10 @@
#include "config.h"
#include "StyleResolver.h"
-#include "Attribute.h"
#include "CSSBorderImage.h"
#include "CSSCalculationValue.h"
#include "CSSCursorImageValue.h"
+#include "CSSCustomPropertyValue.h"
#include "CSSDefaultStyleSheets.h"
#include "CSSFilterImageValue.h"
#include "CSSFontFaceRule.h"
@@ -40,7 +41,12 @@
#include "CSSFontSelector.h"
#include "CSSFontValue.h"
#include "CSSFunctionValue.h"
-#include "CSSGridTemplateValue.h"
+#include "CSSGradientValue.h"
+#include "CSSImageSetValue.h"
+#include "CSSInheritedValue.h"
+#include "CSSInitialValue.h"
+#include "CSSKeyframeRule.h"
+#include "CSSKeyframesRule.h"
#include "CSSLineBoxContainValue.h"
#include "CSSPageRule.h"
#include "CSSParser.h"
@@ -51,33 +57,32 @@
#include "CSSSelectorList.h"
#include "CSSShadowValue.h"
#include "CSSStyleRule.h"
+#include "CSSStyleSheet.h"
#include "CSSSupportsRule.h"
#include "CSSTimingFunctionValue.h"
#include "CSSValueList.h"
+#include "CSSValuePool.h"
#include "CachedImage.h"
#include "CachedResourceLoader.h"
+#include "CachedSVGDocument.h"
+#include "CachedSVGDocumentReference.h"
#include "CalculationValue.h"
#include "ContentData.h"
#include "Counter.h"
#include "CounterContent.h"
#include "CursorList.h"
-#include "DeprecatedStyleBuilder.h"
-#include "DocumentStyleSheetCollection.h"
#include "ElementRuleCollector.h"
+#include "FilterOperation.h"
#include "Frame.h"
#include "FrameSelection.h"
#include "FrameView.h"
#include "HTMLDocument.h"
-#include "HTMLIFrameElement.h"
#include "HTMLInputElement.h"
+#include "HTMLMarqueeElement.h"
#include "HTMLNames.h"
-#include "HTMLOptGroupElement.h"
-#include "HTMLOptionElement.h"
-#include "HTMLProgressElement.h"
-#include "HTMLStyleElement.h"
+#include "HTMLSlotElement.h"
#include "HTMLTableElement.h"
#include "HTMLTextAreaElement.h"
-#include "InsertionPoint.h"
#include "InspectorInstrumentation.h"
#include "KeyframeList.h"
#include "LinkHash.h"
@@ -86,12 +91,13 @@
#include "MediaList.h"
#include "MediaQueryEvaluator.h"
#include "NodeRenderStyle.h"
-#include "NodeRenderingTraversal.h"
#include "Page.h"
#include "PageRuleCollector.h"
#include "Pair.h"
+#include "PseudoElement.h"
#include "QuotesData.h"
#include "Rect.h"
+#include "RenderGrid.h"
#include "RenderRegion.h"
#include "RenderScrollbar.h"
#include "RenderScrollbarTheme.h"
@@ -99,21 +105,25 @@
#include "RenderTheme.h"
#include "RenderView.h"
#include "RuleSet.h"
+#include "SVGDocument.h"
#include "SVGDocumentExtensions.h"
#include "SVGFontFaceElement.h"
-#include "SecurityOrigin.h"
-#include "SelectorCheckerFastPath.h"
+#include "SVGNames.h"
+#include "SVGSVGElement.h"
+#include "SVGURIReference.h"
#include "Settings.h"
#include "ShadowData.h"
#include "ShadowRoot.h"
+#include "StyleBuilder.h"
+#include "StyleColor.h"
#include "StyleCachedImage.h"
#include "StyleFontSizeFunctions.h"
#include "StyleGeneratedImage.h"
-#include "StylePendingImage.h"
#include "StyleProperties.h"
#include "StylePropertyShorthand.h"
#include "StyleRule.h"
#include "StyleRuleImport.h"
+#include "StyleScrollSnapPoints.h"
#include "StyleSheetContents.h"
#include "StyleSheetList.h"
#include "Text.h"
@@ -122,111 +132,39 @@
#include "UserAgentStyleSheets.h"
#include "ViewportStyleResolver.h"
#include "VisitedLinkState.h"
-#include "WebKitCSSKeyframeRule.h"
-#include "WebKitCSSKeyframesRule.h"
#include "WebKitCSSRegionRule.h"
-#include "WebKitCSSTransformValue.h"
#include "WebKitFontFamilyNames.h"
-#include "XMLNames.h"
#include <bitset>
+#include <wtf/SetForScope.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
+#include <wtf/text/AtomicStringHash.h>
-#if ENABLE(CSS_FILTERS)
-#include "FilterOperation.h"
-#include "WebKitCSSFilterValue.h"
-#endif
-
-#if ENABLE(CSS_IMAGE_SET)
-#include "CSSImageSetValue.h"
-#include "StyleCachedImageSet.h"
-#endif
+#include "CSSGridLineNamesValue.h"
+#include "CSSGridTemplateAreasValue.h"
#if ENABLE(DASHBOARD_SUPPORT)
#include "DashboardRegion.h"
#endif
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
-#include "HTMLAudioElement.h"
-#endif
-
-#if ENABLE(SVG)
-#include "CachedSVGDocument.h"
-#include "CachedSVGDocumentReference.h"
-#include "SVGDocument.h"
-#include "SVGElement.h"
-#include "SVGNames.h"
-#include "SVGURIReference.h"
-#endif
-
#if ENABLE(VIDEO_TRACK)
#include "WebVTTElement.h"
#endif
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
-#include "HTMLMediaElement.h"
-#endif
-
namespace WebCore {
using namespace HTMLNames;
-class StyleResolver::CascadedProperties {
-public:
- CascadedProperties(TextDirection, WritingMode);
-
- struct Property {
- void apply(StyleResolver&);
-
- CSSPropertyID id;
- CSSValue* cssValue[3];
- };
-
- bool hasProperty(CSSPropertyID id) const { return m_propertyIsPresent.test(id); }
- Property& property(CSSPropertyID);
- bool addMatches(const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly = false);
-
- void set(CSSPropertyID, CSSValue&, unsigned linkMatchType);
- void setDeferred(CSSPropertyID, CSSValue&, unsigned linkMatchType);
-
- void applyDeferredProperties(StyleResolver&);
-
-private:
- bool addStyleProperties(const StyleProperties&, StyleRule&, bool isImportant, bool inheritedOnly, PropertyWhitelistType, unsigned linkMatchType);
- static void setPropertyInternal(Property&, CSSPropertyID, CSSValue&, unsigned linkMatchType);
-
- Property m_properties[numCSSProperties + 1];
- std::bitset<numCSSProperties + 1> m_propertyIsPresent;
-
- Vector<Property, 8> m_deferredProperties;
-
- TextDirection m_direction;
- WritingMode m_writingMode;
-};
+static const CSSPropertyID firstLowPriorityProperty = static_cast<CSSPropertyID>(lastHighPriorityProperty + 1);
static void extractDirectionAndWritingMode(const RenderStyle&, const StyleResolver::MatchResult&, TextDirection&, WritingMode&);
-#define HANDLE_INHERIT(prop, Prop) \
-if (isInherit) { \
- m_state.style()->set##Prop(m_state.parentStyle()->prop()); \
- return; \
-}
-
-#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
-HANDLE_INHERIT(prop, Prop) \
-if (isInitial) { \
- m_state.style()->set##Prop(RenderStyle::initial##Prop()); \
- return; \
-}
-
-RenderStyle* StyleResolver::s_styleNotYetAvailable;
-
inline void StyleResolver::State::cacheBorderAndBackground()
{
m_hasUAAppearance = m_style->hasAppearance();
if (m_hasUAAppearance) {
m_borderData = m_style->border();
- m_backgroundData = *m_style->backgroundLayers();
+ m_backgroundData = m_style->backgroundLayers();
m_backgroundColor = m_style->backgroundColor();
}
}
@@ -234,36 +172,68 @@ inline void StyleResolver::State::cacheBorderAndBackground()
inline void StyleResolver::State::clear()
{
m_element = nullptr;
- m_styledElement = nullptr;
m_parentStyle = nullptr;
- m_parentNode = nullptr;
+ m_ownedParentStyle = nullptr;
m_regionForStyling = nullptr;
- m_pendingImageProperties.clear();
-#if ENABLE(CSS_FILTERS) && ENABLE(SVG)
- m_filtersWithPendingSVGDocuments.clear();
-#endif
+ m_cssToLengthConversionData = CSSToLengthConversionData();
}
-void StyleResolver::MatchResult::addMatchedProperties(const StyleProperties& properties, StyleRule* rule, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType)
+void StyleResolver::MatchResult::addMatchedProperties(const StyleProperties& properties, StyleRule* rule, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType, Style::ScopeOrdinal styleScopeOrdinal)
{
- matchedProperties.grow(matchedProperties.size() + 1);
- StyleResolver::MatchedProperties& newProperties = matchedProperties.last();
+ m_matchedProperties.grow(m_matchedProperties.size() + 1);
+ StyleResolver::MatchedProperties& newProperties = m_matchedProperties.last();
newProperties.properties = const_cast<StyleProperties*>(&properties);
newProperties.linkMatchType = linkMatchType;
newProperties.whitelistType = propertyWhitelistType;
+ newProperties.styleScopeOrdinal = styleScopeOrdinal;
matchedRules.append(rule);
+
+ if (styleScopeOrdinal != Style::ScopeOrdinal::Element)
+ isCacheable = false;
+
+ if (isCacheable) {
+ for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
+ // Currently the property cache only copy the non-inherited values and resolve
+ // the inherited ones.
+ // Here we define some exception were we have to resolve some properties that are not inherited
+ // by default. If those exceptions become too common on the web, it should be possible
+ // to build a list of exception to resolve instead of completely disabling the cache.
+
+ StyleProperties::PropertyReference current = properties.propertyAt(i);
+ if (!current.isInherited()) {
+ // If the property value is explicitly inherited, we need to apply further non-inherited properties
+ // as they might override the value inherited here. For this reason we don't allow declarations with
+ // explicitly inherited properties to be cached.
+ const CSSValue& value = *current.value();
+ if (value.isInheritedValue()) {
+ isCacheable = false;
+ break;
+ }
+
+ // The value currentColor has implicitely the same side effect. It depends on the value of color,
+ // which is an inherited value, making the non-inherited property implicitly inherited.
+ if (is<CSSPrimitiveValue>(value) && downcast<CSSPrimitiveValue>(value).valueID() == CSSValueCurrentcolor) {
+ isCacheable = false;
+ break;
+ }
+
+ if (value.hasVariableReferences()) {
+ isCacheable = false;
+ break;
+ }
+ }
+ }
+ }
}
-StyleResolver::StyleResolver(Document& document, bool matchAuthorAndUserStyles)
+StyleResolver::StyleResolver(Document& document)
: m_matchedPropertiesCacheAdditionsSinceLastSweep(0)
- , m_matchedPropertiesCacheSweepTimer(this, &StyleResolver::sweepMatchedPropertiesCache)
+ , m_matchedPropertiesCacheSweepTimer(*this, &StyleResolver::sweepMatchedPropertiesCache)
, m_document(document)
- , m_matchAuthorAndUserStyles(matchAuthorAndUserStyles)
- , m_fontSelector(CSSFontSelector::create(&m_document))
+ , m_matchAuthorAndUserStyles(m_document.settings().authorAndUserStylesEnabled())
#if ENABLE(CSS_DEVICE_ADAPTATION)
, m_viewportStyleResolver(ViewportStyleResolver::create(&document))
#endif
- , m_deprecatedStyleBuilder(DeprecatedStyleBuilder::sharedStyleBuilder())
, m_styleMap(this)
{
Element* root = m_document.documentElement();
@@ -278,103 +248,67 @@ StyleResolver::StyleResolver(Document& document, bool matchAuthorAndUserStyles)
// is always from the document that owns the style selector
FrameView* view = m_document.view();
if (view)
- m_medium = std::make_unique<MediaQueryEvaluator>(view->mediaType());
+ m_mediaQueryEvaluator = MediaQueryEvaluator { view->mediaType() };
else
- m_medium = std::make_unique<MediaQueryEvaluator>("all");
+ m_mediaQueryEvaluator = MediaQueryEvaluator { "all" };
- if (root)
- m_rootDefaultStyle = styleForElement(root, 0, DisallowStyleSharing, MatchOnlyUserAgentRules);
+ if (root) {
+ m_rootDefaultStyle = styleForElement(*root, m_document.renderStyle(), nullptr, MatchOnlyUserAgentRules).renderStyle;
+ // Turn off assertion against font lookups during style resolver initialization. We may need root style font for media queries.
+ m_document.fontSelector().setIsComputingRootStyleFont(true);
+ m_rootDefaultStyle->fontCascade().update(&m_document.fontSelector());
+ m_rootDefaultStyle->fontCascade().primaryFont();
+ m_document.fontSelector().setIsComputingRootStyleFont(false);
+ }
if (m_rootDefaultStyle && view)
- m_medium = std::make_unique<MediaQueryEvaluator>(view->mediaType(), &view->frame(), m_rootDefaultStyle.get());
+ m_mediaQueryEvaluator = MediaQueryEvaluator { view->mediaType(), m_document, m_rootDefaultStyle.get() };
m_ruleSets.resetAuthorStyle();
- DocumentStyleSheetCollection& styleSheetCollection = m_document.styleSheetCollection();
- m_ruleSets.initUserStyle(styleSheetCollection, *m_medium, *this);
+ m_ruleSets.initUserStyle(m_document.extensionStyleSheets(), m_mediaQueryEvaluator, *this);
#if ENABLE(SVG_FONTS)
if (m_document.svgExtensions()) {
const HashSet<SVGFontFaceElement*>& svgFontFaceElements = m_document.svgExtensions()->svgFontFaceElements();
- HashSet<SVGFontFaceElement*>::const_iterator end = svgFontFaceElements.end();
- for (HashSet<SVGFontFaceElement*>::const_iterator it = svgFontFaceElements.begin(); it != end; ++it)
- fontSelector()->addFontFaceRule((*it)->fontFaceRule());
+ for (auto* svgFontFaceElement : svgFontFaceElements)
+ m_document.fontSelector().addFontFaceRule(svgFontFaceElement->fontFaceRule(), svgFontFaceElement->isInUserAgentShadowTree());
}
#endif
-
- appendAuthorStyleSheets(0, styleSheetCollection.activeAuthorStyleSheets());
}
-void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet>>& styleSheets)
+void StyleResolver::appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>& styleSheets)
{
- m_ruleSets.appendAuthorStyleSheets(firstNew, styleSheets, m_medium.get(), m_inspectorCSSOMWrappers, document().isViewSource(), this);
+ m_ruleSets.appendAuthorStyleSheets(styleSheets, &m_mediaQueryEvaluator, m_inspectorCSSOMWrappers, this);
+
+ document().fontSelector().buildCompleted();
+
if (auto renderView = document().renderView())
- renderView->style().font().update(fontSelector());
+ renderView->style().fontCascade().update(&document().fontSelector());
#if ENABLE(CSS_DEVICE_ADAPTATION)
viewportStyleResolver()->resolve();
#endif
}
-void StyleResolver::pushParentElement(Element* parent)
-{
- const ContainerNode* parentsParent = parent->parentOrShadowHostElement();
-
- // We are not always invoked consistently. For example, script execution can cause us to enter
- // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree.
- // Reset the stack in this case, or if we see a new root element.
- // Otherwise just push the new parent.
- if (!parentsParent || m_selectorFilter.parentStackIsEmpty())
- m_selectorFilter.setupParentStack(parent);
- else
- m_selectorFilter.pushParent(parent);
-
- // Note: We mustn't skip ShadowRoot nodes for the scope stack.
- if (m_scopeResolver)
- m_scopeResolver->push(parent, parent->parentOrShadowHostNode());
-}
-
-void StyleResolver::popParentElement(Element* parent)
-{
- // Note that we may get invoked for some random elements in some wacky cases during style resolve.
- // Pause maintaining the stack in this case.
- if (m_selectorFilter.parentStackIsConsistent(parent))
- m_selectorFilter.popParent();
- if (m_scopeResolver)
- m_scopeResolver->pop(parent);
-}
-
-void StyleResolver::pushParentShadowRoot(const ShadowRoot* shadowRoot)
-{
- ASSERT(shadowRoot->hostElement());
- if (m_scopeResolver)
- m_scopeResolver->push(shadowRoot, shadowRoot->hostElement());
-}
-
-void StyleResolver::popParentShadowRoot(const ShadowRoot* shadowRoot)
-{
- ASSERT(shadowRoot->hostElement());
- if (m_scopeResolver)
- m_scopeResolver->pop(shadowRoot);
-}
-
// This is a simplified style setting function for keyframe styles
-void StyleResolver::addKeyframeStyle(PassRefPtr<StyleRuleKeyframes> rule)
+void StyleResolver::addKeyframeStyle(Ref<StyleRuleKeyframes>&& rule)
{
AtomicString s(rule->name());
- m_keyframesRuleMap.set(s.impl(), rule);
+ m_keyframesRuleMap.set(s.impl(), WTFMove(rule));
}
StyleResolver::~StyleResolver()
{
- m_fontSelector->clearDocument();
+ RELEASE_ASSERT(!m_isDeleted);
+ m_isDeleted = true;
#if ENABLE(CSS_DEVICE_ADAPTATION)
m_viewportStyleResolver->clearDocument();
#endif
}
-void StyleResolver::sweepMatchedPropertiesCache(Timer<StyleResolver>*)
+void StyleResolver::sweepMatchedPropertiesCache()
{
// Look for cache entries containing a style declaration with a single ref and remove them.
// This may happen when an element attribute mutation causes it to generate a new inlineStyle()
@@ -397,477 +331,115 @@ void StyleResolver::sweepMatchedPropertiesCache(Timer<StyleResolver>*)
m_matchedPropertiesCacheAdditionsSinceLastSweep = 0;
}
-inline bool StyleResolver::styleSharingCandidateMatchesHostRules()
-{
-#if ENABLE(SHADOW_DOM)
- return m_scopeResolver && m_scopeResolver->styleSharingCandidateMatchesHostRules(m_state.element());
-#else
- return false;
-#endif
-}
-
-bool StyleResolver::classNamesAffectedByRules(const SpaceSplitString& classNames) const
-{
- for (unsigned i = 0; i < classNames.size(); ++i) {
- if (m_ruleSets.features().classesInRules.contains(classNames[i].impl()))
- return true;
- }
- return false;
-}
-
-inline void StyleResolver::State::initElement(Element* e)
-{
- m_element = e;
- m_styledElement = e && e->isStyledElement() ? toStyledElement(e) : nullptr;
- m_elementLinkState = e ? e->document().visitedLinkState().determineLinkState(e) : NotInsideLink;
-}
-
-inline void StyleResolver::initElement(Element* e)
-{
- if (m_state.element() != e) {
- m_state.initElement(e);
- if (e && e == e->document().documentElement()) {
- e->document().setDirectionSetOnDocumentElement(false);
- e->document().setWritingModeSetOnDocumentElement(false);
- }
- }
-}
-
-inline void StyleResolver::State::initForStyleResolve(Document& document, Element* e, RenderStyle* parentStyle, RenderRegion* regionForStyling)
-{
- m_regionForStyling = regionForStyling;
-
- if (e) {
- m_parentNode = NodeRenderingTraversal::parent(e);
- bool resetStyleInheritance = hasShadowRootParent(*e) && toShadowRoot(e->parentNode())->resetStyleInheritance();
- m_parentStyle = resetStyleInheritance ? 0 :
- parentStyle ? parentStyle :
- m_parentNode ? m_parentNode->renderStyle() : 0;
- } else {
- m_parentNode = 0;
- m_parentStyle = parentStyle;
- }
-
- Node* docElement = e ? e->document().documentElement() : 0;
- RenderStyle* docStyle = document.renderStyle();
- m_rootElementStyle = docElement && e != docElement ? docElement->renderStyle() : docStyle;
-
- m_style = 0;
- m_pendingImageProperties.clear();
- m_fontDirty = false;
-}
-
-static const unsigned cStyleSearchThreshold = 10;
-static const unsigned cStyleSearchLevelThreshold = 10;
-
-static inline bool parentElementPreventsSharing(const Element* parentElement)
-{
- if (!parentElement)
- return false;
- return parentElement->hasFlagsSetDuringStylingOfChildren();
-}
-
-Node* StyleResolver::locateCousinList(Element* parent, unsigned& visitedNodeCount) const
-{
- if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold)
- return 0;
- if (!parent || !parent->isStyledElement())
- return 0;
- StyledElement* p = toStyledElement(parent);
- if (p->inlineStyle())
- return 0;
-#if ENABLE(SVG)
- if (p->isSVGElement() && toSVGElement(p)->animatedSMILStyleProperties())
- return 0;
-#endif
- if (p->hasID() && m_ruleSets.features().idsInRules.contains(p->idForStyleResolution().impl()))
- return 0;
-
- RenderStyle* parentStyle = p->renderStyle();
- unsigned subcount = 0;
- Node* thisCousin = p;
- Node* currentNode = p->previousSibling();
-
- // Reserve the tries for this level. This effectively makes sure that the algorithm
- // will never go deeper than cStyleSearchLevelThreshold levels into recursion.
- visitedNodeCount += cStyleSearchThreshold;
- while (thisCousin) {
- while (currentNode) {
- ++subcount;
- if (currentNode->renderStyle() == parentStyle && currentNode->lastChild()
- && currentNode->isElementNode() && !parentElementPreventsSharing(toElement(currentNode))
-#if ENABLE(SHADOW_DOM)
- && !toElement(currentNode)->authorShadowRoot()
-#endif
- ) {
- // Adjust for unused reserved tries.
- visitedNodeCount -= cStyleSearchThreshold - subcount;
- return currentNode->lastChild();
- }
- if (subcount >= cStyleSearchThreshold)
- return 0;
- currentNode = currentNode->previousSibling();
- }
- currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount);
- thisCousin = currentNode;
- }
-
- return 0;
-}
-
-bool StyleResolver::styleSharingCandidateMatchesRuleSet(RuleSet* ruleSet)
-{
- if (!ruleSet)
- return false;
-
- ElementRuleCollector collector(this, m_state);
- return collector.hasAnyMatchingRules(ruleSet);
-}
-
-bool StyleResolver::canShareStyleWithControl(StyledElement* element) const
+StyleResolver::State::State(const Element& element, const RenderStyle* parentStyle, const RenderStyle* documentElementStyle, const RenderRegion* regionForStyling, const SelectorFilter* selectorFilter)
+ : m_element(&element)
+ , m_parentStyle(parentStyle)
+ , m_regionForStyling(regionForStyling)
+ , m_elementLinkState(element.document().visitedLinkState().determineLinkState(element))
+ , m_selectorFilter(selectorFilter)
{
- const State& state = m_state;
- HTMLInputElement* thisInputElement = element->toInputElement();
- HTMLInputElement* otherInputElement = state.element()->toInputElement();
-
- if (!thisInputElement || !otherInputElement)
- return false;
-
- if (thisInputElement->elementData() != otherInputElement->elementData()) {
- if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->fastGetAttribute(typeAttr))
- return false;
- if (thisInputElement->fastGetAttribute(readonlyAttr) != otherInputElement->fastGetAttribute(readonlyAttr))
- return false;
- }
-
- if (thisInputElement->isAutofilled() != otherInputElement->isAutofilled())
- return false;
- if (thisInputElement->shouldAppearChecked() != otherInputElement->shouldAppearChecked())
- return false;
- if (thisInputElement->shouldAppearIndeterminate() != otherInputElement->shouldAppearIndeterminate())
- return false;
- if (thisInputElement->isRequired() != otherInputElement->isRequired())
- return false;
-
- if (element->isDisabledFormControl() != state.element()->isDisabledFormControl())
- return false;
+ bool resetStyleInheritance = hasShadowRootParent(element) && downcast<ShadowRoot>(element.parentNode())->resetStyleInheritance();
+ if (resetStyleInheritance)
+ m_parentStyle = nullptr;
- if (element->isDefaultButtonForForm() != state.element()->isDefaultButtonForForm())
- return false;
-
- if (state.document().containsValidityStyleRules()) {
- bool willValidate = element->willValidate();
-
- if (willValidate != state.element()->willValidate())
- return false;
-
- if (willValidate && (element->isValidFormControlElement() != state.element()->isValidFormControlElement()))
- return false;
-
- if (element->isInRange() != state.element()->isInRange())
- return false;
-
- if (element->isOutOfRange() != state.element()->isOutOfRange())
- return false;
- }
+ auto& document = element.document();
+ auto* documentElement = document.documentElement();
+ if (!documentElement || documentElement == &element)
+ m_rootElementStyle = document.renderStyle();
+ else
+ m_rootElementStyle = documentElementStyle ? documentElementStyle : documentElement->renderStyle();
- return true;
+ updateConversionData();
}
-static inline bool elementHasDirectionAuto(Element* element)
+inline void StyleResolver::State::updateConversionData()
{
- // FIXME: This line is surprisingly hot, we may wish to inline hasDirectionAuto into StyleResolver.
- return element->isHTMLElement() && toHTMLElement(element)->hasDirectionAuto();
+ m_cssToLengthConversionData = CSSToLengthConversionData(m_style.get(), m_rootElementStyle, m_element ? document().renderView() : nullptr);
}
-bool StyleResolver::sharingCandidateHasIdenticalStyleAffectingAttributes(StyledElement* sharingCandidate) const
+inline void StyleResolver::State::setStyle(std::unique_ptr<RenderStyle> style)
{
- const State& state = m_state;
- if (state.element()->elementData() == sharingCandidate->elementData())
- return true;
- if (state.element()->fastGetAttribute(XMLNames::langAttr) != sharingCandidate->fastGetAttribute(XMLNames::langAttr))
- return false;
- if (state.element()->fastGetAttribute(langAttr) != sharingCandidate->fastGetAttribute(langAttr))
- return false;
-
- if (!state.elementAffectedByClassRules()) {
- if (sharingCandidate->hasClass() && classNamesAffectedByRules(sharingCandidate->classNames()))
- return false;
- } else if (sharingCandidate->hasClass()) {
-#if ENABLE(SVG)
- // SVG elements require a (slow!) getAttribute comparision because "class" is an animatable attribute for SVG.
- if (state.element()->isSVGElement()) {
- if (state.element()->getAttribute(classAttr) != sharingCandidate->getAttribute(classAttr))
- return false;
- } else {
-#endif
- if (state.element()->classNames() != sharingCandidate->classNames())
- return false;
-#if ENABLE(SVG)
- }
-#endif
- } else
- return false;
-
- if (state.styledElement()->presentationAttributeStyle() != sharingCandidate->presentationAttributeStyle())
- return false;
-
-#if ENABLE(PROGRESS_ELEMENT)
- if (state.element()->hasTagName(progressTag)) {
- if (state.element()->shouldAppearIndeterminate() != sharingCandidate->shouldAppearIndeterminate())
- return false;
- }
-#endif
-
- return true;
+ m_style = WTFMove(style);
+ updateConversionData();
}
-bool StyleResolver::canShareStyleWithElement(StyledElement* element) const
+void StyleResolver::State::setParentStyle(std::unique_ptr<RenderStyle> parentStyle)
{
- RenderStyle* style = element->renderStyle();
- const State& state = m_state;
-
- if (!style)
- return false;
- if (style->unique())
- return false;
- if (style->hasUniquePseudoStyle())
- return false;
- if (element->tagQName() != state.element()->tagQName())
- return false;
- if (element->inlineStyle())
- return false;
- if (element->needsStyleRecalc())
- return false;
-#if ENABLE(SVG)
- if (element->isSVGElement() && toSVGElement(element)->animatedSMILStyleProperties())
- return false;
-#endif
- if (element->isLink() != state.element()->isLink())
- return false;
- if (element->hovered() != state.element()->hovered())
- return false;
- if (element->active() != state.element()->active())
- return false;
- if (element->focused() != state.element()->focused())
- return false;
- if (element->shadowPseudoId() != state.element()->shadowPseudoId())
- return false;
- if (element == element->document().cssTarget())
- return false;
- if (!sharingCandidateHasIdenticalStyleAffectingAttributes(element))
- return false;
- if (element->additionalPresentationAttributeStyle() != state.styledElement()->additionalPresentationAttributeStyle())
- return false;
-
- if (element->hasID() && m_ruleSets.features().idsInRules.contains(element->idForStyleResolution().impl()))
- return false;
-
- // FIXME: We should share style for option and optgroup whenever possible.
- // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
- // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
- if (isHTMLOptionElement(element) || isHTMLOptGroupElement(element))
- return false;
-
- bool isControl = element->isFormControlElement();
-
- if (isControl != state.element()->isFormControlElement())
- return false;
-
- if (isControl && !canShareStyleWithControl(element))
- return false;
-
- if (style->transitions() || style->animations())
- return false;
-
-#if USE(ACCELERATED_COMPOSITING)
- // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
- // See comments in RenderObject::setStyle().
- if (element->hasTagName(iframeTag) || element->hasTagName(frameTag) || element->hasTagName(embedTag) || element->hasTagName(objectTag) || element->hasTagName(appletTag) || element->hasTagName(canvasTag))
- return false;
-
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- // With proxying, the media elements are backed by a RenderEmbeddedObject.
- if ((element->hasTagName(videoTag) || element->hasTagName(audioTag)) && toHTMLMediaElement(element)->shouldUseVideoPluginProxy())
- return false;
-#endif
-
-#endif
-
- if (elementHasDirectionAuto(element))
- return false;
-
- if (element->isLink() && state.elementLinkState() != style->insideLink())
- return false;
-
-#if ENABLE(VIDEO_TRACK)
- // Deny sharing styles between WebVTT and non-WebVTT nodes.
- if (element->isWebVTTElement() != state.element()->isWebVTTElement())
- return false;
-
- if (element->isWebVTTElement() && state.element()->isWebVTTElement() && toWebVTTElement(element)->isPastNode() != toWebVTTElement(state.element())->isPastNode())
- return false;
-#endif
-
-#if ENABLE(FULLSCREEN_API)
- if (element == element->document().webkitCurrentFullScreenElement() || state.element() == state.document().webkitCurrentFullScreenElement())
- return false;
-#endif
- return true;
-}
-
-inline StyledElement* StyleResolver::findSiblingForStyleSharing(Node* node, unsigned& count) const
-{
- for (; node; node = node->previousSibling()) {
- if (!node->isStyledElement())
- continue;
- if (canShareStyleWithElement(toStyledElement(node)))
- break;
- if (count++ == cStyleSearchThreshold)
- return 0;
- }
- return toStyledElement(node);
-}
-
-RenderStyle* StyleResolver::locateSharedStyle()
-{
- State& state = m_state;
- if (!state.styledElement() || !state.parentStyle())
- return 0;
-
- // If the element has inline style it is probably unique.
- if (state.styledElement()->inlineStyle())
- return 0;
-#if ENABLE(SVG)
- if (state.styledElement()->isSVGElement() && toSVGElement(state.styledElement())->animatedSMILStyleProperties())
- return 0;
-#endif
- // Ids stop style sharing if they show up in the stylesheets.
- if (state.styledElement()->hasID() && m_ruleSets.features().idsInRules.contains(state.styledElement()->idForStyleResolution().impl()))
- return 0;
- if (parentElementPreventsSharing(state.element()->parentElement()))
- return 0;
- if (state.element() == state.document().cssTarget())
- return 0;
- if (elementHasDirectionAuto(state.element()))
- return 0;
-
- // Cache whether state.element is affected by any known class selectors.
- // FIXME: This shouldn't be a member variable. The style sharing code could be factored out of StyleResolver.
- state.setElementAffectedByClassRules(state.element() && state.element()->hasClass() && classNamesAffectedByRules(state.element()->classNames()));
-
- // Check previous siblings and their cousins.
- unsigned count = 0;
- unsigned visitedNodeCount = 0;
- StyledElement* shareElement = 0;
- Node* cousinList = state.styledElement()->previousSibling();
- while (cousinList) {
- shareElement = findSiblingForStyleSharing(cousinList, count);
- if (shareElement)
- break;
- cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount);
- }
-
- // If we have exhausted all our budget or our cousins.
- if (!shareElement)
- return 0;
-
- // Can't share if sibling rules apply. This is checked at the end as it should rarely fail.
- if (styleSharingCandidateMatchesRuleSet(m_ruleSets.sibling()))
- return 0;
- // Can't share if attribute rules apply.
- if (styleSharingCandidateMatchesRuleSet(m_ruleSets.uncommonAttribute()))
- return 0;
- // Can't share if @host @-rules apply.
- if (styleSharingCandidateMatchesHostRules())
- return 0;
- // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
- if (parentElementPreventsSharing(state.element()->parentElement()))
- return 0;
- return shareElement->renderStyle();
+ m_ownedParentStyle = WTFMove(parentStyle);
+ m_parentStyle = m_ownedParentStyle.get();
}
-static inline bool isAtShadowBoundary(const Element* element)
+static inline bool isAtShadowBoundary(const Element& element)
{
- if (!element)
- return false;
- ContainerNode* parentNode = element->parentNode();
+ auto* parentNode = element.parentNode();
return parentNode && parentNode->isShadowRoot();
}
-PassRef<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent,
- StyleSharingBehavior sharingBehavior, RuleMatchingBehavior matchingBehavior, RenderRegion* regionForStyling)
+ElementStyle StyleResolver::styleForElement(const Element& element, const RenderStyle* parentStyle, const RenderStyle* parentBoxStyle, RuleMatchingBehavior matchingBehavior, const RenderRegion* regionForStyling, const SelectorFilter* selectorFilter)
{
- // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
- // will vanish if a style recalc happens during loading.
- if (sharingBehavior == AllowStyleSharing && !element->document().haveStylesheetsLoaded() && !element->renderer()) {
- if (!s_styleNotYetAvailable) {
- s_styleNotYetAvailable = &RenderStyle::create().leakRef();
- s_styleNotYetAvailable->setDisplay(NONE);
- s_styleNotYetAvailable->font().update(m_fontSelector);
- }
- element->document().setHasNodesWithPlaceholderStyle();
- return *s_styleNotYetAvailable;
- }
+ RELEASE_ASSERT(!m_isDeleted);
+ m_state = State(element, parentStyle, m_overrideDocumentElementStyle, regionForStyling, selectorFilter);
State& state = m_state;
- initElement(element);
- state.initForStyleResolve(document(), element, defaultParent, regionForStyling);
- if (sharingBehavior == AllowStyleSharing) {
- if (RenderStyle* sharedStyle = locateSharedStyle()) {
- state.clear();
- return *sharedStyle;
- }
- }
if (state.parentStyle()) {
- state.setStyle(RenderStyle::create());
- state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
+ state.setStyle(RenderStyle::createPtr());
+ state.style()->inheritFrom(*state.parentStyle());
} else {
state.setStyle(defaultStyleForElement());
- state.setParentStyle(RenderStyle::clone(state.style()));
+ state.setParentStyle(RenderStyle::clonePtr(*state.style()));
}
- if (element->isLink()) {
- state.style()->setIsLink(true);
+ auto& style = *state.style();
+
+ if (element.isLink()) {
+ style.setIsLink(true);
EInsideLink linkState = state.elementLinkState();
if (linkState != NotInsideLink) {
- bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited);
+ bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassVisited);
if (forceVisited)
linkState = InsideVisitedLink;
}
- state.style()->setInsideLink(linkState);
+ style.setInsideLink(linkState);
}
- bool needsCollection = false;
- CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(element, needsCollection);
- if (needsCollection)
- m_ruleSets.collectFeatures(document().isViewSource(), m_scopeResolver.get());
+ CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(element);
- ElementRuleCollector collector(this, state);
+ ElementRuleCollector collector(element, m_ruleSets, m_state.selectorFilter());
collector.setRegionForStyling(regionForStyling);
- collector.setMedium(m_medium.get());
+ collector.setMedium(&m_mediaQueryEvaluator);
if (matchingBehavior == MatchOnlyUserAgentRules)
collector.matchUARules();
else
collector.matchAllRules(m_matchAuthorAndUserStyles, matchingBehavior != MatchAllRulesExcludingSMIL);
+ if (collector.matchedPseudoElementIds())
+ style.setHasPseudoStyles(collector.matchedPseudoElementIds());
+
+ // This is required for style sharing.
+ if (collector.didMatchUncommonAttributeSelector())
+ style.setUnique();
+
+ auto elementStyleRelations = Style::commitRelationsToRenderStyle(style, element, collector.styleRelations());
+
applyMatchedProperties(collector.matchedResult(), element);
// Clean up our style object's display and text decorations (among other fixups).
- adjustRenderStyle(*state.style(), *state.parentStyle(), element);
+ adjustRenderStyle(*state.style(), *state.parentStyle(), parentBoxStyle, &element);
- state.clear(); // Clear out for the next resolve.
+ if (state.style()->hasViewportUnits())
+ document().setHasStyleWithViewportUnits();
- document().didAccessStyleResolver();
+ state.clear(); // Clear out for the next resolve.
- // Now return the style.
- return state.takeStyle();
+ return { state.takeStyle(), WTFMove(elementStyleRelations) };
}
-PassRef<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementStyle, const StyleKeyframe* keyframe, KeyframeValue& keyframeValue)
+std::unique_ptr<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementStyle, const StyleRuleKeyframe* keyframe, KeyframeValue& keyframeValue)
{
+ RELEASE_ASSERT(!m_isDeleted);
+
MatchResult result;
result.addMatchedProperties(keyframe->properties());
@@ -876,8 +448,8 @@ PassRef<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementS
State& state = m_state;
// Create the style
- state.setStyle(RenderStyle::clone(elementStyle));
- state.setLineHeightValue(0);
+ state.setStyle(RenderStyle::clonePtr(*elementStyle));
+ state.setParentStyle(RenderStyle::clonePtr(*elementStyle));
TextDirection direction;
WritingMode writingMode;
@@ -886,50 +458,45 @@ PassRef<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementS
// We don't need to bother with !important. Since there is only ever one
// decl, there's nothing to override. So just add the first properties.
CascadedProperties cascade(direction, writingMode);
- cascade.addMatches(result, false, 0, result.matchedProperties.size() - 1);
+ cascade.addNormalMatches(result, 0, result.matchedProperties().size() - 1);
+
+ // Resolve custom properties first.
+ applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom, &result);
- applyCascadedProperties(cascade, firstCSSProperty, CSSPropertyLineHeight);
+ applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty, &result);
- // If our font got dirtied, go ahead and update it now.
+ // If our font got dirtied, update it now.
updateFont();
- // Line-height is set when we are sure we decided on the font-size
- if (state.lineHeightValue())
- applyProperty(CSSPropertyLineHeight, state.lineHeightValue());
-
// Now do rest of the properties.
- applyCascadedProperties(cascade, CSSPropertyBackground, lastCSSProperty);
+ applyCascadedProperties(cascade, firstLowPriorityProperty, lastCSSProperty, &result);
- // If our font got dirtied by one of the non-essential font props,
- // go ahead and update it a second time.
+ // If our font got dirtied by one of the non-essential font props, update it a second time.
updateFont();
- cascade.applyDeferredProperties(*this);
+ cascade.applyDeferredProperties(*this, &result);
+
+ adjustRenderStyle(*state.style(), *state.parentStyle(), nullptr, nullptr);
- // Start loading resources referenced by this style.
- loadPendingResources();
-
// Add all the animating properties to the keyframe.
unsigned propertyCount = keyframe->properties().propertyCount();
for (unsigned i = 0; i < propertyCount; ++i) {
CSSPropertyID property = keyframe->properties().propertyAt(i).id();
// Timing-function within keyframes is special, because it is not animated; it just
// describes the timing function between this keyframe and the next.
- if (property != CSSPropertyWebkitAnimationTimingFunction)
+ if (property != CSSPropertyAnimationTimingFunction)
keyframeValue.addProperty(property);
}
- document().didAccessStyleResolver();
-
return state.takeStyle();
}
-void StyleResolver::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list)
+void StyleResolver::keyframeStylesForAnimation(const Element& element, const RenderStyle* elementStyle, KeyframeList& list)
{
list.clear();
- // Get the keyframesRule for this name
- if (!e || list.animationName().isEmpty())
+ // Get the keyframesRule for this name.
+ if (list.animationName().isEmpty())
return;
m_keyframesRuleMap.checkConsistency();
@@ -940,80 +507,108 @@ void StyleResolver::keyframeStylesForAnimation(Element* e, const RenderStyle* el
const StyleRuleKeyframes* keyframesRule = it->value.get();
- // Construct and populate the style for each keyframe
- const Vector<RefPtr<StyleKeyframe>>& keyframes = keyframesRule->keyframes();
- for (unsigned i = 0; i < keyframes.size(); ++i) {
- // Apply the declaration to the style. This is a simplified version of the logic in styleForElement
- initElement(e);
- m_state.initForStyleResolve(document(), e);
+ auto* keyframes = &keyframesRule->keyframes();
+ Vector<Ref<StyleRuleKeyframe>> newKeyframesIfNecessary;
+
+ bool hasDuplicateKeys = false;
+ HashSet<double> keyframeKeys;
+ for (auto& keyframe : *keyframes) {
+ for (auto key : keyframe->keys()) {
+ if (!keyframeKeys.add(key)) {
+ hasDuplicateKeys = true;
+ break;
+ }
+ }
+ if (hasDuplicateKeys)
+ break;
+ }
+
+ // FIXME: If HashMaps could have Ref<> as value types, we wouldn't need
+ // to copy the HashMap into a Vector.
+ if (hasDuplicateKeys) {
+ // Merge duplicate key times.
+ HashMap<double, RefPtr<StyleRuleKeyframe>> keyframesMap;
+
+ for (auto& originalKeyframe : keyframesRule->keyframes()) {
+ for (auto key : originalKeyframe->keys()) {
+ if (auto keyframe = keyframesMap.get(key))
+ keyframe->mutableProperties().mergeAndOverrideOnConflict(originalKeyframe->properties());
+ else {
+ auto StyleRuleKeyframe = StyleRuleKeyframe::create(MutableStyleProperties::create());
+ StyleRuleKeyframe.ptr()->setKey(key);
+ StyleRuleKeyframe.ptr()->mutableProperties().mergeAndOverrideOnConflict(originalKeyframe->properties());
+ keyframesMap.set(key, StyleRuleKeyframe.ptr());
+ }
+ }
+ }
- const StyleKeyframe* keyframe = keyframes[i].get();
+ for (auto& keyframe : keyframesMap.values())
+ newKeyframesIfNecessary.append(*keyframe.get());
- KeyframeValue keyframeValue(0, 0);
- keyframeValue.setStyle(styleForKeyframe(elementStyle, keyframe, keyframeValue));
+ keyframes = &newKeyframesIfNecessary;
+ }
+
+ // Construct and populate the style for each keyframe.
+ for (auto& keyframe : *keyframes) {
+ // Apply the declaration to the style. This is a simplified version of the logic in styleForElement.
+ m_state = State(element, nullptr);
// Add this keyframe style to all the indicated key times
- Vector<double> keys;
- keyframe->getKeys(keys);
- for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) {
- keyframeValue.setKey(keys[keyIndex]);
- list.insert(keyframeValue);
+ for (auto key : keyframe->keys()) {
+ KeyframeValue keyframeValue(0, nullptr);
+ keyframeValue.setStyle(styleForKeyframe(elementStyle, keyframe.ptr(), keyframeValue));
+ keyframeValue.setKey(key);
+ list.insert(WTFMove(keyframeValue));
}
}
- // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe)
+ // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe).
int initialListSize = list.size();
if (initialListSize > 0 && list[0].key()) {
- static StyleKeyframe* zeroPercentKeyframe;
+ static StyleRuleKeyframe* zeroPercentKeyframe;
if (!zeroPercentKeyframe) {
- zeroPercentKeyframe = StyleKeyframe::create(MutableStyleProperties::create()).leakRef();
- zeroPercentKeyframe->setKeyText("0%");
+ zeroPercentKeyframe = &StyleRuleKeyframe::create(MutableStyleProperties::create()).leakRef();
+ zeroPercentKeyframe->setKey(0);
}
- KeyframeValue keyframeValue(0, 0);
+ KeyframeValue keyframeValue(0, nullptr);
keyframeValue.setStyle(styleForKeyframe(elementStyle, zeroPercentKeyframe, keyframeValue));
- list.insert(keyframeValue);
+ list.insert(WTFMove(keyframeValue));
}
- // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe)
+ // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe).
if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) {
- static StyleKeyframe* hundredPercentKeyframe;
+ static StyleRuleKeyframe* hundredPercentKeyframe;
if (!hundredPercentKeyframe) {
- hundredPercentKeyframe = StyleKeyframe::create(MutableStyleProperties::create()).leakRef();
- hundredPercentKeyframe->setKeyText("100%");
+ hundredPercentKeyframe = &StyleRuleKeyframe::create(MutableStyleProperties::create()).leakRef();
+ hundredPercentKeyframe->setKey(1);
}
- KeyframeValue keyframeValue(1, 0);
+ KeyframeValue keyframeValue(1, nullptr);
keyframeValue.setStyle(styleForKeyframe(elementStyle, hundredPercentKeyframe, keyframeValue));
- list.insert(keyframeValue);
+ list.insert(WTFMove(keyframeValue));
}
}
-PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* e, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle)
+std::unique_ptr<RenderStyle> StyleResolver::pseudoStyleForElement(const Element& element, const PseudoStyleRequest& pseudoStyleRequest, const RenderStyle& parentStyle)
{
- ASSERT(parentStyle);
- if (!e)
- return 0;
+ m_state = State(element, &parentStyle);
State& state = m_state;
- initElement(e);
-
- state.initForStyleResolve(document(), e, parentStyle);
-
if (m_state.parentStyle()) {
- state.setStyle(RenderStyle::create());
- state.style()->inheritFrom(m_state.parentStyle());
+ state.setStyle(RenderStyle::createPtr());
+ state.style()->inheritFrom(*m_state.parentStyle());
} else {
state.setStyle(defaultStyleForElement());
- state.setParentStyle(RenderStyle::clone(state.style()));
+ state.setParentStyle(RenderStyle::clonePtr(*state.style()));
}
// Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
// those rules.
// Check UA, user and author rules.
- ElementRuleCollector collector(this, state);
+ ElementRuleCollector collector(element, m_ruleSets, m_state.selectorFilter());
collector.setPseudoStyleRequest(pseudoStyleRequest);
- collector.setMedium(m_medium.get());
+ collector.setMedium(&m_mediaQueryEvaluator);
collector.matchUARules();
if (m_matchAuthorAndUserStyles) {
@@ -1021,35 +616,40 @@ PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* e, const P
collector.matchAuthorRules(false);
}
- if (collector.matchedResult().matchedProperties.isEmpty())
- return 0;
+ ASSERT(!collector.matchedPseudoElementIds());
+
+ if (collector.matchedResult().matchedProperties().isEmpty())
+ return nullptr;
state.style()->setStyleType(pseudoStyleRequest.pseudoId);
- applyMatchedProperties(collector.matchedResult(), e);
+ applyMatchedProperties(collector.matchedResult(), element);
// Clean up our style object's display and text decorations (among other fixups).
- adjustRenderStyle(*state.style(), *m_state.parentStyle(), 0);
-
- // Start loading resources referenced by this style.
- loadPendingResources();
+ adjustRenderStyle(*state.style(), *m_state.parentStyle(), nullptr, nullptr);
- document().didAccessStyleResolver();
+ if (state.style()->hasViewportUnits())
+ document().setHasStyleWithViewportUnits();
// Now return the style.
return state.takeStyle();
}
-PassRef<RenderStyle> StyleResolver::styleForPage(int pageIndex)
+std::unique_ptr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
{
- m_state.initForStyleResolve(document(), document().documentElement()); // m_rootElementStyle will be set to the document style.
+ RELEASE_ASSERT(!m_isDeleted);
- m_state.setStyle(RenderStyle::create());
- m_state.style()->inheritFrom(m_state.rootElementStyle());
+ auto* documentElement = m_document.documentElement();
+ if (!documentElement)
+ return RenderStyle::createPtr();
+
+ m_state = State(*documentElement, m_document.renderStyle());
+
+ m_state.setStyle(RenderStyle::createPtr());
+ m_state.style()->inheritFrom(*m_state.rootElementStyle());
PageRuleCollector collector(m_state, m_ruleSets);
collector.matchAllPageRules(pageIndex);
- m_state.setLineHeightValue(0);
MatchResult& result = collector.matchedResult();
@@ -1058,78 +658,69 @@ PassRef<RenderStyle> StyleResolver::styleForPage(int pageIndex)
extractDirectionAndWritingMode(*m_state.style(), result, direction, writingMode);
CascadedProperties cascade(direction, writingMode);
- cascade.addMatches(result, false, 0, result.matchedProperties.size() - 1);
-
- applyCascadedProperties(cascade, firstCSSProperty, CSSPropertyLineHeight);
+ cascade.addNormalMatches(result, 0, result.matchedProperties().size() - 1);
- // If our font got dirtied, go ahead and update it now.
- updateFont();
-
- // Line-height is set when we are sure we decided on the font-size.
- if (m_state.lineHeightValue())
- applyProperty(CSSPropertyLineHeight, m_state.lineHeightValue());
+ // Resolve custom properties first.
+ applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom, &result);
- applyCascadedProperties(cascade, CSSPropertyBackground, lastCSSProperty);
+ applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty, &result);
- cascade.applyDeferredProperties(*this);
+ // If our font got dirtied, update it now.
+ updateFont();
- // Start loading resources referenced by this style.
- loadPendingResources();
+ applyCascadedProperties(cascade, firstLowPriorityProperty, lastCSSProperty, &result);
- document().didAccessStyleResolver();
+ cascade.applyDeferredProperties(*this, &result);
// Now return the style.
return m_state.takeStyle();
}
-PassRef<RenderStyle> StyleResolver::defaultStyleForElement()
+std::unique_ptr<RenderStyle> StyleResolver::defaultStyleForElement()
{
- m_state.setStyle(RenderStyle::create());
+ m_state.setStyle(RenderStyle::createPtr());
// Make sure our fonts are initialized if we don't inherit them from our parent style.
- if (Settings* settings = documentSettings()) {
- initializeFontStyle(settings);
- m_state.style()->font().update(fontSelector());
- } else
- m_state.style()->font().update(0);
-
+ initializeFontStyle();
+ m_state.style()->fontCascade().update(&document().fontSelector());
return m_state.takeStyle();
}
static void addIntrinsicMargins(RenderStyle& style)
{
// Intrinsic margin value.
- const int intrinsicMargin = 2 * style.effectiveZoom();
+ const int intrinsicMargin = clampToInteger(2 * style.effectiveZoom());
// FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
- // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame.
+ // FIXME: Using "hasQuirk" to decide the margin wasn't set is kind of lame.
if (style.width().isIntrinsicOrAuto()) {
- if (style.marginLeft().quirk())
+ if (style.marginLeft().hasQuirk())
style.setMarginLeft(Length(intrinsicMargin, Fixed));
- if (style.marginRight().quirk())
+ if (style.marginRight().hasQuirk())
style.setMarginRight(Length(intrinsicMargin, Fixed));
}
if (style.height().isAuto()) {
- if (style.marginTop().quirk())
+ if (style.marginTop().hasQuirk())
style.setMarginTop(Length(intrinsicMargin, Fixed));
- if (style.marginBottom().quirk())
+ if (style.marginBottom().hasQuirk())
style.setMarginBottom(Length(intrinsicMargin, Fixed));
}
}
-static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool strictParsing)
+static EDisplay equivalentBlockDisplay(const RenderStyle& style, const Document& document)
{
- switch (display) {
+ switch (auto display = style.display()) {
case BLOCK:
case TABLE:
case BOX:
case FLEX:
+ case WEBKIT_FLEX:
case GRID:
return display;
case LIST_ITEM:
// It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, but only in quirks mode.
- if (!strictParsing && isFloating)
+ if (document.inQuirksMode() && style.isFloating())
return BLOCK;
return display;
case INLINE_TABLE:
@@ -1137,12 +728,12 @@ static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool s
case INLINE_BOX:
return BOX;
case INLINE_FLEX:
+ case WEBKIT_INLINE_FLEX:
return FLEX;
case INLINE_GRID:
return GRID;
case INLINE:
- case RUN_IN:
case COMPACT:
case INLINE_BLOCK:
case TABLE_ROW_GROUP:
@@ -1154,6 +745,9 @@ static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool s
case TABLE_CELL:
case TABLE_CAPTION:
return BLOCK;
+ case CONTENTS:
+ ASSERT_NOT_REACHED();
+ return CONTENTS;
case NONE:
ASSERT_NOT_REACHED();
return NONE;
@@ -1163,20 +757,15 @@ static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool s
}
// CSS requires text-decoration to be reset at each DOM element for tables,
-// inline blocks, inline tables, run-ins, shadow DOM crossings, floating elements,
+// inline blocks, inline tables, shadow DOM crossings, floating elements,
// and absolute or relatively positioned elements.
-static bool doesNotInheritTextDecoration(const RenderStyle& style, Element* e)
+static bool doesNotInheritTextDecoration(const RenderStyle& style, const Element* element)
{
- return style.display() == TABLE || style.display() == INLINE_TABLE || style.display() == RUN_IN
- || style.display() == INLINE_BLOCK || style.display() == INLINE_BOX || isAtShadowBoundary(e)
+ return style.display() == TABLE || style.display() == INLINE_TABLE
+ || style.display() == INLINE_BLOCK || style.display() == INLINE_BOX || (element && isAtShadowBoundary(*element))
|| style.isFloating() || style.hasOutOfFlowPosition();
}
-static bool isDisplayFlexibleBox(EDisplay display)
-{
- return display == FLEX || display == INLINE_FLEX;
-}
-
#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
static bool isScrollableOverflow(EOverflow overflow)
{
@@ -1184,64 +773,90 @@ static bool isScrollableOverflow(EOverflow overflow)
}
#endif
-void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& parentStyle, Element *e)
+void StyleResolver::adjustStyleForInterCharacterRuby()
+{
+ RenderStyle* style = m_state.style();
+ if (style->rubyPosition() != RubyPositionInterCharacter || !m_state.element() || !m_state.element()->hasTagName(rtTag))
+ return;
+ style->setTextAlign(CENTER);
+ if (style->isHorizontalWritingMode())
+ style->setWritingMode(LeftToRightWritingMode);
+}
+
+void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& parentStyle, const RenderStyle* parentBoxStyle, const Element* element)
{
+ // If the composed tree parent has display:contents, the parent box style will be different from the parent style.
+ // We don't have it when resolving computed style for display:none subtree. Use parent style for adjustments in that case.
+ if (!parentBoxStyle)
+ parentBoxStyle = &parentStyle;
+
// Cache our original display.
style.setOriginalDisplay(style.display());
- if (style.display() != NONE) {
- // If we have a <td> that specifies a float property, in quirks mode we just drop the float
- // property.
- // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
- // these tags to retain their display types.
- if (document().inQuirksMode() && e) {
- if (e->hasTagName(tdTag)) {
- style.setDisplay(TABLE_CELL);
- style.setFloating(NoFloat);
- } else if (isHTMLTableElement(e))
- style.setDisplay(style.isDisplayInlineType() ? INLINE_TABLE : TABLE);
- }
+ if (style.display() == CONTENTS) {
+ // FIXME: Enable for all elements.
+ bool elementSupportsDisplayContents = is<HTMLSlotElement>(element);
+ if (!elementSupportsDisplayContents)
+ style.setDisplay(INLINE);
+ }
+
+ if (style.display() != NONE && style.display() != CONTENTS) {
+ if (element) {
+ // If we have a <td> that specifies a float property, in quirks mode we just drop the float
+ // property.
+ // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
+ // these tags to retain their display types.
+ if (document().inQuirksMode()) {
+ if (element->hasTagName(tdTag)) {
+ style.setDisplay(TABLE_CELL);
+ style.setFloating(NoFloat);
+ } else if (is<HTMLTableElement>(*element))
+ style.setDisplay(style.isDisplayInlineType() ? INLINE_TABLE : TABLE);
+ }
- if (e && (e->hasTagName(tdTag) || e->hasTagName(thTag))) {
- if (style.whiteSpace() == KHTML_NOWRAP) {
- // Figure out if we are really nowrapping or if we should just
- // use normal instead. If the width of the cell is fixed, then
- // we don't actually use NOWRAP.
- if (style.width().isFixed())
- style.setWhiteSpace(NORMAL);
- else
- style.setWhiteSpace(NOWRAP);
+ if (element->hasTagName(tdTag) || element->hasTagName(thTag)) {
+ if (style.whiteSpace() == KHTML_NOWRAP) {
+ // Figure out if we are really nowrapping or if we should just
+ // use normal instead. If the width of the cell is fixed, then
+ // we don't actually use NOWRAP.
+ if (style.width().isFixed())
+ style.setWhiteSpace(NORMAL);
+ else
+ style.setWhiteSpace(NOWRAP);
+ }
}
- }
- // Tables never support the -webkit-* values for text-align and will reset back to the default.
- if (e && isHTMLTableElement(e) && (style.textAlign() == WEBKIT_LEFT || style.textAlign() == WEBKIT_CENTER || style.textAlign() == WEBKIT_RIGHT))
- style.setTextAlign(TASTART);
+ // Tables never support the -webkit-* values for text-align and will reset back to the default.
+ if (is<HTMLTableElement>(*element) && (style.textAlign() == WEBKIT_LEFT || style.textAlign() == WEBKIT_CENTER || style.textAlign() == WEBKIT_RIGHT))
+ style.setTextAlign(TASTART);
- // Frames and framesets never honor position:relative or position:absolute. This is necessary to
- // fix a crash where a site tries to position these objects. They also never honor display.
- if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) {
- style.setPosition(StaticPosition);
- style.setDisplay(BLOCK);
- }
+ // Frames and framesets never honor position:relative or position:absolute. This is necessary to
+ // fix a crash where a site tries to position these objects. They also never honor display.
+ if (element->hasTagName(frameTag) || element->hasTagName(framesetTag)) {
+ style.setPosition(StaticPosition);
+ style.setDisplay(BLOCK);
+ }
- // Ruby text does not support float or position. This might change with evolution of the specification.
- if (e && e->hasTagName(rtTag)) {
- style.setPosition(StaticPosition);
- style.setFloating(NoFloat);
- }
+ // Ruby text does not support float or position. This might change with evolution of the specification.
+ if (element->hasTagName(rtTag)) {
+ style.setPosition(StaticPosition);
+ style.setFloating(NoFloat);
+ }
- // FIXME: We shouldn't be overriding start/-webkit-auto like this. Do it in html.css instead.
- // Table headers with a text-align of -webkit-auto will change the text-align to center.
- if (e && e->hasTagName(thTag) && style.textAlign() == TASTART)
- style.setTextAlign(CENTER);
+ // User agents are expected to have a rule in their user agent stylesheet that matches th elements that have a parent
+ // node whose computed value for the 'text-align' property is its initial value, whose declaration block consists of
+ // just a single declaration that sets the 'text-align' property to the value 'center'.
+ // https://html.spec.whatwg.org/multipage/rendering.html#rendering
+ if (element->hasTagName(thTag) && !style.hasExplicitlySetTextAlign() && parentStyle.textAlign() == RenderStyle::initialTextAlign())
+ style.setTextAlign(CENTER);
- if (e && e->hasTagName(legendTag))
- style.setDisplay(BLOCK);
+ if (element->hasTagName(legendTag))
+ style.setDisplay(BLOCK);
+ }
// Absolute/fixed positioned elements, floating elements and the document element need block-like outside display.
- if (style.hasOutOfFlowPosition() || style.isFloating() || (e && e->document().documentElement() == e))
- style.setDisplay(equivalentBlockDisplay(style.display(), style.isFloating(), !document().inQuirksMode()));
+ if (style.hasOutOfFlowPosition() || style.isFloating() || (element && element->document().documentElement() == element))
+ style.setDisplay(equivalentBlockDisplay(style, document()));
// FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely
// clear how that should work.
@@ -1269,50 +884,66 @@ void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& par
if (style.writingMode() != TopToBottomWritingMode && (style.display() == BOX || style.display() == INLINE_BOX))
style.setWritingMode(TopToBottomWritingMode);
- if (isDisplayFlexibleBox(parentStyle.display())) {
+ // https://www.w3.org/TR/css-display/#transformations
+ // "A parent with a grid or flex display value blockifies the box’s display type."
+ if (parentBoxStyle->isDisplayFlexibleOrGridBox()) {
style.setFloating(NoFloat);
- style.setDisplay(equivalentBlockDisplay(style.display(), style.isFloating(), !document().inQuirksMode()));
+ style.setDisplay(equivalentBlockDisplay(style, document()));
}
}
// Make sure our z-index value is only applied if the object is positioned.
- if (style.position() == StaticPosition && !isDisplayFlexibleBox(parentStyle.display()))
+ if (style.position() == StaticPosition && !parentBoxStyle->isDisplayFlexibleOrGridBox())
style.setHasAutoZIndex();
// Auto z-index becomes 0 for the root element and transparent objects. This prevents
// cases where objects that should be blended as a single unit end up with a non-transparent
// object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections.
- if (style.hasAutoZIndex() && ((e && e->document().documentElement() == e)
- || style.opacity() < 1.0f
- || style.hasTransformRelatedProperty()
- || style.hasMask()
- || style.clipPath()
- || style.boxReflect()
- || style.hasFilter()
- || style.hasBlendMode()
- || style.position() == StickyPosition
- || (style.position() == FixedPosition && e && e->document().page() && e->document().page()->settings().fixedPositionCreatesStackingContext())
- || style.hasFlowFrom()
- ))
- style.setZIndex(0);
+ if (style.hasAutoZIndex()) {
+ if ((element && element->document().documentElement() == element)
+ || style.opacity() < 1.0f
+ || style.hasTransformRelatedProperty()
+ || style.hasMask()
+ || style.clipPath()
+ || style.boxReflect()
+ || style.hasFilter()
+#if ENABLE(FILTERS_LEVEL_2)
+ || style.hasBackdropFilter()
+#endif
+ || style.hasBlendMode()
+ || style.hasIsolation()
+ || style.position() == StickyPosition
+ || (style.position() == FixedPosition && settings().fixedPositionCreatesStackingContext())
+ || style.hasFlowFrom()
+ || style.willChangeCreatesStackingContext())
+ style.setZIndex(0);
+ }
+
+ if (element) {
+ // Textarea considers overflow visible as auto.
+ if (is<HTMLTextAreaElement>(*element)) {
+ style.setOverflowX(style.overflowX() == OVISIBLE ? OAUTO : style.overflowX());
+ style.setOverflowY(style.overflowY() == OVISIBLE ? OAUTO : style.overflowY());
+ }
- // Textarea considers overflow visible as auto.
- if (e && isHTMLTextAreaElement(e)) {
- style.setOverflowX(style.overflowX() == OVISIBLE ? OAUTO : style.overflowX());
- style.setOverflowY(style.overflowY() == OVISIBLE ? OAUTO : style.overflowY());
+ // Disallow -webkit-user-modify on :pseudo and ::pseudo elements.
+ if (!element->shadowPseudoId().isNull())
+ style.setUserModify(READ_ONLY);
+
+ // For now, <marquee> requires an overflow clip to work properly.
+ if (is<HTMLMarqueeElement>(*element)) {
+ style.setOverflowX(OHIDDEN);
+ style.setOverflowY(OHIDDEN);
+ }
}
- if (doesNotInheritTextDecoration(style, e))
+ if (doesNotInheritTextDecoration(style, element))
style.setTextDecorationsInEffect(style.textDecoration());
else
style.addToTextDecorationsInEffect(style.textDecoration());
// If either overflow value is not visible, change to auto.
- if (style.overflowX() == OMARQUEE && style.overflowY() != OMARQUEE)
- style.setOverflowY(OMARQUEE);
- else if (style.overflowY() == OMARQUEE && style.overflowX() != OMARQUEE)
- style.setOverflowX(OMARQUEE);
- else if (style.overflowX() == OVISIBLE && style.overflowY() != OVISIBLE) {
+ if (style.overflowX() == OVISIBLE && style.overflowY() != OVISIBLE) {
// FIXME: Once we implement pagination controls, overflow-x should default to hidden
// if overflow-y is set to -webkit-paged-x or -webkit-page-y. For now, we'll let it
// default to auto so we can at least scroll through the pages.
@@ -1323,7 +954,7 @@ void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& par
// Call setStylesForPaginationMode() if a pagination mode is set for any non-root elements. If these
// styles are specified on a root element, then they will be incorporated in
// Style::createForDocument().
- if ((style.overflowY() == OPAGEDX || style.overflowY() == OPAGEDY) && !(e && (e->hasTagName(htmlTag) || e->hasTagName(bodyTag))))
+ if ((style.overflowY() == OPAGEDX || style.overflowY() == OPAGEDY) && !(element && (element->hasTagName(htmlTag) || element->hasTagName(bodyTag))))
style.setColumnStylesFromPaginationMode(WebCore::paginationModeForRenderStyle(style));
// Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
@@ -1358,16 +989,16 @@ void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& par
// Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will
// alter fonts and heights/widths.
- if (e && e->isFormControlElement() && style.fontSize() >= 11) {
+ if (is<HTMLFormControlElement>(element) && style.fontSize() >= 11) {
// Don't apply intrinsic margins to image buttons. The designer knows how big the images are,
// so we have to treat all image buttons as though they were explicitly sized.
- if (!isHTMLInputElement(e) || !toHTMLInputElement(e)->isImageButton())
+ if (!is<HTMLInputElement>(*element) || !downcast<HTMLInputElement>(*element).isImageButton())
addIntrinsicMargins(style);
}
// Let the theme also have a crack at adjusting the style.
if (style.hasAppearance())
- RenderTheme::defaultTheme()->adjustStyle(*this, style, e, m_state.hasUAAppearance(), m_state.borderData(), m_state.backgroundData(), m_state.backgroundColor());
+ RenderTheme::defaultTheme()->adjustStyle(*this, style, element, m_state.hasUAAppearance(), m_state.borderData(), m_state.backgroundData(), m_state.backgroundColor());
// If we have first-letter pseudo style, do not share this style.
if (style.hasPseudoStyle(FIRST_LETTER))
@@ -1376,84 +1007,37 @@ void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& par
// FIXME: when dropping the -webkit prefix on transform-style, we should also have opacity < 1 cause flattening.
if (style.preserves3D() && (style.overflowX() != OVISIBLE
|| style.overflowY() != OVISIBLE
- || style.hasFilter()))
+ || style.hasClip()
+ || style.clipPath()
+ || style.hasFilter()
+#if ENABLE(FILTERS_LEVEL_2)
+ || style.hasBackdropFilter()
+#endif
+ || style.hasBlendMode()))
style.setTransformStyle3D(TransformStyle3DFlat);
- // Seamless iframes behave like blocks. Map their display to inline-block when marked inline.
- if (e && e->hasTagName(iframeTag) && style.display() == INLINE && toHTMLIFrameElement(e)->shouldDisplaySeamlessly())
- style.setDisplay(INLINE_BLOCK);
-
- adjustGridItemPosition(style, parentStyle);
-
-#if ENABLE(SVG)
- if (e && e->isSVGElement()) {
- // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty
- if (style.overflowY() == OSCROLL)
- style.setOverflowY(OHIDDEN);
- else if (style.overflowY() == OAUTO)
- style.setOverflowY(OVISIBLE);
-
- if (style.overflowX() == OSCROLL)
- style.setOverflowX(OHIDDEN);
- else if (style.overflowX() == OAUTO)
- style.setOverflowX(OVISIBLE);
-
+ if (is<SVGElement>(element)) {
// Only the root <svg> element in an SVG document fragment tree honors css position
- if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement()))
+ if (!(element->hasTagName(SVGNames::svgTag) && element->parentNode() && !element->parentNode()->isSVGElement()))
style.setPosition(RenderStyle::initialPosition());
// RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should
// not be scaled again.
- if (e->hasTagName(SVGNames::foreignObjectTag))
+ if (element->hasTagName(SVGNames::foreignObjectTag))
style.setEffectiveZoom(RenderStyle::initialZoom());
// SVG text layout code expects us to be a block-level style element.
- if ((e->hasTagName(SVGNames::foreignObjectTag) || e->hasTagName(SVGNames::textTag)) && style.isDisplayInlineType())
+ if ((element->hasTagName(SVGNames::foreignObjectTag) || element->hasTagName(SVGNames::textTag)) && style.isDisplayInlineType())
style.setDisplay(BLOCK);
}
-#endif
-}
-
-void StyleResolver::adjustGridItemPosition(RenderStyle& style, const RenderStyle& parentStyle) const
-{
- const GridPosition& columnStartPosition = style.gridItemColumnStart();
- const GridPosition& columnEndPosition = style.gridItemColumnEnd();
- const GridPosition& rowStartPosition = style.gridItemRowStart();
- const GridPosition& rowEndPosition = style.gridItemRowEnd();
-
- // If opposing grid-placement properties both specify a grid span, they both compute to ‘auto’.
- if (columnStartPosition.isSpan() && columnEndPosition.isSpan()) {
- style.setGridItemColumnStart(GridPosition());
- style.setGridItemColumnEnd(GridPosition());
- }
-
- if (rowStartPosition.isSpan() && rowEndPosition.isSpan()) {
- style.setGridItemRowStart(GridPosition());
- style.setGridItemRowEnd(GridPosition());
- }
-
- // Unknown named grid area compute to 'auto'.
- const NamedGridAreaMap& map = parentStyle.namedGridArea();
-
-#define CLEAR_UNKNOWN_NAMED_AREA(prop, Prop) \
- if (prop.isNamedGridArea() && !map.contains(prop.namedGridLine())) \
- style.setGridItem##Prop(GridPosition());
-
- CLEAR_UNKNOWN_NAMED_AREA(columnStartPosition, ColumnStart);
- CLEAR_UNKNOWN_NAMED_AREA(columnEndPosition, ColumnEnd);
- CLEAR_UNKNOWN_NAMED_AREA(rowStartPosition, RowStart);
- CLEAR_UNKNOWN_NAMED_AREA(rowEndPosition, RowEnd);
}
-bool StyleResolver::checkRegionStyle(Element* regionElement)
+bool StyleResolver::checkRegionStyle(const Element* regionElement)
{
- // FIXME (BUG 72472): We don't add @-webkit-region rules of scoped style sheets for the moment,
- // so all region rules are global by default. Verify whether that can stand or needs changing.
-
- unsigned rulesSize = m_ruleSets.authorStyle()->regionSelectorsAndRuleSets().size();
+ unsigned rulesSize = m_ruleSets.authorStyle().regionSelectorsAndRuleSets().size();
for (unsigned i = 0; i < rulesSize; ++i) {
- ASSERT(m_ruleSets.authorStyle()->regionSelectorsAndRuleSets().at(i).ruleSet.get());
- if (checkRegionSelector(m_ruleSets.authorStyle()->regionSelectorsAndRuleSets().at(i).selector, regionElement))
+ ASSERT(m_ruleSets.authorStyle().regionSelectorsAndRuleSets().at(i).ruleSet.get());
+ if (checkRegionSelector(m_ruleSets.authorStyle().regionSelectorsAndRuleSets().at(i).selector, regionElement))
return true;
}
@@ -1473,13 +1057,13 @@ static void checkForOrientationChange(RenderStyle* style)
{
FontOrientation fontOrientation;
NonCJKGlyphOrientation glyphOrientation;
- style->getFontAndGlyphOrientation(fontOrientation, glyphOrientation);
+ std::tie(fontOrientation, glyphOrientation) = style->fontAndGlyphOrientation();
- const FontDescription& fontDescription = style->fontDescription();
+ const auto& fontDescription = style->fontDescription();
if (fontDescription.orientation() == fontOrientation && fontDescription.nonCJKGlyphOrientation() == glyphOrientation)
return;
- FontDescription newFontDescription(fontDescription);
+ auto newFontDescription = fontDescription;
newFontDescription.setNonCJKGlyphOrientation(glyphOrientation);
newFontDescription.setOrientation(fontOrientation);
style->setFontDescription(newFontDescription);
@@ -1491,33 +1075,34 @@ void StyleResolver::updateFont()
return;
RenderStyle* style = m_state.style();
-#if ENABLE(IOS_TEXT_AUTOSIZING)
+#if ENABLE(TEXT_AUTOSIZING)
checkForTextSizeAdjust(style);
#endif
checkForGenericFamilyChange(style, m_state.parentStyle());
checkForZoomChange(style, m_state.parentStyle());
checkForOrientationChange(style);
- style->font().update(m_fontSelector);
+ style->fontCascade().update(&document().fontSelector());
+ if (m_state.fontSizeHasViewportUnits())
+ style->setHasViewportUnits(true);
m_state.setFontDirty(false);
}
-Vector<RefPtr<StyleRuleBase>> StyleResolver::styleRulesForElement(Element* e, unsigned rulesToInclude)
+Vector<RefPtr<StyleRule>> StyleResolver::styleRulesForElement(const Element* element, unsigned rulesToInclude)
{
- return pseudoStyleRulesForElement(e, NOPSEUDO, rulesToInclude);
+ return pseudoStyleRulesForElement(element, NOPSEUDO, rulesToInclude);
}
-Vector<RefPtr<StyleRuleBase>> StyleResolver::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, unsigned rulesToInclude)
+Vector<RefPtr<StyleRule>> StyleResolver::pseudoStyleRulesForElement(const Element* element, PseudoId pseudoId, unsigned rulesToInclude)
{
- if (!e || !e->document().haveStylesheetsLoaded())
- return Vector<RefPtr<StyleRuleBase>>();
+ if (!element || !element->document().haveStylesheetsLoaded())
+ return Vector<RefPtr<StyleRule>>();
- initElement(e);
- m_state.initForStyleResolve(document(), e, 0);
+ m_state = State(*element, nullptr);
- ElementRuleCollector collector(this, m_state);
- collector.setMode(SelectorChecker::CollectingRules);
+ ElementRuleCollector collector(*element, m_ruleSets, m_state.selectorFilter());
+ collector.setMode(SelectorChecker::Mode::CollectingRules);
collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
- collector.setMedium(m_medium.get());
+ collector.setMedium(&m_mediaQueryEvaluator);
if (rulesToInclude & UAAndUserCSSRules) {
// First we match rules from the user agent sheet.
@@ -1538,22 +1123,15 @@ Vector<RefPtr<StyleRuleBase>> StyleResolver::pseudoStyleRulesForElement(Element*
return collector.matchedRuleList();
}
-// -------------------------------------------------------------------------------------
-// this is mostly boring stuff on how to apply a certain rule to the renderstyle...
-
-Length StyleResolver::convertToIntLength(const CSSPrimitiveValue* primitiveValue, const RenderStyle* style, const RenderStyle* rootStyle, double multiplier)
-{
- return primitiveValue ? primitiveValue->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined);
-}
-
-Length StyleResolver::convertToFloatLength(const CSSPrimitiveValue* primitiveValue, const RenderStyle* style, const RenderStyle* rootStyle, double multiplier)
-{
- return primitiveValue ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined);
-}
-
static bool shouldApplyPropertyInParseOrder(CSSPropertyID propertyID)
{
switch (propertyID) {
+ case CSSPropertyWebkitBackgroundClip:
+ case CSSPropertyBackgroundClip:
+ case CSSPropertyWebkitBackgroundOrigin:
+ case CSSPropertyBackgroundOrigin:
+ case CSSPropertyWebkitBackgroundSize:
+ case CSSPropertyBackgroundSize:
case CSSPropertyWebkitBorderImage:
case CSSPropertyBorderImage:
case CSSPropertyBorderImageSlice:
@@ -1561,6 +1139,8 @@ static bool shouldApplyPropertyInParseOrder(CSSPropertyID propertyID)
case CSSPropertyBorderImageOutset:
case CSSPropertyBorderImageRepeat:
case CSSPropertyBorderImageWidth:
+ case CSSPropertyWebkitBoxShadow:
+ case CSSPropertyBoxShadow:
case CSSPropertyWebkitTextDecoration:
case CSSPropertyWebkitTextDecorationLine:
case CSSPropertyWebkitTextDecorationStyle:
@@ -1583,8 +1163,7 @@ static bool elementTypeHasAppearanceFromUAStyle(const Element& element)
|| localName == HTMLNames::buttonTag
|| localName == HTMLNames::progressTag
|| localName == HTMLNames::selectTag
- || localName == HTMLNames::meterTag
- || localName == HTMLNames::isindexTag;
+ || localName == HTMLNames::meterTag;
}
unsigned StyleResolver::computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
@@ -1623,18 +1202,18 @@ const StyleResolver::MatchedPropertiesCacheItem* StyleResolver::findFromMatchedP
MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.find(hash);
if (it == m_matchedPropertiesCache.end())
- return 0;
+ return nullptr;
MatchedPropertiesCacheItem& cacheItem = it->value;
- size_t size = matchResult.matchedProperties.size();
+ size_t size = matchResult.matchedProperties().size();
if (size != cacheItem.matchedProperties.size())
- return 0;
+ return nullptr;
for (size_t i = 0; i < size; ++i) {
- if (matchResult.matchedProperties[i] != cacheItem.matchedProperties[i])
- return 0;
+ if (matchResult.matchedProperties()[i] != cacheItem.matchedProperties[i])
+ return nullptr;
}
if (cacheItem.ranges != matchResult.ranges)
- return 0;
+ return nullptr;
return &cacheItem;
}
@@ -1649,13 +1228,13 @@ void StyleResolver::addToMatchedPropertiesCache(const RenderStyle* style, const
ASSERT(hash);
MatchedPropertiesCacheItem cacheItem;
- cacheItem.matchedProperties.appendVector(matchResult.matchedProperties);
+ cacheItem.matchedProperties.appendVector(matchResult.matchedProperties());
cacheItem.ranges = matchResult.ranges;
// Note that we don't cache the original RenderStyle instance. It may be further modified.
// The RenderStyle in the cache is really just a holder for the substructures and never used as-is.
- cacheItem.renderStyle = RenderStyle::clone(style);
- cacheItem.parentRenderStyle = RenderStyle::clone(parentStyle);
- m_matchedPropertiesCache.add(hash, std::move(cacheItem));
+ cacheItem.renderStyle = RenderStyle::clonePtr(*style);
+ cacheItem.parentRenderStyle = RenderStyle::clonePtr(*parentStyle);
+ m_matchedPropertiesCache.add(hash, WTFMove(cacheItem));
}
void StyleResolver::invalidateMatchedPropertiesCache()
@@ -1663,21 +1242,34 @@ void StyleResolver::invalidateMatchedPropertiesCache()
m_matchedPropertiesCache.clear();
}
-static bool isCacheableInMatchedPropertiesCache(const Element* element, const RenderStyle* style, const RenderStyle* parentStyle)
+void StyleResolver::clearCachedPropertiesAffectedByViewportUnits()
{
- // FIXME: CSSPropertyWebkitWritingMode modifies state when applying to document element. We can't skip the applying by caching.
- if (element == element->document().documentElement() && element->document().writingModeSetOnDocumentElement())
+ Vector<unsigned, 16> toRemove;
+ for (auto& cacheKeyValue : m_matchedPropertiesCache) {
+ if (cacheKeyValue.value.renderStyle->hasViewportUnits())
+ toRemove.append(cacheKeyValue.key);
+ }
+ for (auto key : toRemove)
+ m_matchedPropertiesCache.remove(key);
+}
+
+static bool isCacheableInMatchedPropertiesCache(const Element& element, const RenderStyle* style, const RenderStyle* parentStyle)
+{
+ // FIXME: Writing mode and direction properties modify state when applying to document element by calling
+ // Document::setWritingMode/DirectionSetOnDocumentElement. We can't skip the applying by caching.
+ if (&element == element.document().documentElement())
return false;
- if (style->unique() || (style->styleType() != NOPSEUDO && parentStyle->unique()))
+ // content:attr() value depends on the element it is being applied to.
+ if (style->hasAttrContent() || (style->styleType() != NOPSEUDO && parentStyle->hasAttrContent()))
return false;
if (style->hasAppearance())
return false;
if (style->zoom() != RenderStyle::initialZoom())
return false;
- if (style->writingMode() != RenderStyle::initialWritingMode())
+ if (style->writingMode() != RenderStyle::initialWritingMode() || style->direction() != RenderStyle::initialDirection())
return false;
// The cache assumes static knowledge about which properties are inherited.
- if (parentStyle->hasExplicitlyInheritedProperties())
+ if (style->hasExplicitlyInheritedProperties())
return false;
return true;
}
@@ -1687,24 +1279,24 @@ void extractDirectionAndWritingMode(const RenderStyle& style, const StyleResolve
direction = style.direction();
writingMode = style.writingMode();
- bool hadImportantWebkitWritingMode = false;
+ bool hadImportantWritingMode = false;
bool hadImportantDirection = false;
- for (auto& matchedProperties : matchResult.matchedProperties) {
+ for (const auto& matchedProperties : matchResult.matchedProperties()) {
for (unsigned i = 0, count = matchedProperties.properties->propertyCount(); i < count; ++i) {
auto property = matchedProperties.properties->propertyAt(i);
if (!property.value()->isPrimitiveValue())
continue;
switch (property.id()) {
- case CSSPropertyWebkitWritingMode:
- if (!hadImportantWebkitWritingMode || property.isImportant()) {
- writingMode = toCSSPrimitiveValue(*property.value());
- hadImportantWebkitWritingMode = property.isImportant();
+ case CSSPropertyWritingMode:
+ if (!hadImportantWritingMode || property.isImportant()) {
+ writingMode = downcast<CSSPrimitiveValue>(*property.value());
+ hadImportantWritingMode = property.isImportant();
}
break;
case CSSPropertyDirection:
if (!hadImportantDirection || property.isImportant()) {
- direction = toCSSPrimitiveValue(*property.value());
+ direction = downcast<CSSPrimitiveValue>(*property.value());
hadImportantDirection = property.isImportant();
}
break;
@@ -1715,23 +1307,23 @@ void extractDirectionAndWritingMode(const RenderStyle& style, const StyleResolve
}
}
-void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const Element* element, ShouldUseMatchedPropertiesCache shouldUseMatchedPropertiesCache)
+void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const Element& element, ShouldUseMatchedPropertiesCache shouldUseMatchedPropertiesCache)
{
- ASSERT(element);
State& state = m_state;
- unsigned cacheHash = shouldUseMatchedPropertiesCache && matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
+ unsigned cacheHash = shouldUseMatchedPropertiesCache && matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties().data(), matchResult.matchedProperties().size()) : 0;
bool applyInheritedOnly = false;
- const MatchedPropertiesCacheItem* cacheItem = 0;
- if (cacheHash && (cacheItem = findFromMatchedPropertiesCache(cacheHash, matchResult))) {
+ const MatchedPropertiesCacheItem* cacheItem = nullptr;
+ if (cacheHash && (cacheItem = findFromMatchedPropertiesCache(cacheHash, matchResult))
+ && isCacheableInMatchedPropertiesCache(element, state.style(), state.parentStyle())) {
// We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
// style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the
// element context. This is fast and saves memory by reusing the style data structures.
- state.style()->copyNonInheritedFrom(cacheItem->renderStyle.get());
+ state.style()->copyNonInheritedFrom(*cacheItem->renderStyle);
if (state.parentStyle()->inheritedDataShared(cacheItem->parentRenderStyle.get()) && !isAtShadowBoundary(element)) {
EInsideLink linkStatus = state.style()->insideLink();
// If the cache item parent style has identical inherited properties to the current parent style then the
// resulting style will be identical too. We copy the inherited properties over from the cache and are done.
- state.style()->inheritFrom(cacheItem->renderStyle.get());
+ state.style()->inheritFrom(*cacheItem->renderStyle);
// Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
state.style()->setInsideLink(linkStatus);
@@ -1751,71 +1343,75 @@ void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const
// Find out if there's a -webkit-appearance property in effect from the UA sheet.
// If so, we cache the border and background styles so that RenderTheme::adjustStyle()
// can look at them later to figure out if this is a styled form control or not.
- state.setLineHeightValue(nullptr);
CascadedProperties cascade(direction, writingMode);
- if (!cascade.addMatches(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly)
- || !cascade.addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly))
- return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
+ cascade.addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+ cascade.addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+
+ applyCascadedProperties(cascade, CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition, &matchResult);
+ adjustStyleForInterCharacterRuby();
+
+ // Resolve custom variables first.
+ applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom, &matchResult);
- applyCascadedProperties(cascade, firstCSSProperty, CSSPropertyLineHeight);
+ // Start by applying properties that other properties may depend on.
+ applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty, &matchResult);
+
updateFont();
- applyCascadedProperties(cascade, CSSPropertyBackground, lastCSSProperty);
+ applyCascadedProperties(cascade, firstLowPriorityProperty, lastCSSProperty, &matchResult);
state.cacheBorderAndBackground();
}
CascadedProperties cascade(direction, writingMode);
- if (!cascade.addMatches(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly)
- || !cascade.addMatches(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly)
- || !cascade.addMatches(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly)
- || !cascade.addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly))
- return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
+ cascade.addNormalMatches(matchResult, 0, matchResult.matchedProperties().size() - 1, applyInheritedOnly);
+ cascade.addImportantMatches(matchResult, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
+ cascade.addImportantMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
+ cascade.addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+
+ // Resolve custom properties first.
+ applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom, &matchResult);
- state.setLineHeightValue(nullptr);
+ applyCascadedProperties(cascade, CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition, &matchResult);
+
+ // Adjust the font size to be smaller if ruby-position is inter-character.
+ adjustStyleForInterCharacterRuby();
// Start by applying properties that other properties may depend on.
- applyCascadedProperties(cascade, firstCSSProperty, CSSPropertyLineHeight);
+ applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty, &matchResult);
// If the effective zoom value changes, we can't use the matched properties cache. Start over.
if (cacheItem && cacheItem->renderStyle->effectiveZoom() != state.style()->effectiveZoom())
return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
- // If our font got dirtied, go ahead and update it now.
+ // If our font got dirtied, update it now.
updateFont();
- // Line-height is set when we are sure we decided on the font-size.
- if (state.lineHeightValue())
- applyProperty(CSSPropertyLineHeight, state.lineHeightValue());
-
// If the font changed, we can't use the matched properties cache. Start over.
if (cacheItem && cacheItem->renderStyle->fontDescription() != state.style()->fontDescription())
return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
// Apply properties that no other properties depend on.
- applyCascadedProperties(cascade, CSSPropertyBackground, lastCSSProperty);
+ applyCascadedProperties(cascade, firstLowPriorityProperty, lastCSSProperty, &matchResult);
// Finally, some properties must be applied in the order they were parsed.
// There are some CSS properties that affect the same RenderStyle values,
// so to preserve behavior, we queue them up during cascade and flush here.
- cascade.applyDeferredProperties(*this);
+ cascade.applyDeferredProperties(*this, &matchResult);
- // Start loading resources referenced by this style.
- loadPendingResources();
-
ASSERT(!state.fontDirty());
if (cacheItem || !cacheHash)
return;
- if (!isCacheableInMatchedPropertiesCache(state.element(), state.style(), state.parentStyle()))
+ if (!isCacheableInMatchedPropertiesCache(*state.element(), state.style(), state.parentStyle()))
return;
addToMatchedPropertiesCache(state.style(), state.parentStyle(), cacheHash, matchResult);
}
-void StyleResolver::applyPropertyToStyle(CSSPropertyID id, CSSValue* value, RenderStyle* style)
+void StyleResolver::applyPropertyToStyle(CSSPropertyID id, CSSValue* value, std::unique_ptr<RenderStyle> style)
{
- initElement(0);
- m_state.initForStyleResolve(document(), 0, style);
- m_state.setStyle(*style);
+ m_state = State();
+ m_state.setParentStyle(RenderStyle::clonePtr(*style));
+ m_state.setStyle(WTFMove(style));
applyPropertyToCurrentStyle(id, value);
}
@@ -1835,15 +1431,13 @@ inline bool isValidVisitedLinkProperty(CSSPropertyID id)
case CSSPropertyBorderBottomColor:
case CSSPropertyColor:
case CSSPropertyOutlineColor:
- case CSSPropertyWebkitColumnRuleColor:
+ case CSSPropertyColumnRuleColor:
case CSSPropertyWebkitTextDecorationColor:
case CSSPropertyWebkitTextEmphasisColor:
case CSSPropertyWebkitTextFillColor:
case CSSPropertyWebkitTextStrokeColor:
-#if ENABLE(SVG)
case CSSPropertyFill:
case CSSPropertyStroke:
-#endif
return true;
default:
break;
@@ -1881,15 +1475,13 @@ inline bool StyleResolver::isValidCueStyleProperty(CSSPropertyID id)
case CSSPropertyBackgroundPositionX:
case CSSPropertyBackgroundPositionY:
case CSSPropertyBackgroundRepeat:
- case CSSPropertyBackgroundRepeatX:
- case CSSPropertyBackgroundRepeatY:
case CSSPropertyBackgroundSize:
case CSSPropertyColor:
case CSSPropertyFont:
case CSSPropertyFontFamily:
case CSSPropertyFontSize:
case CSSPropertyFontStyle:
- case CSSPropertyFontVariant:
+ case CSSPropertyFontVariantCaps:
case CSSPropertyFontWeight:
case CSSPropertyLineHeight:
case CSSPropertyOpacity:
@@ -1903,6 +1495,11 @@ inline bool StyleResolver::isValidCueStyleProperty(CSSPropertyID id)
case CSSPropertyTextDecoration:
case CSSPropertyTextShadow:
case CSSPropertyBorderStyle:
+ case CSSPropertyPaintOrder:
+ case CSSPropertyStrokeLinejoin:
+ case CSSPropertyStrokeLinecap:
+ case CSSPropertyWebkitTextStrokeColor:
+ case CSSPropertyWebkitTextStrokeWidth:
return true;
default:
break;
@@ -1923,1251 +1520,183 @@ bool StyleResolver::useSVGZoomRules()
return m_state.element() && m_state.element()->isSVGElement();
}
-static bool createGridTrackBreadth(CSSPrimitiveValue* primitiveValue, const StyleResolver::State& state, GridLength& workingLength)
-{
- if (primitiveValue->getValueID() == CSSValueWebkitMinContent) {
- workingLength = Length(MinContent);
- return true;
- }
-
- if (primitiveValue->getValueID() == CSSValueWebkitMaxContent) {
- workingLength = Length(MaxContent);
- return true;
- }
-
- if (primitiveValue->isFlex()) {
- // Fractional unit.
- workingLength.setFlex(primitiveValue->getDoubleValue());
- return true;
- }
-
- workingLength = primitiveValue->convertToLength<FixedIntegerConversion | PercentConversion | ViewportPercentageConversion | AutoConversion>(state.style(), state.rootElementStyle(), state.style()->effectiveZoom());
- if (workingLength.length().isUndefined())
- return false;
-
- if (primitiveValue->isLength())
- workingLength.length().setQuirk(primitiveValue->isQuirkValue());
-
- return true;
-}
-
-static bool createGridTrackSize(CSSValue* value, GridTrackSize& trackSize, const StyleResolver::State& state)
-{
- if (value->isPrimitiveValue()) {
- CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
- GridLength workingLength;
- if (!createGridTrackBreadth(primitiveValue, state, workingLength))
- return false;
-
- trackSize.setLength(workingLength);
- return true;
- }
-
- CSSFunctionValue* minmaxFunction = toCSSFunctionValue(value);
- CSSValueList* arguments = minmaxFunction->arguments();
- ASSERT_WITH_SECURITY_IMPLICATION(arguments->length() == 2);
- GridLength minTrackBreadth;
- GridLength maxTrackBreadth;
- if (!createGridTrackBreadth(toCSSPrimitiveValue(arguments->itemWithoutBoundsCheck(0)), state, minTrackBreadth) || !createGridTrackBreadth(toCSSPrimitiveValue(arguments->itemWithoutBoundsCheck(1)), state, maxTrackBreadth))
- return false;
-
- trackSize.setMinMax(minTrackBreadth, maxTrackBreadth);
- return true;
-}
-
-static bool createGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, const StyleResolver::State& state)
+// Scale with/height properties on inline SVG root.
+bool StyleResolver::useSVGZoomRulesForLength()
{
- // Handle 'none'.
- if (value->isPrimitiveValue()) {
- CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
- return primitiveValue->getValueID() == CSSValueNone;
- }
-
- if (!value->isValueList())
- return false;
-
- size_t currentNamedGridLine = 0;
- for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
- CSSValue* currValue = i.value();
- if (currValue->isPrimitiveValue()) {
- CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(currValue);
- if (primitiveValue->isString()) {
- NamedGridLinesMap::AddResult result = namedGridLines.add(primitiveValue->getStringValue(), Vector<size_t>());
- result.iterator->value.append(currentNamedGridLine);
- continue;
- }
- }
-
- ++currentNamedGridLine;
- GridTrackSize trackSize;
- if (!createGridTrackSize(currValue, trackSize, state))
- return false;
-
- trackSizes.append(trackSize);
- }
-
- // The parser should have rejected any <track-list> without any <track-size> as
- // this is not conformant to the syntax.
- ASSERT(!trackSizes.isEmpty());
- return true;
+ return is<SVGElement>(m_state.element()) && !(is<SVGSVGElement>(*m_state.element()) && m_state.element()->parentNode());
}
-
-static bool createGridPosition(CSSValue* value, GridPosition& position)
+StyleResolver::CascadedProperties* StyleResolver::cascadedPropertiesForRollback(const MatchResult& matchResult)
{
- // We accept the specification's grammar:
- // 'auto' | [ <integer> || <string> ] | [ span && [ <integer> || string ] ] | <ident>
- if (value->isPrimitiveValue()) {
- CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
- // We translate <ident> to <string> during parsing as it makes handling it simpler.
- if (primitiveValue->isString()) {
- position.setNamedGridArea(primitiveValue->getStringValue());
- return true;
- }
-
- ASSERT(primitiveValue->getValueID() == CSSValueAuto);
- return true;
- }
-
- CSSValueList* values = toCSSValueList(value);
- ASSERT(values->length());
-
- bool isSpanPosition = false;
- // The specification makes the <integer> optional, in which case it default to '1'.
- int gridLineNumber = 1;
- String gridLineName;
-
- CSSValueListIterator it = values;
- CSSPrimitiveValue* currentValue = toCSSPrimitiveValue(it.value());
- if (currentValue->getValueID() == CSSValueSpan) {
- isSpanPosition = true;
- it.advance();
- currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
- }
+ ASSERT(cascadeLevel() != UserAgentLevel);
+
+ TextDirection direction;
+ WritingMode writingMode;
+ extractDirectionAndWritingMode(*state().style(), matchResult, direction, writingMode);
- if (currentValue && currentValue->isNumber()) {
- gridLineNumber = currentValue->getIntValue();
- it.advance();
- currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
+ if (cascadeLevel() == AuthorLevel) {
+ CascadedProperties* authorRollback = state().authorRollback();
+ if (authorRollback)
+ return authorRollback;
+
+ auto newAuthorRollback(std::make_unique<CascadedProperties>(direction, writingMode));
+
+ // This special rollback cascade contains UA rules and user rules but no author rules.
+ newAuthorRollback->addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
+ newAuthorRollback->addNormalMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, false);
+ newAuthorRollback->addImportantMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, false);
+ newAuthorRollback->addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
+
+ state().setAuthorRollback(newAuthorRollback);
+ return state().authorRollback();
}
-
- if (currentValue && currentValue->isString()) {
- gridLineName = currentValue->getStringValue();
- it.advance();
+
+ if (cascadeLevel() == UserLevel) {
+ CascadedProperties* userRollback = state().userRollback();
+ if (userRollback)
+ return userRollback;
+
+ auto newUserRollback(std::make_unique<CascadedProperties>(direction, writingMode));
+
+ // This special rollback cascade contains only UA rules.
+ newUserRollback->addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
+ newUserRollback->addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
+
+ state().setUserRollback(newUserRollback);
+ return state().userRollback();
}
-
- ASSERT(!it.hasMore());
- if (isSpanPosition)
- position.setSpanPosition(gridLineNumber, gridLineName);
- else
- position.setExplicitPosition(gridLineNumber, gridLineName);
-
- return true;
+
+ return nullptr;
}
-void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
+void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value, SelectorChecker::LinkMatchMask linkMatchMask, const MatchResult* matchResult)
{
- ASSERT_WITH_MESSAGE(!isExpandedShorthand(id), "Shorthand property id = %d wasn't expanded at parsing time", id);
+ ASSERT_WITH_MESSAGE(!isShorthandCSSProperty(id), "Shorthand property id = %d wasn't expanded at parsing time", id);
State& state = m_state;
+
+ RefPtr<CSSValue> valueToApply = value;
+ if (value->hasVariableReferences()) {
+ valueToApply = resolvedVariableValue(id, *value);
+ if (!valueToApply) {
+ if (CSSProperty::isInheritedProperty(id))
+ valueToApply = CSSValuePool::singleton().createInheritedValue();
+ else
+ valueToApply = CSSValuePool::singleton().createExplicitInitialValue();
+ }
+ }
if (CSSProperty::isDirectionAwareProperty(id)) {
CSSPropertyID newId = CSSProperty::resolveDirectionAwareProperty(id, state.style()->direction(), state.style()->writingMode());
ASSERT(newId != id);
- return applyProperty(newId, value);
- }
-
- bool isInherit = state.parentNode() && value->isInheritedValue();
- bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue());
-
- ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit
- ASSERT(!isInherit || (state.parentNode() && state.parentStyle())); // isInherit -> (state.parentNode() && state.parentStyle())
-
- if (!state.applyPropertyToRegularStyle() && (!state.applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) {
- // Limit the properties that can be applied to only the ones honored by :visited.
- return;
+ return applyProperty(newId, valueToApply.get(), linkMatchMask, matchResult);
}
-
- if (isInherit && !state.parentStyle()->hasExplicitlyInheritedProperties() && !CSSProperty::isInheritedProperty(id))
- state.parentStyle()->setHasExplicitlyInheritedProperties();
-
- // Check lookup table for implementations and use when available.
- const PropertyHandler& handler = m_deprecatedStyleBuilder.propertyHandler(id);
- if (handler.isValid()) {
- if (isInherit)
- handler.applyInheritValue(id, this);
- else if (isInitial)
- handler.applyInitialValue(id, this);
- else
- handler.applyValue(id, this, value);
- return;
+
+ CSSValue* valueToCheckForInheritInitial = valueToApply.get();
+ CSSCustomPropertyValue* customPropertyValue = nullptr;
+ CSSValueID customPropertyValueID = CSSValueInvalid;
+
+ if (id == CSSPropertyCustom) {
+ customPropertyValue = &downcast<CSSCustomPropertyValue>(*valueToApply);
+ customPropertyValueID = customPropertyValue->valueID();
}
- CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? toCSSPrimitiveValue(value) : 0;
-
- float zoomFactor = state.style()->effectiveZoom();
-
- // What follows is a list that maps the CSS properties into their corresponding front-end
- // RenderStyle values.
- switch (id) {
- // lists
- case CSSPropertyContent:
- // list of string, uri, counter, attr, i
- {
- // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
- // note is a reminder that eventually "inherit" needs to be supported.
-
- if (isInitial) {
- state.style()->clearContent();
- return;
- }
-
- if (!value->isValueList())
- return;
-
- bool didSet = false;
- for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
- CSSValue* item = i.value();
- if (item->isImageGeneratorValue()) {
- if (item->isGradientValue())
- state.style()->setContent(StyleGeneratedImage::create(*toCSSGradientValue(item)->gradientWithStylesResolved(this)), didSet);
- else
- state.style()->setContent(StyleGeneratedImage::create(*toCSSImageGeneratorValue(item)), didSet);
- didSet = true;
-#if ENABLE(CSS_IMAGE_SET)
- } else if (item->isImageSetValue()) {
- state.style()->setContent(setOrPendingFromValue(CSSPropertyContent, toCSSImageSetValue(item)), didSet);
- didSet = true;
-#endif
- }
-
- if (item->isImageValue()) {
- state.style()->setContent(cachedOrPendingFromValue(CSSPropertyContent, toCSSImageValue(item)), didSet);
- didSet = true;
- continue;
- }
-
- if (!item->isPrimitiveValue())
- continue;
-
- CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item);
-
- if (contentValue->isString()) {
- state.style()->setContent(contentValue->getStringValue().impl(), didSet);
- didSet = true;
- } else if (contentValue->isAttr()) {
- // FIXME: Can a namespace be specified for an attr(foo)?
- if (state.style()->styleType() == NOPSEUDO)
- state.style()->setUnique();
- else
- state.parentStyle()->setUnique();
- QualifiedName attr(nullAtom, contentValue->getStringValue().impl(), nullAtom);
- const AtomicString& value = state.element()->getAttribute(attr);
- state.style()->setContent(value.isNull() ? emptyAtom : value.impl(), didSet);
- didSet = true;
- // Register the fact that the attribute value affects the style.
- m_ruleSets.features().attrsInRules.add(attr.localName().impl());
- } else if (contentValue->isCounter()) {
- Counter* counterValue = contentValue->getCounterValue();
- EListStyleType listStyleType = NoneListStyle;
- CSSValueID listStyleIdent = counterValue->listStyleIdent();
- if (listStyleIdent != CSSValueNone)
- listStyleType = static_cast<EListStyleType>(listStyleIdent - CSSValueDisc);
- auto counter = std::make_unique<CounterContent>(counterValue->identifier(), listStyleType, counterValue->separator());
- state.style()->setContent(std::move(counter), didSet);
- didSet = true;
- } else {
- switch (contentValue->getValueID()) {
- case CSSValueOpenQuote:
- state.style()->setContent(OPEN_QUOTE, didSet);
- didSet = true;
- break;
- case CSSValueCloseQuote:
- state.style()->setContent(CLOSE_QUOTE, didSet);
- didSet = true;
- break;
- case CSSValueNoOpenQuote:
- state.style()->setContent(NO_OPEN_QUOTE, didSet);
- didSet = true;
- break;
- case CSSValueNoCloseQuote:
- state.style()->setContent(NO_CLOSE_QUOTE, didSet);
- didSet = true;
- break;
- default:
- // normal and none do not have any effect.
- { }
- }
+ bool isInherit = state.parentStyle() ? valueToCheckForInheritInitial->isInheritedValue() || customPropertyValueID == CSSValueInherit : false;
+ bool isInitial = valueToCheckForInheritInitial->isInitialValue() || customPropertyValueID == CSSValueInitial || (!state.parentStyle() && (valueToCheckForInheritInitial->isInheritedValue() || customPropertyValueID == CSSValueInherit));
+
+ bool isUnset = valueToCheckForInheritInitial->isUnsetValue() || customPropertyValueID == CSSValueUnset;
+ bool isRevert = valueToCheckForInheritInitial->isRevertValue() || customPropertyValueID == CSSValueRevert;
+
+ if (isRevert) {
+ if (cascadeLevel() == UserAgentLevel || !matchResult)
+ isUnset = true;
+ else {
+ // Fetch the correct rollback object from the state, building it if necessary.
+ // This requires having the original MatchResult available.
+ auto* rollback = cascadedPropertiesForRollback(*matchResult);
+ ASSERT(rollback);
+
+ // With the cascade built, we need to obtain the property and apply it. If the property is
+ // not present, then we behave like "unset." Otherwise we apply the property instead of
+ // our own.
+ if (customPropertyValue) {
+ if (rollback->hasCustomProperty(customPropertyValue->name())) {
+ auto property = rollback->customProperty(customPropertyValue->name());
+ if (property.cssValue[linkMatchMask])
+ applyProperty(property.id, property.cssValue[linkMatchMask], linkMatchMask, matchResult);
+ return;
}
- }
- if (!didSet)
- state.style()->clearContent();
- return;
- }
- case CSSPropertyWebkitAlt:
- {
- bool didSet = false;
- if (primitiveValue->isString()) {
- state.style()->setContentAltText(primitiveValue->getStringValue().impl());
- didSet = true;
- } else if (primitiveValue->isAttr()) {
- // FIXME: Can a namespace be specified for an attr(foo)?
- if (state.style()->styleType() == NOPSEUDO)
- state.style()->setUnique();
- else
- state.parentStyle()->setUnique();
- QualifiedName attr(nullAtom, primitiveValue->getStringValue().impl(), nullAtom);
- const AtomicString& value = state.element()->getAttribute(attr);
- state.style()->setContentAltText(value.isNull() ? emptyAtom : value.impl());
- didSet = true;
- // Register the fact that the attribute value affects the style.
- m_ruleSets.features().attrsInRules.add(attr.localName().impl());
- }
- if (!didSet)
- state.style()->setContentAltText(emptyAtom);
- return;
- }
-
- case CSSPropertyQuotes:
- if (isInherit) {
- state.style()->setQuotes(state.parentStyle()->quotes());
- return;
- }
- if (isInitial) {
- state.style()->setQuotes(0);
- return;
- }
- if (value->isValueList()) {
- CSSValueList* list = toCSSValueList(value);
- Vector<std::pair<String, String>> quotes;
- for (size_t i = 0; i < list->length(); i += 2) {
- CSSValue* first = list->itemWithoutBoundsCheck(i);
- // item() returns null if out of bounds so this is safe.
- CSSValue* second = list->item(i + 1);
- if (!second)
- continue;
- ASSERT_WITH_SECURITY_IMPLICATION(first->isPrimitiveValue());
- ASSERT_WITH_SECURITY_IMPLICATION(second->isPrimitiveValue());
- String startQuote = toCSSPrimitiveValue(first)->getStringValue();
- String endQuote = toCSSPrimitiveValue(second)->getStringValue();
- quotes.append(std::make_pair(startQuote, endQuote));
- }
- state.style()->setQuotes(QuotesData::create(quotes));
- return;
- }
- if (primitiveValue) {
- if (primitiveValue->getValueID() == CSSValueNone)
- state.style()->setQuotes(QuotesData::create(Vector<std::pair<String, String>>()));
- }
- return;
- // Shorthand properties.
- case CSSPropertyFont:
- if (isInherit) {
- FontDescription fontDescription = state.parentStyle()->fontDescription();
- state.style()->setLineHeight(state.parentStyle()->specifiedLineHeight());
- state.setLineHeightValue(0);
- setFontDescription(fontDescription);
- } else if (isInitial) {
- Settings* settings = documentSettings();
- ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
- if (!settings)
+ } else if (rollback->hasProperty(id)) {
+ auto& property = rollback->property(id);
+ if (property.cssValue[linkMatchMask])
+ applyProperty(property.id, property.cssValue[linkMatchMask], linkMatchMask, matchResult);
return;
- initializeFontStyle(settings);
- } else if (primitiveValue) {
- state.style()->setLineHeight(RenderStyle::initialLineHeight());
- state.setLineHeightValue(0);
-
- FontDescription fontDescription;
- RenderTheme::defaultTheme()->systemFont(primitiveValue->getValueID(), fontDescription);
-
- // Double-check and see if the theme did anything. If not, don't bother updating the font.
- if (fontDescription.isAbsoluteSize()) {
- // Make sure the rendering mode and printer font settings are updated.
- Settings* settings = documentSettings();
- ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
- if (!settings)
- return;
- fontDescription.setRenderingMode(settings->fontRenderingMode());
- fontDescription.setUsePrinterFont(document().printing() || !settings->screenFontSubstitutionEnabled());
-
- // Handle the zoom factor.
- fontDescription.setComputedSize(Style::computedFontSizeFromSpecifiedSize(fontDescription.specifiedSize(), fontDescription.isAbsoluteSize(), useSVGZoomRules(), state.style(), document()));
- setFontDescription(fontDescription);
}
- } else if (value->isFontValue()) {
- CSSFontValue* font = toCSSFontValue(value);
- if (!font->style || !font->variant || !font->weight
- || !font->size || !font->lineHeight || !font->family)
- return;
- applyProperty(CSSPropertyFontStyle, font->style.get());
- applyProperty(CSSPropertyFontVariant, font->variant.get());
- applyProperty(CSSPropertyFontWeight, font->weight.get());
- // The previous properties can dirty our font but they don't try to read the font's
- // properties back, which is safe. However if font-size is using the 'ex' unit, it will
- // need query the dirtied font's x-height to get the computed size. To be safe in this
- // case, let's just update the font now.
- updateFont();
- applyProperty(CSSPropertyFontSize, font->size.get());
-
- state.setLineHeightValue(font->lineHeight.get());
-
- applyProperty(CSSPropertyFontFamily, font->family.get());
- }
- return;
-
- case CSSPropertyBackground:
- case CSSPropertyBackgroundPosition:
- case CSSPropertyBackgroundRepeat:
- case CSSPropertyBorder:
- case CSSPropertyBorderBottom:
- case CSSPropertyBorderColor:
- case CSSPropertyBorderImage:
- case CSSPropertyBorderLeft:
- case CSSPropertyBorderRadius:
- case CSSPropertyBorderRight:
- case CSSPropertyBorderSpacing:
- case CSSPropertyBorderStyle:
- case CSSPropertyBorderTop:
- case CSSPropertyBorderWidth:
- case CSSPropertyListStyle:
- case CSSPropertyMargin:
- case CSSPropertyOutline:
- case CSSPropertyOverflow:
- case CSSPropertyPadding:
- case CSSPropertyTransition:
- case CSSPropertyWebkitAnimation:
- case CSSPropertyWebkitBorderAfter:
- case CSSPropertyWebkitBorderBefore:
- case CSSPropertyWebkitBorderEnd:
- case CSSPropertyWebkitBorderStart:
- case CSSPropertyWebkitBorderRadius:
- case CSSPropertyWebkitColumns:
- case CSSPropertyWebkitColumnRule:
- case CSSPropertyWebkitFlex:
- case CSSPropertyWebkitFlexFlow:
- case CSSPropertyWebkitGridArea:
- case CSSPropertyWebkitGridColumn:
- case CSSPropertyWebkitGridRow:
- case CSSPropertyWebkitMarginCollapse:
- case CSSPropertyWebkitMarquee:
- case CSSPropertyWebkitMask:
- case CSSPropertyWebkitMaskPosition:
- case CSSPropertyWebkitMaskRepeat:
- case CSSPropertyWebkitTextEmphasis:
- case CSSPropertyWebkitTextStroke:
- case CSSPropertyWebkitTransition:
- case CSSPropertyWebkitTransformOrigin:
- ASSERT(isExpandedShorthand(id));
- ASSERT_NOT_REACHED();
- break;
-
- // CSS3 Properties
- case CSSPropertyTextShadow:
- case CSSPropertyBoxShadow:
- case CSSPropertyWebkitBoxShadow: {
- if (isInherit) {
- if (id == CSSPropertyTextShadow)
- return state.style()->setTextShadow(state.parentStyle()->textShadow() ? adoptPtr(new ShadowData(*state.parentStyle()->textShadow())) : nullptr);
- return state.style()->setBoxShadow(state.parentStyle()->boxShadow() ? adoptPtr(new ShadowData(*state.parentStyle()->boxShadow())) : nullptr);
- }
- if (isInitial || primitiveValue) // initial | none
- return id == CSSPropertyTextShadow ? state.style()->setTextShadow(nullptr) : state.style()->setBoxShadow(nullptr);
-
- if (!value->isValueList())
- return;
-
- for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
- CSSValue* currValue = i.value();
- if (!currValue->isShadowValue())
- continue;
- CSSShadowValue* item = toCSSShadowValue(currValue);
- int x = item->x->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor);
- if (item->x->isViewportPercentageLength())
- x = viewportPercentageValue(*item->x, x);
- int y = item->y->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor);
- if (item->y->isViewportPercentageLength())
- y = viewportPercentageValue(*item->y, y);
- int blur = item->blur ? item->blur->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor) : 0;
- if (item->blur && item->blur->isViewportPercentageLength())
- blur = viewportPercentageValue(*item->blur, blur);
- int spread = item->spread ? item->spread->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor) : 0;
- if (item->spread && item->spread->isViewportPercentageLength())
- spread = viewportPercentageValue(*item->spread, spread);
- ShadowStyle shadowStyle = item->style && item->style->getValueID() == CSSValueInset ? Inset : Normal;
- Color color;
- if (item->color)
- color = colorFromPrimitiveValue(item->color.get());
- else if (state.style())
- color = state.style()->color();
-
- OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(IntPoint(x, y), blur, spread, shadowStyle, id == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent));
- if (id == CSSPropertyTextShadow)
- state.style()->setTextShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry
- else
- state.style()->setBoxShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry
- }
- return;
- }
- case CSSPropertyWebkitBoxReflect: {
- HANDLE_INHERIT_AND_INITIAL(boxReflect, BoxReflect)
- if (primitiveValue) {
- state.style()->setBoxReflect(RenderStyle::initialBoxReflect());
- return;
- }
-
- if (!value->isReflectValue())
- return;
-
- CSSReflectValue* reflectValue = toCSSReflectValue(value);
- RefPtr<StyleReflection> reflection = StyleReflection::create();
- reflection->setDirection(*reflectValue->direction());
- if (reflectValue->offset())
- reflection->setOffset(reflectValue->offset()->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(state.style(), state.rootElementStyle(), zoomFactor));
- NinePieceImage mask;
- mask.setMaskDefaults();
- m_styleMap.mapNinePieceImage(id, reflectValue->mask(), mask);
- reflection->setMask(mask);
-
- state.style()->setBoxReflect(reflection.release());
- return;
- }
- case CSSPropertySrc: // Only used in @font-face rules.
- return;
- case CSSPropertyUnicodeRange: // Only used in @font-face rules.
- return;
- case CSSPropertyWebkitLocale: {
- HANDLE_INHERIT_AND_INITIAL(locale, Locale);
- if (!primitiveValue)
- return;
- if (primitiveValue->getValueID() == CSSValueAuto)
- state.style()->setLocale(nullAtom);
- else
- state.style()->setLocale(primitiveValue->getStringValue());
- FontDescription fontDescription = state.style()->fontDescription();
- fontDescription.setScript(localeToScriptCodeForFontSelection(state.style()->locale()));
- setFontDescription(fontDescription);
- return;
- }
-#if ENABLE(IOS_TEXT_AUTOSIZING)
- case CSSPropertyWebkitTextSizeAdjust: {
- HANDLE_INHERIT_AND_INITIAL(textSizeAdjust, TextSizeAdjust)
- if (!primitiveValue)
- return;
-
- if (primitiveValue->getValueID() == CSSValueAuto)
- state.style()->setTextSizeAdjust(TextSizeAdjustment(AutoTextSizeAdjustment));
- else if (primitiveValue->getValueID() == CSSValueNone)
- state.style()->setTextSizeAdjust(TextSizeAdjustment(NoTextSizeAdjustment));
- else
- state.style()->setTextSizeAdjust(TextSizeAdjustment(primitiveValue->getFloatValue()));
-
- state.setFontDirty(true);
- return;
- }
-#endif
-#if ENABLE(DASHBOARD_SUPPORT)
- case CSSPropertyWebkitDashboardRegion:
- {
- HANDLE_INHERIT_AND_INITIAL(dashboardRegions, DashboardRegions)
- if (!primitiveValue)
- return;
-
- if (primitiveValue->getValueID() == CSSValueNone) {
- state.style()->setDashboardRegions(RenderStyle::noneDashboardRegions());
- return;
- }
-
- DashboardRegion* region = primitiveValue->getDashboardRegionValue();
- if (!region)
- return;
-
- DashboardRegion* first = region;
- while (region) {
- Length top = convertToIntLength(region->top(), state.style(), state.rootElementStyle());
- Length right = convertToIntLength(region->right(), state.style(), state.rootElementStyle());
- Length bottom = convertToIntLength(region->bottom(), state.style(), state.rootElementStyle());
- Length left = convertToIntLength(region->left(), state.style(), state.rootElementStyle());
-
- if (top.isUndefined())
- top = Length();
- if (right.isUndefined())
- right = Length();
- if (bottom.isUndefined())
- bottom = Length();
- if (left.isUndefined())
- left = Length();
-
- if (region->m_isCircle)
- state.style()->setDashboardRegion(StyleDashboardRegion::Circle, region->m_label, top, right, bottom, left, region == first ? false : true);
- else if (region->m_isRectangle)
- state.style()->setDashboardRegion(StyleDashboardRegion::Rectangle, region->m_label, top, right, bottom, left, region == first ? false : true);
- region = region->m_next.get();
- }
-
- state.document().setHasAnnotatedRegions(true);
-
- return;
- }
-#endif
- case CSSPropertyWebkitTextStrokeWidth: {
- HANDLE_INHERIT_AND_INITIAL(textStrokeWidth, TextStrokeWidth)
- float width = 0;
- switch (primitiveValue->getValueID()) {
- case CSSValueThin:
- case CSSValueMedium:
- case CSSValueThick: {
- double result = 1.0 / 48;
- if (primitiveValue->getValueID() == CSSValueMedium)
- result *= 3;
- else if (primitiveValue->getValueID() == CSSValueThick)
- result *= 5;
- Ref<CSSPrimitiveValue> value(CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS));
- width = value.get().computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor);
- break;
- }
- default:
- width = primitiveValue->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor);
- break;
- }
- state.style()->setTextStrokeWidth(width);
- return;
- }
- case CSSPropertyWebkitTransform: {
- HANDLE_INHERIT_AND_INITIAL(transform, Transform);
- TransformOperations operations;
- transformsForValue(state.style(), state.rootElementStyle(), value, operations);
- state.style()->setTransform(operations);
- return;
- }
- case CSSPropertyWebkitPerspective: {
- HANDLE_INHERIT_AND_INITIAL(perspective, Perspective)
-
- if (!primitiveValue)
- return;
-
- if (primitiveValue->getValueID() == CSSValueNone) {
- state.style()->setPerspective(0);
- return;
- }
-
- float perspectiveValue;
- if (primitiveValue->isLength())
- perspectiveValue = primitiveValue->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor);
- else if (primitiveValue->isNumber()) {
- // For backward compatibility, treat valueless numbers as px.
- Ref<CSSPrimitiveValue> value(CSSPrimitiveValue::create(primitiveValue->getDoubleValue(), CSSPrimitiveValue::CSS_PX));
- perspectiveValue = value.get().computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor);
- } else
- return;
-
- if (perspectiveValue >= 0.0f)
- state.style()->setPerspective(perspectiveValue);
- return;
- }
-#if PLATFORM(IOS)
- case CSSPropertyWebkitTouchCallout: {
- HANDLE_INHERIT_AND_INITIAL(touchCalloutEnabled, TouchCalloutEnabled);
- if (!primitiveValue)
- break;
-
- state.style()->setTouchCalloutEnabled(primitiveValue->getStringValue().lower() != "none");
- return;
- }
-
- // FIXME: CSSPropertyWebkitCompositionFillColor shouldn't be iOS-specific. Once we fix up its usage in
- // InlineTextBox::paintCompositionBackground() we should move it outside the PLATFORM(IOS)-guard.
- // See <https://bugs.webkit.org/show_bug.cgi?id=126296>.
- case CSSPropertyWebkitCompositionFillColor: {
- HANDLE_INHERIT_AND_INITIAL(compositionFillColor, CompositionFillColor);
- if (!primitiveValue)
- break;
- state.style()->setCompositionFillColor(colorFromPrimitiveValue(primitiveValue));
- return;
- }
-#endif
-#if ENABLE(TOUCH_EVENTS)
- case CSSPropertyWebkitTapHighlightColor: {
- HANDLE_INHERIT_AND_INITIAL(tapHighlightColor, TapHighlightColor);
- if (!primitiveValue)
- break;
-
- Color col = colorFromPrimitiveValue(primitiveValue);
- state.style()->setTapHighlightColor(col);
- return;
- }
-#endif
-#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
- case CSSPropertyWebkitOverflowScrolling: {
- HANDLE_INHERIT_AND_INITIAL(useTouchOverflowScrolling, UseTouchOverflowScrolling);
- if (!primitiveValue)
- break;
- state.style()->setUseTouchOverflowScrolling(primitiveValue->getValueID() == CSSValueTouch);
- return;
- }
-#endif
- case CSSPropertyInvalid:
- return;
- case CSSPropertyFontStretch:
- case CSSPropertyPage:
- case CSSPropertyTextLineThrough:
- case CSSPropertyTextLineThroughColor:
- case CSSPropertyTextLineThroughMode:
- case CSSPropertyTextLineThroughStyle:
- case CSSPropertyTextLineThroughWidth:
- case CSSPropertyTextOverline:
- case CSSPropertyTextOverlineColor:
- case CSSPropertyTextOverlineMode:
- case CSSPropertyTextOverlineStyle:
- case CSSPropertyTextOverlineWidth:
- case CSSPropertyTextUnderline:
- case CSSPropertyTextUnderlineColor:
- case CSSPropertyTextUnderlineMode:
- case CSSPropertyTextUnderlineStyle:
- case CSSPropertyTextUnderlineWidth:
- case CSSPropertyWebkitFontSizeDelta:
- case CSSPropertyWebkitTextDecorationsInEffect:
- return;
-
- // CSS Text Layout Module Level 3: Vertical writing support
- case CSSPropertyWebkitWritingMode: {
- HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode);
- if (primitiveValue)
- setWritingMode(*primitiveValue);
-
- // FIXME: It is not ok to modify document state while applying style.
- if (state.element() && state.element() == state.document().documentElement())
- state.document().setWritingModeSetOnDocumentElement(true);
- return;
- }
-
- case CSSPropertyWebkitTextOrientation: {
- HANDLE_INHERIT_AND_INITIAL(textOrientation, TextOrientation);
-
- if (primitiveValue)
- setTextOrientation(*primitiveValue);
-
- return;
- }
-
- case CSSPropertyWebkitLineBoxContain: {
- HANDLE_INHERIT_AND_INITIAL(lineBoxContain, LineBoxContain)
- if (primitiveValue && primitiveValue->getValueID() == CSSValueNone) {
- state.style()->setLineBoxContain(LineBoxContainNone);
- return;
- }
-
- if (!value->isLineBoxContainValue())
- return;
-
- state.style()->setLineBoxContain(toCSSLineBoxContainValue(value)->value());
- return;
- }
-
- // CSS Fonts Module Level 3
- case CSSPropertyWebkitFontFeatureSettings: {
- if (primitiveValue && primitiveValue->getValueID() == CSSValueNormal) {
- setFontDescription(state.style()->fontDescription().makeNormalFeatureSettings());
- return;
- }
-
- if (!value->isValueList())
- return;
-
- FontDescription fontDescription = state.style()->fontDescription();
- CSSValueList* list = toCSSValueList(value);
- RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create();
- int len = list->length();
- for (int i = 0; i < len; ++i) {
- CSSValue* item = list->itemWithoutBoundsCheck(i);
- if (!item->isFontFeatureValue())
- continue;
- CSSFontFeatureValue* feature = toCSSFontFeatureValue(item);
- settings->append(FontFeature(feature->tag(), feature->value()));
- }
- fontDescription.setFeatureSettings(settings.release());
- setFontDescription(fontDescription);
- return;
- }
-
-#if ENABLE(CSS_FILTERS)
- case CSSPropertyWebkitFilter: {
- HANDLE_INHERIT_AND_INITIAL(filter, Filter);
- FilterOperations operations;
- if (createFilterOperations(value, operations))
- state.style()->setFilter(operations);
- return;
- }
-#endif
- case CSSPropertyWebkitGridAutoColumns: {
- HANDLE_INHERIT_AND_INITIAL(gridAutoColumns, GridAutoColumns);
- GridTrackSize trackSize;
- if (!createGridTrackSize(value, trackSize, state))
- return;
- state.style()->setGridAutoColumns(trackSize);
- return;
- }
- case CSSPropertyWebkitGridAutoRows: {
- HANDLE_INHERIT_AND_INITIAL(gridAutoRows, GridAutoRows);
- GridTrackSize trackSize;
- if (!createGridTrackSize(value, trackSize, state))
- return;
- state.style()->setGridAutoRows(trackSize);
- return;
- }
- case CSSPropertyWebkitGridDefinitionColumns: {
- if (isInherit) {
- m_state.style()->setGridColumns(m_state.parentStyle()->gridColumns());
- m_state.style()->setNamedGridColumnLines(m_state.parentStyle()->namedGridColumnLines());
- return;
+ isUnset = true;
}
- if (isInitial) {
- m_state.style()->setGridColumns(RenderStyle::initialGridColumns());
- m_state.style()->setNamedGridColumnLines(RenderStyle::initialNamedGridColumnLines());
- return;
- }
- Vector<GridTrackSize> trackSizes;
- NamedGridLinesMap namedGridLines;
- if (!createGridTrackList(value, trackSizes, namedGridLines, state))
- return;
- state.style()->setGridColumns(trackSizes);
- state.style()->setNamedGridColumnLines(namedGridLines);
- return;
}
- case CSSPropertyWebkitGridDefinitionRows: {
- if (isInherit) {
- m_state.style()->setGridRows(m_state.parentStyle()->gridRows());
- m_state.style()->setNamedGridRowLines(m_state.parentStyle()->namedGridRowLines());
- return;
- }
- if (isInitial) {
- m_state.style()->setGridRows(RenderStyle::initialGridRows());
- m_state.style()->setNamedGridRowLines(RenderStyle::initialNamedGridRowLines());
- return;
- }
- Vector<GridTrackSize> trackSizes;
- NamedGridLinesMap namedGridLines;
- if (!createGridTrackList(value, trackSizes, namedGridLines, state))
- return;
- state.style()->setGridRows(trackSizes);
- state.style()->setNamedGridRowLines(namedGridLines);
- return;
+
+ if (isUnset) {
+ if (CSSProperty::isInheritedProperty(id))
+ isInherit = true;
+ else
+ isInitial = true;
}
- case CSSPropertyWebkitGridColumnStart: {
- HANDLE_INHERIT_AND_INITIAL(gridItemColumnStart, GridItemColumnStart);
- GridPosition columnStartPosition;
- if (!createGridPosition(value, columnStartPosition))
- return;
- state.style()->setGridItemColumnStart(columnStartPosition);
- return;
- }
- case CSSPropertyWebkitGridColumnEnd: {
- HANDLE_INHERIT_AND_INITIAL(gridItemColumnEnd, GridItemColumnEnd);
- GridPosition columnEndPosition;
- if (!createGridPosition(value, columnEndPosition))
- return;
- state.style()->setGridItemColumnEnd(columnEndPosition);
- return;
- }
+ ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit
- case CSSPropertyWebkitGridRowStart: {
- HANDLE_INHERIT_AND_INITIAL(gridItemRowStart, GridItemRowStart);
- GridPosition rowStartPosition;
- if (!createGridPosition(value, rowStartPosition))
- return;
- state.style()->setGridItemRowStart(rowStartPosition);
- return;
- }
- case CSSPropertyWebkitGridRowEnd: {
- HANDLE_INHERIT_AND_INITIAL(gridItemRowEnd, GridItemRowEnd);
- GridPosition rowEndPosition;
- if (!createGridPosition(value, rowEndPosition))
- return;
- state.style()->setGridItemRowEnd(rowEndPosition);
+ if (!state.applyPropertyToRegularStyle() && (!state.applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) {
+ // Limit the properties that can be applied to only the ones honored by :visited.
return;
}
- case CSSPropertyWebkitGridTemplate: {
- if (isInherit) {
- state.style()->setNamedGridArea(state.parentStyle()->namedGridArea());
- state.style()->setNamedGridAreaRowCount(state.parentStyle()->namedGridAreaRowCount());
- state.style()->setNamedGridAreaColumnCount(state.parentStyle()->namedGridAreaColumnCount());
- return;
- }
- if (isInitial) {
- state.style()->setNamedGridArea(RenderStyle::initialNamedGridArea());
- state.style()->setNamedGridAreaRowCount(RenderStyle::initialNamedGridAreaCount());
- state.style()->setNamedGridAreaColumnCount(RenderStyle::initialNamedGridAreaCount());
- return;
- }
-
- if (value->isPrimitiveValue()) {
- ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
- return;
- }
- CSSGridTemplateValue* gridTemplateValue = toCSSGridTemplateValue(value);
- state.style()->setNamedGridArea(gridTemplateValue->gridAreaMap());
- state.style()->setNamedGridAreaRowCount(gridTemplateValue->rowCount());
- state.style()->setNamedGridAreaColumnCount(gridTemplateValue->columnCount());
+ if (isInherit && !CSSProperty::isInheritedProperty(id))
+ state.style()->setHasExplicitlyInheritedProperties();
+
+ if (customPropertyValue) {
+ auto& name = customPropertyValue->name();
+ auto* value = isInitial ? nullptr : isInherit ? state.parentStyle()->customProperties().get(name) : customPropertyValue;
+ state.style()->setCustomPropertyValue(name, value ? makeRef(*value) : CSSCustomPropertyValue::createInvalid());
return;
}
- // These properties are aliased and DeprecatedStyleBuilder already applied the property on the prefixed version.
- case CSSPropertyTransitionDelay:
- case CSSPropertyTransitionDuration:
- case CSSPropertyTransitionProperty:
- case CSSPropertyTransitionTimingFunction:
- return;
- // These properties are implemented in the DeprecatedStyleBuilder lookup table.
- case CSSPropertyBackgroundAttachment:
- case CSSPropertyBackgroundClip:
- case CSSPropertyBackgroundColor:
- case CSSPropertyBackgroundImage:
- case CSSPropertyBackgroundOrigin:
- case CSSPropertyBackgroundPositionX:
- case CSSPropertyBackgroundPositionY:
- case CSSPropertyBackgroundRepeatX:
- case CSSPropertyBackgroundRepeatY:
- case CSSPropertyBackgroundSize:
- case CSSPropertyBorderBottomColor:
- case CSSPropertyBorderBottomLeftRadius:
- case CSSPropertyBorderBottomRightRadius:
- case CSSPropertyBorderBottomStyle:
- case CSSPropertyBorderBottomWidth:
- case CSSPropertyBorderCollapse:
- case CSSPropertyBorderImageOutset:
- case CSSPropertyBorderImageRepeat:
- case CSSPropertyBorderImageSlice:
- case CSSPropertyBorderImageSource:
- case CSSPropertyBorderImageWidth:
- case CSSPropertyBorderLeftColor:
- case CSSPropertyBorderLeftStyle:
- case CSSPropertyBorderLeftWidth:
- case CSSPropertyBorderRightColor:
- case CSSPropertyBorderRightStyle:
- case CSSPropertyBorderRightWidth:
- case CSSPropertyBorderTopColor:
- case CSSPropertyBorderTopLeftRadius:
- case CSSPropertyBorderTopRightRadius:
- case CSSPropertyBorderTopStyle:
- case CSSPropertyBorderTopWidth:
- case CSSPropertyBottom:
- case CSSPropertyBoxSizing:
- case CSSPropertyCaptionSide:
- case CSSPropertyClear:
- case CSSPropertyClip:
- case CSSPropertyColor:
- case CSSPropertyCounterIncrement:
- case CSSPropertyCounterReset:
- case CSSPropertyCursor:
- case CSSPropertyDirection:
- case CSSPropertyDisplay:
- case CSSPropertyEmptyCells:
- case CSSPropertyFloat:
- case CSSPropertyFontSize:
- case CSSPropertyFontStyle:
- case CSSPropertyFontVariant:
- case CSSPropertyFontWeight:
- case CSSPropertyHeight:
-#if ENABLE(CSS_IMAGE_ORIENTATION)
- case CSSPropertyImageOrientation:
-#endif
- case CSSPropertyImageRendering:
-#if ENABLE(CSS_IMAGE_RESOLUTION)
- case CSSPropertyImageResolution:
-#endif
- case CSSPropertyLeft:
- case CSSPropertyLetterSpacing:
- case CSSPropertyLineHeight:
- case CSSPropertyListStyleImage:
- case CSSPropertyListStylePosition:
- case CSSPropertyListStyleType:
- case CSSPropertyMarginBottom:
- case CSSPropertyMarginLeft:
- case CSSPropertyMarginRight:
- case CSSPropertyMarginTop:
- case CSSPropertyMaxHeight:
- case CSSPropertyMaxWidth:
- case CSSPropertyMinHeight:
- case CSSPropertyMinWidth:
- case CSSPropertyObjectFit:
- case CSSPropertyOpacity:
- case CSSPropertyOrphans:
- case CSSPropertyOutlineColor:
- case CSSPropertyOutlineOffset:
- case CSSPropertyOutlineStyle:
- case CSSPropertyOutlineWidth:
- case CSSPropertyOverflowWrap:
- case CSSPropertyOverflowX:
- case CSSPropertyOverflowY:
- case CSSPropertyPaddingBottom:
- case CSSPropertyPaddingLeft:
- case CSSPropertyPaddingRight:
- case CSSPropertyPaddingTop:
- case CSSPropertyPageBreakAfter:
- case CSSPropertyPageBreakBefore:
- case CSSPropertyPageBreakInside:
- case CSSPropertyPointerEvents:
- case CSSPropertyPosition:
- case CSSPropertyResize:
- case CSSPropertyRight:
- case CSSPropertySize:
- case CSSPropertySpeak:
- case CSSPropertyTabSize:
- case CSSPropertyTableLayout:
- case CSSPropertyTextAlign:
- case CSSPropertyTextDecoration:
- case CSSPropertyTextIndent:
- case CSSPropertyTextOverflow:
- case CSSPropertyTextRendering:
- case CSSPropertyTextTransform:
- case CSSPropertyTop:
- case CSSPropertyUnicodeBidi:
- case CSSPropertyVerticalAlign:
- case CSSPropertyVisibility:
- case CSSPropertyWebkitAnimationDelay:
- case CSSPropertyWebkitAnimationDirection:
- case CSSPropertyWebkitAnimationDuration:
- case CSSPropertyWebkitAnimationFillMode:
- case CSSPropertyWebkitAnimationIterationCount:
- case CSSPropertyWebkitAnimationName:
- case CSSPropertyWebkitAnimationPlayState:
- case CSSPropertyWebkitAnimationTimingFunction:
- case CSSPropertyWebkitAppearance:
- case CSSPropertyWebkitAspectRatio:
- case CSSPropertyWebkitBackfaceVisibility:
- case CSSPropertyWebkitBackgroundClip:
- case CSSPropertyWebkitBackgroundComposite:
- case CSSPropertyWebkitBackgroundOrigin:
- case CSSPropertyWebkitBackgroundSize:
- case CSSPropertyWebkitBorderFit:
- case CSSPropertyWebkitBorderHorizontalSpacing:
- case CSSPropertyWebkitBorderImage:
- case CSSPropertyWebkitBorderVerticalSpacing:
- case CSSPropertyWebkitBoxAlign:
-#if ENABLE(CSS_BOX_DECORATION_BREAK)
- case CSSPropertyWebkitBoxDecorationBreak:
-#endif
- case CSSPropertyWebkitBoxDirection:
- case CSSPropertyWebkitBoxFlex:
- case CSSPropertyWebkitBoxFlexGroup:
- case CSSPropertyWebkitBoxLines:
- case CSSPropertyWebkitBoxOrdinalGroup:
- case CSSPropertyWebkitBoxOrient:
- case CSSPropertyWebkitBoxPack:
- case CSSPropertyWebkitColorCorrection:
- case CSSPropertyWebkitColumnAxis:
- case CSSPropertyWebkitColumnBreakAfter:
- case CSSPropertyWebkitColumnBreakBefore:
- case CSSPropertyWebkitColumnBreakInside:
- case CSSPropertyWebkitColumnCount:
- case CSSPropertyWebkitColumnGap:
- case CSSPropertyWebkitColumnProgression:
- case CSSPropertyWebkitColumnRuleColor:
- case CSSPropertyWebkitColumnRuleStyle:
- case CSSPropertyWebkitColumnRuleWidth:
- case CSSPropertyWebkitColumnSpan:
- case CSSPropertyWebkitColumnWidth:
-#if ENABLE(CURSOR_VISIBILITY)
- case CSSPropertyWebkitCursorVisibility:
-#endif
- case CSSPropertyWebkitAlignContent:
- case CSSPropertyWebkitAlignItems:
- case CSSPropertyWebkitAlignSelf:
- case CSSPropertyWebkitFlexBasis:
- case CSSPropertyWebkitFlexDirection:
- case CSSPropertyWebkitFlexGrow:
- case CSSPropertyWebkitFlexShrink:
- case CSSPropertyWebkitFlexWrap:
- case CSSPropertyWebkitJustifyContent:
- case CSSPropertyWebkitOrder:
-#if ENABLE(CSS_REGIONS)
- case CSSPropertyWebkitFlowFrom:
- case CSSPropertyWebkitFlowInto:
-#endif
- case CSSPropertyWebkitFontKerning:
- case CSSPropertyWebkitFontSmoothing:
- case CSSPropertyWebkitFontVariantLigatures:
- case CSSPropertyWebkitHighlight:
- case CSSPropertyWebkitHyphenateCharacter:
- case CSSPropertyWebkitHyphenateLimitAfter:
- case CSSPropertyWebkitHyphenateLimitBefore:
- case CSSPropertyWebkitHyphenateLimitLines:
- case CSSPropertyWebkitHyphens:
- case CSSPropertyWebkitLineAlign:
- case CSSPropertyWebkitLineBreak:
- case CSSPropertyWebkitLineClamp:
- case CSSPropertyWebkitLineGrid:
- case CSSPropertyWebkitLineSnap:
- case CSSPropertyWebkitMarqueeDirection:
- case CSSPropertyWebkitMarqueeIncrement:
- case CSSPropertyWebkitMarqueeRepetition:
- case CSSPropertyWebkitMarqueeSpeed:
- case CSSPropertyWebkitMarqueeStyle:
- case CSSPropertyWebkitMaskBoxImage:
- case CSSPropertyWebkitMaskBoxImageOutset:
- case CSSPropertyWebkitMaskBoxImageRepeat:
- case CSSPropertyWebkitMaskBoxImageSlice:
- case CSSPropertyWebkitMaskBoxImageSource:
- case CSSPropertyWebkitMaskBoxImageWidth:
- case CSSPropertyWebkitMaskClip:
- case CSSPropertyWebkitMaskComposite:
- case CSSPropertyWebkitMaskImage:
- case CSSPropertyWebkitMaskOrigin:
- case CSSPropertyWebkitMaskPositionX:
- case CSSPropertyWebkitMaskPositionY:
- case CSSPropertyWebkitMaskRepeatX:
- case CSSPropertyWebkitMaskRepeatY:
- case CSSPropertyWebkitMaskSize:
- case CSSPropertyWebkitMaskSourceType:
- case CSSPropertyWebkitNbspMode:
- case CSSPropertyWebkitPerspectiveOrigin:
- case CSSPropertyWebkitPerspectiveOriginX:
- case CSSPropertyWebkitPerspectiveOriginY:
- case CSSPropertyWebkitPrintColorAdjust:
-#if ENABLE(CSS_REGIONS)
- case CSSPropertyWebkitRegionBreakAfter:
- case CSSPropertyWebkitRegionBreakBefore:
- case CSSPropertyWebkitRegionBreakInside:
- case CSSPropertyWebkitRegionFragment:
-#endif
- case CSSPropertyWebkitRtlOrdering:
- case CSSPropertyWebkitRubyPosition:
- case CSSPropertyWebkitTextCombine:
-#if ENABLE(CSS3_TEXT)
- case CSSPropertyWebkitTextAlignLast:
- case CSSPropertyWebkitTextJustify:
-#endif // CSS3_TEXT
- case CSSPropertyWebkitTextDecorationLine:
- case CSSPropertyWebkitTextDecorationStyle:
- case CSSPropertyWebkitTextDecorationColor:
- case CSSPropertyWebkitTextDecorationSkip:
- case CSSPropertyWebkitTextUnderlinePosition:
- case CSSPropertyWebkitTextEmphasisColor:
- case CSSPropertyWebkitTextEmphasisPosition:
- case CSSPropertyWebkitTextEmphasisStyle:
- case CSSPropertyWebkitTextFillColor:
- case CSSPropertyWebkitTextSecurity:
- case CSSPropertyWebkitTextStrokeColor:
- case CSSPropertyWebkitTransformOriginX:
- case CSSPropertyWebkitTransformOriginY:
- case CSSPropertyWebkitTransformOriginZ:
- case CSSPropertyWebkitTransformStyle:
- case CSSPropertyWebkitTransitionDelay:
- case CSSPropertyWebkitTransitionDuration:
- case CSSPropertyWebkitTransitionProperty:
- case CSSPropertyWebkitTransitionTimingFunction:
- case CSSPropertyWebkitUserDrag:
- case CSSPropertyWebkitUserModify:
- case CSSPropertyWebkitUserSelect:
- case CSSPropertyWebkitClipPath:
-#if ENABLE(CSS_SHAPES)
- case CSSPropertyWebkitShapeMargin:
- case CSSPropertyWebkitShapePadding:
- case CSSPropertyWebkitShapeImageThreshold:
- case CSSPropertyWebkitShapeInside:
- case CSSPropertyWebkitShapeOutside:
-#endif
-#if ENABLE(CSS_EXCLUSIONS)
- case CSSPropertyWebkitWrapFlow:
- case CSSPropertyWebkitWrapThrough:
-#endif
- case CSSPropertyWhiteSpace:
- case CSSPropertyWidows:
- case CSSPropertyWidth:
- case CSSPropertyWordBreak:
- case CSSPropertyWordSpacing:
- case CSSPropertyWordWrap:
- case CSSPropertyZIndex:
- case CSSPropertyZoom:
-#if ENABLE(CSS_DEVICE_ADAPTATION)
- case CSSPropertyMaxZoom:
- case CSSPropertyMinZoom:
- case CSSPropertyOrientation:
- case CSSPropertyUserZoom:
-#endif
- ASSERT_NOT_REACHED();
- return;
- default:
-#if ENABLE(SVG)
- // Try the SVG properties
- applySVGProperty(id, value);
-#endif
- return;
- }
+ // Use the generated StyleBuilder.
+ StyleBuilder::applyProperty(id, *this, *valueToApply, isInitial, isInherit);
}
-PassRefPtr<StyleImage> StyleResolver::styleImage(CSSPropertyID property, CSSValue* value)
+RefPtr<CSSValue> StyleResolver::resolvedVariableValue(CSSPropertyID propID, const CSSValue& value)
{
- if (value->isImageValue())
- return cachedOrPendingFromValue(property, toCSSImageValue(value));
-
- if (value->isImageGeneratorValue()) {
- if (value->isGradientValue())
- return generatedOrPendingFromValue(property, *toCSSGradientValue(value)->gradientWithStylesResolved(this));
- return generatedOrPendingFromValue(property, toCSSImageGeneratorValue(*value));
- }
-
-#if ENABLE(CSS_IMAGE_SET)
- if (value->isImageSetValue())
- return setOrPendingFromValue(property, toCSSImageSetValue(value));
-#endif
-
- if (value->isCursorImageValue())
- return cursorOrPendingFromValue(property, toCSSCursorImageValue(value));
-
- return 0;
+ CSSParser parser(m_state.document());
+ return parser.parseValueWithVariableReferences(propID, value, m_state.style()->customProperties(), m_state.style()->direction(), m_state.style()->writingMode());
}
-PassRefPtr<StyleImage> StyleResolver::cachedOrPendingFromValue(CSSPropertyID property, CSSImageValue* value)
+RefPtr<StyleImage> StyleResolver::styleImage(CSSValue& value)
{
- RefPtr<StyleImage> image = value->cachedOrPendingImage();
- if (image && image->isPendingImage())
- m_state.pendingImageProperties().set(property, value);
- return image.release();
-}
+ if (is<CSSImageGeneratorValue>(value)) {
+ if (is<CSSGradientValue>(value))
+ return StyleGeneratedImage::create(downcast<CSSGradientValue>(value).gradientWithStylesResolved(*this));
-PassRefPtr<StyleImage> StyleResolver::generatedOrPendingFromValue(CSSPropertyID property, CSSImageGeneratorValue& value)
-{
-#if ENABLE(CSS_FILTERS)
- if (value.isFilterImageValue()) {
- // FilterImage needs to calculate FilterOperations.
- toCSSFilterImageValue(value).createFilterOperations(this);
- }
-#endif
- if (value.isPending()) {
- m_state.pendingImageProperties().set(property, &value);
- return StylePendingImage::create(&value);
+ if (is<CSSFilterImageValue>(value)) {
+ // FilterImage needs to calculate FilterOperations.
+ downcast<CSSFilterImageValue>(value).createFilterOperations(this);
+ }
+ return StyleGeneratedImage::create(downcast<CSSImageGeneratorValue>(value));
}
- return StyleGeneratedImage::create(value);
-}
-#if ENABLE(CSS_IMAGE_SET)
-PassRefPtr<StyleImage> StyleResolver::setOrPendingFromValue(CSSPropertyID property, CSSImageSetValue* value)
-{
- RefPtr<StyleImage> image = value->cachedOrPendingImageSet(document());
- if (image && image->isPendingImage())
- m_state.pendingImageProperties().set(property, value);
- return image.release();
-}
-#endif
+ if (is<CSSImageValue>(value) || is<CSSImageSetValue>(value) || is<CSSCursorImageValue>(value))
+ return StyleCachedImage::create(value);
-PassRefPtr<StyleImage> StyleResolver::cursorOrPendingFromValue(CSSPropertyID property, CSSCursorImageValue* value)
-{
- RefPtr<StyleImage> image = value->cachedOrPendingImage(document());
- if (image && image->isPendingImage())
- m_state.pendingImageProperties().set(property, value);
- return image.release();
+ return nullptr;
}
-#if ENABLE(IOS_TEXT_AUTOSIZING)
+#if ENABLE(TEXT_AUTOSIZING)
void StyleResolver::checkForTextSizeAdjust(RenderStyle* style)
{
if (style->textSizeAdjust().isAuto())
return;
- FontDescription newFontDescription(style->fontDescription());
+ auto newFontDescription = style->fontDescription();
if (!style->textSizeAdjust().isNone())
newFontDescription.setComputedSize(newFontDescription.specifiedSize() * style->textSizeAdjust().multiplier());
else
@@ -3176,117 +1705,70 @@ void StyleResolver::checkForTextSizeAdjust(RenderStyle* style)
}
#endif
-void StyleResolver::checkForZoomChange(RenderStyle* style, RenderStyle* parentStyle)
+void StyleResolver::checkForZoomChange(RenderStyle* style, const RenderStyle* parentStyle)
{
- if (style->effectiveZoom() == parentStyle->effectiveZoom())
+ if (!parentStyle)
+ return;
+
+ if (style->effectiveZoom() == parentStyle->effectiveZoom() && style->textZoom() == parentStyle->textZoom())
return;
- const FontDescription& childFont = style->fontDescription();
- FontDescription newFontDescription(childFont);
+ const auto& childFont = style->fontDescription();
+ auto newFontDescription = childFont;
setFontSize(newFontDescription, childFont.specifiedSize());
style->setFontDescription(newFontDescription);
}
-void StyleResolver::checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle)
+void StyleResolver::checkForGenericFamilyChange(RenderStyle* style, const RenderStyle* parentStyle)
{
- const FontDescription& childFont = style->fontDescription();
+ const auto& childFont = style->fontDescription();
if (childFont.isAbsoluteSize() || !parentStyle)
return;
- const FontDescription& parentFont = parentStyle->fontDescription();
+ const auto& parentFont = parentStyle->fontDescription();
if (childFont.useFixedDefaultSize() == parentFont.useFixedDefaultSize())
return;
-
- // For now, lump all families but monospace together.
- if (childFont.genericFamily() != FontDescription::MonospaceFamily
- && parentFont.genericFamily() != FontDescription::MonospaceFamily)
- return;
-
// We know the parent is monospace or the child is monospace, and that font
// size was unspecified. We want to scale our font size as appropriate.
// If the font uses a keyword size, then we refetch from the table rather than
// multiplying by our scale factor.
float size;
- if (childFont.keywordSize())
- size = Style::fontSizeForKeyword(CSSValueXxSmall + childFont.keywordSize() - 1, childFont.useFixedDefaultSize(), document());
+ if (CSSValueID sizeIdentifier = childFont.keywordSizeAsIdentifier())
+ size = Style::fontSizeForKeyword(sizeIdentifier, childFont.useFixedDefaultSize(), document());
else {
- Settings* settings = documentSettings();
- float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize())
- ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize()
+ float fixedScaleFactor = (settings().defaultFixedFontSize() && settings().defaultFontSize())
+ ? static_cast<float>(settings().defaultFixedFontSize()) / settings().defaultFontSize()
: 1;
size = parentFont.useFixedDefaultSize() ?
childFont.specifiedSize() / fixedScaleFactor :
childFont.specifiedSize() * fixedScaleFactor;
}
- FontDescription newFontDescription(childFont);
+ auto newFontDescription = childFont;
setFontSize(newFontDescription, size);
style->setFontDescription(newFontDescription);
}
-void StyleResolver::initializeFontStyle(Settings* settings)
+void StyleResolver::initializeFontStyle()
{
- FontDescription fontDescription;
- fontDescription.setGenericFamily(FontDescription::StandardFamily);
- fontDescription.setRenderingMode(settings->fontRenderingMode());
- fontDescription.setUsePrinterFont(document().printing() || !settings->screenFontSubstitutionEnabled());
- const AtomicString& standardFontFamily = documentSettings()->standardFontFamily();
- if (!standardFontFamily.isEmpty())
- fontDescription.setOneFamily(standardFontFamily);
- fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
+ FontCascadeDescription fontDescription;
+ fontDescription.setRenderingMode(settings().fontRenderingMode());
+ fontDescription.setOneFamily(standardFamily);
+ fontDescription.setKeywordSizeFromIdentifier(CSSValueMedium);
setFontSize(fontDescription, Style::fontSizeForKeyword(CSSValueMedium, false, document()));
- m_state.style()->setLineHeight(RenderStyle::initialLineHeight());
- m_state.setLineHeightValue(0);
setFontDescription(fontDescription);
}
-void StyleResolver::setFontSize(FontDescription& fontDescription, float size)
+void StyleResolver::setFontSize(FontCascadeDescription& fontDescription, float size)
{
fontDescription.setSpecifiedSize(size);
fontDescription.setComputedSize(Style::computedFontSizeFromSpecifiedSize(size, fontDescription.isAbsoluteSize(), useSVGZoomRules(), m_state.style(), document()));
}
-static Color colorForCSSValue(CSSValueID cssValueId)
+bool StyleResolver::colorFromPrimitiveValueIsDerivedFromElement(const CSSPrimitiveValue& value)
{
- struct ColorValue {
- CSSValueID cssValueId;
- RGBA32 color;
- };
-
- static const ColorValue colorValues[] = {
- { CSSValueAqua, 0xFF00FFFF },
- { CSSValueBlack, 0xFF000000 },
- { CSSValueBlue, 0xFF0000FF },
- { CSSValueFuchsia, 0xFFFF00FF },
- { CSSValueGray, 0xFF808080 },
- { CSSValueGreen, 0xFF008000 },
- { CSSValueGrey, 0xFF808080 },
- { CSSValueLime, 0xFF00FF00 },
- { CSSValueMaroon, 0xFF800000 },
- { CSSValueNavy, 0xFF000080 },
- { CSSValueOlive, 0xFF808000 },
- { CSSValueOrange, 0xFFFFA500 },
- { CSSValuePurple, 0xFF800080 },
- { CSSValueRed, 0xFFFF0000 },
- { CSSValueSilver, 0xFFC0C0C0 },
- { CSSValueTeal, 0xFF008080 },
- { CSSValueTransparent, 0x00000000 },
- { CSSValueWhite, 0xFFFFFFFF },
- { CSSValueYellow, 0xFFFFFF00 },
- { CSSValueInvalid, CSSValueInvalid }
- };
-
- for (const ColorValue* col = colorValues; col->cssValueId; ++col) {
- if (col->cssValueId == cssValueId)
- return col->color;
- }
- return RenderTheme::defaultTheme()->systemColor(cssValueId);
-}
-
-bool StyleResolver::colorFromPrimitiveValueIsDerivedFromElement(CSSPrimitiveValue* value)
-{
- int ident = value->getValueID();
+ int ident = value.valueID();
switch (ident) {
case CSSValueWebkitText:
case CSSValueWebkitLink:
@@ -3298,13 +1780,13 @@ bool StyleResolver::colorFromPrimitiveValueIsDerivedFromElement(CSSPrimitiveValu
}
}
-Color StyleResolver::colorFromPrimitiveValue(CSSPrimitiveValue* value, bool forVisitedLink) const
+Color StyleResolver::colorFromPrimitiveValue(const CSSPrimitiveValue& value, bool forVisitedLink) const
{
- if (value->isRGBColor())
- return Color(value->getRGBA32Value());
+ if (value.isRGBColor())
+ return value.color();
const State& state = m_state;
- CSSValueID ident = value->getValueID();
+ CSSValueID ident = value.valueID();
switch (ident) {
case 0:
return Color();
@@ -3317,154 +1799,135 @@ Color StyleResolver::colorFromPrimitiveValue(CSSPrimitiveValue* value, bool forV
case CSSValueWebkitFocusRingColor:
return RenderTheme::focusRingColor();
case CSSValueCurrentcolor:
+ // Color is an inherited property so depending on it effectively makes the property inherited.
+ state.style()->setHasExplicitlyInheritedProperties();
return state.style()->color();
- default:
- return colorForCSSValue(ident);
+ default: {
+ return StyleColor::colorFromKeyword(ident);
+ }
+ }
+}
+
+void StyleResolver::addViewportDependentMediaQueryResult(const MediaQueryExpression& expression, bool result)
+{
+ m_viewportDependentMediaQueryResults.append(MediaQueryResult { expression, result });
+}
+
+bool StyleResolver::hasMediaQueriesAffectedByViewportChange() const
+{
+ for (auto& result : m_viewportDependentMediaQueryResults) {
+ if (m_mediaQueryEvaluator.evaluate(result.expression) != result.result)
+ return true;
}
+ return false;
}
-void StyleResolver::addViewportDependentMediaQueryResult(const MediaQueryExp* expr, bool result)
+void StyleResolver::addAccessibilitySettingsDependentMediaQueryResult(const MediaQueryExpression& expression, bool result)
{
- m_viewportDependentMediaQueryResults.append(std::make_unique<MediaQueryResult>(*expr, result));
+ m_accessibilitySettingsDependentMediaQueryResults.append(MediaQueryResult { expression, result });
}
-bool StyleResolver::affectedByViewportChange() const
+bool StyleResolver::hasMediaQueriesAffectedByAccessibilitySettingsChange() const
{
- unsigned s = m_viewportDependentMediaQueryResults.size();
- for (unsigned i = 0; i < s; i++) {
- if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result)
+ for (auto& result : m_accessibilitySettingsDependentMediaQueryResults) {
+ if (m_mediaQueryEvaluator.evaluate(result.expression) != result.result)
return true;
}
return false;
}
-#if ENABLE(CSS_FILTERS)
-static FilterOperation::OperationType filterOperationForType(WebKitCSSFilterValue::FilterOperationType type)
+static FilterOperation::OperationType filterOperationForType(CSSValueID type)
{
switch (type) {
- case WebKitCSSFilterValue::ReferenceFilterOperation:
+ case CSSValueUrl:
return FilterOperation::REFERENCE;
- case WebKitCSSFilterValue::GrayscaleFilterOperation:
+ case CSSValueGrayscale:
return FilterOperation::GRAYSCALE;
- case WebKitCSSFilterValue::SepiaFilterOperation:
+ case CSSValueSepia:
return FilterOperation::SEPIA;
- case WebKitCSSFilterValue::SaturateFilterOperation:
+ case CSSValueSaturate:
return FilterOperation::SATURATE;
- case WebKitCSSFilterValue::HueRotateFilterOperation:
+ case CSSValueHueRotate:
return FilterOperation::HUE_ROTATE;
- case WebKitCSSFilterValue::InvertFilterOperation:
+ case CSSValueInvert:
return FilterOperation::INVERT;
- case WebKitCSSFilterValue::OpacityFilterOperation:
+ case CSSValueOpacity:
return FilterOperation::OPACITY;
- case WebKitCSSFilterValue::BrightnessFilterOperation:
+ case CSSValueBrightness:
return FilterOperation::BRIGHTNESS;
- case WebKitCSSFilterValue::ContrastFilterOperation:
+ case CSSValueContrast:
return FilterOperation::CONTRAST;
- case WebKitCSSFilterValue::BlurFilterOperation:
+ case CSSValueBlur:
return FilterOperation::BLUR;
- case WebKitCSSFilterValue::DropShadowFilterOperation:
+ case CSSValueDropShadow:
return FilterOperation::DROP_SHADOW;
- case WebKitCSSFilterValue::UnknownFilterOperation:
- return FilterOperation::NONE;
+ default:
+ break;
}
+ ASSERT_NOT_REACHED();
return FilterOperation::NONE;
}
-#if ENABLE(CSS_FILTERS) && ENABLE(SVG)
-void StyleResolver::loadPendingSVGDocuments()
-{
- State& state = m_state;
-
- // Crash reports indicate that we've seen calls to this function when our
- // style is NULL. We don't know exactly why this happens. Our guess is
- // reentering styleForElement().
- ASSERT(state.style());
- if (!state.style() || !state.style()->hasFilter() || state.filtersWithPendingSVGDocuments().isEmpty())
- return;
-
- CachedResourceLoader* cachedResourceLoader = state.document().cachedResourceLoader();
- for (auto filterOperation : state.filtersWithPendingSVGDocuments())
- filterOperation->getOrCreateCachedSVGDocumentReference()->load(cachedResourceLoader);
-
- state.filtersWithPendingSVGDocuments().clear();
-}
-#endif
-
-bool StyleResolver::createFilterOperations(CSSValue* inValue, FilterOperations& outOperations)
+bool StyleResolver::createFilterOperations(const CSSValue& inValue, FilterOperations& outOperations)
{
State& state = m_state;
- RenderStyle* style = state.style();
- RenderStyle* rootStyle = state.rootElementStyle();
ASSERT(outOperations.isEmpty());
- if (!inValue)
- return false;
-
- if (inValue->isPrimitiveValue()) {
- CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inValue);
- if (primitiveValue->getValueID() == CSSValueNone)
+ if (is<CSSPrimitiveValue>(inValue)) {
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(inValue);
+ if (primitiveValue.valueID() == CSSValueNone)
return true;
}
- if (!inValue->isValueList())
+ if (!is<CSSValueList>(inValue))
return false;
- float zoomFactor = style ? style->effectiveZoom() : 1;
FilterOperations operations;
- for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) {
- CSSValue* currValue = i.value();
- if (!currValue->isWebKitCSSFilterValue())
- continue;
+ for (auto& currentValue : downcast<CSSValueList>(inValue)) {
- WebKitCSSFilterValue* filterValue = toWebKitCSSFilterValue(i.value());
- FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType());
-
- if (operationType == FilterOperation::REFERENCE) {
-#if ENABLE(SVG)
- if (filterValue->length() != 1)
- continue;
- CSSValue* argument = filterValue->itemWithoutBoundsCheck(0);
-
- if (!argument->isPrimitiveValue())
+ if (is<CSSPrimitiveValue>(currentValue.get())) {
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
+ if (!primitiveValue.isURI())
continue;
- CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(*argument);
- String cssUrl = primitiveValue.getStringValue();
+ String cssUrl = primitiveValue.stringValue();
URL url = m_state.document().completeURL(cssUrl);
- RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(cssUrl, url.fragmentIdentifier(), operationType);
- if (SVGURIReference::isExternalURIReference(cssUrl, m_state.document()))
- state.filtersWithPendingSVGDocuments().append(operation);
-
+ RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(cssUrl, url.fragmentIdentifier());
operations.operations().append(operation);
-#endif
continue;
}
+ if (!is<CSSFunctionValue>(currentValue.get()))
+ continue;
+
+ auto& filterValue = downcast<CSSFunctionValue>(currentValue.get());
+ FilterOperation::OperationType operationType = filterOperationForType(filterValue.name());
+
// Check that all parameters are primitive values, with the
// exception of drop shadow which has a CSSShadowValue parameter.
- CSSPrimitiveValue* firstValue = nullptr;
+ const CSSPrimitiveValue* firstValue = nullptr;
if (operationType != FilterOperation::DROP_SHADOW) {
bool haveNonPrimitiveValue = false;
- for (unsigned j = 0; j < filterValue->length(); ++j) {
- if (!filterValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) {
+ for (unsigned j = 0; j < filterValue.length(); ++j) {
+ if (!is<CSSPrimitiveValue>(*filterValue.itemWithoutBoundsCheck(j))) {
haveNonPrimitiveValue = true;
break;
}
}
if (haveNonPrimitiveValue)
continue;
- if (filterValue->length())
- firstValue = toCSSPrimitiveValue(filterValue->itemWithoutBoundsCheck(0));
+ if (filterValue.length())
+ firstValue = downcast<CSSPrimitiveValue>(filterValue.itemWithoutBoundsCheck(0));
}
- switch (filterValue->operationType()) {
- case WebKitCSSFilterValue::GrayscaleFilterOperation:
- case WebKitCSSFilterValue::SepiaFilterOperation:
- case WebKitCSSFilterValue::SaturateFilterOperation: {
+ switch (operationType) {
+ case FilterOperation::GRAYSCALE:
+ case FilterOperation::SEPIA:
+ case FilterOperation::SATURATE: {
double amount = 1;
- if (filterValue->length() == 1) {
- amount = firstValue->getDoubleValue();
+ if (filterValue.length() == 1) {
+ amount = firstValue->doubleValue();
if (firstValue->isPercentage())
amount /= 100;
}
@@ -3472,21 +1935,21 @@ bool StyleResolver::createFilterOperations(CSSValue* inValue, FilterOperations&
operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType));
break;
}
- case WebKitCSSFilterValue::HueRotateFilterOperation: {
+ case FilterOperation::HUE_ROTATE: {
double angle = 0;
- if (filterValue->length() == 1)
+ if (filterValue.length() == 1)
angle = firstValue->computeDegrees();
operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType));
break;
}
- case WebKitCSSFilterValue::InvertFilterOperation:
- case WebKitCSSFilterValue::BrightnessFilterOperation:
- case WebKitCSSFilterValue::ContrastFilterOperation:
- case WebKitCSSFilterValue::OpacityFilterOperation: {
- double amount = (filterValue->operationType() == WebKitCSSFilterValue::BrightnessFilterOperation) ? 0 : 1;
- if (filterValue->length() == 1) {
- amount = firstValue->getDoubleValue();
+ case FilterOperation::INVERT:
+ case FilterOperation::BRIGHTNESS:
+ case FilterOperation::CONTRAST:
+ case FilterOperation::OPACITY: {
+ double amount = (operationType == FilterOperation::BRIGHTNESS) ? 0 : 1;
+ if (filterValue.length() == 1) {
+ amount = firstValue->doubleValue();
if (firstValue->isPercentage())
amount /= 100;
}
@@ -3494,43 +1957,36 @@ bool StyleResolver::createFilterOperations(CSSValue* inValue, FilterOperations&
operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType));
break;
}
- case WebKitCSSFilterValue::BlurFilterOperation: {
+ case FilterOperation::BLUR: {
Length stdDeviation = Length(0, Fixed);
- if (filterValue->length() >= 1)
- stdDeviation = convertToFloatLength(firstValue, style, rootStyle, zoomFactor);
+ if (filterValue.length() >= 1)
+ stdDeviation = convertToFloatLength(firstValue, state.cssToLengthConversionData());
if (stdDeviation.isUndefined())
return false;
- operations.operations().append(BlurFilterOperation::create(stdDeviation, operationType));
+ operations.operations().append(BlurFilterOperation::create(stdDeviation));
break;
}
- case WebKitCSSFilterValue::DropShadowFilterOperation: {
- if (filterValue->length() != 1)
+ case FilterOperation::DROP_SHADOW: {
+ if (filterValue.length() != 1)
return false;
- CSSValue* cssValue = filterValue->itemWithoutBoundsCheck(0);
- if (!cssValue->isShadowValue())
+ const auto* cssValue = filterValue.itemWithoutBoundsCheck(0);
+ if (!is<CSSShadowValue>(cssValue))
continue;
- CSSShadowValue* item = toCSSShadowValue(cssValue);
- int x = item->x->computeLength<int>(style, rootStyle, zoomFactor);
- if (item->x->isViewportPercentageLength())
- x = viewportPercentageValue(*item->x, x);
- int y = item->y->computeLength<int>(style, rootStyle, zoomFactor);
- if (item->y->isViewportPercentageLength())
- y = viewportPercentageValue(*item->y, y);
+ const auto& item = downcast<CSSShadowValue>(*cssValue);
+ int x = item.x->computeLength<int>(state.cssToLengthConversionData());
+ int y = item.y->computeLength<int>(state.cssToLengthConversionData());
IntPoint location(x, y);
- int blur = item->blur ? item->blur->computeLength<int>(style, rootStyle, zoomFactor) : 0;
- if (item->blur && item->blur->isViewportPercentageLength())
- blur = viewportPercentageValue(*item->blur, blur);
+ int blur = item.blur ? item.blur->computeLength<int>(state.cssToLengthConversionData()) : 0;
Color color;
- if (item->color)
- color = colorFromPrimitiveValue(item->color.get());
+ if (item.color)
+ color = colorFromPrimitiveValue(*item.color);
- operations.operations().append(DropShadowFilterOperation::create(location, blur, color.isValid() ? color : Color::transparent, operationType));
+ operations.operations().append(DropShadowFilterOperation::create(location, blur, color.isValid() ? color : Color::transparent));
break;
}
- case WebKitCSSFilterValue::UnknownFilterOperation:
default:
ASSERT_NOT_REACHED();
break;
@@ -3541,218 +1997,47 @@ bool StyleResolver::createFilterOperations(CSSValue* inValue, FilterOperations&
return true;
}
-#endif
-
-PassRefPtr<StyleImage> StyleResolver::loadPendingImage(StylePendingImage* pendingImage, const ResourceLoaderOptions& options)
-{
- if (auto imageValue = pendingImage->cssImageValue())
- return imageValue->cachedImage(m_state.document().cachedResourceLoader(), options);
-
- if (auto imageGeneratorValue = pendingImage->cssImageGeneratorValue()) {
- imageGeneratorValue->loadSubimages(m_state.document().cachedResourceLoader());
- return StyleGeneratedImage::create(*imageGeneratorValue);
- }
-
- if (auto cursorImageValue = pendingImage->cssCursorImageValue())
- return cursorImageValue->cachedImage(m_state.document().cachedResourceLoader());
-
-#if ENABLE(CSS_IMAGE_SET)
- if (CSSImageSetValue* imageSetValue = pendingImage->cssImageSetValue())
- return imageSetValue->cachedImageSet(m_state.document().cachedResourceLoader(), options);
-#endif
-
- return nullptr;
-}
-
-PassRefPtr<StyleImage> StyleResolver::loadPendingImage(StylePendingImage* pendingImage)
-{
- return loadPendingImage(pendingImage, CachedResourceLoader::defaultCachedResourceOptions());
-}
-
-#if ENABLE(CSS_SHAPES)
-void StyleResolver::loadPendingShapeImage(ShapeValue* shapeValue)
-{
- if (!shapeValue)
- return;
-
- StyleImage* image = shapeValue->image();
- if (!image || !image->isPendingImage())
- return;
-
- StylePendingImage* pendingImage = static_cast<StylePendingImage*>(image);
-
- ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
- options.requestOriginPolicy = PotentiallyCrossOriginEnabled;
- options.allowCredentials = DoNotAllowStoredCredentials;
-
- shapeValue->setImage(loadPendingImage(pendingImage, options));
-}
-#endif
-
-void StyleResolver::loadPendingImages()
+inline StyleResolver::MatchedProperties::MatchedProperties()
{
- if (m_state.pendingImageProperties().isEmpty())
- return;
-
- auto end = m_state.pendingImageProperties().end().keys();
- for (auto it = m_state.pendingImageProperties().begin().keys(); it != end; ++it) {
- CSSPropertyID currentProperty = *it;
-
- switch (currentProperty) {
- case CSSPropertyBackgroundImage: {
- for (FillLayer* backgroundLayer = m_state.style()->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) {
- if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage())
- backgroundLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(backgroundLayer->image())));
- }
- break;
- }
- case CSSPropertyContent: {
- for (ContentData* contentData = const_cast<ContentData*>(m_state.style()->contentData()); contentData; contentData = contentData->next()) {
- if (contentData->isImage()) {
- StyleImage* image = static_cast<ImageContentData*>(contentData)->image();
- if (image->isPendingImage()) {
- RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image));
- if (loadedImage)
- static_cast<ImageContentData*>(contentData)->setImage(loadedImage.release());
- }
- }
- }
- break;
- }
- case CSSPropertyCursor: {
- if (CursorList* cursorList = m_state.style()->cursors()) {
- for (size_t i = 0; i < cursorList->size(); ++i) {
- CursorData& currentCursor = cursorList->at(i);
- if (StyleImage* image = currentCursor.image()) {
- if (image->isPendingImage())
- currentCursor.setImage(loadPendingImage(static_cast<StylePendingImage*>(image)));
- }
- }
- }
- break;
- }
- case CSSPropertyListStyleImage: {
- if (m_state.style()->listStyleImage() && m_state.style()->listStyleImage()->isPendingImage())
- m_state.style()->setListStyleImage(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->listStyleImage())));
- break;
- }
- case CSSPropertyBorderImageSource: {
- if (m_state.style()->borderImageSource() && m_state.style()->borderImageSource()->isPendingImage())
- m_state.style()->setBorderImageSource(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->borderImageSource())));
- break;
- }
- case CSSPropertyWebkitBoxReflect: {
- if (StyleReflection* reflection = m_state.style()->boxReflect()) {
- const NinePieceImage& maskImage = reflection->mask();
- if (maskImage.image() && maskImage.image()->isPendingImage()) {
- RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskImage.image()));
- reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule()));
- }
- }
- break;
- }
- case CSSPropertyWebkitMaskBoxImageSource: {
- if (m_state.style()->maskBoxImageSource() && m_state.style()->maskBoxImageSource()->isPendingImage())
- m_state.style()->setMaskBoxImageSource(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->maskBoxImageSource())));
- break;
- }
- case CSSPropertyWebkitMaskImage: {
- for (FillLayer* maskLayer = m_state.style()->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) {
- if (maskLayer->image() && maskLayer->image()->isPendingImage())
- maskLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(maskLayer->image())));
- }
- break;
- }
-#if ENABLE(CSS_SHAPES)
- case CSSPropertyWebkitShapeInside:
- loadPendingShapeImage(m_state.style()->shapeInside());
- break;
- case CSSPropertyWebkitShapeOutside:
- loadPendingShapeImage(m_state.style()->shapeOutside());
- break;
-#endif
- default:
- ASSERT_NOT_REACHED();
- }
- }
-
- m_state.pendingImageProperties().clear();
}
-#ifndef NDEBUG
-static bool inLoadPendingResources = false;
-#endif
-
-void StyleResolver::loadPendingResources()
+StyleResolver::MatchedProperties::~MatchedProperties()
{
- // We've seen crashes in all three of the functions below. Some of them
- // indicate that style() is NULL. This NULL check will cut down on total
- // crashes, while the ASSERT will help us find the cause in debug builds.
- ASSERT(style());
- if (!style())
- return;
-
-#ifndef NDEBUG
- // Re-entering this function will probably mean trouble. Catch it in debug builds.
- ASSERT(!inLoadPendingResources);
- inLoadPendingResources = true;
-#endif
-
- // Start loading images referenced by this style.
- loadPendingImages();
-
-#if ENABLE(CSS_FILTERS) && ENABLE(SVG)
- // Start loading the SVG Documents referenced by this style.
- loadPendingSVGDocuments();
-#endif
-
-#ifndef NDEBUG
- inLoadPendingResources = false;
-#endif
}
-inline StyleResolver::MatchedProperties::MatchedProperties()
- : possiblyPaddedMember(0)
+StyleResolver::CascadedProperties::CascadedProperties(TextDirection direction, WritingMode writingMode)
+ : m_direction(direction)
+ , m_writingMode(writingMode)
{
}
-inline StyleResolver::MatchedProperties::~MatchedProperties()
+inline bool StyleResolver::CascadedProperties::hasProperty(CSSPropertyID id) const
{
+ ASSERT(id < m_propertyIsPresent.size());
+ return m_propertyIsPresent[id];
}
-int StyleResolver::viewportPercentageValue(CSSPrimitiveValue& unit, int percentage)
+inline StyleResolver::CascadedProperties::Property& StyleResolver::CascadedProperties::property(CSSPropertyID id)
{
- int viewPortHeight = document().renderView()->viewportSize().height() * percentage / 100.0f;
- int viewPortWidth = document().renderView()->viewportSize().width() * percentage / 100.0f;
-
- if (unit.isViewportPercentageHeight())
- return viewPortHeight;
- if (unit.isViewportPercentageWidth())
- return viewPortWidth;
- if (unit.isViewportPercentageMax())
- return std::max(viewPortWidth, viewPortHeight);
- if (unit.isViewportPercentageMin())
- return std::min(viewPortWidth, viewPortHeight);
-
- ASSERT_NOT_REACHED();
- return 0;
+ return m_properties[id];
}
-StyleResolver::CascadedProperties::CascadedProperties(TextDirection direction, WritingMode writingMode)
- : m_direction(direction)
- , m_writingMode(writingMode)
+inline bool StyleResolver::CascadedProperties::hasCustomProperty(const String& name) const
{
+ return m_customProperties.contains(name);
}
-inline StyleResolver::CascadedProperties::Property& StyleResolver::CascadedProperties::property(CSSPropertyID id)
+inline StyleResolver::CascadedProperties::Property StyleResolver::CascadedProperties::customProperty(const String& name) const
{
- return m_properties[id];
+ return m_customProperties.get(name);
}
-void StyleResolver::CascadedProperties::setPropertyInternal(Property& property, CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType)
+void StyleResolver::CascadedProperties::setPropertyInternal(Property& property, CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel, Style::ScopeOrdinal styleScopeOrdinal)
{
ASSERT(linkMatchType <= SelectorChecker::MatchAll);
property.id = id;
+ property.level = cascadeLevel;
+ property.styleScopeOrdinal = styleScopeOrdinal;
if (linkMatchType == SelectorChecker::MatchAll) {
property.cssValue[0] = &cssValue;
property.cssValue[SelectorChecker::MatchLink] = &cssValue;
@@ -3761,7 +2046,7 @@ void StyleResolver::CascadedProperties::setPropertyInternal(Property& property,
property.cssValue[linkMatchType] = &cssValue;
}
-void StyleResolver::CascadedProperties::set(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType)
+void StyleResolver::CascadedProperties::set(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel, Style::ScopeOrdinal styleScopeOrdinal)
{
if (CSSProperty::isDirectionAwareProperty(id))
id = CSSProperty::resolveDirectionAwareProperty(id, m_direction, m_writingMode);
@@ -3769,35 +2054,67 @@ void StyleResolver::CascadedProperties::set(CSSPropertyID id, CSSValue& cssValue
ASSERT(!shouldApplyPropertyInParseOrder(id));
auto& property = m_properties[id];
- if (!m_propertyIsPresent.test(id))
+ ASSERT(id < m_propertyIsPresent.size());
+ if (id == CSSPropertyCustom) {
+ m_propertyIsPresent.set(id);
+ const auto& customValue = downcast<CSSCustomPropertyValue>(cssValue);
+ bool hasValue = customProperties().contains(customValue.name());
+ if (!hasValue) {
+ Property property;
+ property.id = id;
+ memset(property.cssValue, 0, sizeof(property.cssValue));
+ setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
+ customProperties().set(customValue.name(), property);
+ } else {
+ Property property = customProperties().get(customValue.name());
+ setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
+ customProperties().set(customValue.name(), property);
+ }
+ return;
+ }
+
+ if (!m_propertyIsPresent[id])
memset(property.cssValue, 0, sizeof(property.cssValue));
m_propertyIsPresent.set(id);
- setPropertyInternal(property, id, cssValue, linkMatchType);
+ setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
}
-void StyleResolver::CascadedProperties::setDeferred(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType)
+void StyleResolver::CascadedProperties::setDeferred(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel, Style::ScopeOrdinal styleScopeOrdinal)
{
ASSERT(!CSSProperty::isDirectionAwareProperty(id));
ASSERT(shouldApplyPropertyInParseOrder(id));
Property property;
memset(property.cssValue, 0, sizeof(property.cssValue));
- setPropertyInternal(property, id, cssValue, linkMatchType);
+ setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
m_deferredProperties.append(property);
}
-bool StyleResolver::CascadedProperties::addStyleProperties(const StyleProperties& properties, StyleRule&, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType, unsigned linkMatchType)
+static CascadeLevel cascadeLevelForIndex(const StyleResolver::MatchResult& matchResult, int index)
{
- for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
- auto current = properties.propertyAt(i);
+ if (index >= matchResult.ranges.firstUARule && index <= matchResult.ranges.lastUARule)
+ return UserAgentLevel;
+ if (index >= matchResult.ranges.firstUserRule && index <= matchResult.ranges.lastUserRule)
+ return UserLevel;
+ return AuthorLevel;
+}
+
+void StyleResolver::CascadedProperties::addMatch(const MatchResult& matchResult, unsigned index, bool isImportant, bool inheritedOnly)
+{
+ auto& matchedProperties = matchResult.matchedProperties()[index];
+ auto& styleProperties = *matchedProperties.properties;
+
+ auto propertyWhitelistType = static_cast<PropertyWhitelistType>(matchedProperties.whitelistType);
+ auto cascadeLevel = cascadeLevelForIndex(matchResult, index);
+
+ for (unsigned i = 0, count = styleProperties.propertyCount(); i < count; ++i) {
+ auto current = styleProperties.propertyAt(i);
if (isImportant != current.isImportant())
continue;
if (inheritedOnly && !current.isInherited()) {
- // If the property value is explicitly inherited, we need to apply further non-inherited properties
- // as they might override the value inherited here. For this reason we don't allow declarations with
- // explicitly inherited properties to be cached.
- if (current.value()->isInheritedValue())
- return false;
+ // We apply the inherited properties only when using the property cache.
+ // A match with a value that is explicitely inherited should never have been cached.
+ ASSERT(!current.value()->isInheritedValue());
continue;
}
CSSPropertyID propertyID = current.id();
@@ -3810,47 +2127,84 @@ bool StyleResolver::CascadedProperties::addStyleProperties(const StyleProperties
#endif
if (shouldApplyPropertyInParseOrder(propertyID))
- setDeferred(propertyID, *current.value(), linkMatchType);
+ setDeferred(propertyID, *current.value(), matchedProperties.linkMatchType, cascadeLevel, matchedProperties.styleScopeOrdinal);
else
- set(propertyID, *current.value(), linkMatchType);
+ set(propertyID, *current.value(), matchedProperties.linkMatchType, cascadeLevel, matchedProperties.styleScopeOrdinal);
}
- return true;
}
-bool StyleResolver::CascadedProperties::addMatches(const MatchResult& matchResult, bool important, int startIndex, int endIndex, bool inheritedOnly)
+void StyleResolver::CascadedProperties::addNormalMatches(const MatchResult& matchResult, int startIndex, int endIndex, bool inheritedOnly)
{
if (startIndex == -1)
- return true;
+ return;
+
+ for (int i = startIndex; i <= endIndex; ++i)
+ addMatch(matchResult, i, false, inheritedOnly);
+}
+
+static bool hasImportantProperties(const StyleProperties& properties)
+{
+ for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
+ if (properties.propertyAt(i).isImportant())
+ return true;
+ }
+ return false;
+}
+
+void StyleResolver::CascadedProperties::addImportantMatches(const MatchResult& matchResult, int startIndex, int endIndex, bool inheritedOnly)
+{
+ if (startIndex == -1)
+ return;
+
+ struct IndexAndOrdinal {
+ int index;
+ Style::ScopeOrdinal ordinal;
+ };
+ Vector<IndexAndOrdinal> shadowTreeMatches;
for (int i = startIndex; i <= endIndex; ++i) {
- const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
- if (!addStyleProperties(*matchedProperties.properties, *matchResult.matchedRules[i], important, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType), matchedProperties.linkMatchType))
- return false;
+ const MatchedProperties& matchedProperties = matchResult.matchedProperties()[i];
+
+ if (!hasImportantProperties(*matchedProperties.properties))
+ continue;
+
+ if (matchedProperties.styleScopeOrdinal != Style::ScopeOrdinal::Element) {
+ shadowTreeMatches.append({ i, matchedProperties.styleScopeOrdinal });
+ continue;
+ }
+
+ addMatch(matchResult, i, true, inheritedOnly);
}
- return true;
+
+ if (shadowTreeMatches.isEmpty())
+ return;
+
+ // For !important properties a later shadow tree wins.
+ // Match results are sorted in reverse tree context order so this is not needed for normal properties.
+ std::stable_sort(shadowTreeMatches.begin(), shadowTreeMatches.end(), [] (const IndexAndOrdinal& a, const IndexAndOrdinal& b) {
+ return a.ordinal < b.ordinal;
+ });
+
+ for (auto& match : shadowTreeMatches)
+ addMatch(matchResult, match.index, true, inheritedOnly);
}
-void StyleResolver::CascadedProperties::applyDeferredProperties(StyleResolver& resolver)
+void StyleResolver::CascadedProperties::applyDeferredProperties(StyleResolver& resolver, const MatchResult* matchResult)
{
for (auto& property : m_deferredProperties)
- property.apply(resolver);
+ property.apply(resolver, matchResult);
}
-void StyleResolver::CascadedProperties::Property::apply(StyleResolver& resolver)
+void StyleResolver::CascadedProperties::Property::apply(StyleResolver& resolver, const MatchResult* matchResult)
{
State& state = resolver.state();
+ state.setCascadeLevel(level);
+ state.setStyleScopeOrdinal(styleScopeOrdinal);
- // FIXME: It would be nice if line-height were less of a special snowflake.
- if (id == CSSPropertyLineHeight) {
- if (auto value = state.style()->insideLink() == NotInsideLink ? cssValue[0] : cssValue[SelectorChecker::MatchLink])
- state.setLineHeightValue(value);
- return;
- }
-
- if (cssValue[0]) {
+ if (cssValue[SelectorChecker::MatchDefault]) {
state.setApplyPropertyToRegularStyle(true);
state.setApplyPropertyToVisitedLinkStyle(false);
- resolver.applyProperty(id, cssValue[0]);
+ resolver.applyProperty(id, cssValue[SelectorChecker::MatchDefault], SelectorChecker::MatchDefault, matchResult);
}
if (state.style()->insideLink() == NotInsideLink)
@@ -3859,29 +2213,38 @@ void StyleResolver::CascadedProperties::Property::apply(StyleResolver& resolver)
if (cssValue[SelectorChecker::MatchLink]) {
state.setApplyPropertyToRegularStyle(true);
state.setApplyPropertyToVisitedLinkStyle(false);
- resolver.applyProperty(id, cssValue[SelectorChecker::MatchLink]);
+ resolver.applyProperty(id, cssValue[SelectorChecker::MatchLink], SelectorChecker::MatchLink, matchResult);
}
if (cssValue[SelectorChecker::MatchVisited]) {
state.setApplyPropertyToRegularStyle(false);
state.setApplyPropertyToVisitedLinkStyle(true);
- resolver.applyProperty(id, cssValue[SelectorChecker::MatchVisited]);
+ resolver.applyProperty(id, cssValue[SelectorChecker::MatchVisited], SelectorChecker::MatchVisited, matchResult);
}
state.setApplyPropertyToRegularStyle(true);
state.setApplyPropertyToVisitedLinkStyle(false);
}
-void StyleResolver::applyCascadedProperties(CascadedProperties& cascade, int firstProperty, int lastProperty)
+void StyleResolver::applyCascadedProperties(CascadedProperties& cascade, int firstProperty, int lastProperty, const MatchResult* matchResult)
{
for (int id = firstProperty; id <= lastProperty; ++id) {
CSSPropertyID propertyID = static_cast<CSSPropertyID>(id);
if (!cascade.hasProperty(propertyID))
continue;
+ if (propertyID == CSSPropertyCustom) {
+ HashMap<AtomicString, CascadedProperties::Property>::iterator end = cascade.customProperties().end();
+ for (HashMap<AtomicString, CascadedProperties::Property>::iterator it = cascade.customProperties().begin(); it != end; ++it)
+ it->value.apply(*this, matchResult);
+ continue;
+ }
auto& property = cascade.property(propertyID);
ASSERT(!shouldApplyPropertyInParseOrder(propertyID));
- property.apply(*this);
+ property.apply(*this, matchResult);
}
+
+ if (firstProperty == CSSPropertyCustom)
+ m_state.style()->checkVariablesInCustomProperties();
}
} // namespace WebCore