| /** |
| * Copyright (C) 2003-2025 Apple Inc. 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. |
| */ |
| |
| #pragma once |
| |
| #include <WebCore/DocumentView.h> |
| #include <WebCore/RenderBlock.h> |
| #include <WebCore/RenderBox.h> |
| #include <WebCore/RenderBoxModelObjectInlines.h> |
| #include <WebCore/RenderElementInlines.h> |
| #include <WebCore/StyleContainmentCheckerInlines.h> |
| |
| namespace WebCore { |
| |
| inline LayoutUnit RenderBox::marginBoxLogicalHeight(WritingMode writingMode) const { return writingMode.isHorizontal() ? m_marginBox.top() + borderBoxHeight() + m_marginBox.bottom() : m_marginBox.right() + borderBoxWidth() + m_marginBox.left(); } |
| inline LayoutRect RenderBox::computedCSSContentBoxRect() const { return LayoutRect(borderLeft() + computedCSSPaddingLeft(), borderTop() + computedCSSPaddingTop(), paddingBoxWidth() - computedCSSPaddingLeft() - computedCSSPaddingRight() - (style().scrollbarGutter().isStableBothEdges() ? verticalScrollbarWidth() : 0), paddingBoxHeight() - computedCSSPaddingTop() - computedCSSPaddingBottom() - (style().scrollbarGutter().isStableBothEdges() ? horizontalScrollbarHeight() : 0)); } |
| inline LayoutUnit RenderBox::contentBoxHeight() const { return std::max(0_lu, paddingBoxHeight() - paddingTop() - paddingBottom() - (style().scrollbarGutter().isStableBothEdges() ? horizontalScrollbarHeight() : 0)); } |
| inline LayoutUnit RenderBox::contentBoxLogicalHeight() const { return writingMode().isHorizontal() ? contentBoxHeight() : contentBoxWidth(); } |
| inline LayoutUnit RenderBox::contentBoxLogicalHeight(LayoutUnit overridingBorderBoxHeight) const |
| { |
| auto scrollbarLogicalHeight = this->scrollbarLogicalHeight(); |
| return std::max(0_lu, overridingBorderBoxHeight - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight - (style().scrollbarGutter().isStableBothEdges() ? scrollbarLogicalHeight : 0)); |
| } |
| inline LayoutSize RenderBox::contentBoxLogicalSize() const { return writingMode().isHorizontal() ? contentBoxSize() : contentBoxSize().transposedSize(); } |
| inline LayoutUnit RenderBox::contentBoxLogicalWidth() const { return writingMode().isHorizontal() ? contentBoxWidth() : contentBoxHeight(); } |
| inline LayoutUnit RenderBox::contentBoxLogicalWidth(LayoutUnit overridingBorderBoxWidth) const |
| { |
| auto scrollbarLogicalWidth = this->scrollbarLogicalWidth(); |
| return std::max(LayoutUnit(), overridingBorderBoxWidth - borderAndPaddingLogicalWidth() - scrollbarLogicalWidth - (style().scrollbarGutter().isStableBothEdges() ? scrollbarLogicalWidth : 0)); |
| } |
| inline LayoutSize RenderBox::contentBoxSize() const { return { contentBoxWidth(), contentBoxHeight() }; } |
| inline LayoutUnit RenderBox::contentBoxWidth() const { return std::max(0_lu, paddingBoxWidth() - paddingLeft() - paddingRight() - (style().scrollbarGutter().isStableBothEdges() ? verticalScrollbarWidth() : 0)); } |
| inline std::optional<LayoutUnit> RenderBox::explicitIntrinsicInnerLogicalHeight() const { return writingMode().isHorizontal() ? explicitIntrinsicInnerHeight() : explicitIntrinsicInnerWidth(); } |
| inline std::optional<LayoutUnit> RenderBox::explicitIntrinsicInnerLogicalWidth() const { return writingMode().isHorizontal() ? explicitIntrinsicInnerWidth() : explicitIntrinsicInnerHeight(); } |
| inline bool RenderBox::hasHorizontalOverflow() const { return scrollWidth() != roundToInt(paddingBoxWidth()); } |
| inline bool RenderBox::hasScrollableOverflow() const { return hasScrollableOverflowX() || hasScrollableOverflowY(); } |
| inline bool RenderBox::hasScrollableOverflowX() const { return scrollsOverflowX() && hasHorizontalOverflow(); } |
| inline bool RenderBox::hasScrollableOverflowY() const { return scrollsOverflowY() && hasVerticalOverflow(); } |
| inline bool RenderBox::hasVerticalOverflow() const { return scrollHeight() != roundToInt(paddingBoxHeight()); } |
| inline LayoutUnit RenderBox::intrinsicLogicalHeight() const { return writingMode().isHorizontal() ? intrinsicSize().height() : intrinsicSize().width(); } |
| inline LayoutUnit RenderBox::logicalBottom() const { return logicalTop() + logicalHeight(); } |
| inline LayoutUnit RenderBox::logicalHeight() const { return writingMode().isHorizontal() ? borderBoxHeight() : borderBoxWidth(); } |
| inline LayoutUnit RenderBox::logicalLeft() const { return writingMode().isHorizontal() ? x() : y(); } |
| inline LayoutUnit RenderBox::logicalLeftLayoutOverflow() const { return writingMode().isHorizontal() ? layoutOverflowRect().x() : layoutOverflowRect().y(); } |
| inline LayoutUnit RenderBox::logicalLeftVisualOverflow() const { return writingMode().isHorizontal() ? visualOverflowRect().x() : visualOverflowRect().y(); } |
| inline LayoutUnit RenderBox::logicalRight() const { return logicalLeft() + logicalWidth(); } |
| inline LayoutUnit RenderBox::logicalRightLayoutOverflow() const { return writingMode().isHorizontal() ? layoutOverflowRect().maxX() : layoutOverflowRect().maxY(); } |
| inline LayoutUnit RenderBox::logicalRightVisualOverflow() const { return writingMode().isHorizontal() ? visualOverflowRect().maxX() : visualOverflowRect().maxY(); } |
| inline LayoutSize RenderBox::logicalSize() const { return writingMode().isHorizontal() ? m_borderBoxRectInContainer.size() : m_borderBoxRectInContainer.size().transposedSize(); } |
| inline LayoutUnit RenderBox::logicalTop() const { return writingMode().isHorizontal() ? y() : x(); } |
| inline LayoutUnit RenderBox::logicalWidth() const { return writingMode().isHorizontal() ? borderBoxWidth() : borderBoxHeight(); } |
| inline LayoutUnit RenderBox::paddingBoxHeight() const { return std::max(0_lu, borderBoxHeight() - borderTop() - borderBottom() - horizontalScrollbarHeight()); } |
| inline LayoutUnit RenderBox::paddingBoxLogicalBottom() const { return borderBefore() + paddingBoxLogicalHeight(); } |
| inline LayoutUnit RenderBox::paddingBoxLogicalHeight() const { return writingMode().isHorizontal() ? paddingBoxHeight() : paddingBoxWidth(); } |
| inline LayoutUnit RenderBox::paddingBoxLogicalWidth() const { return writingMode().isHorizontal() ? paddingBoxWidth() : paddingBoxHeight(); } |
| inline LayoutUnit RenderBox::paddingBoxWidth() const { return std::max(0_lu, borderBoxWidth() - borderLeft() - borderRight() - verticalScrollbarWidth()); } |
| inline int RenderBox::scrollbarLogicalHeight() const { return writingMode().isHorizontal() ? horizontalScrollbarHeight() : verticalScrollbarWidth(); } |
| inline int RenderBox::scrollbarLogicalWidth() const { return writingMode().isHorizontal() ? verticalScrollbarWidth() : horizontalScrollbarHeight(); } |
| inline void RenderBox::setLogicalLocation(LayoutPoint location) { setLocation(writingMode().isHorizontal() ? location : location.transposedPoint()); } |
| inline void RenderBox::setLogicalSize(LayoutSize size) { setBorderBoxSize(writingMode().isHorizontal() ? size : size.transposedSize()); } |
| inline bool RenderBox::stretchesToViewport() const { return document().inQuirksMode() && style().logicalHeight().isAuto() && !isFloatingOrOutOfFlowPositioned() && (isDocumentElementRenderer() || isBody()) && !shouldComputeLogicalHeightFromAspectRatio() && !isInline(); } |
| inline bool RenderBox::isColumnSpanner() const { return style().columnSpan() == ColumnSpan::All; } |
| |
| inline bool RenderBox::scrollsOverflow() const |
| { |
| return scrollsOverflowX() || scrollsOverflowY(); |
| } |
| |
| inline bool RenderBox::scrollsOverflowX() const |
| { |
| return hasNonVisibleOverflow() && (style().overflowX() == Overflow::Scroll || style().overflowX() == Overflow::Auto); |
| } |
| |
| inline bool RenderBox::scrollsOverflowY() const |
| { |
| return hasNonVisibleOverflow() && (style().overflowY() == Overflow::Scroll || style().overflowY() == Overflow::Auto); |
| } |
| |
| inline bool RenderBox::isScrollContainerX() const |
| { |
| return style().overflowX() == Overflow::Scroll || style().overflowX() == Overflow::Hidden || style().overflowX() == Overflow::Auto; |
| } |
| |
| inline bool RenderBox::isScrollContainerY() const |
| { |
| return style().overflowY() == Overflow::Scroll || style().overflowY() == Overflow::Hidden || style().overflowY() == Overflow::Auto; |
| } |
| |
| inline LayoutPoint RenderBox::topLeftLocation() const |
| { |
| // This is inlined for speed, since it is used by updateLayerPosition() during scrolling. |
| if (!document().view() || !document().view()->hasFlippedBlockRenderers()) |
| return location(); |
| return topLeftLocationWithFlipping(); |
| } |
| |
| inline LayoutSize RenderBox::topLeftLocationOffset() const |
| { |
| // This is inlined for speed, since it is used by updateLayerPosition() during scrolling. |
| if (!document().view() || !document().view()->hasFlippedBlockRenderers()) |
| return locationOffset(); |
| return toLayoutSize(topLeftLocationWithFlipping()); |
| } |
| |
| inline LayoutRect RenderBox::paddingBoxRectIncludingScrollbar() const |
| { |
| auto borderWidths = this->borderWidths(); |
| return LayoutRect(borderWidths.left(), borderWidths.top(), borderBoxWidth() - borderWidths.left() - borderWidths.right(), borderBoxHeight() - borderWidths.top() - borderWidths.bottom()); |
| } |
| |
| inline LayoutRect RenderBox::contentBoxRect() const |
| { |
| auto verticalScrollbarWidth = 0_lu; |
| auto horizontalScrollbarHeight = 0_lu; |
| auto leftScrollbarSpace = 0_lu; |
| auto topScrollbarSpace = 0_lu; |
| |
| if (hasNonVisibleOverflow()) { |
| verticalScrollbarWidth = this->verticalScrollbarWidth(); |
| horizontalScrollbarHeight = this->horizontalScrollbarHeight(); |
| |
| bool bothEdgeScrollbarGutters = style().scrollbarGutter().isStableBothEdges(); |
| |
| if ((shouldPlaceVerticalScrollbarOnLeft() || bothEdgeScrollbarGutters)) |
| leftScrollbarSpace = verticalScrollbarWidth; |
| // FIXME: It's wrong that scrollbar-gutter: both-edges affects height: webkit.org/b/266938 |
| if (bothEdgeScrollbarGutters) |
| topScrollbarSpace = horizontalScrollbarHeight; |
| } |
| |
| auto padding = this->padding(); |
| auto borderWidths = this->borderWidths(); |
| auto location = LayoutPoint { borderWidths.left() + padding.left() + leftScrollbarSpace, borderWidths.top() + padding.top() + topScrollbarSpace }; |
| |
| auto paddingBoxWidth = std::max(0_lu, borderBoxWidth() - borderWidths.left() - borderWidths.right() - verticalScrollbarWidth); |
| auto paddingBoxHeight = std::max(0_lu, borderBoxHeight() - borderWidths.top() - borderWidths.bottom() - horizontalScrollbarHeight); |
| |
| auto width = std::max(0_lu, paddingBoxWidth - padding.left() - padding.right() - leftScrollbarSpace); |
| auto height = std::max(0_lu, paddingBoxHeight - padding.top() - padding.bottom() - topScrollbarSpace); |
| |
| auto size = LayoutSize { width, height }; |
| |
| return { location, size }; |
| } |
| |
| inline LayoutRect RenderBox::flippedContentBoxRect() const |
| { |
| auto rect = flippedPaddingBoxRect(); |
| auto padding = this->padding(); |
| if (!padding.isZero()) { |
| if (writingMode().isBlockFlipped()) |
| padding = padding.blockFlippedCopy(writingMode()); |
| rect.contract(padding); |
| rect.floorSize(); |
| } |
| return rect; |
| } |
| |
| inline LayoutRect RenderBox::marginBoxRect() const |
| { |
| auto zoomFactor = style().usedZoomForLength(); |
| auto left = resolveLengthPercentageUsingContainerLogicalWidth(style().marginLeft(), zoomFactor); |
| auto right = resolveLengthPercentageUsingContainerLogicalWidth(style().marginRight(), zoomFactor); |
| auto top = resolveLengthPercentageUsingContainerLogicalWidth(style().marginTop(), zoomFactor); |
| auto bottom = resolveLengthPercentageUsingContainerLogicalWidth(style().marginBottom(), zoomFactor); |
| return { -left, -top, borderBoxSize().width() + left + right, borderBoxSize().height() + top + bottom }; |
| } |
| |
| |
| inline const LayoutRect RenderBox::scrollableContentAreaOverflowRect() const |
| { |
| if (!m_overflow) |
| return flippedContentBoxRect(); |
| |
| return m_overflow->contentArea(); |
| } |
| |
| inline const LayoutRect RenderBox::scrollablePaddingAreaOverflowRect() const |
| { |
| if (!m_overflow) |
| return flippedPaddingBoxRect(); |
| |
| auto overflowRect = m_overflow->contentArea(); |
| flipForWritingMode(overflowRect); |
| overflowRect.expand(padding()); |
| flipForWritingMode(overflowRect); |
| return overflowRect; |
| } |
| |
| inline void RenderBox::setLogicalHeight(LayoutUnit size) |
| { |
| if (writingMode().isHorizontal()) |
| setBorderBoxHeight(size); |
| else |
| setBorderBoxWidth(size); |
| } |
| |
| inline void RenderBox::setLogicalLeft(LayoutUnit left) |
| { |
| if (writingMode().isHorizontal()) |
| setX(left); |
| else |
| setY(left); |
| } |
| |
| inline void RenderBox::setLogicalTop(LayoutUnit top) |
| { |
| if (writingMode().isHorizontal()) |
| setY(top); |
| else |
| setX(top); |
| } |
| |
| inline void RenderBox::setLogicalWidth(LayoutUnit size) |
| { |
| if (writingMode().isHorizontal()) |
| setBorderBoxWidth(size); |
| else |
| setBorderBoxHeight(size); |
| } |
| |
| inline bool RenderBox::hasStretchedLogicalHeight(StretchingMode mode) const |
| { |
| CheckedPtr containingBlock = this->containingBlock(); |
| if (!containingBlock) |
| return false; |
| |
| auto containingAxis = writingMode().isOrthogonal(containingBlock->writingMode()) |
| ? LogicalBoxAxis::Inline : LogicalBoxAxis::Block; |
| |
| return containingBlock->willStretchItem(*this, containingAxis, mode); |
| } |
| |
| inline bool RenderBox::hasStretchedLogicalWidth(StretchingMode mode) const |
| { |
| CheckedPtr containingBlock = this->containingBlock(); |
| if (!containingBlock) |
| return false; |
| |
| auto containingAxis = writingMode().isOrthogonal(containingBlock->writingMode()) |
| ? LogicalBoxAxis::Block : LogicalBoxAxis::Inline; |
| |
| return containingBlock->willStretchItem(*this, containingAxis, mode); |
| } |
| |
| inline bool RenderBox::tryLayoutDoingOutOfFlowMovementOnly() |
| { |
| LayoutUnit oldWidth = borderBoxWidth(); |
| updateLogicalWidth(); |
| // If we shrink to fit our width may have changed, so we still need full layout. |
| if (oldWidth != borderBoxWidth()) |
| return false; |
| updateLogicalHeight(); |
| return true; |
| } |
| |
| inline void RenderBox::markShapeOutsideDependentsForLayout() |
| { |
| if (isFloating()) |
| removeFloatingOrOutOfFlowChildFromBlockLists(); |
| } |
| |
| inline LayoutUnit resolveHeightForRatio(LayoutUnit borderAndPaddingLogicalWidth, LayoutUnit borderAndPaddingLogicalHeight, LayoutUnit logicalWidth, double aspectRatio, BoxSizing boxSizing) |
| { |
| if (boxSizing == BoxSizing::BorderBox) |
| return LayoutUnit((logicalWidth + borderAndPaddingLogicalWidth) * aspectRatio) - borderAndPaddingLogicalHeight; |
| return LayoutUnit(logicalWidth * aspectRatio); |
| } |
| |
| inline bool isSkippedContentRoot(const RenderBox& renderBox) |
| { |
| RefPtr element = renderBox.element(); |
| if (!element) |
| return false; |
| |
| return Style::ContainmentChecker { renderBox.style(), *element }.isSkippedContentRoot(); |
| } |
| |
| inline bool RenderBox::backgroundIsKnownToBeObscured(const LayoutPoint& paintOffset) |
| { |
| if (boxDecorationState() == BoxDecorationState::InvalidObscurationStatus) { |
| auto computedBoxDecorationState = [&] { |
| if (isSkippedContentRoot(*this)) |
| return BoxDecorationState::MayBeVisible; |
| return computeBackgroundIsKnownToBeObscured(paintOffset) ? BoxDecorationState::IsKnownToBeObscured : BoxDecorationState::MayBeVisible; |
| }; |
| setBoxDecorationState(computedBoxDecorationState()); |
| } |
| return boxDecorationState() == BoxDecorationState::IsKnownToBeObscured; |
| } |
| |
| inline LayoutUnit RenderBox::blockSizeFromAspectRatio(LayoutUnit borderPaddingInlineSum, LayoutUnit borderPaddingBlockSum, double aspectRatioValue, BoxSizing boxSizing, LayoutUnit inlineSize, const Style::AspectRatio& aspectRatio, bool isRenderReplaced) |
| { |
| if (boxSizing == BoxSizing::BorderBox && aspectRatio.isRatio() && !isRenderReplaced) |
| return std::max(borderPaddingBlockSum, LayoutUnit(inlineSize / aspectRatioValue)); |
| return LayoutUnit((inlineSize - borderPaddingInlineSum) / aspectRatioValue) + borderPaddingBlockSum; |
| } |
| |
| } // namespace WebCore |