/* * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) * Copyright (C) 2004-2017 Apple Inc. All rights reserved. * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "config.h" #include "RenderStyle.h" #include "ContentData.h" #include "CSSCustomPropertyValue.h" #include "CSSParser.h" #include "CSSPropertyNames.h" #include "CursorList.h" #include "FloatRoundedRect.h" #include "FontCascade.h" #include "FontSelector.h" #include "InlineTextBoxStyle.h" #include "Pagination.h" #include "QuotesData.h" #include "RenderObject.h" #include "RenderTheme.h" #include "RuntimeEnabledFeatures.h" #include "ScaleTransformOperation.h" #include "ShadowData.h" #include "StyleImage.h" #include "StyleInheritedData.h" #include "StyleResolver.h" #include "StyleScrollSnapPoints.h" #include "StyleSelfAlignmentData.h" #include "StyleTreeResolver.h" #include "WillChangeData.h" #include #include #include #include #if ENABLE(TEXT_AUTOSIZING) #include #endif namespace WebCore { struct SameSizeAsBorderValue { float m_width; Color m_color; int m_restBits; }; COMPILE_ASSERT(sizeof(BorderValue) == sizeof(SameSizeAsBorderValue), BorderValue_should_not_grow); struct SameSizeAsRenderStyle { void* dataRefs[7]; void* ownPtrs[1]; void* dataRefSvgStyle; struct InheritedFlags { unsigned m_bitfields[2]; } m_inheritedFlags; struct NonInheritedFlags { uint64_t m_flags; } m_nonInheritedFlags; #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) bool deletionCheck; #endif }; COMPILE_ASSERT(sizeof(RenderStyle) == sizeof(SameSizeAsRenderStyle), RenderStyle_should_stay_small); RenderStyle& RenderStyle::defaultStyle() { static NeverDestroyed style { CreateDefaultStyle }; return style; } RenderStyle RenderStyle::create() { return clone(defaultStyle()); } std::unique_ptr RenderStyle::createPtr() { return clonePtr(defaultStyle()); } RenderStyle RenderStyle::clone(const RenderStyle& style) { return RenderStyle(style, Clone); } std::unique_ptr RenderStyle::clonePtr(const RenderStyle& style) { return std::make_unique(style, Clone); } RenderStyle RenderStyle::createAnonymousStyleWithDisplay(const RenderStyle& parentStyle, EDisplay display) { auto newStyle = create(); newStyle.inheritFrom(parentStyle); newStyle.inheritUnicodeBidiFrom(&parentStyle); newStyle.setDisplay(display); return newStyle; } RenderStyle RenderStyle::createStyleInheritingFromPseudoStyle(const RenderStyle& pseudoStyle) { ASSERT(pseudoStyle.styleType() == BEFORE || pseudoStyle.styleType() == AFTER); auto style = create(); style.inheritFrom(pseudoStyle); return style; } RenderStyle::RenderStyle(CreateDefaultStyleTag) : m_boxData(StyleBoxData::create()) , m_visualData(StyleVisualData::create()) , m_backgroundData(StyleBackgroundData::create()) , m_surroundData(StyleSurroundData::create()) , m_rareNonInheritedData(StyleRareNonInheritedData::create()) , m_rareInheritedData(StyleRareInheritedData::create()) , m_inheritedData(StyleInheritedData::create()) , m_svgStyle(SVGRenderStyle::create()) { m_inheritedFlags.emptyCells = initialEmptyCells(); m_inheritedFlags.captionSide = initialCaptionSide(); m_inheritedFlags.listStyleType = initialListStyleType(); m_inheritedFlags.listStylePosition = initialListStylePosition(); m_inheritedFlags.visibility = initialVisibility(); m_inheritedFlags.textAlign = initialTextAlign(); m_inheritedFlags.textTransform = initialTextTransform(); m_inheritedFlags.textDecorations = initialTextDecoration(); m_inheritedFlags.cursor = initialCursor(); #if ENABLE(CURSOR_VISIBILITY) m_inheritedFlags.cursorVisibility = initialCursorVisibility(); #endif m_inheritedFlags.direction = initialDirection(); m_inheritedFlags.whiteSpace = initialWhiteSpace(); m_inheritedFlags.borderCollapse = initialBorderCollapse(); m_inheritedFlags.rtlOrdering = initialRTLOrdering(); m_inheritedFlags.boxDirection = initialBoxDirection(); m_inheritedFlags.printColorAdjust = initialPrintColorAdjust(); m_inheritedFlags.pointerEvents = initialPointerEvents(); m_inheritedFlags.insideLink = NotInsideLink; m_inheritedFlags.insideDefaultButton = false; m_inheritedFlags.writingMode = initialWritingMode(); static_assert((sizeof(InheritedFlags) <= 8), "InheritedFlags does not grow"); static_assert((sizeof(NonInheritedFlags) <= 8), "NonInheritedFlags does not grow"); } inline RenderStyle::RenderStyle(const RenderStyle& other, CloneTag) : m_boxData(other.m_boxData) , m_visualData(other.m_visualData) , m_backgroundData(other.m_backgroundData) , m_surroundData(other.m_surroundData) , m_rareNonInheritedData(other.m_rareNonInheritedData) , m_nonInheritedFlags(other.m_nonInheritedFlags) , m_rareInheritedData(other.m_rareInheritedData) , m_inheritedData(other.m_inheritedData) , m_inheritedFlags(other.m_inheritedFlags) , m_svgStyle(other.m_svgStyle) { } inline RenderStyle::RenderStyle(RenderStyle& a, RenderStyle&& b) : m_boxData(a.m_boxData.replace(WTFMove(b.m_boxData))) , m_visualData(a.m_visualData.replace(WTFMove(b.m_visualData))) , m_backgroundData(a.m_backgroundData.replace(WTFMove(b.m_backgroundData))) , m_surroundData(a.m_surroundData.replace(WTFMove(b.m_surroundData))) , m_rareNonInheritedData(a.m_rareNonInheritedData.replace(WTFMove(b.m_rareNonInheritedData))) , m_nonInheritedFlags(std::exchange(a.m_nonInheritedFlags, b.m_nonInheritedFlags)) , m_rareInheritedData(a.m_rareInheritedData.replace(WTFMove(b.m_rareInheritedData))) , m_inheritedData(a.m_inheritedData.replace(WTFMove(b.m_inheritedData))) , m_inheritedFlags(std::exchange(a.m_inheritedFlags, b.m_inheritedFlags)) , m_cachedPseudoStyles(std::exchange(a.m_cachedPseudoStyles, WTFMove(b.m_cachedPseudoStyles))) , m_svgStyle(a.m_svgStyle.replace(WTFMove(b.m_svgStyle))) { } RenderStyle::~RenderStyle() { #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun); m_deletionHasBegun = true; #endif } RenderStyle RenderStyle::replace(RenderStyle&& newStyle) { return RenderStyle { *this, WTFMove(newStyle) }; } bool RenderStyle::isCSSGridLayoutEnabled() { return RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled(); } static StyleSelfAlignmentData resolvedSelfAlignment(const StyleSelfAlignmentData& value, ItemPosition normalValueBehavior) { ASSERT(value.position() != ItemPositionAuto); if (value.position() == ItemPositionNormal) return { normalValueBehavior, OverflowAlignmentDefault }; return value; } StyleSelfAlignmentData RenderStyle::resolvedAlignItems(ItemPosition normalValueBehaviour) const { return resolvedSelfAlignment(alignItems(), normalValueBehaviour); } StyleSelfAlignmentData RenderStyle::resolvedAlignSelf(const RenderStyle& parentStyle, ItemPosition normalValueBehaviour) const { // The auto keyword computes to the parent's align-items computed value. // We will return the behaviour of 'normal' value if needed, which is specific of each layout model. if (alignSelf().position() == ItemPositionAuto) return parentStyle.resolvedAlignItems(normalValueBehaviour); return resolvedSelfAlignment(alignSelf(), normalValueBehaviour); } StyleSelfAlignmentData RenderStyle::resolvedJustifyItems(ItemPosition normalValueBehaviour) const { // FIXME: justify-items 'auto' value is allowed only to provide the 'legacy' keyword's behavior, which it's still not implemented for layout. // "If the inherited value of justify-items includes the legacy keyword, auto computes to the inherited value." // https://drafts.csswg.org/css-align/#justify-items-property if (justifyItems().position() == ItemPositionAuto) return { normalValueBehaviour, OverflowAlignmentDefault }; return resolvedSelfAlignment(justifyItems(), normalValueBehaviour); } StyleSelfAlignmentData RenderStyle::resolvedJustifySelf(const RenderStyle& parentStyle, ItemPosition normalValueBehaviour) const { // The auto keyword computes to the parent's justify-items computed value. // We will return the behaviour of 'normal' value if needed, which is specific of each layout model. if (justifySelf().position() == ItemPositionAuto) return parentStyle.resolvedJustifyItems(normalValueBehaviour); return resolvedSelfAlignment(justifySelf(), normalValueBehaviour); } static inline ContentPosition resolvedContentAlignmentPosition(const StyleContentAlignmentData& value, const StyleContentAlignmentData& normalValueBehavior) { return (value.position() == ContentPositionNormal && value.distribution() == ContentDistributionDefault) ? normalValueBehavior.position() : value.position(); } static inline ContentDistributionType resolvedContentAlignmentDistribution(const StyleContentAlignmentData& value, const StyleContentAlignmentData& normalValueBehavior) { return (value.position() == ContentPositionNormal && value.distribution() == ContentDistributionDefault) ? normalValueBehavior.distribution() : value.distribution(); } ContentPosition RenderStyle::resolvedJustifyContentPosition(const StyleContentAlignmentData& normalValueBehavior) const { return resolvedContentAlignmentPosition(justifyContent(), normalValueBehavior); } ContentDistributionType RenderStyle::resolvedJustifyContentDistribution(const StyleContentAlignmentData& normalValueBehavior) const { return resolvedContentAlignmentDistribution(justifyContent(), normalValueBehavior); } ContentPosition RenderStyle::resolvedAlignContentPosition(const StyleContentAlignmentData& normalValueBehavior) const { return resolvedContentAlignmentPosition(alignContent(), normalValueBehavior); } ContentDistributionType RenderStyle::resolvedAlignContentDistribution(const StyleContentAlignmentData& normalValueBehavior) const { return resolvedContentAlignmentDistribution(alignContent(), normalValueBehavior); } void RenderStyle::inheritFrom(const RenderStyle& inheritParent) { m_rareInheritedData = inheritParent.m_rareInheritedData; m_inheritedData = inheritParent.m_inheritedData; m_inheritedFlags = inheritParent.m_inheritedFlags; if (m_svgStyle != inheritParent.m_svgStyle) m_svgStyle.access().inheritFrom(inheritParent.m_svgStyle.get()); } void RenderStyle::copyNonInheritedFrom(const RenderStyle& other) { m_boxData = other.m_boxData; m_visualData = other.m_visualData; m_backgroundData = other.m_backgroundData; m_surroundData = other.m_surroundData; m_rareNonInheritedData = other.m_rareNonInheritedData; m_nonInheritedFlags.copyNonInheritedFrom(other.m_nonInheritedFlags); if (m_svgStyle != other.m_svgStyle) m_svgStyle.access().copyNonInheritedFrom(other.m_svgStyle.get()); ASSERT(zoom() == initialZoom()); } bool RenderStyle::operator==(const RenderStyle& other) const { // compare everything except the pseudoStyle pointer return m_inheritedFlags == other.m_inheritedFlags && m_nonInheritedFlags == other.m_nonInheritedFlags && m_boxData == other.m_boxData && m_visualData == other.m_visualData && m_backgroundData == other.m_backgroundData && m_surroundData == other.m_surroundData && m_rareNonInheritedData == other.m_rareNonInheritedData && m_rareInheritedData == other.m_rareInheritedData && m_inheritedData == other.m_inheritedData && m_svgStyle == other.m_svgStyle; } bool RenderStyle::hasUniquePseudoStyle() const { if (!m_cachedPseudoStyles || styleType() != NOPSEUDO) return false; for (auto& pseudoStyle : *m_cachedPseudoStyles) { if (pseudoStyle->unique()) return true; } return false; } RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const { if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size()) return nullptr; if (styleType() != NOPSEUDO) return nullptr; for (auto& pseudoStyle : *m_cachedPseudoStyles) { if (pseudoStyle->styleType() == pid) return pseudoStyle.get(); } return nullptr; } RenderStyle* RenderStyle::addCachedPseudoStyle(std::unique_ptr pseudo) { if (!pseudo) return nullptr; ASSERT(pseudo->styleType() > NOPSEUDO); RenderStyle* result = pseudo.get(); if (!m_cachedPseudoStyles) m_cachedPseudoStyles = std::make_unique(); m_cachedPseudoStyles->append(WTFMove(pseudo)); return result; } void RenderStyle::removeCachedPseudoStyle(PseudoId pid) { if (!m_cachedPseudoStyles) return; for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) { RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get(); if (pseudoStyle->styleType() == pid) { m_cachedPseudoStyles->remove(i); return; } } } bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const { return m_inheritedFlags != other->m_inheritedFlags || m_inheritedData != other->m_inheritedData || m_svgStyle->inheritedNotEqual(other->m_svgStyle) || m_rareInheritedData != other->m_rareInheritedData; } #if ENABLE(TEXT_AUTOSIZING) static inline unsigned computeFontHash(const FontCascade& font) { IntegerHasher hasher; hasher.add(ASCIICaseInsensitiveHash::hash(font.fontDescription().firstFamily())); hasher.add(font.fontDescription().specifiedSize()); return hasher.hash(); } unsigned RenderStyle::hashForTextAutosizing() const { // FIXME: Not a very smart hash. Could be improved upon. See . unsigned hash = m_rareNonInheritedData->appearance; hash ^= m_rareNonInheritedData->marginBeforeCollapse; hash ^= m_rareNonInheritedData->marginAfterCollapse; hash ^= m_rareNonInheritedData->lineClamp.value(); hash ^= m_rareInheritedData->overflowWrap; hash ^= m_rareInheritedData->nbspMode; hash ^= m_rareInheritedData->lineBreak; hash ^= WTF::FloatHash::hash(m_inheritedData->specifiedLineHeight.value()); hash ^= computeFontHash(m_inheritedData->fontCascade); hash ^= WTF::FloatHash::hash(m_inheritedData->horizontalBorderSpacing); hash ^= WTF::FloatHash::hash(m_inheritedData->verticalBorderSpacing); hash ^= m_inheritedFlags.boxDirection; hash ^= m_inheritedFlags.rtlOrdering; hash ^= m_nonInheritedFlags.position(); hash ^= m_nonInheritedFlags.floating(); hash ^= m_rareNonInheritedData->textOverflow; hash ^= m_rareInheritedData->textSecurity; return hash; } bool RenderStyle::equalForTextAutosizing(const RenderStyle& other) const { return m_rareNonInheritedData->appearance == other.m_rareNonInheritedData->appearance && m_rareNonInheritedData->marginBeforeCollapse == other.m_rareNonInheritedData->marginBeforeCollapse && m_rareNonInheritedData->marginAfterCollapse == other.m_rareNonInheritedData->marginAfterCollapse && m_rareNonInheritedData->lineClamp == other.m_rareNonInheritedData->lineClamp && m_rareInheritedData->textSizeAdjust == other.m_rareInheritedData->textSizeAdjust && m_rareInheritedData->overflowWrap == other.m_rareInheritedData->overflowWrap && m_rareInheritedData->nbspMode == other.m_rareInheritedData->nbspMode && m_rareInheritedData->lineBreak == other.m_rareInheritedData->lineBreak && m_rareInheritedData->textSecurity == other.m_rareInheritedData->textSecurity && m_inheritedData->specifiedLineHeight == other.m_inheritedData->specifiedLineHeight && m_inheritedData->fontCascade.equalForTextAutoSizing(other.m_inheritedData->fontCascade) && m_inheritedData->horizontalBorderSpacing == other.m_inheritedData->horizontalBorderSpacing && m_inheritedData->verticalBorderSpacing == other.m_inheritedData->verticalBorderSpacing && m_inheritedFlags.boxDirection == other.m_inheritedFlags.boxDirection && m_inheritedFlags.rtlOrdering == other.m_inheritedFlags.rtlOrdering && m_nonInheritedFlags.position() == other.m_nonInheritedFlags.position() && m_nonInheritedFlags.floating() == other.m_nonInheritedFlags.floating() && m_rareNonInheritedData->textOverflow == other.m_rareNonInheritedData->textOverflow; } #endif // ENABLE(TEXT_AUTOSIZING) bool RenderStyle::inheritedDataShared(const RenderStyle* other) const { // This is a fast check that only looks if the data structures are shared. return m_inheritedFlags == other->m_inheritedFlags && m_inheritedData.get() == other->m_inheritedData.get() && m_svgStyle.get() == other->m_svgStyle.get() && m_rareInheritedData.get() == other->m_rareInheritedData.get(); } static bool positionChangeIsMovementOnly(const LengthBox& a, const LengthBox& b, const Length& width) { // If any unit types are different, then we can't guarantee // that this was just a movement. if (a.left().type() != b.left().type() || a.right().type() != b.right().type() || a.top().type() != b.top().type() || a.bottom().type() != b.bottom().type()) return false; // Only one unit can be non-auto in the horizontal direction and // in the vertical direction. Otherwise the adjustment of values // is changing the size of the box. if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto()) return false; if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto()) return false; // If our width is auto and left or right is specified then this // is not just a movement - we need to resize to our container. if ((!a.left().isIntrinsicOrAuto() || !a.right().isIntrinsicOrAuto()) && width.isIntrinsicOrAuto()) return false; // One of the units is fixed or percent in both directions and stayed // that way in the new style. Therefore all we are doing is moving. return true; } inline bool RenderStyle::changeAffectsVisualOverflow(const RenderStyle& other) const { if (m_rareNonInheritedData.get() != other.m_rareNonInheritedData.get() && !arePointingToEqualData(m_rareNonInheritedData->boxShadow, other.m_rareNonInheritedData->boxShadow)) return true; if (m_rareInheritedData.get() != other.m_rareInheritedData.get() && !arePointingToEqualData(m_rareInheritedData->textShadow, other.m_rareInheritedData->textShadow)) return true; if (m_inheritedFlags.textDecorations != other.m_inheritedFlags.textDecorations || m_visualData->textDecoration != other.m_visualData->textDecoration || m_rareNonInheritedData->textDecorationStyle != other.m_rareNonInheritedData->textDecorationStyle) { // Underlines are always drawn outside of their textbox bounds when text-underline-position: under; // is specified. We can take an early out here. if (textUnderlinePosition() == TextUnderlinePositionUnder || other.textUnderlinePosition() == TextUnderlinePositionUnder) return true; return visualOverflowForDecorations(*this, nullptr) != visualOverflowForDecorations(other, nullptr); } if (hasOutlineInVisualOverflow() != other.hasOutlineInVisualOverflow()) return true; return false; } bool RenderStyle::changeRequiresLayout(const RenderStyle& other, unsigned& changedContextSensitiveProperties) const { if (m_boxData->width() != other.m_boxData->width() || m_boxData->minWidth() != other.m_boxData->minWidth() || m_boxData->maxWidth() != other.m_boxData->maxWidth() || m_boxData->height() != other.m_boxData->height() || m_boxData->minHeight() != other.m_boxData->minHeight() || m_boxData->maxHeight() != other.m_boxData->maxHeight()) return true; if (m_boxData->verticalAlign() != other.m_boxData->verticalAlign() || m_nonInheritedFlags.verticalAlign() != other.m_nonInheritedFlags.verticalAlign()) return true; if (m_boxData->boxSizing() != other.m_boxData->boxSizing()) return true; if (m_surroundData->margin != other.m_surroundData->margin) return true; if (m_surroundData->padding != other.m_surroundData->padding) return true; // FIXME: We should add an optimized form of layout that just recomputes visual overflow. if (changeAffectsVisualOverflow(other)) return true; if (m_rareNonInheritedData.get() != other.m_rareNonInheritedData.get()) { if (m_rareNonInheritedData->appearance != other.m_rareNonInheritedData->appearance || m_rareNonInheritedData->marginBeforeCollapse != other.m_rareNonInheritedData->marginBeforeCollapse || m_rareNonInheritedData->marginAfterCollapse != other.m_rareNonInheritedData->marginAfterCollapse || m_rareNonInheritedData->lineClamp != other.m_rareNonInheritedData->lineClamp || m_rareNonInheritedData->initialLetter != other.m_rareNonInheritedData->initialLetter || m_rareNonInheritedData->textOverflow != other.m_rareNonInheritedData->textOverflow) return true; if (m_rareNonInheritedData->regionFragment != other.m_rareNonInheritedData->regionFragment) return true; if (m_rareNonInheritedData->shapeMargin != other.m_rareNonInheritedData->shapeMargin) return true; if (m_rareNonInheritedData->deprecatedFlexibleBox != other.m_rareNonInheritedData->deprecatedFlexibleBox) return true; if (m_rareNonInheritedData->flexibleBox != other.m_rareNonInheritedData->flexibleBox) return true; if (m_rareNonInheritedData->order != other.m_rareNonInheritedData->order || m_rareNonInheritedData->alignContent != other.m_rareNonInheritedData->alignContent || m_rareNonInheritedData->alignItems != other.m_rareNonInheritedData->alignItems || m_rareNonInheritedData->alignSelf != other.m_rareNonInheritedData->alignSelf || m_rareNonInheritedData->justifyContent != other.m_rareNonInheritedData->justifyContent || m_rareNonInheritedData->justifyItems != other.m_rareNonInheritedData->justifyItems || m_rareNonInheritedData->justifySelf != other.m_rareNonInheritedData->justifySelf) return true; if (!arePointingToEqualData(m_rareNonInheritedData->boxReflect, other.m_rareNonInheritedData->boxReflect)) return true; if (m_rareNonInheritedData->multiCol != other.m_rareNonInheritedData->multiCol) return true; if (m_rareNonInheritedData->transform != other.m_rareNonInheritedData->transform) { if (m_rareNonInheritedData->transform->hasTransform() != other.m_rareNonInheritedData->transform->hasTransform()) return true; if (*m_rareNonInheritedData->transform != *other.m_rareNonInheritedData->transform) { changedContextSensitiveProperties |= ContextSensitivePropertyTransform; // Don't return; keep looking for another change } } if (m_rareNonInheritedData->grid != other.m_rareNonInheritedData->grid || m_rareNonInheritedData->gridItem != other.m_rareNonInheritedData->gridItem) return true; #if ENABLE(DASHBOARD_SUPPORT) // If regions change, trigger a relayout to re-calc regions. if (m_rareNonInheritedData->dashboardRegions != other.m_rareNonInheritedData->dashboardRegions) return true; #endif if (!arePointingToEqualData(m_rareNonInheritedData->willChange, other.m_rareNonInheritedData->willChange)) { changedContextSensitiveProperties |= ContextSensitivePropertyWillChange; // Don't return; keep looking for another change } } if (m_rareInheritedData.get() != other.m_rareInheritedData.get()) { if (m_rareInheritedData->indent != other.m_rareInheritedData->indent #if ENABLE(CSS3_TEXT) || m_rareInheritedData->textAlignLast != other.m_rareInheritedData->textAlignLast || m_rareInheritedData->textJustify != other.m_rareInheritedData->textJustify || m_rareInheritedData->textIndentLine != other.m_rareInheritedData->textIndentLine #endif || m_rareInheritedData->effectiveZoom != other.m_rareInheritedData->effectiveZoom || m_rareInheritedData->textZoom != other.m_rareInheritedData->textZoom #if ENABLE(TEXT_AUTOSIZING) || m_rareInheritedData->textSizeAdjust != other.m_rareInheritedData->textSizeAdjust #endif || m_rareInheritedData->wordBreak != other.m_rareInheritedData->wordBreak || m_rareInheritedData->overflowWrap != other.m_rareInheritedData->overflowWrap || m_rareInheritedData->nbspMode != other.m_rareInheritedData->nbspMode || m_rareInheritedData->lineBreak != other.m_rareInheritedData->lineBreak || m_rareInheritedData->textSecurity != other.m_rareInheritedData->textSecurity || m_rareInheritedData->hyphens != other.m_rareInheritedData->hyphens || m_rareInheritedData->hyphenationLimitBefore != other.m_rareInheritedData->hyphenationLimitBefore || m_rareInheritedData->hyphenationLimitAfter != other.m_rareInheritedData->hyphenationLimitAfter || m_rareInheritedData->hyphenationString != other.m_rareInheritedData->hyphenationString || m_rareInheritedData->rubyPosition != other.m_rareInheritedData->rubyPosition || m_rareInheritedData->textEmphasisMark != other.m_rareInheritedData->textEmphasisMark || m_rareInheritedData->textEmphasisPosition != other.m_rareInheritedData->textEmphasisPosition || m_rareInheritedData->textEmphasisCustomMark != other.m_rareInheritedData->textEmphasisCustomMark || m_rareInheritedData->textOrientation != other.m_rareInheritedData->textOrientation || m_rareInheritedData->tabSize != other.m_rareInheritedData->tabSize || m_rareInheritedData->lineBoxContain != other.m_rareInheritedData->lineBoxContain || m_rareInheritedData->lineGrid != other.m_rareInheritedData->lineGrid #if ENABLE(CSS_IMAGE_ORIENTATION) || m_rareInheritedData->imageOrientation != other.m_rareInheritedData->imageOrientation #endif #if ENABLE(CSS_IMAGE_RESOLUTION) || m_rareInheritedData->imageResolutionSource != other.m_rareInheritedData->imageResolutionSource || m_rareInheritedData->imageResolutionSnap != other.m_rareInheritedData->imageResolutionSnap || m_rareInheritedData->imageResolution != other.m_rareInheritedData->imageResolution #endif || m_rareInheritedData->lineSnap != other.m_rareInheritedData->lineSnap || m_rareInheritedData->lineAlign != other.m_rareInheritedData->lineAlign || m_rareInheritedData->hangingPunctuation != other.m_rareInheritedData->hangingPunctuation #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) || m_rareInheritedData->useTouchOverflowScrolling != other.m_rareInheritedData->useTouchOverflowScrolling #endif || m_rareInheritedData->listStyleImage != other.m_rareInheritedData->listStyleImage) // FIXME: needs arePointingToEqualData()? return true; if (textStrokeWidth() != other.textStrokeWidth()) return true; } if (m_inheritedData->lineHeight != other.m_inheritedData->lineHeight #if ENABLE(TEXT_AUTOSIZING) || m_inheritedData->specifiedLineHeight != other.m_inheritedData->specifiedLineHeight #endif || m_inheritedData->fontCascade != other.m_inheritedData->fontCascade || m_inheritedData->horizontalBorderSpacing != other.m_inheritedData->horizontalBorderSpacing || m_inheritedData->verticalBorderSpacing != other.m_inheritedData->verticalBorderSpacing || m_inheritedFlags.boxDirection != other.m_inheritedFlags.boxDirection || m_inheritedFlags.rtlOrdering != other.m_inheritedFlags.rtlOrdering || m_nonInheritedFlags.position() != other.m_nonInheritedFlags.position() || m_nonInheritedFlags.floating() != other.m_nonInheritedFlags.floating() || m_nonInheritedFlags.originalDisplay() != other.m_nonInheritedFlags.originalDisplay()) return true; if ((m_nonInheritedFlags.effectiveDisplay()) >= TABLE) { if (m_inheritedFlags.borderCollapse != other.m_inheritedFlags.borderCollapse || m_inheritedFlags.emptyCells != other.m_inheritedFlags.emptyCells || m_inheritedFlags.captionSide != other.m_inheritedFlags.captionSide || m_nonInheritedFlags.tableLayout() != other.m_nonInheritedFlags.tableLayout()) return true; // In the collapsing border model, 'hidden' suppresses other borders, while 'none' // does not, so these style differences can be width differences. if (m_inheritedFlags.borderCollapse && ((borderTopStyle() == BHIDDEN && other.borderTopStyle() == BNONE) || (borderTopStyle() == BNONE && other.borderTopStyle() == BHIDDEN) || (borderBottomStyle() == BHIDDEN && other.borderBottomStyle() == BNONE) || (borderBottomStyle() == BNONE && other.borderBottomStyle() == BHIDDEN) || (borderLeftStyle() == BHIDDEN && other.borderLeftStyle() == BNONE) || (borderLeftStyle() == BNONE && other.borderLeftStyle() == BHIDDEN) || (borderRightStyle() == BHIDDEN && other.borderRightStyle() == BNONE) || (borderRightStyle() == BNONE && other.borderRightStyle() == BHIDDEN))) return true; } if (m_nonInheritedFlags.effectiveDisplay() == LIST_ITEM) { if (m_inheritedFlags.listStyleType != other.m_inheritedFlags.listStyleType || m_inheritedFlags.listStylePosition != other.m_inheritedFlags.listStylePosition) return true; } if (m_inheritedFlags.textAlign != other.m_inheritedFlags.textAlign || m_inheritedFlags.textTransform != other.m_inheritedFlags.textTransform || m_inheritedFlags.direction != other.m_inheritedFlags.direction || m_inheritedFlags.whiteSpace != other.m_inheritedFlags.whiteSpace || m_nonInheritedFlags.clear() != other.m_nonInheritedFlags.clear() || m_nonInheritedFlags.unicodeBidi() != other.m_nonInheritedFlags.unicodeBidi()) return true; // Check block flow direction. if (m_inheritedFlags.writingMode != other.m_inheritedFlags.writingMode) return true; // Check text combine mode. if (m_rareNonInheritedData->textCombine != other.m_rareNonInheritedData->textCombine) return true; // Check breaks. if (m_rareNonInheritedData->breakBefore != other.m_rareNonInheritedData->breakBefore || m_rareNonInheritedData->breakAfter != other.m_rareNonInheritedData->breakAfter || m_rareNonInheritedData->breakInside != other.m_rareNonInheritedData->breakInside) return true; // Overflow returns a layout hint. if (m_nonInheritedFlags.overflowX() != other.m_nonInheritedFlags.overflowX() || m_nonInheritedFlags.overflowY() != other.m_nonInheritedFlags.overflowY()) return true; // If our border widths change, then we need to layout. Other changes to borders // only necessitate a repaint. if (borderLeftWidth() != other.borderLeftWidth() || borderTopWidth() != other.borderTopWidth() || borderBottomWidth() != other.borderBottomWidth() || borderRightWidth() != other.borderRightWidth()) return true; // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree. if (!arePointingToEqualData(m_rareNonInheritedData->counterDirectives, other.m_rareNonInheritedData->counterDirectives)) return true; if ((visibility() == COLLAPSE) != (other.visibility() == COLLAPSE)) return true; if (m_rareNonInheritedData->hasOpacity() != other.m_rareNonInheritedData->hasOpacity()) { // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet. // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). // In addition we need to solve the floating object issue when layers come and go. Right now // a full layout is necessary to keep floating object lists sane. return true; } if (m_rareNonInheritedData->hasFilters() != other.m_rareNonInheritedData->hasFilters()) return true; #if ENABLE(FILTERS_LEVEL_2) if (m_rareNonInheritedData->hasBackdropFilters() != other.m_rareNonInheritedData->hasBackdropFilters()) return true; #endif if (!arePointingToEqualData(m_rareInheritedData->quotes, other.m_rareInheritedData->quotes)) return true; if (position() != StaticPosition) { if (m_surroundData->offset != other.m_surroundData->offset) { // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet. // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). if (position() != AbsolutePosition) return true; // Optimize for the case where a positioned layer is moving but not changing size. if (!positionChangeIsMovementOnly(m_surroundData->offset, other.m_surroundData->offset, m_boxData->width())) return true; } } bool hasFirstLineStyle = hasPseudoStyle(FIRST_LINE); if (hasFirstLineStyle != other.hasPseudoStyle(FIRST_LINE)) return true; if (hasFirstLineStyle) { auto* firstLineStyle = getCachedPseudoStyle(FIRST_LINE); if (!firstLineStyle) return true; auto* otherFirstLineStyle = other.getCachedPseudoStyle(FIRST_LINE); if (!otherFirstLineStyle) return true; // FIXME: Not all first line style changes actually need layout. if (*firstLineStyle != *otherFirstLineStyle) return true; } return false; } bool RenderStyle::changeRequiresPositionedLayoutOnly(const RenderStyle& other, unsigned&) const { if (position() == StaticPosition) return false; if (m_surroundData->offset != other.m_surroundData->offset) { // Optimize for the case where a positioned layer is moving but not changing size. if (position() == AbsolutePosition && positionChangeIsMovementOnly(m_surroundData->offset, other.m_surroundData->offset, m_boxData->width())) return true; } return false; } bool RenderStyle::changeRequiresLayerRepaint(const RenderStyle& other, unsigned& changedContextSensitiveProperties) const { // StyleResolver has ensured that zIndex is non-auto only if it's applicable. if (m_boxData->zIndex() != other.m_boxData->zIndex() || m_boxData->hasAutoZIndex() != other.m_boxData->hasAutoZIndex()) return true; if (position() != StaticPosition) { if (m_visualData->clip != other.m_visualData->clip || m_visualData->hasClip != other.m_visualData->hasClip) { changedContextSensitiveProperties |= ContextSensitivePropertyClipRect; return true; } } #if ENABLE(CSS_COMPOSITING) if (m_rareNonInheritedData->effectiveBlendMode != other.m_rareNonInheritedData->effectiveBlendMode) return true; #endif if (m_rareNonInheritedData->opacity != other.m_rareNonInheritedData->opacity) { changedContextSensitiveProperties |= ContextSensitivePropertyOpacity; // Don't return; keep looking for another change. } if (m_rareNonInheritedData->filter != other.m_rareNonInheritedData->filter) { changedContextSensitiveProperties |= ContextSensitivePropertyFilter; // Don't return; keep looking for another change. } #if ENABLE(FILTERS_LEVEL_2) if (m_rareNonInheritedData->backdropFilter != other.m_rareNonInheritedData->backdropFilter) { changedContextSensitiveProperties |= ContextSensitivePropertyFilter; // Don't return; keep looking for another change. } #endif if (m_rareNonInheritedData->mask != other.m_rareNonInheritedData->mask || m_rareNonInheritedData->maskBoxImage != other.m_rareNonInheritedData->maskBoxImage) return true; return false; } static bool requiresPainting(const RenderStyle& style) { if (style.visibility() == HIDDEN) return false; if (!style.opacity()) return false; return true; } bool RenderStyle::changeRequiresRepaint(const RenderStyle& other, unsigned& changedContextSensitiveProperties) const { if (!requiresPainting(*this) && !requiresPainting(other)) return false; if (m_inheritedFlags.visibility != other.m_inheritedFlags.visibility || m_inheritedFlags.printColorAdjust != other.m_inheritedFlags.printColorAdjust || m_inheritedFlags.insideLink != other.m_inheritedFlags.insideLink || m_inheritedFlags.insideDefaultButton != other.m_inheritedFlags.insideDefaultButton || m_surroundData->border != other.m_surroundData->border || !m_backgroundData->isEquivalentForPainting(*other.m_backgroundData) || m_rareInheritedData->userModify != other.m_rareInheritedData->userModify || m_rareInheritedData->userSelect != other.m_rareInheritedData->userSelect || m_rareNonInheritedData->userDrag != other.m_rareNonInheritedData->userDrag || m_rareNonInheritedData->borderFit != other.m_rareNonInheritedData->borderFit || m_rareNonInheritedData->objectFit != other.m_rareNonInheritedData->objectFit || m_rareNonInheritedData->objectPosition != other.m_rareNonInheritedData->objectPosition || m_rareInheritedData->imageRendering != other.m_rareInheritedData->imageRendering) return true; if (m_rareNonInheritedData->shapeOutside != other.m_rareNonInheritedData->shapeOutside) return true; // FIXME: this should probably be moved to changeRequiresLayerRepaint(). if (m_rareNonInheritedData->clipPath != other.m_rareNonInheritedData->clipPath) { changedContextSensitiveProperties |= ContextSensitivePropertyClipPath; // Don't return; keep looking for another change. } return false; } bool RenderStyle::changeRequiresRepaintIfTextOrBorderOrOutline(const RenderStyle& other, unsigned&) const { if (m_inheritedData->color != other.m_inheritedData->color || m_inheritedFlags.textDecorations != other.m_inheritedFlags.textDecorations || m_visualData->textDecoration != other.m_visualData->textDecoration || m_rareNonInheritedData->textDecorationStyle != other.m_rareNonInheritedData->textDecorationStyle || m_rareNonInheritedData->textDecorationColor != other.m_rareNonInheritedData->textDecorationColor || m_rareInheritedData->textDecorationSkip != other.m_rareInheritedData->textDecorationSkip || m_rareInheritedData->textFillColor != other.m_rareInheritedData->textFillColor || m_rareInheritedData->textStrokeColor != other.m_rareInheritedData->textStrokeColor || m_rareInheritedData->textEmphasisColor != other.m_rareInheritedData->textEmphasisColor || m_rareInheritedData->textEmphasisFill != other.m_rareInheritedData->textEmphasisFill) return true; return false; } bool RenderStyle::changeRequiresRecompositeLayer(const RenderStyle& other, unsigned&) const { if (m_rareNonInheritedData.get() != other.m_rareNonInheritedData.get()) { if (m_rareNonInheritedData->transformStyle3D != other.m_rareNonInheritedData->transformStyle3D || m_rareNonInheritedData->backfaceVisibility != other.m_rareNonInheritedData->backfaceVisibility || m_rareNonInheritedData->perspective != other.m_rareNonInheritedData->perspective || m_rareNonInheritedData->perspectiveOriginX != other.m_rareNonInheritedData->perspectiveOriginX || m_rareNonInheritedData->perspectiveOriginY != other.m_rareNonInheritedData->perspectiveOriginY) return true; } return false; } StyleDifference RenderStyle::diff(const RenderStyle& other, unsigned& changedContextSensitiveProperties) const { changedContextSensitiveProperties = ContextSensitivePropertyNone; StyleDifference svgChange = StyleDifferenceEqual; if (m_svgStyle != other.m_svgStyle) { svgChange = m_svgStyle->diff(other.m_svgStyle.get()); if (svgChange == StyleDifferenceLayout) return svgChange; } // These properties affect the cached stroke bounding box rects. if (m_rareInheritedData->capStyle != other.m_rareInheritedData->capStyle || m_rareInheritedData->joinStyle != other.m_rareInheritedData->joinStyle || m_rareInheritedData->strokeWidth != other.m_rareInheritedData->strokeWidth) return StyleDifferenceLayout; if (changeRequiresLayout(other, changedContextSensitiveProperties)) return StyleDifferenceLayout; // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes. // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint, // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches // that are relevant for SVG and might return StyleDifferenceLayout. if (svgChange != StyleDifferenceEqual) return svgChange; if (changeRequiresPositionedLayoutOnly(other, changedContextSensitiveProperties)) return StyleDifferenceLayoutPositionedMovementOnly; if (changeRequiresLayerRepaint(other, changedContextSensitiveProperties)) return StyleDifferenceRepaintLayer; if (changeRequiresRepaint(other, changedContextSensitiveProperties)) return StyleDifferenceRepaint; if (changeRequiresRecompositeLayer(other, changedContextSensitiveProperties)) return StyleDifferenceRecompositeLayer; if (changeRequiresRepaintIfTextOrBorderOrOutline(other, changedContextSensitiveProperties)) return StyleDifferenceRepaintIfTextOrBorderOrOutline; // Cursors are not checked, since they will be set appropriately in response to mouse events, // so they don't need to cause any repaint or layout. // Animations don't need to be checked either. We always set the new style on the RenderObject, so we will get a chance to fire off // the resulting transition properly. return StyleDifferenceEqual; } bool RenderStyle::diffRequiresLayerRepaint(const RenderStyle& style, bool isComposited) const { unsigned changedContextSensitiveProperties = 0; if (changeRequiresRepaint(style, changedContextSensitiveProperties)) return true; if (isComposited && changeRequiresLayerRepaint(style, changedContextSensitiveProperties)) return changedContextSensitiveProperties & ContextSensitivePropertyClipRect; return false; } void RenderStyle::setClip(Length&& top, Length&& right, Length&& bottom, Length&& left) { auto& data = m_visualData.access(); data.clip.top() = WTFMove(top); data.clip.right() = WTFMove(right); data.clip.bottom() = WTFMove(bottom); data.clip.left() = WTFMove(left); } void RenderStyle::addCursor(RefPtr&& image, const IntPoint& hotSpot) { auto& cursorData = m_rareInheritedData.access().cursorData; if (!cursorData) cursorData = CursorList::create(); cursorData->append(CursorData(WTFMove(image), hotSpot)); } void RenderStyle::setCursorList(RefPtr&& list) { m_rareInheritedData.access().cursorData = WTFMove(list); } void RenderStyle::setQuotes(RefPtr&& q) { if (m_rareInheritedData->quotes == q || (m_rareInheritedData->quotes && q && *m_rareInheritedData->quotes == *q)) return; m_rareInheritedData.access().quotes = WTFMove(q); } void RenderStyle::setWillChange(RefPtr&& willChangeData) { if (arePointingToEqualData(m_rareNonInheritedData->willChange.get(), willChangeData.get())) return; m_rareNonInheritedData.access().willChange = WTFMove(willChangeData); } void RenderStyle::clearCursorList() { if (m_rareInheritedData->cursorData) m_rareInheritedData.access().cursorData = nullptr; } void RenderStyle::clearContent() { if (m_rareNonInheritedData->content) m_rareNonInheritedData.access().content = nullptr; } static inline ContentData& lastContent(ContentData& firstContent) { auto* lastContent = &firstContent; for (auto* content = &firstContent; content; content = content->next()) lastContent = content; return *lastContent; } void RenderStyle::setContent(std::unique_ptr contentData, bool add) { auto& data = m_rareNonInheritedData.access(); if (add && data.content) lastContent(*data.content).setNext(WTFMove(contentData)); else { data.content = WTFMove(contentData); auto& altText = data.altText; if (!altText.isNull()) data.content->setAltText(altText); } } void RenderStyle::setContent(RefPtr&& image, bool add) { if (!image) return; setContent(std::make_unique(image.releaseNonNull()), add); } void RenderStyle::setContent(const String& string, bool add) { auto& data = m_rareNonInheritedData.access(); if (add && data.content) { auto& last = lastContent(*data.content); if (!is(last)) last.setNext(std::make_unique(string)); else { auto& textContent = downcast(last); textContent.setText(textContent.text() + string); } } else { data.content = std::make_unique(string); auto& altText = data.altText; if (!altText.isNull()) data.content->setAltText(altText); } } void RenderStyle::setContent(std::unique_ptr counter, bool add) { if (!counter) return; setContent(std::make_unique(WTFMove(counter)), add); } void RenderStyle::setContent(QuoteType quote, bool add) { setContent(std::make_unique(quote), add); } void RenderStyle::setContentAltText(const String& string) { auto& data = m_rareNonInheritedData.access(); data.altText = string; if (data.content) data.content->setAltText(string); } const String& RenderStyle::contentAltText() const { return m_rareNonInheritedData->altText; } void RenderStyle::setHasAttrContent() { setUnique(); SET_VAR(m_rareNonInheritedData, hasAttrContent, true); } static inline bool requireTransformOrigin(const Vector>& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin) { // The transform-origin property brackets the transform with translate operations. // When the only transform is a translation, the transform-origin is irrelevant. if (applyOrigin != RenderStyle::IncludeTransformOrigin) return false; for (auto& operation : transformOperations) { // FIXME: Use affectedByTransformOrigin(). auto type = operation->type(); if (type != TransformOperation::TRANSLATE && type != TransformOperation::TRANSLATE_3D && type != TransformOperation::TRANSLATE_X && type != TransformOperation::TRANSLATE_Y && type != TransformOperation::TRANSLATE_Z) return true; } return false; } void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const { auto& operations = m_rareNonInheritedData->transform->operations.operations(); bool applyTransformOrigin = requireTransformOrigin(operations, applyOrigin); float offsetX = transformOriginX().isPercent() ? boundingBox.x() : 0; float offsetY = transformOriginY().isPercent() ? boundingBox.y() : 0; if (applyTransformOrigin) { transform.translate3d(floatValueForLength(transformOriginX(), boundingBox.width()) + offsetX, floatValueForLength(transformOriginY(), boundingBox.height()) + offsetY, transformOriginZ()); } for (auto& operation : operations) operation->apply(transform, boundingBox.size()); if (applyTransformOrigin) { transform.translate3d(-floatValueForLength(transformOriginX(), boundingBox.width()) - offsetX, -floatValueForLength(transformOriginY(), boundingBox.height()) - offsetY, -transformOriginZ()); } } void RenderStyle::setPageScaleTransform(float scale) { if (scale == 1) return; TransformOperations transform; transform.operations().append(ScaleTransformOperation::create(scale, scale, ScaleTransformOperation::SCALE)); setTransform(transform); setTransformOriginX(Length(0, Fixed)); setTransformOriginY(Length(0, Fixed)); } void RenderStyle::setTextShadow(std::unique_ptr shadowData, bool add) { ASSERT(!shadowData || (!shadowData->spread() && shadowData->style() == Normal)); auto& rareData = m_rareInheritedData.access(); if (!add) { rareData.textShadow = WTFMove(shadowData); return; } shadowData->setNext(WTFMove(rareData.textShadow)); rareData.textShadow = WTFMove(shadowData); } void RenderStyle::setBoxShadow(std::unique_ptr shadowData, bool add) { auto& rareData = m_rareNonInheritedData.access(); if (!add) { rareData.boxShadow = WTFMove(shadowData); return; } shadowData->setNext(WTFMove(rareData.boxShadow)); rareData.boxShadow = WTFMove(shadowData); } static RoundedRect::Radii calcRadiiFor(const BorderData& border, const LayoutSize& size) { return { sizeForLengthSize(border.topLeft(), size), sizeForLengthSize(border.topRight(), size), sizeForLengthSize(border.bottomLeft(), size), sizeForLengthSize(border.bottomRight(), size) }; } StyleImage* RenderStyle::listStyleImage() const { return m_rareInheritedData->listStyleImage.get(); } void RenderStyle::setListStyleImage(RefPtr&& v) { if (m_rareInheritedData->listStyleImage != v) m_rareInheritedData.access().listStyleImage = WTFMove(v); } const Color& RenderStyle::color() const { return m_inheritedData->color; } const Color& RenderStyle::visitedLinkColor() const { return m_inheritedData->visitedLinkColor; } void RenderStyle::setColor(const Color& v) { SET_VAR(m_inheritedData, color, v); } void RenderStyle::setVisitedLinkColor(const Color& v) { SET_VAR(m_inheritedData, visitedLinkColor, v); } float RenderStyle::horizontalBorderSpacing() const { return m_inheritedData->horizontalBorderSpacing; } float RenderStyle::verticalBorderSpacing() const { return m_inheritedData->verticalBorderSpacing; } void RenderStyle::setHorizontalBorderSpacing(float v) { SET_VAR(m_inheritedData, horizontalBorderSpacing, v); } void RenderStyle::setVerticalBorderSpacing(float v) { SET_VAR(m_inheritedData, verticalBorderSpacing, v); } RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { RoundedRect roundedRect(borderRect); if (hasBorderRadius()) { RoundedRect::Radii radii = calcRadiiFor(m_surroundData->border, borderRect.size()); radii.scale(calcBorderRadiiConstraintScaleFor(borderRect, radii)); roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); } return roundedRect; } RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { bool horizontal = isHorizontalWritingMode(); auto leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0; auto rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0; auto topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0; auto bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0; return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge); } RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, LayoutUnit topWidth, LayoutUnit bottomWidth, LayoutUnit leftWidth, LayoutUnit rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { RoundedRect roundedRect { { borderRect.x() + leftWidth, borderRect.y() + topWidth, borderRect.width() - leftWidth - rightWidth, borderRect.height() - topWidth - bottomWidth } }; if (hasBorderRadius()) { auto radii = getRoundedBorderFor(borderRect).radii(); radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth); roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); } return roundedRect; } static bool allLayersAreFixed(const FillLayer& layers) { for (auto* layer = &layers; layer; layer = layer->next()) { if (!(layer->image() && layer->attachment() == FixedBackgroundAttachment)) return false; } return true; } bool RenderStyle::hasEntirelyFixedBackground() const { return allLayersAreFixed(backgroundLayers()); } const CounterDirectiveMap* RenderStyle::counterDirectives() const { return m_rareNonInheritedData->counterDirectives.get(); } CounterDirectiveMap& RenderStyle::accessCounterDirectives() { auto& map = m_rareNonInheritedData.access().counterDirectives; if (!map) map = std::make_unique(); return *map; } const CounterDirectives RenderStyle::getCounterDirectives(const AtomicString& identifier) const { if (const CounterDirectiveMap* directives = counterDirectives()) return directives->get(identifier); return CounterDirectives(); } const AtomicString& RenderStyle::hyphenString() const { ASSERT(hyphens() != HyphensNone); auto& hyphenationString = m_rareInheritedData->hyphenationString; if (!hyphenationString.isNull()) return hyphenationString; // FIXME: This should depend on locale. static NeverDestroyed hyphenMinusString(&hyphenMinus, 1); static NeverDestroyed hyphenString(&hyphen, 1); return fontCascade().primaryFont().glyphForCharacter(hyphen) ? hyphenString : hyphenMinusString; } const AtomicString& RenderStyle::textEmphasisMarkString() const { switch (textEmphasisMark()) { case TextEmphasisMarkNone: return nullAtom; case TextEmphasisMarkCustom: return textEmphasisCustomMark(); case TextEmphasisMarkDot: { static NeverDestroyed filledDotString(&bullet, 1); static NeverDestroyed openDotString(&whiteBullet, 1); return textEmphasisFill() == TextEmphasisFillFilled ? filledDotString : openDotString; } case TextEmphasisMarkCircle: { static NeverDestroyed filledCircleString(&blackCircle, 1); static NeverDestroyed openCircleString(&whiteCircle, 1); return textEmphasisFill() == TextEmphasisFillFilled ? filledCircleString : openCircleString; } case TextEmphasisMarkDoubleCircle: { static NeverDestroyed filledDoubleCircleString(&fisheye, 1); static NeverDestroyed openDoubleCircleString(&bullseye, 1); return textEmphasisFill() == TextEmphasisFillFilled ? filledDoubleCircleString : openDoubleCircleString; } case TextEmphasisMarkTriangle: { static NeverDestroyed filledTriangleString(&blackUpPointingTriangle, 1); static NeverDestroyed openTriangleString(&whiteUpPointingTriangle, 1); return textEmphasisFill() == TextEmphasisFillFilled ? filledTriangleString : openTriangleString; } case TextEmphasisMarkSesame: { static NeverDestroyed filledSesameString(&sesameDot, 1); static NeverDestroyed openSesameString(&whiteSesameDot, 1); return textEmphasisFill() == TextEmphasisFillFilled ? filledSesameString : openSesameString; } case TextEmphasisMarkAuto: ASSERT_NOT_REACHED(); return nullAtom; } ASSERT_NOT_REACHED(); return nullAtom; } #if ENABLE(DASHBOARD_SUPPORT) const Vector& RenderStyle::initialDashboardRegions() { static NeverDestroyed> emptyList; return emptyList; } const Vector& RenderStyle::noneDashboardRegions() { static NeverDestroyed> noneList; static bool noneListInitialized = false; if (!noneListInitialized) { noneList.get().append(StyleDashboardRegion { emptyString(), { }, StyleDashboardRegion::None }); noneListInitialized = true; } return noneList; } #endif void RenderStyle::adjustAnimations() { auto* animationList = m_rareNonInheritedData->animations.get(); if (!animationList) return; // Get rid of empty animations and anything beyond them for (size_t i = 0, size = animationList->size(); i < size; ++i) { if (animationList->animation(i).isEmpty()) { animationList->resize(i); break; } } if (animationList->isEmpty()) { clearAnimations(); return; } // Repeat patterns into layers that don't have some properties set. animationList->fillUnsetProperties(); } void RenderStyle::adjustTransitions() { auto* transitionList = m_rareNonInheritedData->transitions.get(); if (!transitionList) return; // Get rid of empty transitions and anything beyond them for (size_t i = 0, size = transitionList->size(); i < size; ++i) { if (transitionList->animation(i).isEmpty()) { transitionList->resize(i); break; } } if (transitionList->isEmpty()) { clearTransitions(); return; } // Repeat patterns into layers that don't have some properties set. transitionList->fillUnsetProperties(); // Make sure there are no duplicate properties. // This is an O(n^2) algorithm but the lists tend to be short, so it is probably OK. for (size_t i = 0; i < transitionList->size(); ++i) { for (size_t j = i + 1; j < transitionList->size(); ++j) { if (transitionList->animation(i).property() == transitionList->animation(j).property()) { // toss i transitionList->remove(i); j = i; } } } } AnimationList& RenderStyle::ensureAnimations() { if (!m_rareNonInheritedData.access().animations) m_rareNonInheritedData.access().animations = std::make_unique(); return *m_rareNonInheritedData->animations; } AnimationList& RenderStyle::ensureTransitions() { if (!m_rareNonInheritedData.access().transitions) m_rareNonInheritedData.access().transitions = std::make_unique(); return *m_rareNonInheritedData->transitions; } const Animation* RenderStyle::transitionForProperty(CSSPropertyID property) const { auto* transitions = this->transitions(); if (!transitions) return nullptr; for (size_t i = 0, size = transitions->size(); i < size; ++i) { auto& animation = transitions->animation(i); if (animation.animationMode() == Animation::AnimateAll || animation.property() == property) return &animation; } return nullptr; } const FontCascade& RenderStyle::fontCascade() const { return m_inheritedData->fontCascade; } const FontMetrics& RenderStyle::fontMetrics() const { return m_inheritedData->fontCascade.fontMetrics(); } const FontCascadeDescription& RenderStyle::fontDescription() const { return m_inheritedData->fontCascade.fontDescription(); } float RenderStyle::specifiedFontSize() const { return fontDescription().specifiedSize(); } float RenderStyle::computedFontSize() const { return fontDescription().computedSize(); } int RenderStyle::fontSize() const { return m_inheritedData->fontCascade.pixelSize(); } const Length& RenderStyle::wordSpacing() const { return m_rareInheritedData->wordSpacing; } float RenderStyle::letterSpacing() const { return m_inheritedData->fontCascade.letterSpacing(); } bool RenderStyle::setFontDescription(const FontCascadeDescription& description) { if (m_inheritedData->fontCascade.fontDescription() == description) return false; auto& cascade = m_inheritedData.access().fontCascade; cascade = { description, cascade.letterSpacing(), cascade.wordSpacing() }; return true; } const Length& RenderStyle::specifiedLineHeight() const { #if ENABLE(TEXT_AUTOSIZING) return m_inheritedData->specifiedLineHeight; #else return m_inheritedData->lineHeight; #endif } #if ENABLE(TEXT_AUTOSIZING) void RenderStyle::setSpecifiedLineHeight(Length&& height) { SET_VAR(m_inheritedData, specifiedLineHeight, WTFMove(height)); } #endif const Length& RenderStyle::lineHeight() const { return m_inheritedData->lineHeight; } void RenderStyle::setLineHeight(Length&& height) { SET_VAR(m_inheritedData, lineHeight, WTFMove(height)); } int RenderStyle::computedLineHeight() const { const Length& lh = lineHeight(); // Negative value means the line height is not set. Use the font's built-in spacing. if (lh.isNegative()) return fontMetrics().lineSpacing(); if (lh.isPercentOrCalculated()) return minimumValueForLength(lh, fontSize()); return clampTo(lh.value()); } void RenderStyle::setWordSpacing(Length&& value) { float fontWordSpacing; switch (value.type()) { case Auto: fontWordSpacing = 0; break; case Percent: fontWordSpacing = value.percent() * fontCascade().spaceWidth() / 100; break; case Fixed: fontWordSpacing = value.value(); break; case Calculated: fontWordSpacing = value.nonNanCalculatedValue(maxValueForCssLength); break; default: ASSERT_NOT_REACHED(); fontWordSpacing = 0; break; } m_inheritedData.access().fontCascade.setWordSpacing(fontWordSpacing); m_rareInheritedData.access().wordSpacing = WTFMove(value); } void RenderStyle::setLetterSpacing(float v) { m_inheritedData.access().fontCascade.setLetterSpacing(v); } void RenderStyle::setFontSize(float size) { // size must be specifiedSize if Text Autosizing is enabled, but computedSize if text // zoom is enabled (if neither is enabled it's irrelevant as they're probably the same). ASSERT(std::isfinite(size)); if (!std::isfinite(size) || size < 0) size = 0; else size = std::min(maximumAllowedFontSize, size); FontSelector* currentFontSelector = fontCascade().fontSelector(); auto description = fontDescription(); description.setSpecifiedSize(size); description.setComputedSize(size); setFontDescription(description); fontCascade().update(currentFontSelector); } #if ENABLE(VARIATION_FONTS) void RenderStyle::setFontVariationSettings(FontVariationSettings settings) { FontSelector* currentFontSelector = fontCascade().fontSelector(); auto description = fontDescription(); description.setVariationSettings(WTFMove(settings)); setFontDescription(description); fontCascade().update(currentFontSelector); } #endif void RenderStyle::getShadowExtent(const ShadowData* shadow, LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const { top = 0; right = 0; bottom = 0; left = 0; for ( ; shadow; shadow = shadow->next()) { if (shadow->style() == Inset) continue; int extentAndSpread = shadow->paintingExtent() + shadow->spread(); top = std::min(top, shadow->y() - extentAndSpread); right = std::max(right, shadow->x() + extentAndSpread); bottom = std::max(bottom, shadow->y() + extentAndSpread); left = std::min(left, shadow->x() - extentAndSpread); } } LayoutBoxExtent RenderStyle::getShadowInsetExtent(const ShadowData* shadow) const { LayoutUnit top = 0; LayoutUnit right = 0; LayoutUnit bottom = 0; LayoutUnit left = 0; for ( ; shadow; shadow = shadow->next()) { if (shadow->style() == Normal) continue; int extentAndSpread = shadow->paintingExtent() + shadow->spread(); top = std::max(top, shadow->y() + extentAndSpread); right = std::min(right, shadow->x() - extentAndSpread); bottom = std::min(bottom, shadow->y() - extentAndSpread); left = std::max(left, shadow->x() + extentAndSpread); } return LayoutBoxExtent(top, right, bottom, left); } void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, LayoutUnit &left, LayoutUnit &right) const { left = 0; right = 0; for ( ; shadow; shadow = shadow->next()) { if (shadow->style() == Inset) continue; int extentAndSpread = shadow->paintingExtent() + shadow->spread(); left = std::min(left, shadow->x() - extentAndSpread); right = std::max(right, shadow->x() + extentAndSpread); } } void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, LayoutUnit &top, LayoutUnit &bottom) const { top = 0; bottom = 0; for ( ; shadow; shadow = shadow->next()) { if (shadow->style() == Inset) continue; int extentAndSpread = shadow->paintingExtent() + shadow->spread(); top = std::min(top, shadow->y() - extentAndSpread); bottom = std::max(bottom, shadow->y() + extentAndSpread); } } Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) const { Color result; EBorderStyle borderStyle = BNONE; switch (colorProperty) { case CSSPropertyBackgroundColor: return visitedLink ? visitedLinkBackgroundColor() : backgroundColor(); // Background color doesn't fall back. case CSSPropertyBorderLeftColor: result = visitedLink ? visitedLinkBorderLeftColor() : borderLeftColor(); borderStyle = borderLeftStyle(); break; case CSSPropertyBorderRightColor: result = visitedLink ? visitedLinkBorderRightColor() : borderRightColor(); borderStyle = borderRightStyle(); break; case CSSPropertyBorderTopColor: result = visitedLink ? visitedLinkBorderTopColor() : borderTopColor(); borderStyle = borderTopStyle(); break; case CSSPropertyBorderBottomColor: result = visitedLink ? visitedLinkBorderBottomColor() : borderBottomColor(); borderStyle = borderBottomStyle(); break; case CSSPropertyColor: result = visitedLink ? visitedLinkColor() : color(); break; case CSSPropertyOutlineColor: result = visitedLink ? visitedLinkOutlineColor() : outlineColor(); break; case CSSPropertyColumnRuleColor: result = visitedLink ? visitedLinkColumnRuleColor() : columnRuleColor(); break; case CSSPropertyWebkitTextDecorationColor: // Text decoration color fallback is handled in RenderObject::decorationColor. return visitedLink ? visitedLinkTextDecorationColor() : textDecorationColor(); case CSSPropertyWebkitTextEmphasisColor: result = visitedLink ? visitedLinkTextEmphasisColor() : textEmphasisColor(); break; case CSSPropertyWebkitTextFillColor: result = visitedLink ? visitedLinkTextFillColor() : textFillColor(); break; case CSSPropertyWebkitTextStrokeColor: result = visitedLink ? visitedLinkTextStrokeColor() : textStrokeColor(); break; default: ASSERT_NOT_REACHED(); break; } if (!result.isValid()) { if (!visitedLink && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE)) result = Color(238, 238, 238); else result = visitedLink ? visitedLinkColor() : color(); } return result; } Color RenderStyle::visitedDependentColor(int colorProperty) const { Color unvisitedColor = colorIncludingFallback(colorProperty, false); if (insideLink() != InsideVisitedLink) return unvisitedColor; Color visitedColor = colorIncludingFallback(colorProperty, true); // Text decoration color validity is preserved (checked in RenderObject::decorationColor). if (colorProperty == CSSPropertyWebkitTextDecorationColor) return visitedColor; // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just // assume that if the background color is transparent that it wasn't set. Note that it's weird that // we're returning unvisited info for a visited link, but given our restriction that the alpha values // have to match, it makes more sense to return the unvisited background color if specified than it // does to return black. This behavior matches what Firefox 4 does as well. if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent) return unvisitedColor; // Take the alpha from the unvisited color, but get the RGB values from the visited color. return visitedColor.colorWithAlpha(unvisitedColor.alphaAsFloat()); } const BorderValue& RenderStyle::borderBefore() const { switch (writingMode()) { case TopToBottomWritingMode: return borderTop(); case BottomToTopWritingMode: return borderBottom(); case LeftToRightWritingMode: return borderLeft(); case RightToLeftWritingMode: return borderRight(); } ASSERT_NOT_REACHED(); return borderTop(); } const BorderValue& RenderStyle::borderAfter() const { switch (writingMode()) { case TopToBottomWritingMode: return borderBottom(); case BottomToTopWritingMode: return borderTop(); case LeftToRightWritingMode: return borderRight(); case RightToLeftWritingMode: return borderLeft(); } ASSERT_NOT_REACHED(); return borderBottom(); } const BorderValue& RenderStyle::borderStart() const { if (isHorizontalWritingMode()) return isLeftToRightDirection() ? borderLeft() : borderRight(); return isLeftToRightDirection() ? borderTop() : borderBottom(); } const BorderValue& RenderStyle::borderEnd() const { if (isHorizontalWritingMode()) return isLeftToRightDirection() ? borderRight() : borderLeft(); return isLeftToRightDirection() ? borderBottom() : borderTop(); } float RenderStyle::borderBeforeWidth() const { switch (writingMode()) { case TopToBottomWritingMode: return borderTopWidth(); case BottomToTopWritingMode: return borderBottomWidth(); case LeftToRightWritingMode: return borderLeftWidth(); case RightToLeftWritingMode: return borderRightWidth(); } ASSERT_NOT_REACHED(); return borderTopWidth(); } float RenderStyle::borderAfterWidth() const { switch (writingMode()) { case TopToBottomWritingMode: return borderBottomWidth(); case BottomToTopWritingMode: return borderTopWidth(); case LeftToRightWritingMode: return borderRightWidth(); case RightToLeftWritingMode: return borderLeftWidth(); } ASSERT_NOT_REACHED(); return borderBottomWidth(); } float RenderStyle::borderStartWidth() const { if (isHorizontalWritingMode()) return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth(); return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth(); } float RenderStyle::borderEndWidth() const { if (isHorizontalWritingMode()) return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth(); return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth(); } void RenderStyle::setMarginStart(Length&& margin) { if (isHorizontalWritingMode()) { if (isLeftToRightDirection()) setMarginLeft(WTFMove(margin)); else setMarginRight(WTFMove(margin)); } else { if (isLeftToRightDirection()) setMarginTop(WTFMove(margin)); else setMarginBottom(WTFMove(margin)); } } void RenderStyle::setMarginEnd(Length&& margin) { if (isHorizontalWritingMode()) { if (isLeftToRightDirection()) setMarginRight(WTFMove(margin)); else setMarginLeft(WTFMove(margin)); } else { if (isLeftToRightDirection()) setMarginBottom(WTFMove(margin)); else setMarginTop(WTFMove(margin)); } } TextEmphasisMark RenderStyle::textEmphasisMark() const { auto mark = static_cast(m_rareInheritedData->textEmphasisMark); if (mark != TextEmphasisMarkAuto) return mark; if (isHorizontalWritingMode()) return TextEmphasisMarkDot; return TextEmphasisMarkSesame; } #if ENABLE(TOUCH_EVENTS) Color RenderStyle::initialTapHighlightColor() { return RenderTheme::tapHighlightColor(); } #endif LayoutBoxExtent RenderStyle::imageOutsets(const NinePieceImage& image) const { return LayoutBoxExtent(NinePieceImage::computeOutset(image.outset().top(), borderTopWidth()), NinePieceImage::computeOutset(image.outset().right(), borderRightWidth()), NinePieceImage::computeOutset(image.outset().bottom(), borderBottomWidth()), NinePieceImage::computeOutset(image.outset().left(), borderLeftWidth())); } std::pair RenderStyle::fontAndGlyphOrientation() { // FIXME: TextOrientationSideways should map to sideways-left in vertical-lr, which is not supported yet. if (isHorizontalWritingMode()) return { Horizontal, NonCJKGlyphOrientation::Mixed }; switch (textOrientation()) { case TextOrientation::Mixed: return { Vertical, NonCJKGlyphOrientation::Mixed }; case TextOrientation::Upright: return { Vertical, NonCJKGlyphOrientation::Upright }; case TextOrientation::Sideways: return { Horizontal, NonCJKGlyphOrientation::Mixed }; default: ASSERT_NOT_REACHED(); return { Horizontal, NonCJKGlyphOrientation::Mixed }; } } void RenderStyle::setBorderImageSource(RefPtr&& image) { if (m_surroundData->border.m_image.image() == image.get()) return; m_surroundData.access().border.m_image.setImage(WTFMove(image)); } void RenderStyle::setBorderImageSlices(LengthBox&& slices) { if (m_surroundData->border.m_image.imageSlices() == slices) return; m_surroundData.access().border.m_image.setImageSlices(WTFMove(slices)); } void RenderStyle::setBorderImageWidth(LengthBox&& slices) { if (m_surroundData->border.m_image.borderSlices() == slices) return; m_surroundData.access().border.m_image.setBorderSlices(WTFMove(slices)); } void RenderStyle::setBorderImageOutset(LengthBox&& outset) { if (m_surroundData->border.m_image.outset() == outset) return; m_surroundData.access().border.m_image.setOutset(WTFMove(outset)); } void RenderStyle::setColumnStylesFromPaginationMode(const Pagination::Mode& paginationMode) { if (paginationMode == Pagination::Unpaginated) return; setColumnFill(ColumnFillAuto); switch (paginationMode) { case Pagination::LeftToRightPaginated: setColumnAxis(HorizontalColumnAxis); if (isHorizontalWritingMode()) setColumnProgression(isLeftToRightDirection() ? NormalColumnProgression : ReverseColumnProgression); else setColumnProgression(isFlippedBlocksWritingMode() ? ReverseColumnProgression : NormalColumnProgression); break; case Pagination::RightToLeftPaginated: setColumnAxis(HorizontalColumnAxis); if (isHorizontalWritingMode()) setColumnProgression(isLeftToRightDirection() ? ReverseColumnProgression : NormalColumnProgression); else setColumnProgression(isFlippedBlocksWritingMode() ? NormalColumnProgression : ReverseColumnProgression); break; case Pagination::TopToBottomPaginated: setColumnAxis(VerticalColumnAxis); if (isHorizontalWritingMode()) setColumnProgression(isFlippedBlocksWritingMode() ? ReverseColumnProgression : NormalColumnProgression); else setColumnProgression(isLeftToRightDirection() ? NormalColumnProgression : ReverseColumnProgression); break; case Pagination::BottomToTopPaginated: setColumnAxis(VerticalColumnAxis); if (isHorizontalWritingMode()) setColumnProgression(isFlippedBlocksWritingMode() ? NormalColumnProgression : ReverseColumnProgression); else setColumnProgression(isLeftToRightDirection() ? ReverseColumnProgression : NormalColumnProgression); break; case Pagination::Unpaginated: ASSERT_NOT_REACHED(); break; } } #if ENABLE(CSS_SCROLL_SNAP) ScrollSnapType RenderStyle::initialScrollSnapType() { return { }; } ScrollSnapAlign RenderStyle::initialScrollSnapAlign() { return { }; } const StyleScrollSnapArea& RenderStyle::scrollSnapArea() const { return *m_rareNonInheritedData->scrollSnapArea; } const StyleScrollSnapPort& RenderStyle::scrollSnapPort() const { return *m_rareNonInheritedData->scrollSnapPort; } const ScrollSnapType& RenderStyle::scrollSnapType() const { return m_rareNonInheritedData->scrollSnapPort->type; } const LengthBox& RenderStyle::scrollPadding() const { return m_rareNonInheritedData->scrollSnapPort->scrollPadding; } const Length& RenderStyle::scrollPaddingTop() const { return scrollPadding().top(); } const Length& RenderStyle::scrollPaddingBottom() const { return scrollPadding().bottom(); } const Length& RenderStyle::scrollPaddingLeft() const { return scrollPadding().left(); } const Length& RenderStyle::scrollPaddingRight() const { return scrollPadding().right(); } const ScrollSnapAlign& RenderStyle::scrollSnapAlign() const { return m_rareNonInheritedData->scrollSnapArea->alignment; } const LengthBox& RenderStyle::scrollSnapMargin() const { return m_rareNonInheritedData->scrollSnapArea->scrollSnapMargin; } const Length& RenderStyle::scrollSnapMarginTop() const { return scrollSnapMargin().top(); } const Length& RenderStyle::scrollSnapMarginBottom() const { return scrollSnapMargin().bottom(); } const Length& RenderStyle::scrollSnapMarginLeft() const { return scrollSnapMargin().left(); } const Length& RenderStyle::scrollSnapMarginRight() const { return scrollSnapMargin().right(); } void RenderStyle::setScrollSnapType(const ScrollSnapType& type) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, type, type); } void RenderStyle::setScrollPaddingTop(Length&& length) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, scrollPadding.top(), WTFMove(length)); } void RenderStyle::setScrollPaddingBottom(Length&& length) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, scrollPadding.bottom(), WTFMove(length)); } void RenderStyle::setScrollPaddingLeft(Length&& length) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, scrollPadding.left(), WTFMove(length)); } void RenderStyle::setScrollPaddingRight(Length&& length) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, scrollPadding.right(), WTFMove(length)); } void RenderStyle::setScrollSnapAlign(const ScrollSnapAlign& alignment) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, alignment, alignment); } void RenderStyle::setScrollSnapMarginTop(Length&& length) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, scrollSnapMargin.top(), WTFMove(length)); } void RenderStyle::setScrollSnapMarginBottom(Length&& length) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, scrollSnapMargin.bottom(), WTFMove(length)); } void RenderStyle::setScrollSnapMarginLeft(Length&& length) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, scrollSnapMargin.left(), WTFMove(length)); } void RenderStyle::setScrollSnapMarginRight(Length&& length) { SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, scrollSnapMargin.right(), WTFMove(length)); } #endif bool RenderStyle::hasReferenceFilterOnly() const { if (!hasFilter()) return false; auto& filterOperations = m_rareNonInheritedData->filter->operations; return filterOperations.size() == 1 && filterOperations.at(0)->type() == FilterOperation::REFERENCE; } void RenderStyle::checkVariablesInCustomProperties() { if (!m_rareInheritedData->customProperties->containsVariables) return; auto& customPropertyData = m_rareInheritedData.access().customProperties.access(); // Our first pass checks the variables for validity and replaces any properties that became // invalid with empty values. auto& customProperties = customPropertyData.values; HashSet invalidProperties; for (auto entry : customProperties) { if (!entry.value->containsVariables()) continue; HashSet seenProperties; entry.value->checkVariablesForCycles(entry.key, customProperties, seenProperties, invalidProperties); } // Now insert invalid values. if (!invalidProperties.isEmpty()) { auto invalidValue = CSSCustomPropertyValue::createInvalid(); for (auto& property : invalidProperties) customProperties.set(property, invalidValue.copyRef()); } // Now that all of the properties have been tested for validity and replaced with // invalid values if they failed, we can perform variable substitution on the valid values. Vector> resolvedValues; for (auto entry : customProperties) { if (!entry.value->containsVariables()) continue; entry.value->resolveVariableReferences(customProperties, resolvedValues); } // With all results computed, we can now mutate our table to eliminate the variables and // hold the final values. This way when we inherit, we don't end up resubstituting variables, etc. for (auto& resolvedValue : resolvedValues) customProperties.set(resolvedValue->name(), resolvedValue.copyRef()); customPropertyData.containsVariables = false; } float RenderStyle::outlineWidth() const { if (m_backgroundData->outline.style() == BNONE) return 0; if (outlineStyleIsAuto()) return std::max(m_backgroundData->outline.width(), RenderTheme::platformFocusRingWidth()); return m_backgroundData->outline.width(); } float RenderStyle::outlineOffset() const { if (m_backgroundData->outline.style() == BNONE) return 0; if (outlineStyleIsAuto()) return (m_backgroundData->outline.offset() + RenderTheme::platformFocusRingOffset(outlineWidth())); return m_backgroundData->outline.offset(); } bool RenderStyle::shouldPlaceBlockDirectionScrollbarOnLeft() const { return !isLeftToRightDirection() && isHorizontalWritingMode(); } #if ENABLE(DASHBOARD_SUPPORT) void RenderStyle::setDashboardRegion(int type, const String& label, Length&& top, Length&& right, Length&& bottom, Length&& left, bool append) { if (!append) m_rareNonInheritedData.access().dashboardRegions.clear(); m_rareNonInheritedData.access().dashboardRegions.append({ label, { WTFMove(top), WTFMove(right), WTFMove(bottom), WTFMove(left) }, type }); } #endif Vector RenderStyle::paintTypesForPaintOrder() const { Vector paintOrder; switch (this->paintOrder()) { case PaintOrderNormal: FALLTHROUGH; case PaintOrderFill: paintOrder.append(PaintTypeFill); paintOrder.append(PaintTypeStroke); paintOrder.append(PaintTypeMarkers); break; case PaintOrderFillMarkers: paintOrder.append(PaintTypeFill); paintOrder.append(PaintTypeMarkers); paintOrder.append(PaintTypeStroke); break; case PaintOrderStroke: paintOrder.append(PaintTypeStroke); paintOrder.append(PaintTypeFill); paintOrder.append(PaintTypeMarkers); break; case PaintOrderStrokeMarkers: paintOrder.append(PaintTypeStroke); paintOrder.append(PaintTypeMarkers); paintOrder.append(PaintTypeFill); break; case PaintOrderMarkers: paintOrder.append(PaintTypeMarkers); paintOrder.append(PaintTypeFill); paintOrder.append(PaintTypeStroke); break; case PaintOrderMarkersStroke: paintOrder.append(PaintTypeMarkers); paintOrder.append(PaintTypeStroke); paintOrder.append(PaintTypeFill); break; }; return paintOrder; } } // namespace WebCore