| /* |
| * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| * Copyright (C) 2003, 2006, 2007 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. |
| * |
| */ |
| |
| #ifndef LayoutBox_h |
| #define LayoutBox_h |
| |
| #include "core/CoreExport.h" |
| #include "core/layout/LayoutBoxModelObject.h" |
| #include "core/layout/OverflowModel.h" |
| #include "core/layout/ScrollEnums.h" |
| #include "platform/scroll/ScrollTypes.h" |
| #include "wtf/PtrUtil.h" |
| #include <memory> |
| |
| namespace blink { |
| |
| class LayoutBlockFlow; |
| class LayoutMultiColumnSpannerPlaceholder; |
| class ShapeOutsideInfo; |
| |
| struct PaintInfo; |
| |
| enum SizeType { MainOrPreferredSize, MinSize, MaxSize }; |
| enum AvailableLogicalHeightType { |
| ExcludeMarginBorderPadding, |
| IncludeMarginBorderPadding |
| }; |
| // When painting, overlay scrollbars do not take up space and should not affect |
| // clipping behavior. During hit testing, overlay scrollbars behave like regular |
| // scrollbars and should change how hit testing is clipped. |
| enum MarginDirection { BlockDirection, InlineDirection }; |
| enum BackgroundRectType { BackgroundClipRect, BackgroundKnownOpaqueRect }; |
| |
| enum ShouldComputePreferred { ComputeActual, ComputePreferred }; |
| |
| enum ApplyOverflowClipFlag { |
| ApplyOverflowClip, |
| // Don't apply overflow clipping or scrolling. |
| ApplyNonScrollOverflowClip |
| }; |
| |
| using SnapAreaSet = HashSet<const LayoutBox*>; |
| |
| struct LayoutBoxRareData { |
| WTF_MAKE_NONCOPYABLE(LayoutBoxRareData); |
| USING_FAST_MALLOC(LayoutBoxRareData); |
| |
| public: |
| LayoutBoxRareData() |
| : m_spannerPlaceholder(nullptr), |
| m_overrideLogicalContentWidth(-1), |
| m_overrideLogicalContentHeight(-1), |
| m_hasOverrideContainingBlockContentLogicalWidth(false), |
| m_hasOverrideContainingBlockContentLogicalHeight(false), |
| m_percentHeightContainer(nullptr), |
| m_snapContainer(nullptr), |
| m_snapAreas(nullptr) {} |
| |
| // For spanners, the spanner placeholder that lays us out within the multicol |
| // container. |
| LayoutMultiColumnSpannerPlaceholder* m_spannerPlaceholder; |
| |
| LayoutUnit m_overrideLogicalContentWidth; |
| LayoutUnit m_overrideLogicalContentHeight; |
| |
| bool m_hasOverrideContainingBlockContentLogicalWidth; |
| bool m_hasOverrideContainingBlockContentLogicalHeight; |
| LayoutUnit m_overrideContainingBlockContentLogicalWidth; |
| LayoutUnit m_overrideContainingBlockContentLogicalHeight; |
| |
| LayoutUnit m_pageLogicalOffset; |
| LayoutUnit m_paginationStrut; |
| |
| LayoutBlock* m_percentHeightContainer; |
| // For snap area, the owning snap container. |
| LayoutBox* m_snapContainer; |
| // For snap container, the descendant snap areas that contribute snap |
| // points. |
| std::unique_ptr<SnapAreaSet> m_snapAreas; |
| |
| SnapAreaSet& ensureSnapAreas() { |
| if (!m_snapAreas) |
| m_snapAreas = wrapUnique(new SnapAreaSet); |
| |
| return *m_snapAreas; |
| } |
| }; |
| |
| // LayoutBox implements the full CSS box model. |
| // |
| // LayoutBoxModelObject only introduces some abstractions for LayoutInline and |
| // LayoutBox. The logic for the model is in LayoutBox, e.g. the storage for the |
| // rectangle and offset forming the CSS box (m_frameRect) and the getters for |
| // the different boxes. |
| // |
| // LayoutBox is also the uppermost class to support scrollbars, however the |
| // logic is delegated to PaintLayerScrollableArea. |
| // Per the CSS specification, scrollbars should "be inserted between the inner |
| // border edge and the outer padding edge". |
| // (see http://www.w3.org/TR/CSS21/visufx.html#overflow) |
| // Also the scrollbar width / height are removed from the content box. Taking |
| // the following example: |
| // |
| // <!DOCTYPE html> |
| // <style> |
| // ::-webkit-scrollbar { |
| // /* Force non-overlay scrollbars */ |
| // width: 10px; |
| // height: 20px; |
| // } |
| // </style> |
| // <div style="overflow:scroll; width: 100px; height: 100px"> |
| // |
| // The <div>'s content box is not 100x100 as specified in the style but 90x80 as |
| // we remove the scrollbars from the box. |
| // |
| // The presence of scrollbars is determined by the 'overflow' property and can |
| // be conditioned on having layout overflow (see OverflowModel for more details |
| // on how we track overflow). |
| // |
| // There are 2 types of scrollbars: |
| // - non-overlay scrollbars take space from the content box. |
| // - overlay scrollbars don't and just overlay hang off from the border box, |
| // potentially overlapping with the padding box's content. |
| // For more details on scrollbars, see PaintLayerScrollableArea. |
| // |
| // |
| // ***** THE BOX MODEL ***** |
| // The CSS box model is based on a series of nested boxes: |
| // http://www.w3.org/TR/CSS21/box.html |
| // |
| // |----------------------------------------------------| |
| // | | |
| // | margin-top | |
| // | | |
| // | |-----------------------------------------| | |
| // | | | | |
| // | | border-top | | |
| // | | | | |
| // | | |--------------------------|----| | | |
| // | | | | | | | |
| // | | | padding-top |####| | | |
| // | | | |####| | | |
| // | | | |----------------| |####| | | |
| // | | | | | | | | | |
| // | ML | BL | PL | content box | PR | SW | BR | MR | |
| // | | | | | | | | | |
| // | | | |----------------| | | | | |
| // | | | | | | | |
| // | | | padding-bottom | | | | |
| // | | |--------------------------|----| | | |
| // | | | ####| | | | |
| // | | | scrollbar height ####| SC | | | |
| // | | | ####| | | | |
| // | | |-------------------------------| | | |
| // | | | | |
| // | | border-bottom | | |
| // | | | | |
| // | |-----------------------------------------| | |
| // | | |
| // | margin-bottom | |
| // | | |
| // |----------------------------------------------------| |
| // |
| // BL = border-left |
| // BR = border-right |
| // ML = margin-left |
| // MR = margin-right |
| // PL = padding-left |
| // PR = padding-right |
| // SC = scroll corner (contains UI for resizing (see the 'resize' property) |
| // SW = scrollbar width |
| // |
| // Those are just the boxes from the CSS model. Extra boxes are tracked by Blink |
| // (e.g. the overflows). Thus it is paramount to know which box a function is |
| // manipulating. Also of critical importance is the coordinate system used (see |
| // the COORDINATE SYSTEMS section in LayoutBoxModelObject). |
| class CORE_EXPORT LayoutBox : public LayoutBoxModelObject { |
| public: |
| explicit LayoutBox(ContainerNode*); |
| |
| PaintLayerType layerTypeRequired() const override; |
| |
| bool backgroundIsKnownToBeOpaqueInRect( |
| const LayoutRect& localRect) const override; |
| |
| virtual bool backgroundShouldAlwaysBeClipped() const { return false; } |
| |
| // Use this with caution! No type checking is done! |
| LayoutBox* firstChildBox() const; |
| LayoutBox* lastChildBox() const; |
| |
| int pixelSnappedWidth() const { return m_frameRect.pixelSnappedWidth(); } |
| int pixelSnappedHeight() const { return m_frameRect.pixelSnappedHeight(); } |
| |
| void setX(LayoutUnit x) { |
| if (x == m_frameRect.x()) |
| return; |
| m_frameRect.setX(x); |
| frameRectChanged(); |
| } |
| void setY(LayoutUnit y) { |
| if (y == m_frameRect.y()) |
| return; |
| m_frameRect.setY(y); |
| frameRectChanged(); |
| } |
| void setWidth(LayoutUnit width) { |
| if (width == m_frameRect.width()) |
| return; |
| m_frameRect.setWidth(width); |
| frameRectChanged(); |
| } |
| void setHeight(LayoutUnit height) { |
| if (height == m_frameRect.height()) |
| return; |
| m_frameRect.setHeight(height); |
| frameRectChanged(); |
| } |
| |
| LayoutUnit logicalLeft() const { |
| return style()->isHorizontalWritingMode() ? m_frameRect.x() |
| : m_frameRect.y(); |
| } |
| LayoutUnit logicalRight() const { return logicalLeft() + logicalWidth(); } |
| LayoutUnit logicalTop() const { |
| return style()->isHorizontalWritingMode() ? m_frameRect.y() |
| : m_frameRect.x(); |
| } |
| LayoutUnit logicalBottom() const { return logicalTop() + logicalHeight(); } |
| LayoutUnit logicalWidth() const { |
| return style()->isHorizontalWritingMode() ? m_frameRect.width() |
| : m_frameRect.height(); |
| } |
| LayoutUnit logicalHeight() const { |
| return style()->isHorizontalWritingMode() ? m_frameRect.height() |
| : m_frameRect.width(); |
| } |
| |
| LayoutUnit constrainLogicalWidthByMinMax(LayoutUnit, |
| LayoutUnit, |
| LayoutBlock*) const; |
| LayoutUnit constrainLogicalHeightByMinMax( |
| LayoutUnit logicalHeight, |
| LayoutUnit intrinsicContentHeight) const; |
| LayoutUnit constrainContentBoxLogicalHeightByMinMax( |
| LayoutUnit logicalHeight, |
| LayoutUnit intrinsicContentHeight) const; |
| |
| int pixelSnappedLogicalHeight() const { |
| return style()->isHorizontalWritingMode() ? pixelSnappedHeight() |
| : pixelSnappedWidth(); |
| } |
| int pixelSnappedLogicalWidth() const { |
| return style()->isHorizontalWritingMode() ? pixelSnappedWidth() |
| : pixelSnappedHeight(); |
| } |
| |
| LayoutUnit minimumLogicalHeightForEmptyLine() const { |
| return borderAndPaddingLogicalHeight() + scrollbarLogicalHeight() + |
| lineHeight(true, |
| isHorizontalWritingMode() ? HorizontalLine : VerticalLine, |
| PositionOfInteriorLineBoxes); |
| } |
| |
| void setLogicalLeft(LayoutUnit left) { |
| if (style()->isHorizontalWritingMode()) |
| setX(left); |
| else |
| setY(left); |
| } |
| void setLogicalTop(LayoutUnit top) { |
| if (style()->isHorizontalWritingMode()) |
| setY(top); |
| else |
| setX(top); |
| } |
| void setLogicalLocation(const LayoutPoint& location) { |
| if (style()->isHorizontalWritingMode()) |
| setLocation(location); |
| else |
| setLocation(location.transposedPoint()); |
| } |
| void setLogicalWidth(LayoutUnit size) { |
| if (style()->isHorizontalWritingMode()) |
| setWidth(size); |
| else |
| setHeight(size); |
| } |
| void setLogicalHeight(LayoutUnit size) { |
| if (style()->isHorizontalWritingMode()) |
| setHeight(size); |
| else |
| setWidth(size); |
| } |
| |
| LayoutPoint location() const { return m_frameRect.location(); } |
| LayoutSize locationOffset() const { |
| return LayoutSize(m_frameRect.x(), m_frameRect.y()); |
| } |
| LayoutSize size() const { return m_frameRect.size(); } |
| IntSize pixelSnappedSize() const { return m_frameRect.pixelSnappedSize(); } |
| |
| void setLocation(const LayoutPoint& location) { |
| if (location == m_frameRect.location()) |
| return; |
| m_frameRect.setLocation(location); |
| frameRectChanged(); |
| } |
| |
| // The ancestor box that this object's location and topLeftLocation are |
| // relative to. |
| virtual LayoutBox* locationContainer() const; |
| |
| // FIXME: Currently scrollbars are using int geometry and positioned based on |
| // pixelSnappedBorderBoxRect whose size may change when location changes |
| // because of pixel snapping. This function is used to change location of the |
| // LayoutBox outside of LayoutBox::layout(). Will remove when we use |
| // LayoutUnits for scrollbars. |
| void setLocationAndUpdateOverflowControlsIfNeeded(const LayoutPoint&); |
| |
| void setSize(const LayoutSize& size) { |
| if (size == m_frameRect.size()) |
| return; |
| m_frameRect.setSize(size); |
| frameRectChanged(); |
| } |
| void move(LayoutUnit dx, LayoutUnit dy) { |
| if (!dx && !dy) |
| return; |
| m_frameRect.move(dx, dy); |
| frameRectChanged(); |
| } |
| |
| // This function is in the container's coordinate system, meaning |
| // that it includes the logical top/left offset and the |
| // inline-start/block-start margins. |
| LayoutRect frameRect() const { return m_frameRect; } |
| void setFrameRect(const LayoutRect& rect) { |
| if (rect == m_frameRect) |
| return; |
| m_frameRect = rect; |
| frameRectChanged(); |
| } |
| |
| // Note that those functions have their origin at this box's CSS border box. |
| // As such their location doesn't account for 'top'/'left'. |
| LayoutRect borderBoxRect() const { return LayoutRect(LayoutPoint(), size()); } |
| LayoutRect paddingBoxRect() const { |
| return LayoutRect(LayoutUnit(borderLeft()), LayoutUnit(borderTop()), |
| clientWidth(), clientHeight()); |
| } |
| IntRect pixelSnappedBorderBoxRect() const { |
| return IntRect(IntPoint(), m_frameRect.pixelSnappedSize()); |
| } |
| IntRect borderBoundingBox() const final { |
| return pixelSnappedBorderBoxRect(); |
| } |
| |
| // The content area of the box (excludes padding - and intrinsic padding for |
| // table cells, etc... - and border). |
| DISABLE_CFI_PERF LayoutRect contentBoxRect() const { |
| return LayoutRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), |
| contentWidth(), contentHeight()); |
| } |
| LayoutSize contentBoxOffset() const { |
| return LayoutSize(borderLeft() + paddingLeft(), borderTop() + paddingTop()); |
| } |
| // The content box in absolute coords. Ignores transforms. |
| IntRect absoluteContentBox() const; |
| // The offset of the content box in absolute coords, ignoring transforms. |
| IntSize absoluteContentBoxOffset() const; |
| // The content box converted to absolute coords (taking transforms into |
| // account). |
| FloatQuad absoluteContentQuad() const; |
| // The enclosing rectangle of the background with given opacity requirement. |
| LayoutRect backgroundRect(BackgroundRectType) const; |
| |
| // This returns the content area of the box (excluding padding and border). |
| // The only difference with contentBoxRect is that computedCSSContentBoxRect |
| // does include the intrinsic padding in the content box as this is what some |
| // callers expect (like getComputedStyle). |
| LayoutRect computedCSSContentBoxRect() const { |
| return LayoutRect( |
| borderLeft() + computedCSSPaddingLeft(), |
| borderTop() + computedCSSPaddingTop(), |
| clientWidth() - computedCSSPaddingLeft() - computedCSSPaddingRight(), |
| clientHeight() - computedCSSPaddingTop() - computedCSSPaddingBottom()); |
| } |
| |
| void addOutlineRects(Vector<LayoutRect>&, |
| const LayoutPoint& additionalOffset, |
| IncludeBlockVisualOverflowOrNot) const override; |
| |
| // Use this with caution! No type checking is done! |
| LayoutBox* previousSiblingBox() const; |
| LayoutBox* previousInFlowSiblingBox() const; |
| LayoutBox* nextSiblingBox() const; |
| LayoutBox* nextInFlowSiblingBox() const; |
| LayoutBox* parentBox() const; |
| |
| // Return the previous sibling column set or spanner placeholder. Only to be |
| // used on multicol container children. |
| LayoutBox* previousSiblingMultiColumnBox() const; |
| // Return the next sibling column set or spanner placeholder. Only to be used |
| // on multicol container children. |
| LayoutBox* nextSiblingMultiColumnBox() const; |
| |
| bool canResize() const; |
| |
| // Visual and layout overflow are in the coordinate space of the box. This |
| // means that they aren't purely physical directions. For horizontal-tb and |
| // vertical-lr they will match physical directions, but for vertical-rl, the |
| // left/right are flipped when compared to their physical counterparts. |
| // For example minX is on the left in vertical-lr, but it is on the right in |
| // vertical-rl. |
| LayoutRect noOverflowRect() const; |
| LayoutRect layoutOverflowRect() const { |
| return m_overflow ? m_overflow->layoutOverflowRect() : noOverflowRect(); |
| } |
| IntRect pixelSnappedLayoutOverflowRect() const { |
| return pixelSnappedIntRect(layoutOverflowRect()); |
| } |
| LayoutSize maxLayoutOverflow() const { |
| return LayoutSize(layoutOverflowRect().maxX(), layoutOverflowRect().maxY()); |
| } |
| LayoutUnit logicalLeftLayoutOverflow() const { |
| return style()->isHorizontalWritingMode() ? layoutOverflowRect().x() |
| : layoutOverflowRect().y(); |
| } |
| LayoutUnit logicalRightLayoutOverflow() const { |
| return style()->isHorizontalWritingMode() ? layoutOverflowRect().maxX() |
| : layoutOverflowRect().maxY(); |
| } |
| |
| LayoutRect visualOverflowRect() const override; |
| LayoutUnit logicalLeftVisualOverflow() const { |
| return style()->isHorizontalWritingMode() ? visualOverflowRect().x() |
| : visualOverflowRect().y(); |
| } |
| LayoutUnit logicalRightVisualOverflow() const { |
| return style()->isHorizontalWritingMode() ? visualOverflowRect().maxX() |
| : visualOverflowRect().maxY(); |
| } |
| |
| LayoutRect selfVisualOverflowRect() const { |
| return m_overflow ? m_overflow->selfVisualOverflowRect() : borderBoxRect(); |
| } |
| LayoutRect contentsVisualOverflowRect() const { |
| return m_overflow ? m_overflow->contentsVisualOverflowRect() : LayoutRect(); |
| } |
| |
| // These methods don't mean the box *actually* has top/left overflow. They |
| // mean that *if* the box overflows, it will overflow to the top/left rather |
| // than the bottom/right. This happens when child content is laid out |
| // right-to-left (e.g. direction:rtl) or or bottom-to-top (e.g. direction:rtl |
| // writing-mode:vertical-rl). |
| virtual bool hasTopOverflow() const; |
| virtual bool hasLeftOverflow() const; |
| |
| void addLayoutOverflow(const LayoutRect&); |
| void addSelfVisualOverflow(const LayoutRect&); |
| void addContentsVisualOverflow(const LayoutRect&); |
| |
| void addVisualEffectOverflow(); |
| LayoutRectOutsets computeVisualEffectOverflowOutsets() const; |
| void addOverflowFromChild(LayoutBox* child) { |
| addOverflowFromChild(child, child->locationOffset()); |
| } |
| void addOverflowFromChild(LayoutBox* child, const LayoutSize& delta); |
| void clearLayoutOverflow(); |
| void clearAllOverflows() { m_overflow.reset(); } |
| |
| void updateLayerTransformAfterLayout(); |
| |
| DISABLE_CFI_PERF LayoutUnit contentWidth() const { |
| return clientWidth() - paddingLeft() - paddingRight(); |
| } |
| DISABLE_CFI_PERF LayoutUnit contentHeight() const { |
| return clientHeight() - paddingTop() - paddingBottom(); |
| } |
| LayoutSize contentSize() const { |
| return LayoutSize(contentWidth(), contentHeight()); |
| } |
| LayoutUnit contentLogicalWidth() const { |
| return style()->isHorizontalWritingMode() ? contentWidth() |
| : contentHeight(); |
| } |
| LayoutUnit contentLogicalHeight() const { |
| return style()->isHorizontalWritingMode() ? contentHeight() |
| : contentWidth(); |
| } |
| |
| // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines |
| // (LayoutFlow) to return the remaining width on a given line (and the height |
| // of a single line). |
| LayoutUnit offsetWidth() const override { return m_frameRect.width(); } |
| LayoutUnit offsetHeight() const override { return m_frameRect.height(); } |
| |
| int pixelSnappedOffsetWidth(const Element*) const final; |
| int pixelSnappedOffsetHeight(const Element*) const final; |
| |
| // More IE extensions. clientWidth and clientHeight represent the interior of |
| // an object excluding border and scrollbar. clientLeft/Top are just the |
| // borderLeftWidth and borderTopWidth. |
| DISABLE_CFI_PERF LayoutUnit clientLeft() const { |
| return LayoutUnit(borderLeft() + |
| (shouldPlaceBlockDirectionScrollbarOnLogicalLeft() |
| ? verticalScrollbarWidth() |
| : 0)); |
| } |
| DISABLE_CFI_PERF LayoutUnit clientTop() const { |
| return LayoutUnit(borderTop()); |
| } |
| LayoutUnit clientWidth() const; |
| LayoutUnit clientHeight() const; |
| DISABLE_CFI_PERF LayoutUnit clientLogicalWidth() const { |
| return style()->isHorizontalWritingMode() ? clientWidth() : clientHeight(); |
| } |
| DISABLE_CFI_PERF LayoutUnit clientLogicalHeight() const { |
| return style()->isHorizontalWritingMode() ? clientHeight() : clientWidth(); |
| } |
| DISABLE_CFI_PERF LayoutUnit clientLogicalBottom() const { |
| return borderBefore() + clientLogicalHeight(); |
| } |
| DISABLE_CFI_PERF LayoutRect clientBoxRect() const { |
| return LayoutRect(clientLeft(), clientTop(), clientWidth(), clientHeight()); |
| } |
| |
| int pixelSnappedClientWidth() const; |
| int pixelSnappedClientHeight() const; |
| |
| // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight |
| // unless the object has overflow:hidden/scroll/auto specified and also has |
| // overflow. scrollLeft/Top return the current scroll position. These methods |
| // are virtual so that objects like textareas can scroll shadow content (but |
| // pretend that they are the objects that are scrolling). |
| virtual LayoutUnit scrollLeft() const; |
| virtual LayoutUnit scrollTop() const; |
| virtual LayoutUnit scrollWidth() const; |
| virtual LayoutUnit scrollHeight() const; |
| int pixelSnappedScrollWidth() const; |
| int pixelSnappedScrollHeight() const; |
| virtual void setScrollLeft(LayoutUnit); |
| virtual void setScrollTop(LayoutUnit); |
| |
| void scrollToOffset(const DoubleSize&, |
| ScrollBehavior = ScrollBehaviorInstant); |
| void scrollByRecursively(const DoubleSize& delta, |
| ScrollOffsetClamping = ScrollOffsetUnclamped); |
| // If makeVisibleInVisualViewport is set, the visual viewport will be scrolled |
| // if required to make the rect visible. |
| void scrollRectToVisible(const LayoutRect&, |
| const ScrollAlignment& alignX, |
| const ScrollAlignment& alignY, |
| ScrollType = ProgrammaticScroll, |
| bool makeVisibleInVisualViewport = true); |
| |
| LayoutRectOutsets marginBoxOutsets() const override { |
| return m_marginBoxOutsets; |
| } |
| LayoutUnit marginTop() const override { return m_marginBoxOutsets.top(); } |
| LayoutUnit marginBottom() const override { |
| return m_marginBoxOutsets.bottom(); |
| } |
| LayoutUnit marginLeft() const override { return m_marginBoxOutsets.left(); } |
| LayoutUnit marginRight() const override { return m_marginBoxOutsets.right(); } |
| void setMarginTop(LayoutUnit margin) { m_marginBoxOutsets.setTop(margin); } |
| void setMarginBottom(LayoutUnit margin) { |
| m_marginBoxOutsets.setBottom(margin); |
| } |
| void setMarginLeft(LayoutUnit margin) { m_marginBoxOutsets.setLeft(margin); } |
| void setMarginRight(LayoutUnit margin) { |
| m_marginBoxOutsets.setRight(margin); |
| } |
| |
| LayoutUnit marginLogicalLeft() const { |
| return m_marginBoxOutsets.logicalLeft(style()->getWritingMode()); |
| } |
| LayoutUnit marginLogicalRight() const { |
| return m_marginBoxOutsets.logicalRight(style()->getWritingMode()); |
| } |
| |
| LayoutUnit marginBefore( |
| const ComputedStyle* overrideStyle = nullptr) const final { |
| return m_marginBoxOutsets.before( |
| (overrideStyle ? overrideStyle : style())->getWritingMode()); |
| } |
| LayoutUnit marginAfter( |
| const ComputedStyle* overrideStyle = nullptr) const final { |
| return m_marginBoxOutsets.after( |
| (overrideStyle ? overrideStyle : style())->getWritingMode()); |
| } |
| LayoutUnit marginStart( |
| const ComputedStyle* overrideStyle = nullptr) const final { |
| const ComputedStyle* styleToUse = overrideStyle ? overrideStyle : style(); |
| return m_marginBoxOutsets.start(styleToUse->getWritingMode(), |
| styleToUse->direction()); |
| } |
| LayoutUnit marginEnd( |
| const ComputedStyle* overrideStyle = nullptr) const final { |
| const ComputedStyle* styleToUse = overrideStyle ? overrideStyle : style(); |
| return m_marginBoxOutsets.end(styleToUse->getWritingMode(), |
| styleToUse->direction()); |
| } |
| LayoutUnit marginOver() const final { |
| return m_marginBoxOutsets.over(style()->getWritingMode()); |
| } |
| LayoutUnit marginUnder() const final { |
| return m_marginBoxOutsets.under(style()->getWritingMode()); |
| } |
| void setMarginBefore(LayoutUnit value, |
| const ComputedStyle* overrideStyle = nullptr) { |
| m_marginBoxOutsets.setBefore( |
| (overrideStyle ? overrideStyle : style())->getWritingMode(), value); |
| } |
| void setMarginAfter(LayoutUnit value, |
| const ComputedStyle* overrideStyle = nullptr) { |
| m_marginBoxOutsets.setAfter( |
| (overrideStyle ? overrideStyle : style())->getWritingMode(), value); |
| } |
| void setMarginStart(LayoutUnit value, |
| const ComputedStyle* overrideStyle = nullptr) { |
| const ComputedStyle* styleToUse = overrideStyle ? overrideStyle : style(); |
| m_marginBoxOutsets.setStart(styleToUse->getWritingMode(), |
| styleToUse->direction(), value); |
| } |
| void setMarginEnd(LayoutUnit value, |
| const ComputedStyle* overrideStyle = nullptr) { |
| const ComputedStyle* styleToUse = overrideStyle ? overrideStyle : style(); |
| m_marginBoxOutsets.setEnd(styleToUse->getWritingMode(), |
| styleToUse->direction(), value); |
| } |
| |
| // The following functions are used to implement collapsing margins. |
| // All objects know their maximal positive and negative margins. The formula |
| // for computing a collapsed margin is |maxPosMargin| - |maxNegmargin|. |
| // For a non-collapsing box, such as a leaf element, this formula will simply |
| // return the margin of the element. Blocks override the maxMarginBefore and |
| // maxMarginAfter methods. |
| virtual bool isSelfCollapsingBlock() const { return false; } |
| virtual LayoutUnit collapsedMarginBefore() const { return marginBefore(); } |
| virtual LayoutUnit collapsedMarginAfter() const { return marginAfter(); } |
| LayoutRectOutsets collapsedMarginBoxLogicalOutsets() const { |
| return LayoutRectOutsets(collapsedMarginBefore(), LayoutUnit(), |
| collapsedMarginAfter(), LayoutUnit()); |
| } |
| |
| void absoluteRects(Vector<IntRect>&, |
| const LayoutPoint& accumulatedOffset) const override; |
| void absoluteQuads(Vector<FloatQuad>&) const override; |
| FloatRect localBoundingBoxRectForAccessibility() const final; |
| |
| int reflectionOffset() const; |
| // Given a rect in the object's coordinate space, returns the corresponding |
| // rect in the reflection. |
| LayoutRect reflectedRect(const LayoutRect&) const; |
| |
| void layout() override; |
| void paint(const PaintInfo&, const LayoutPoint&) const override; |
| bool nodeAtPoint(HitTestResult&, |
| const HitTestLocation& locationInContainer, |
| const LayoutPoint& accumulatedOffset, |
| HitTestAction) override; |
| |
| LayoutUnit minPreferredLogicalWidth() const override; |
| LayoutUnit maxPreferredLogicalWidth() const override; |
| |
| // FIXME: We should rename these back to overrideLogicalHeight/Width and have |
| // them store the border-box height/width like the regular height/width |
| // accessors on LayoutBox. Right now, these are different than contentHeight/ |
| // contentWidth because they still include the scrollbar height/width. |
| LayoutUnit overrideLogicalContentWidth() const; |
| LayoutUnit overrideLogicalContentHeight() const; |
| bool hasOverrideLogicalContentHeight() const; |
| bool hasOverrideLogicalContentWidth() const; |
| void setOverrideLogicalContentHeight(LayoutUnit); |
| void setOverrideLogicalContentWidth(LayoutUnit); |
| void clearOverrideSize(); |
| void clearOverrideLogicalContentHeight(); |
| void clearOverrideLogicalContentWidth(); |
| |
| LayoutUnit overrideContainingBlockContentLogicalWidth() const; |
| LayoutUnit overrideContainingBlockContentLogicalHeight() const; |
| bool hasOverrideContainingBlockLogicalWidth() const; |
| bool hasOverrideContainingBlockLogicalHeight() const; |
| void setOverrideContainingBlockContentLogicalWidth(LayoutUnit); |
| void setOverrideContainingBlockContentLogicalHeight(LayoutUnit); |
| void clearContainingBlockOverrideSize(); |
| void clearOverrideContainingBlockContentLogicalHeight(); |
| |
| LayoutUnit extraInlineOffset() const; |
| LayoutUnit extraBlockOffset() const; |
| void setExtraInlineOffset(LayoutUnit inlineOffest); |
| void setExtraBlockOffset(LayoutUnit blockOffest); |
| void clearExtraInlineAndBlockOffests(); |
| |
| LayoutSize offsetFromContainer(const LayoutObject*) const override; |
| |
| LayoutUnit adjustBorderBoxLogicalWidthForBoxSizing(float width) const; |
| LayoutUnit adjustBorderBoxLogicalHeightForBoxSizing(float height) const; |
| LayoutUnit adjustContentBoxLogicalWidthForBoxSizing(float width) const; |
| LayoutUnit adjustContentBoxLogicalHeightForBoxSizing(float height) const; |
| |
| // ComputedMarginValues holds the actual values for margins. It ignores |
| // margin collapsing as they are handled in LayoutBlockFlow. |
| // The margins are stored in logical coordinates (see COORDINATE |
| // SYSTEMS in LayoutBoxModel) for use during layout. |
| struct ComputedMarginValues { |
| DISALLOW_NEW(); |
| ComputedMarginValues() {} |
| |
| LayoutUnit m_before; |
| LayoutUnit m_after; |
| LayoutUnit m_start; |
| LayoutUnit m_end; |
| }; |
| |
| // LogicalExtentComputedValues is used both for the |
| // block-flow and inline-direction axis. |
| struct LogicalExtentComputedValues { |
| STACK_ALLOCATED(); |
| LogicalExtentComputedValues() {} |
| |
| // This is the dimension in the measured direction |
| // (logical height or logical width). |
| LayoutUnit m_extent; |
| |
| // This is the offset in the measured direction |
| // (logical top or logical left). |
| LayoutUnit m_position; |
| |
| // |m_margins| represents the margins in the measured direction. |
| // Note that ComputedMarginValues has also the margins in |
| // the orthogonal direction to have clearer names but they are |
| // ignored in the code. |
| ComputedMarginValues m_margins; |
| }; |
| |
| // Resolve auto margins in the chosen direction of the containing block so |
| // that objects can be pushed to the start, middle or end of the containing |
| // block. |
| void computeMarginsForDirection(MarginDirection forDirection, |
| const LayoutBlock* containingBlock, |
| LayoutUnit containerWidth, |
| LayoutUnit childWidth, |
| LayoutUnit& marginStart, |
| LayoutUnit& marginEnd, |
| Length marginStartLength, |
| Length marginStartEnd) const; |
| |
| // Used to resolve margins in the containing block's block-flow direction. |
| void computeAndSetBlockDirectionMargins(const LayoutBlock* containingBlock); |
| |
| LayoutUnit offsetFromLogicalTopOfFirstPage() const; |
| |
| // The page logical offset is the object's offset from the top of the page in |
| // the page progression direction (so an x-offset in vertical text and a |
| // y-offset for horizontal text). |
| LayoutUnit pageLogicalOffset() const { |
| return m_rareData ? m_rareData->m_pageLogicalOffset : LayoutUnit(); |
| } |
| void setPageLogicalOffset(LayoutUnit); |
| |
| // Specify which page or column to associate with an offset, if said offset is |
| // exactly at a page or column boundary. |
| enum PageBoundaryRule { AssociateWithFormerPage, AssociateWithLatterPage }; |
| LayoutUnit pageLogicalHeightForOffset(LayoutUnit) const; |
| LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, |
| PageBoundaryRule) const; |
| |
| // Calculate the strut to insert in order fit content of size |
| // |contentLogicalHeight|. |strutToNextPage| is the strut to add to |offset| |
| // to merely get to the top of the next page or column. This is what will be |
| // returned if the content can actually fit there. Otherwise, return the |
| // distance to the next fragmentainer that can fit this piece of content. |
| virtual LayoutUnit calculatePaginationStrutToFitContent( |
| LayoutUnit offset, |
| LayoutUnit strutToNextPage, |
| LayoutUnit contentLogicalHeight) const; |
| |
| void positionLineBox(InlineBox*); |
| void moveWithEdgeOfInlineContainerIfNecessary(bool isHorizontal); |
| |
| virtual InlineBox* createInlineBox(); |
| void dirtyLineBoxes(bool fullLayout); |
| |
| // For atomic inline elements, this function returns the inline box that |
| // contains us. Enables the atomic inline LayoutObject to quickly determine |
| // what line it is contained on and to easily iterate over structures on the |
| // line. |
| InlineBox* inlineBoxWrapper() const { return m_inlineBoxWrapper; } |
| void setInlineBoxWrapper(InlineBox*); |
| void deleteLineBoxWrapper(); |
| |
| void setSpannerPlaceholder(LayoutMultiColumnSpannerPlaceholder&); |
| void clearSpannerPlaceholder(); |
| LayoutMultiColumnSpannerPlaceholder* spannerPlaceholder() const final { |
| return m_rareData ? m_rareData->m_spannerPlaceholder : 0; |
| } |
| |
| // A pagination strut is the amount of space needed to push an in-flow block- |
| // level object (or float) to the logical top of the next page or column. It |
| // will be set both for forced breaks (e.g. page-break-before:always) and soft |
| // breaks (when there's not enough space in the current page / column for the |
| // object). The strut is baked into the logicalTop() of the object, so that |
| // logicalTop() - paginationStrut() == the original position in the previous |
| // column before deciding to break. |
| // |
| // Pagination struts are either set in front of a block-level box (here) or |
| // before a line (RootInlineBox::paginationStrut()). |
| LayoutUnit paginationStrut() const { |
| return m_rareData ? m_rareData->m_paginationStrut : LayoutUnit(); |
| } |
| void setPaginationStrut(LayoutUnit); |
| void resetPaginationStrut() { |
| if (m_rareData) |
| m_rareData->m_paginationStrut = LayoutUnit(); |
| } |
| |
| // Is the specified break-before or break-after value supported on this |
| // object? It needs to be in-flow all the way up to a fragmentation context |
| // that supports the specified value. |
| bool isBreakBetweenControllable(EBreak) const; |
| |
| // Is the specified break-inside value supported on this object? It needs to |
| // be contained by a fragmentation context that supports the specified value. |
| bool isBreakInsideControllable(EBreak) const; |
| |
| virtual EBreak breakAfter() const; |
| virtual EBreak breakBefore() const; |
| EBreak breakInside() const; |
| |
| // Join two adjacent break values specified on break-before and/or break- |
| // after. avoid* values win over auto values, and forced break values win over |
| // avoid* values. |firstValue| is specified on an element earlier in the flow |
| // than |secondValue|. This method is used at class A break points [1], to |
| // join the values of the previous break-after and the next break-before, to |
| // figure out whether we may, must, or should not, break at that point. It is |
| // also used when propagating break-before values from first children and |
| // break-after values on last children to their container. |
| // |
| // [1] https://drafts.csswg.org/css-break/#possible-breaks |
| static EBreak joinFragmentainerBreakValues(EBreak firstValue, |
| EBreak secondValue); |
| |
| static bool isForcedFragmentainerBreakValue(EBreak); |
| |
| EBreak classABreakPointValue(EBreak previousBreakAfterValue) const; |
| |
| // Return true if we should insert a break in front of this box. The box needs |
| // to start at a valid class A break point in order to allow a forced break. |
| // To determine whether or not to break, we also need to know the break-after |
| // value of the previous in-flow sibling. |
| bool needsForcedBreakBefore(EBreak previousBreakAfterValue) const; |
| |
| bool paintedOutputOfObjectHasNoEffectRegardlessOfSize() const override; |
| LayoutRect localOverflowRectForPaintInvalidation() const override; |
| bool mapToVisualRectInAncestorSpace( |
| const LayoutBoxModelObject* ancestor, |
| LayoutRect&, |
| VisualRectFlags = DefaultVisualRectFlags) const override; |
| |
| LayoutUnit containingBlockLogicalHeightForGetComputedStyle() const; |
| |
| LayoutUnit containingBlockLogicalWidthForContent() const override; |
| LayoutUnit containingBlockLogicalHeightForContent( |
| AvailableLogicalHeightType) const; |
| |
| LayoutUnit containingBlockAvailableLineWidth() const; |
| LayoutUnit perpendicularContainingBlockLogicalHeight() const; |
| |
| virtual void updateLogicalWidth(); |
| void updateLogicalHeight(); |
| virtual void computeLogicalHeight(LayoutUnit logicalHeight, |
| LayoutUnit logicalTop, |
| LogicalExtentComputedValues&) const; |
| // This function will compute the logical border-box height, without laying |
| // out the box. This means that the result is only "correct" when the height |
| // is explicitly specified. This function exists so that intrinsic width |
| // calculations have a way to deal with children that have orthogonal flows. |
| // When there is no explicit height, this function assumes a content height of |
| // zero (and returns just border+padding). |
| LayoutUnit computeLogicalHeightWithoutLayout() const; |
| |
| void computeLogicalWidth(LogicalExtentComputedValues&) const; |
| |
| bool stretchesToViewport() const { |
| return document().inQuirksMode() && stretchesToViewportInQuirksMode(); |
| } |
| |
| virtual LayoutSize intrinsicSize() const { return LayoutSize(); } |
| LayoutUnit intrinsicLogicalWidth() const { |
| return style()->isHorizontalWritingMode() ? intrinsicSize().width() |
| : intrinsicSize().height(); |
| } |
| LayoutUnit intrinsicLogicalHeight() const { |
| return style()->isHorizontalWritingMode() ? intrinsicSize().height() |
| : intrinsicSize().width(); |
| } |
| virtual LayoutUnit intrinsicContentLogicalHeight() const { |
| return m_intrinsicContentLogicalHeight; |
| } |
| |
| // Whether or not the element shrinks to its intrinsic width (rather than |
| // filling the width of a containing block). HTML4 buttons, <select>s, |
| // <input>s, legends, and floating/compact elements do this. |
| bool sizesLogicalWidthToFitContent(const Length& logicalWidth) const; |
| |
| LayoutUnit shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, |
| LayoutUnit childMarginEnd, |
| const LayoutBlockFlow* cb) const; |
| |
| LayoutUnit computeLogicalWidthUsing(SizeType, |
| const Length& logicalWidth, |
| LayoutUnit availableLogicalWidth, |
| const LayoutBlock* containingBlock) const; |
| LayoutUnit computeLogicalHeightUsing(SizeType, |
| const Length& height, |
| LayoutUnit intrinsicContentHeight) const; |
| LayoutUnit computeContentLogicalHeight( |
| SizeType, |
| const Length& height, |
| LayoutUnit intrinsicContentHeight) const; |
| LayoutUnit computeContentAndScrollbarLogicalHeightUsing( |
| SizeType, |
| const Length& height, |
| LayoutUnit intrinsicContentHeight) const; |
| LayoutUnit computeReplacedLogicalWidthUsing(SizeType, |
| const Length& width) const; |
| LayoutUnit computeReplacedLogicalWidthRespectingMinMaxWidth( |
| LayoutUnit logicalWidth, |
| ShouldComputePreferred = ComputeActual) const; |
| LayoutUnit computeReplacedLogicalHeightUsing(SizeType, |
| const Length& height) const; |
| LayoutUnit computeReplacedLogicalHeightRespectingMinMaxHeight( |
| LayoutUnit logicalHeight) const; |
| |
| virtual LayoutUnit computeReplacedLogicalWidth( |
| ShouldComputePreferred = ComputeActual) const; |
| virtual LayoutUnit computeReplacedLogicalHeight( |
| LayoutUnit estimatedUsedWidth = LayoutUnit()) const; |
| |
| bool percentageLogicalHeightIsResolvable() const; |
| LayoutUnit computePercentageLogicalHeight(const Length& height) const; |
| |
| // Block flows subclass availableWidth/Height to handle multi column layout |
| // (shrinking the width/height available to children when laying out.) |
| LayoutUnit availableLogicalWidth() const { return contentLogicalWidth(); } |
| LayoutUnit availableLogicalHeight(AvailableLogicalHeightType) const; |
| LayoutUnit availableLogicalHeightUsing(const Length&, |
| AvailableLogicalHeightType) const; |
| |
| // There are a few cases where we need to refer specifically to the available |
| // physical width and available physical height. Relative positioning is one |
| // of those cases, since left/top offsets are physical. |
| LayoutUnit availableWidth() const { |
| return style()->isHorizontalWritingMode() |
| ? availableLogicalWidth() |
| : availableLogicalHeight(IncludeMarginBorderPadding); |
| } |
| LayoutUnit availableHeight() const { |
| return style()->isHorizontalWritingMode() |
| ? availableLogicalHeight(IncludeMarginBorderPadding) |
| : availableLogicalWidth(); |
| } |
| |
| int verticalScrollbarWidth() const; |
| int horizontalScrollbarHeight() const; |
| int scrollbarLogicalWidth() const { |
| return style()->isHorizontalWritingMode() ? verticalScrollbarWidth() |
| : horizontalScrollbarHeight(); |
| } |
| int scrollbarLogicalHeight() const { |
| return style()->isHorizontalWritingMode() ? horizontalScrollbarHeight() |
| : verticalScrollbarWidth(); |
| } |
| virtual ScrollResult scroll(ScrollGranularity, const FloatSize&); |
| bool canBeScrolledAndHasScrollableArea() const; |
| virtual bool canBeProgramaticallyScrolled() const; |
| virtual void autoscroll(const IntPoint&); |
| bool canAutoscroll() const; |
| IntSize calculateAutoscrollDirection(const IntPoint& pointInRootFrame) const; |
| static LayoutBox* findAutoscrollable(LayoutObject*); |
| virtual void stopAutoscroll() {} |
| virtual void middleClickAutoscroll(const IntPoint&); |
| |
| DISABLE_CFI_PERF bool hasAutoVerticalScrollbar() const { |
| return hasOverflowClip() && (style()->overflowY() == OverflowAuto || |
| style()->overflowY() == OverflowPagedY || |
| style()->overflowY() == OverflowOverlay); |
| } |
| DISABLE_CFI_PERF bool hasAutoHorizontalScrollbar() const { |
| return hasOverflowClip() && (style()->overflowX() == OverflowAuto || |
| style()->overflowX() == OverflowOverlay); |
| } |
| DISABLE_CFI_PERF bool scrollsOverflow() const { |
| return scrollsOverflowX() || scrollsOverflowY(); |
| } |
| virtual bool shouldPlaceBlockDirectionScrollbarOnLogicalLeft() const { |
| return style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft(); |
| } |
| |
| bool hasScrollableOverflowX() const { |
| return scrollsOverflowX() && |
| pixelSnappedScrollWidth() != pixelSnappedClientWidth(); |
| } |
| bool hasScrollableOverflowY() const { |
| return scrollsOverflowY() && |
| pixelSnappedScrollHeight() != pixelSnappedClientHeight(); |
| } |
| virtual bool scrollsOverflowX() const { |
| return hasOverflowClip() && (style()->overflowX() == OverflowScroll || |
| hasAutoHorizontalScrollbar()); |
| } |
| virtual bool scrollsOverflowY() const { |
| return hasOverflowClip() && (style()->overflowY() == OverflowScroll || |
| hasAutoVerticalScrollbar()); |
| } |
| |
| // Elements such as the <input> field override this to specify that they are |
| // scrollable outside the context of the CSS overflow style |
| virtual bool isIntrinsicallyScrollable( |
| ScrollbarOrientation orientation) const { |
| return false; |
| } |
| |
| bool hasUnsplittableScrollingOverflow() const; |
| |
| // Page / column breakability inside block-level objects. |
| enum PaginationBreakability { |
| AllowAnyBreaks, // No restrictions on breaking. May examine children to |
| // find possible break points. |
| ForbidBreaks, // Forbid breaks inside this object. Content cannot be split |
| // nicely into smaller pieces. |
| AvoidBreaks // Preferably avoid breaks. If not possible, examine children |
| // to find possible break points. |
| }; |
| PaginationBreakability getPaginationBreakability() const; |
| |
| LayoutRect localCaretRect( |
| InlineBox*, |
| int caretOffset, |
| LayoutUnit* extraWidthToEndOfLine = nullptr) override; |
| |
| virtual LayoutRect overflowClipRect( |
| const LayoutPoint& location, |
| OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const; |
| LayoutRect clipRect(const LayoutPoint& location) const; |
| virtual bool hasControlClip() const { return false; } |
| virtual LayoutRect controlClipRect(const LayoutPoint&) const { |
| return LayoutRect(); |
| } |
| |
| // Returns the combination of overflow clip, contain: paint clip and CSS clip |
| // for this object, in local space. |
| LayoutRect clippingRect() const; |
| |
| virtual void paintBoxDecorationBackground(const PaintInfo&, |
| const LayoutPoint&) const; |
| virtual void paintMask(const PaintInfo&, const LayoutPoint&) const; |
| void imageChanged(WrappedImagePtr, const IntRect* = nullptr) override; |
| ResourcePriority computeResourcePriority() const final; |
| |
| void logicalExtentAfterUpdatingLogicalWidth(const LayoutUnit& logicalTop, |
| LogicalExtentComputedValues&); |
| |
| PositionWithAffinity positionForPoint(const LayoutPoint&) override; |
| |
| void removeFloatingOrPositionedChildFromBlockLists(); |
| |
| PaintLayer* enclosingFloatPaintingLayer() const; |
| |
| virtual int firstLineBoxBaseline() const { return -1; } |
| virtual int inlineBlockBaseline(LineDirectionMode) const { |
| return -1; |
| } // Returns -1 if we should skip this box when computing the baseline of an |
| // inline-block. |
| |
| virtual Node* nodeForHitTest() const { return node(); } |
| |
| bool shrinkToAvoidFloats() const; |
| virtual bool avoidsFloats() const; |
| |
| void markChildForPaginationRelayoutIfNeeded(LayoutBox& child, |
| SubtreeLayoutScope&); |
| |
| bool isWritingModeRoot() const { |
| return !parent() || |
| parent()->style()->getWritingMode() != style()->getWritingMode(); |
| } |
| bool isOrthogonalWritingModeRoot() const { |
| return parent() && |
| parent()->isHorizontalWritingMode() != isHorizontalWritingMode(); |
| } |
| void markOrthogonalWritingModeRoot(); |
| void unmarkOrthogonalWritingModeRoot(); |
| |
| bool isDeprecatedFlexItem() const { |
| return !isInline() && !isFloatingOrOutOfFlowPositioned() && parent() && |
| parent()->isDeprecatedFlexibleBox(); |
| } |
| bool isFlexItemIncludingDeprecated() const { |
| return !isInline() && !isFloatingOrOutOfFlowPositioned() && parent() && |
| parent()->isFlexibleBoxIncludingDeprecated(); |
| } |
| bool isFlexItem() const { |
| return !isInline() && !isFloatingOrOutOfFlowPositioned() && parent() && |
| parent()->isFlexibleBox(); |
| } |
| |
| bool isGridItem() const { return parent() && parent()->isLayoutGrid(); } |
| |
| LayoutUnit lineHeight( |
| bool firstLine, |
| LineDirectionMode, |
| LinePositionMode = PositionOnContainingLine) const override; |
| int baselinePosition( |
| FontBaseline, |
| bool firstLine, |
| LineDirectionMode, |
| LinePositionMode = PositionOnContainingLine) const override; |
| |
| LayoutUnit offsetLeft(const Element*) const override; |
| LayoutUnit offsetTop(const Element*) const override; |
| |
| LayoutPoint flipForWritingModeForChild(const LayoutBox* child, |
| const LayoutPoint&) const; |
| LayoutUnit flipForWritingMode(LayoutUnit position) const WARN_UNUSED_RETURN { |
| // The offset is in the block direction (y for horizontal writing modes, x |
| // for vertical writing modes). |
| if (!UNLIKELY(hasFlippedBlocksWritingMode())) |
| return position; |
| return logicalHeight() - position; |
| } |
| LayoutPoint flipForWritingMode(const LayoutPoint& position) const |
| WARN_UNUSED_RETURN { |
| if (!UNLIKELY(hasFlippedBlocksWritingMode())) |
| return position; |
| return isHorizontalWritingMode() |
| ? LayoutPoint(position.x(), m_frameRect.height() - position.y()) |
| : LayoutPoint(m_frameRect.width() - position.x(), position.y()); |
| } |
| LayoutSize flipForWritingMode(const LayoutSize& offset) const |
| WARN_UNUSED_RETURN { |
| if (!UNLIKELY(hasFlippedBlocksWritingMode())) |
| return offset; |
| return LayoutSize(m_frameRect.width() - offset.width(), offset.height()); |
| } |
| void flipForWritingMode(LayoutRect& rect) const { |
| if (!UNLIKELY(hasFlippedBlocksWritingMode())) |
| return; |
| rect.setX(m_frameRect.width() - rect.maxX()); |
| } |
| FloatPoint flipForWritingMode(const FloatPoint& position) const |
| WARN_UNUSED_RETURN { |
| if (!UNLIKELY(hasFlippedBlocksWritingMode())) |
| return position; |
| return FloatPoint(m_frameRect.width() - position.x(), position.y()); |
| } |
| void flipForWritingMode(FloatRect& rect) const { |
| if (!UNLIKELY(hasFlippedBlocksWritingMode())) |
| return; |
| rect.setX(m_frameRect.width() - rect.maxX()); |
| } |
| // These represent your location relative to your container as a physical |
| // offset. In layout related methods you almost always want the logical |
| // location (e.g. x() and y()). Passing |container| causes flipped-block |
| // flipping w.r.t. that container, or containingBlock() otherwise. |
| LayoutPoint topLeftLocation( |
| const LayoutBox* flippedBlocksContainer = nullptr) const; |
| LayoutSize topLeftLocationOffset() const { |
| return toLayoutSize(topLeftLocation()); |
| } |
| |
| LayoutRect logicalVisualOverflowRectForPropagation( |
| const ComputedStyle&) const; |
| LayoutRect visualOverflowRectForPropagation(const ComputedStyle&) const; |
| LayoutRect logicalLayoutOverflowRectForPropagation( |
| const ComputedStyle&) const; |
| LayoutRect layoutOverflowRectForPropagation(const ComputedStyle&) const; |
| |
| bool hasOverflowModel() const { return m_overflow.get(); } |
| bool hasSelfVisualOverflow() const { |
| return m_overflow && |
| !borderBoxRect().contains(m_overflow->selfVisualOverflowRect()); |
| } |
| bool hasVisualOverflow() const { |
| return m_overflow && !borderBoxRect().contains(visualOverflowRect()); |
| } |
| |
| virtual bool needsPreferredWidthsRecalculation() const; |
| |
| // See README.md for an explanation of scroll origin. |
| virtual IntSize originAdjustmentForScrollbars() const; |
| IntSize scrolledContentOffset() const; |
| |
| // Maps a rect in scrolling contents space to box space and apply overflow |
| // clip if needed. Returns true if no clipping applied or the rect actually |
| // intersects the clipping region. If edgeInclusive is true, then this method |
| // may return true even if the resulting rect has zero area. |
| bool mapScrollingContentsRectToBoxSpace( |
| LayoutRect&, |
| ApplyOverflowClipFlag, |
| VisualRectFlags = DefaultVisualRectFlags) const; |
| |
| virtual bool hasRelativeLogicalWidth() const; |
| virtual bool hasRelativeLogicalHeight() const; |
| |
| bool hasHorizontalLayoutOverflow() const { |
| if (!m_overflow) |
| return false; |
| |
| LayoutRect layoutOverflowRect = m_overflow->layoutOverflowRect(); |
| LayoutRect noOverflowRect = this->noOverflowRect(); |
| return layoutOverflowRect.x() < noOverflowRect.x() || |
| layoutOverflowRect.maxX() > noOverflowRect.maxX(); |
| } |
| |
| bool hasVerticalLayoutOverflow() const { |
| if (!m_overflow) |
| return false; |
| |
| LayoutRect layoutOverflowRect = m_overflow->layoutOverflowRect(); |
| LayoutRect noOverflowRect = this->noOverflowRect(); |
| return layoutOverflowRect.y() < noOverflowRect.y() || |
| layoutOverflowRect.maxY() > noOverflowRect.maxY(); |
| } |
| |
| virtual LayoutBox* createAnonymousBoxWithSameTypeAs( |
| const LayoutObject*) const { |
| ASSERT_NOT_REACHED(); |
| return nullptr; |
| } |
| |
| bool hasSameDirectionAs(const LayoutBox* object) const { |
| return style()->direction() == object->style()->direction(); |
| } |
| |
| ShapeOutsideInfo* shapeOutsideInfo() const; |
| |
| void markShapeOutsideDependentsForLayout() { |
| if (isFloating()) |
| removeFloatingOrPositionedChildFromBlockLists(); |
| } |
| |
| void setIntrinsicContentLogicalHeight( |
| LayoutUnit intrinsicContentLogicalHeight) const { |
| m_intrinsicContentLogicalHeight = intrinsicContentLogicalHeight; |
| } |
| |
| bool canRenderBorderImage() const; |
| |
| void mapLocalToAncestor( |
| const LayoutBoxModelObject* ancestor, |
| TransformState&, |
| MapCoordinatesFlags = ApplyContainerFlip) const override; |
| void mapAncestorToLocal(const LayoutBoxModelObject*, |
| TransformState&, |
| MapCoordinatesFlags) const override; |
| |
| void clearPreviousPaintInvalidationRects() override; |
| |
| LayoutBlock* percentHeightContainer() const { |
| return m_rareData ? m_rareData->m_percentHeightContainer : nullptr; |
| } |
| void setPercentHeightContainer(LayoutBlock*); |
| void removeFromPercentHeightContainer(); |
| void clearPercentHeightDescendants(); |
| // For snap areas, returns the snap container that owns us. |
| LayoutBox* snapContainer() const; |
| void setSnapContainer(LayoutBox*); |
| // For snap containers, returns all associated snap areas. |
| SnapAreaSet* snapAreas() const; |
| void clearSnapAreas(); |
| |
| bool hitTestClippedOutByRoundedBorder( |
| const HitTestLocation& locationInContainer, |
| const LayoutPoint& borderBoxLocation) const; |
| |
| static bool mustInvalidateFillLayersPaintOnWidthChange(const FillLayer&); |
| static bool mustInvalidateFillLayersPaintOnHeightChange(const FillLayer&); |
| |
| bool mustInvalidateBackgroundOrBorderPaintOnHeightChange() const; |
| bool mustInvalidateBackgroundOrBorderPaintOnWidthChange() const; |
| |
| // Returns true if the box intersects the viewport visible to the user. |
| bool intersectsVisibleViewport() const; |
| |
| bool hasNonCompositedScrollbars() const final; |
| |
| protected: |
| void willBeDestroyed() override; |
| |
| void insertedIntoTree() override; |
| void willBeRemovedFromTree() override; |
| |
| void styleWillChange(StyleDifference, const ComputedStyle& newStyle) override; |
| void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override; |
| void updateFromStyle() override; |
| |
| virtual ItemPosition selfAlignmentNormalBehavior() const { |
| return ItemPositionStretch; |
| } |
| |
| // Returns false if it could not cheaply compute the extent (e.g. fixed |
| // background), in which case the returned rect may be incorrect. |
| // FIXME: make this a const method once the LayoutBox reference in BoxPainter |
| // is const. |
| bool getBackgroundPaintedExtent(LayoutRect&) const; |
| virtual bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, |
| unsigned maxDepthToTest) const; |
| bool computeBackgroundIsKnownToBeObscured() const override; |
| |
| virtual void computePositionedLogicalWidth( |
| LogicalExtentComputedValues&) const; |
| |
| LayoutUnit computeIntrinsicLogicalWidthUsing( |
| const Length& logicalWidthLength, |
| LayoutUnit availableLogicalWidth, |
| LayoutUnit borderAndPadding) const; |
| virtual LayoutUnit computeIntrinsicLogicalContentHeightUsing( |
| const Length& logicalHeightLength, |
| LayoutUnit intrinsicContentHeight, |
| LayoutUnit borderAndPadding) const; |
| |
| virtual bool shouldComputeSizeAsReplaced() const { |
| return isAtomicInlineLevel() && !isInlineBlockOrInlineTable(); |
| } |
| |
| LayoutObject* splitAnonymousBoxesAroundChild(LayoutObject* beforeChild); |
| |
| virtual bool hitTestOverflowControl(HitTestResult&, |
| const HitTestLocation&, |
| const LayoutPoint&) { |
| return false; |
| } |
| virtual bool hitTestChildren(HitTestResult&, |
| const HitTestLocation& locationInContainer, |
| const LayoutPoint& accumulatedOffset, |
| HitTestAction); |
| void addLayerHitTestRects(LayerHitTestRects&, |
| const PaintLayer* currentCompositedLayer, |
| const LayoutPoint& layerOffset, |
| const LayoutRect& containerRect) const override; |
| void computeSelfHitTestRects(Vector<LayoutRect>&, |
| const LayoutPoint& layerOffset) const override; |
| |
| PaintInvalidationReason invalidatePaintIfNeeded( |
| const PaintInvalidationState&) override; |
| PaintInvalidationReason invalidatePaintIfNeeded( |
| const PaintInvalidatorContext&) const override; |
| |
| bool columnFlexItemHasStretchAlignment() const; |
| bool isStretchingColumnFlexItem() const; |
| bool hasStretchedLogicalWidth() const; |
| |
| void excludeScrollbars( |
| LayoutRect&, |
| OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const; |
| |
| LayoutUnit containingBlockLogicalWidthForPositioned( |
| const LayoutBoxModelObject* containingBlock, |
| bool checkForPerpendicularWritingMode = true) const; |
| LayoutUnit containingBlockLogicalHeightForPositioned( |
| const LayoutBoxModelObject* containingBlock, |
| bool checkForPerpendicularWritingMode = true) const; |
| |
| static void computeBlockStaticDistance( |
| Length& logicalTop, |
| Length& logicalBottom, |
| const LayoutBox* child, |
| const LayoutBoxModelObject* containerBlock); |
| static void computeInlineStaticDistance( |
| Length& logicalLeft, |
| Length& logicalRight, |
| const LayoutBox* child, |
| const LayoutBoxModelObject* containerBlock, |
| LayoutUnit containerLogicalWidth); |
| static void computeLogicalLeftPositionedOffset( |
| LayoutUnit& logicalLeftPos, |
| const LayoutBox* child, |
| LayoutUnit logicalWidthValue, |
| const LayoutBoxModelObject* containerBlock, |
| LayoutUnit containerLogicalWidth); |
| static void computeLogicalTopPositionedOffset( |
| LayoutUnit& logicalTopPos, |
| const LayoutBox* child, |
| LayoutUnit logicalHeightValue, |
| const LayoutBoxModelObject* containerBlock, |
| LayoutUnit containerLogicalHeight); |
| bool skipContainingBlockForPercentHeightCalculation( |
| const LayoutBox* containingBlock) const; |
| |
| private: |
| void updateShapeOutsideInfoAfterStyleChange(const ComputedStyle&, |
| const ComputedStyle* oldStyle); |
| void updateGridPositionAfterStyleChange(const ComputedStyle*); |
| void updateScrollSnapMappingAfterStyleChange(const ComputedStyle*, |
| const ComputedStyle* oldStyle); |
| void clearScrollSnapMapping(); |
| void addScrollSnapMapping(); |
| |
| bool autoWidthShouldFitContent() const; |
| LayoutUnit shrinkToFitLogicalWidth(LayoutUnit availableLogicalWidth, |
| LayoutUnit bordersPlusPadding) const; |
| |
| bool stretchesToViewportInQuirksMode() const; |
| |
| virtual void computePositionedLogicalHeight( |
| LogicalExtentComputedValues&) const; |
| void computePositionedLogicalWidthUsing( |
| SizeType, |
| Length logicalWidth, |
| const LayoutBoxModelObject* containerBlock, |
| TextDirection containerDirection, |
| LayoutUnit containerLogicalWidth, |
| LayoutUnit bordersPlusPadding, |
| const Length& logicalLeft, |
| const Length& logicalRight, |
| const Length& marginLogicalLeft, |
| const Length& marginLogicalRight, |
| LogicalExtentComputedValues&) const; |
| void computePositionedLogicalHeightUsing( |
| SizeType, |
| Length logicalHeightLength, |
| const LayoutBoxModelObject* containerBlock, |
| LayoutUnit containerLogicalHeight, |
| LayoutUnit bordersPlusPadding, |
| LayoutUnit logicalHeight, |
| const Length& logicalTop, |
| const Length& logicalBottom, |
| const Length& marginLogicalTop, |
| const Length& marginLogicalBottom, |
| LogicalExtentComputedValues&) const; |
| |
| LayoutUnit fillAvailableMeasure(LayoutUnit availableLogicalWidth) const; |
| LayoutUnit fillAvailableMeasure(LayoutUnit availableLogicalWidth, |
| LayoutUnit& marginStart, |
| LayoutUnit& marginEnd) const; |
| |
| // Calculates the intrinsic(https://drafts.csswg.org/css-sizing-3/#intrinsic) |
| // logical widths for this layout box. |
| // |
| // intrinsicWidth is defined as: |
| // intrinsic size of content (without our border and padding) + |
| // scrollbarWidth. |
| // |
| // preferredWidth is defined as: |
| // fixedWidth OR (intrinsicWidth plus border and padding). |
| // Note: fixedWidth includes border and padding and scrollbarWidth. |
| virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, |
| LayoutUnit& maxLogicalWidth) const; |
| |
| // This function calculates the preferred widths for an object. |
| // |
| // This function is only expected to be called if |
| // the boolean preferredLogicalWidthsDirty is true. It also MUST clear the |
| // boolean before returning. |
| // |
| // See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS in LayoutObject.h for more |
| // details about those widths. |
| virtual void computePreferredLogicalWidths() { |
| clearPreferredLogicalWidthsDirty(); |
| } |
| |
| LayoutBoxRareData& ensureRareData() { |
| if (!m_rareData) |
| m_rareData = wrapUnique(new LayoutBoxRareData()); |
| return *m_rareData.get(); |
| } |
| |
| bool logicalHeightComputesAsNone(SizeType) const; |
| |
| bool isBox() const = |
| delete; // This will catch anyone doing an unnecessary check. |
| |
| void frameRectChanged(); |
| |
| virtual bool isInSelfHitTestingPhase(HitTestAction hitTestAction) const { |
| return hitTestAction == HitTestForeground; |
| } |
| |
| void updateBackgroundAttachmentFixedStatusAfterStyleChange(); |
| |
| // The CSS border box rect for this box. |
| // |
| // The rectangle is in this box's physical coordinates but with a |
| // flipped block-flow direction (see the COORDINATE SYSTEMS section |
| // in LayoutBoxModelObject). The location is the distance from this |
| // object's border edge to the container's border edge (which is not |
| // always the parent). Thus it includes any logical top/left along |
| // with this box's margins. |
| LayoutRect m_frameRect; |
| |
| // Our intrinsic height, used for min-height: min-content etc. Maintained by |
| // updateLogicalHeight. This is logicalHeight() before it is clamped to |
| // min/max. |
| mutable LayoutUnit m_intrinsicContentLogicalHeight; |
| |
| void inflateVisualRectForFilter(LayoutRect&) const; |
| void inflateVisualRectForFilterUnderContainer( |
| LayoutRect&, |
| const LayoutObject& container, |
| const LayoutBoxModelObject* ancestorToStopAt) const; |
| |
| LayoutRectOutsets m_marginBoxOutsets; |
| |
| void addSnapArea(const LayoutBox&); |
| void removeSnapArea(const LayoutBox&); |
| |
| LayoutRect debugRect() const override; |
| |
| protected: |
| // The logical width of the element if it were to break its lines at every |
| // possible opportunity. |
| // |
| // See LayoutObject::minPreferredLogicalWidth() for more details. |
| LayoutUnit m_minPreferredLogicalWidth; |
| |
| // The logical width of the element if it never breaks any lines at all. |
| // |
| // See LayoutObject::maxPreferredLogicalWidth() for more details. |
| LayoutUnit m_maxPreferredLogicalWidth; |
| |
| // Our overflow information. |
| std::unique_ptr<BoxOverflowModel> m_overflow; |
| |
| private: |
| // The inline box containing this LayoutBox, for atomic inline elements. |
| InlineBox* m_inlineBoxWrapper; |
| |
| std::unique_ptr<LayoutBoxRareData> m_rareData; |
| }; |
| |
| DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutBox, isBox()); |
| |
| inline LayoutBox* LayoutBox::previousSiblingBox() const { |
| return toLayoutBox(previousSibling()); |
| } |
| |
| inline LayoutBox* LayoutBox::previousInFlowSiblingBox() const { |
| LayoutBox* previous = previousSiblingBox(); |
| while (previous && previous->isOutOfFlowPositioned()) |
| previous = previous->previousSiblingBox(); |
| return previous; |
| } |
| |
| inline LayoutBox* LayoutBox::nextSiblingBox() const { |
| return toLayoutBox(nextSibling()); |
| } |
| |
| inline LayoutBox* LayoutBox::nextInFlowSiblingBox() const { |
| LayoutBox* next = nextSiblingBox(); |
| while (next && next->isOutOfFlowPositioned()) |
| next = next->nextSiblingBox(); |
| return next; |
| } |
| |
| inline LayoutBox* LayoutBox::parentBox() const { |
| return toLayoutBox(parent()); |
| } |
| |
| inline LayoutBox* LayoutBox::firstChildBox() const { |
| return toLayoutBox(slowFirstChild()); |
| } |
| |
| inline LayoutBox* LayoutBox::lastChildBox() const { |
| return toLayoutBox(slowLastChild()); |
| } |
| |
| inline LayoutBox* LayoutBox::previousSiblingMultiColumnBox() const { |
| ASSERT(isLayoutMultiColumnSpannerPlaceholder() || isLayoutMultiColumnSet()); |
| LayoutBox* previousBox = previousSiblingBox(); |
| if (previousBox->isLayoutFlowThread()) |
| return nullptr; |
| return previousBox; |
| } |
| |
| inline LayoutBox* LayoutBox::nextSiblingMultiColumnBox() const { |
| ASSERT(isLayoutMultiColumnSpannerPlaceholder() || isLayoutMultiColumnSet()); |
| return nextSiblingBox(); |
| } |
| |
| inline void LayoutBox::setInlineBoxWrapper(InlineBox* boxWrapper) { |
| if (boxWrapper) { |
| ASSERT(!m_inlineBoxWrapper); |
| // m_inlineBoxWrapper should already be nullptr. Deleting it is a safeguard |
| // against security issues. Otherwise, there will two line box wrappers |
| // keeping the reference to this layoutObject, and only one will be notified |
| // when the layoutObject is getting destroyed. The second line box wrapper |
| // will keep a stale reference. |
| if (UNLIKELY(m_inlineBoxWrapper != nullptr)) |
| deleteLineBoxWrapper(); |
| } |
| |
| m_inlineBoxWrapper = boxWrapper; |
| } |
| |
| inline bool LayoutBox::isForcedFragmentainerBreakValue(EBreak breakValue) { |
| return breakValue == BreakColumn || breakValue == BreakLeft || |
| breakValue == BreakPage || breakValue == BreakRecto || |
| breakValue == BreakRight || breakValue == BreakVerso; |
| } |
| |
| } // namespace blink |
| |
| #endif // LayoutBox_h |