| /* |
| * 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 <wtf/MathExtras.h> |
| #include <wtf/PointerComparison.h> |
| #include <wtf/StdLibExtras.h> |
| #include <algorithm> |
| |
| #if ENABLE(TEXT_AUTOSIZING) |
| #include <wtf/text/StringHash.h> |
| #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 { |
| unsigned m_bitfields[2]; |
| } m_nonInheritedFlags; |
| #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS) |
| bool deletionCheck; |
| #endif |
| }; |
| |
| static_assert(sizeof(RenderStyle) == sizeof(SameSizeAsRenderStyle), "RenderStyle should stay small"); |
| |
| RenderStyle& RenderStyle::defaultStyle() |
| { |
| static NeverDestroyed<RenderStyle> style { CreateDefaultStyle }; |
| return style; |
| } |
| |
| RenderStyle RenderStyle::create() |
| { |
| return clone(defaultStyle()); |
| } |
| |
| std::unique_ptr<RenderStyle> RenderStyle::createPtr() |
| { |
| return clonePtr(defaultStyle()); |
| } |
| |
| RenderStyle RenderStyle::clone(const RenderStyle& style) |
| { |
| return RenderStyle(style, Clone); |
| } |
| |
| std::unique_ptr<RenderStyle> RenderStyle::clonePtr(const RenderStyle& style) |
| { |
| return std::make_unique<RenderStyle>(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(RenderStyle&&) = default; |
| RenderStyle& RenderStyle::operator=(RenderStyle&&) = default; |
| |
| 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(); |
| |
| m_nonInheritedFlags.effectiveDisplay = initialDisplay(); |
| m_nonInheritedFlags.originalDisplay = initialDisplay(); |
| m_nonInheritedFlags.overflowX = initialOverflowX(); |
| m_nonInheritedFlags.overflowY = initialOverflowY(); |
| m_nonInheritedFlags.verticalAlign = initialVerticalAlign(); |
| m_nonInheritedFlags.clear = initialClear(); |
| m_nonInheritedFlags.position = initialPosition(); |
| m_nonInheritedFlags.unicodeBidi = initialUnicodeBidi(); |
| m_nonInheritedFlags.floating = initialFloating(); |
| m_nonInheritedFlags.tableLayout = initialTableLayout(); |
| m_nonInheritedFlags.hasExplicitlySetDirection = false; |
| m_nonInheritedFlags.hasExplicitlySetWritingMode = false; |
| m_nonInheritedFlags.hasExplicitlySetTextAlign = false; |
| m_nonInheritedFlags.hasViewportUnits = false; |
| m_nonInheritedFlags.hasExplicitlyInheritedProperties = false; |
| m_nonInheritedFlags.isUnique = false; |
| m_nonInheritedFlags.emptyState = false; |
| m_nonInheritedFlags.firstChildState = false; |
| m_nonInheritedFlags.lastChildState = false; |
| m_nonInheritedFlags.affectedByHover = false; |
| m_nonInheritedFlags.affectedByActive = false; |
| m_nonInheritedFlags.affectedByDrag = false; |
| m_nonInheritedFlags.isLink = false; |
| m_nonInheritedFlags.styleType = NOPSEUDO; |
| m_nonInheritedFlags.pseudoBits = NOPSEUDO; |
| |
| 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) }; |
| } |
| |
| static StyleSelfAlignmentData resolvedSelfAlignment(const StyleSelfAlignmentData& value, ItemPosition normalValueBehavior) |
| { |
| if (value.position() == ItemPositionLegacy || value.position() == ItemPositionNormal || value.position() == ItemPositionAuto) |
| 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 (!parentStyle || alignSelf().position() != ItemPositionAuto) |
| return resolvedSelfAlignment(alignSelf(), normalValueBehaviour); |
| return parentStyle->resolvedAlignItems(normalValueBehaviour); |
| } |
| |
| StyleSelfAlignmentData RenderStyle::resolvedJustifyItems(ItemPosition normalValueBehaviour) const |
| { |
| 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 (!parentStyle || justifySelf().position() != ItemPositionAuto) |
| return resolvedSelfAlignment(justifySelf(), normalValueBehaviour); |
| return parentStyle->resolvedJustifyItems(normalValueBehaviour); |
| } |
| |
| static inline StyleContentAlignmentData resolvedContentAlignment(const StyleContentAlignmentData& value, const StyleContentAlignmentData& normalValueBehavior) |
| { |
| return (value.position() == ContentPositionNormal && value.distribution() == ContentDistributionDefault) ? normalValueBehavior : value; |
| } |
| |
| StyleContentAlignmentData RenderStyle::resolvedAlignContent(const StyleContentAlignmentData& normalValueBehavior) const |
| { |
| // We will return the behaviour of 'normal' value if needed, which is specific of each layout model. |
| return resolvedContentAlignment(alignContent(), normalValueBehavior); |
| } |
| |
| StyleContentAlignmentData RenderStyle::resolvedJustifyContent(const StyleContentAlignmentData& normalValueBehavior) const |
| { |
| // We will return the behaviour of 'normal' value if needed, which is specific of each layout model. |
| return resolvedContentAlignment(justifyContent(), normalValueBehavior); |
| } |
| |
| 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()); |
| } |
| |
| void RenderStyle::copyContentFrom(const RenderStyle& other) |
| { |
| if (!other.m_rareNonInheritedData->content) |
| return; |
| m_rareNonInheritedData.access().content = other.m_rareNonInheritedData->content->clone(); |
| } |
| |
| 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<RenderStyle> pseudo) |
| { |
| if (!pseudo) |
| return nullptr; |
| |
| ASSERT(pseudo->styleType() > NOPSEUDO); |
| |
| RenderStyle* result = pseudo.get(); |
| |
| if (!m_cachedPseudoStyles) |
| m_cachedPseudoStyles = std::make_unique<PseudoStyleCache>(); |
| |
| 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 <https://bugs.webkit.org/show_bug.cgi?id=121131>. |
| 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<float>::hash(m_inheritedData->specifiedLineHeight.value()); |
| hash ^= computeFontHash(m_inheritedData->fontCascade); |
| hash ^= WTF::FloatHash<float>::hash(m_inheritedData->horizontalBorderSpacing); |
| hash ^= WTF::FloatHash<float>::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.ptr() == other->m_inheritedData.ptr() |
| && m_svgStyle.ptr() == other->m_svgStyle.ptr() |
| && m_rareInheritedData.ptr() == other->m_rareInheritedData.ptr(); |
| } |
| |
| 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.ptr() != other.m_rareNonInheritedData.ptr() |
| && !arePointingToEqualData(m_rareNonInheritedData->boxShadow, other.m_rareNonInheritedData->boxShadow)) |
| return true; |
| |
| if (m_rareInheritedData.ptr() != other.m_rareInheritedData.ptr() |
| && !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.ptr() != other.m_rareNonInheritedData.ptr()) { |
| 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->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.ptr() != other.m_rareInheritedData.ptr()) { |
| 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; |
| |
| // 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 |
| || m_rareInheritedData->miterLimit != other.m_rareInheritedData->miterLimit) |
| 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_rareInheritedData->colorFilter != other.m_rareInheritedData->colorFilter |
| || 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->isNotFinal != other.m_rareNonInheritedData->isNotFinal) |
| 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 |
| || m_rareInheritedData->strokeColor != other.m_rareInheritedData->strokeColor |
| || m_rareInheritedData->caretColor != other.m_rareInheritedData->caretColor) |
| return true; |
| |
| return false; |
| } |
| |
| bool RenderStyle::changeRequiresRecompositeLayer(const RenderStyle& other, unsigned&) const |
| { |
| if (m_rareNonInheritedData.ptr() != other.m_rareNonInheritedData.ptr()) { |
| 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; |
| } |
| |
| 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<StyleImage>&& 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<CursorList>&& list) |
| { |
| m_rareInheritedData.access().cursorData = WTFMove(list); |
| } |
| |
| void RenderStyle::setQuotes(RefPtr<QuotesData>&& 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>&& 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> 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<StyleImage>&& image, bool add) |
| { |
| if (!image) |
| return; |
| setContent(std::make_unique<ImageContentData>(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<TextContentData>(last)) |
| last.setNext(std::make_unique<TextContentData>(string)); |
| else { |
| auto& textContent = downcast<TextContentData>(last); |
| textContent.setText(textContent.text() + string); |
| } |
| } else { |
| data.content = std::make_unique<TextContentData>(string); |
| auto& altText = data.altText; |
| if (!altText.isNull()) |
| data.content->setAltText(altText); |
| } |
| } |
| |
| void RenderStyle::setContent(std::unique_ptr<CounterContent> counter, bool add) |
| { |
| if (!counter) |
| return; |
| setContent(std::make_unique<CounterContentData>(WTFMove(counter)), add); |
| } |
| |
| void RenderStyle::setContent(QuoteType quote, bool add) |
| { |
| setContent(std::make_unique<QuoteContentData>(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<RefPtr<TransformOperation>>& 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); |
| |
| FloatPoint3D originTranslate; |
| if (applyTransformOrigin) { |
| originTranslate.setX(boundingBox.x() + floatValueForLength(transformOriginX(), boundingBox.width())); |
| originTranslate.setY(boundingBox.y() + floatValueForLength(transformOriginY(), boundingBox.height())); |
| originTranslate.setZ(transformOriginZ()); |
| transform.translate3d(originTranslate.x(), originTranslate.y(), originTranslate.z()); |
| } |
| |
| for (auto& operation : operations) |
| operation->apply(transform, boundingBox.size()); |
| |
| if (applyTransformOrigin) |
| transform.translate3d(-originTranslate.x(), -originTranslate.y(), -originTranslate.z()); |
| } |
| |
| 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> 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> 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<StyleImage>&& 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<CounterDirectiveMap>(); |
| return *map; |
| } |
| |
| 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<AtomicString> hyphenMinusString(&hyphenMinus, 1); |
| static NeverDestroyed<AtomicString> 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<AtomicString> filledDotString(&bullet, 1); |
| static NeverDestroyed<AtomicString> openDotString(&whiteBullet, 1); |
| return textEmphasisFill() == TextEmphasisFillFilled ? filledDotString : openDotString; |
| } |
| case TextEmphasisMarkCircle: { |
| static NeverDestroyed<AtomicString> filledCircleString(&blackCircle, 1); |
| static NeverDestroyed<AtomicString> openCircleString(&whiteCircle, 1); |
| return textEmphasisFill() == TextEmphasisFillFilled ? filledCircleString : openCircleString; |
| } |
| case TextEmphasisMarkDoubleCircle: { |
| static NeverDestroyed<AtomicString> filledDoubleCircleString(&fisheye, 1); |
| static NeverDestroyed<AtomicString> openDoubleCircleString(&bullseye, 1); |
| return textEmphasisFill() == TextEmphasisFillFilled ? filledDoubleCircleString : openDoubleCircleString; |
| } |
| case TextEmphasisMarkTriangle: { |
| static NeverDestroyed<AtomicString> filledTriangleString(&blackUpPointingTriangle, 1); |
| static NeverDestroyed<AtomicString> openTriangleString(&whiteUpPointingTriangle, 1); |
| return textEmphasisFill() == TextEmphasisFillFilled ? filledTriangleString : openTriangleString; |
| } |
| case TextEmphasisMarkSesame: { |
| static NeverDestroyed<AtomicString> filledSesameString(&sesameDot, 1); |
| static NeverDestroyed<AtomicString> 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<StyleDashboardRegion>& RenderStyle::initialDashboardRegions() |
| { |
| static NeverDestroyed<Vector<StyleDashboardRegion>> emptyList; |
| return emptyList; |
| } |
| |
| const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions() |
| { |
| static NeverDestroyed<Vector<StyleDashboardRegion>> 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<AnimationList>(); |
| return *m_rareNonInheritedData->animations; |
| } |
| |
| AnimationList& RenderStyle::ensureTransitions() |
| { |
| if (!m_rareNonInheritedData.access().transitions) |
| m_rareNonInheritedData.access().transitions = std::make_unique<AnimationList>(); |
| 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(); |
| } |
| |
| unsigned RenderStyle::computedFontPixelSize() const |
| { |
| return fontDescription().computedPixelSize(); |
| } |
| |
| 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, computedFontPixelSize()); |
| |
| return clampTo<int>(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::setFontWeight(FontSelectionValue value) |
| { |
| FontSelector* currentFontSelector = fontCascade().fontSelector(); |
| auto description = fontDescription(); |
| description.setWeight(value); |
| |
| setFontDescription(description); |
| fontCascade().update(currentFontSelector); |
| } |
| |
| void RenderStyle::setFontStretch(FontSelectionValue value) |
| { |
| FontSelector* currentFontSelector = fontCascade().fontSelector(); |
| auto description = fontDescription(); |
| description.setStretch(value); |
| |
| setFontDescription(description); |
| fontCascade().update(currentFontSelector); |
| } |
| |
| void RenderStyle::setFontItalic(FontSelectionValue value) |
| { |
| FontSelector* currentFontSelector = fontCascade().fontSelector(); |
| auto description = fontDescription(); |
| description.setItalic(value); |
| |
| setFontDescription(description); |
| fontCascade().update(currentFontSelector); |
| } |
| |
| 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<LayoutUnit>(top, shadow->y() - extentAndSpread); |
| right = std::max<LayoutUnit>(right, shadow->x() + extentAndSpread); |
| bottom = std::max<LayoutUnit>(bottom, shadow->y() + extentAndSpread); |
| left = std::min<LayoutUnit>(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<LayoutUnit>(top, shadow->y() + extentAndSpread); |
| right = std::min<LayoutUnit>(right, shadow->x() - extentAndSpread); |
| bottom = std::min<LayoutUnit>(bottom, shadow->y() - extentAndSpread); |
| left = std::max<LayoutUnit>(left, shadow->x() + extentAndSpread); |
| } |
| |
| return LayoutBoxExtent(WTFMove(top), WTFMove(right), WTFMove(bottom), WTFMove(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<LayoutUnit>(left, shadow->x() - extentAndSpread); |
| right = std::max<LayoutUnit>(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<LayoutUnit>(top, shadow->y() - extentAndSpread); |
| bottom = std::max<LayoutUnit>(bottom, shadow->y() + extentAndSpread); |
| } |
| } |
| |
| Color RenderStyle::colorIncludingFallback(CSSPropertyID 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 CSSPropertyCaretColor: |
| result = visitedLink ? visitedLinkCaretColor() : caretColor(); |
| 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; |
| case CSSPropertyStrokeColor: |
| result = visitedLink ? visitedLinkStrokeColor() : strokeColor(); |
| 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(CSSPropertyID 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()); |
| } |
| |
| Color RenderStyle::visitedDependentColorWithColorFilter(CSSPropertyID colorProperty) const |
| { |
| if (!hasColorFilter()) |
| return visitedDependentColor(colorProperty); |
| |
| return colorByApplyingColorFilter(visitedDependentColor(colorProperty)); |
| } |
| |
| Color RenderStyle::colorByApplyingColorFilter(const Color& color) const |
| { |
| Color transformedColor = color; |
| colorFilter().transformColor(transformedColor); |
| return transformedColor; |
| } |
| |
| 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<TextEmphasisMark>(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<FontOrientation, NonCJKGlyphOrientation> 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<StyleImage>&& 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<AtomicString> invalidProperties; |
| for (auto entry : customProperties) { |
| if (!entry.value->containsVariables()) |
| continue; |
| HashSet<AtomicString> 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<Ref<CSSCustomPropertyValue>> 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<PaintType, 3> RenderStyle::paintTypesForPaintOrder(PaintOrder order) |
| { |
| Vector<PaintType, 3> paintOrder; |
| switch (order) { |
| case PaintOrder::Normal: |
| FALLTHROUGH; |
| case PaintOrder::Fill: |
| paintOrder.append(PaintType::Fill); |
| paintOrder.append(PaintType::Stroke); |
| paintOrder.append(PaintType::Markers); |
| break; |
| case PaintOrder::FillMarkers: |
| paintOrder.append(PaintType::Fill); |
| paintOrder.append(PaintType::Markers); |
| paintOrder.append(PaintType::Stroke); |
| break; |
| case PaintOrder::Stroke: |
| paintOrder.append(PaintType::Stroke); |
| paintOrder.append(PaintType::Fill); |
| paintOrder.append(PaintType::Markers); |
| break; |
| case PaintOrder::StrokeMarkers: |
| paintOrder.append(PaintType::Stroke); |
| paintOrder.append(PaintType::Markers); |
| paintOrder.append(PaintType::Fill); |
| break; |
| case PaintOrder::Markers: |
| paintOrder.append(PaintType::Markers); |
| paintOrder.append(PaintType::Fill); |
| paintOrder.append(PaintType::Stroke); |
| break; |
| case PaintOrder::MarkersStroke: |
| paintOrder.append(PaintType::Markers); |
| paintOrder.append(PaintType::Stroke); |
| paintOrder.append(PaintType::Fill); |
| break; |
| }; |
| return paintOrder; |
| } |
| |
| float RenderStyle::computedStrokeWidth(const IntSize& viewportSize) const |
| { |
| // Use the stroke-width and stroke-color value combination only if stroke-color has been explicitly specified. |
| // Since there will be no visible stroke when stroke-color is not specified (transparent by default), we fall |
| // back to the legacy Webkit text stroke combination in that case. |
| if (!hasExplicitlySetStrokeColor()) |
| return textStrokeWidth(); |
| |
| const Length& length = strokeWidth(); |
| |
| if (length.isPercent()) { |
| // According to the spec, https://drafts.fxtf.org/paint/#stroke-width, the percentage is relative to the scaled viewport size. |
| // The scaled viewport size is the geometric mean of the viewport width and height. |
| ExceptionOr<float> result = length.value() * (viewportSize.width() + viewportSize.height()) / 200.0f; |
| if (result.hasException()) |
| return 0; |
| return result.releaseReturnValue(); |
| } |
| |
| if (length.isAuto() || !length.isSpecified()) |
| return 0; |
| |
| return floatValueForLength(length, viewportSize.width()); |
| } |
| |
| bool RenderStyle::hasPositiveStrokeWidth() const |
| { |
| if (!hasExplicitlySetStrokeWidth()) |
| return textStrokeWidth() > 0; |
| |
| return strokeWidth().isPositive(); |
| } |
| |
| Color RenderStyle::computedStrokeColor() const |
| { |
| CSSPropertyID propertyID = CSSPropertyStrokeColor; |
| if (!hasExplicitlySetStrokeColor()) |
| propertyID = CSSPropertyWebkitTextStrokeColor; |
| return visitedDependentColor(propertyID); |
| } |
| |
| } // namespace WebCore |