diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/css/StyleResolver.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/css/StyleResolver.cpp')
-rw-r--r-- | Source/WebCore/css/StyleResolver.cpp | 3457 |
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 |