blob: 5d442d4d1e49e2eb10c15edecdd463600a3bc2be [file] [log] [blame]
/*
* Copyright (C) 2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "LayoutUnits.h"
#include "RenderStyle.h"
#include <wtf/CheckedPtr.h>
#include <wtf/IsoMalloc.h>
namespace WebCore {
namespace Layout {
class ContainerBox;
class BoxGeometry;
class InitialContainingBlock;
class LayoutState;
class TreeBuilder;
class Box : public CanMakeCheckedPtr {
WTF_MAKE_ISO_ALLOCATED(Box);
public:
enum class ElementType {
Document,
Body,
TableWrapperBox, // The table generates a principal block container box called the table wrapper box that contains the table box and any caption boxes.
TableBox, // The table box is a block-level box that contains the table's internal table boxes.
Image,
IFrame,
InsideListMarker,
OutsideListMarker,
IntegrationBlockContainer,
IntegrationInlineBlock, // Integration sets up inline-block boxes as replaced boxes.
GenericElement
};
struct ElementAttributes {
ElementType elementType;
};
enum BaseTypeFlag : uint8_t {
BoxFlag = 1 << 0,
InlineTextBoxFlag = 1 << 1,
LineBreakBoxFlag = 1 << 2,
ReplacedBoxFlag = 1 << 3,
InitialContainingBlockFlag = 1 << 4,
ContainerBoxFlag = 1 << 5
};
virtual ~Box();
bool establishesFormattingContext() const;
bool establishesBlockFormattingContext() const;
bool establishesInlineFormattingContext() const;
bool establishesTableFormattingContext() const;
bool establishesFlexFormattingContext() const;
bool establishesIndependentFormattingContext() const;
bool isInFlow() const { return !isFloatingOrOutOfFlowPositioned(); }
bool isPositioned() const { return isInFlowPositioned() || isOutOfFlowPositioned(); }
bool isInFlowPositioned() const { return isRelativelyPositioned() || isStickyPositioned(); }
bool isOutOfFlowPositioned() const { return isAbsolutelyPositioned(); }
bool isRelativelyPositioned() const;
bool isStickyPositioned() const;
bool isAbsolutelyPositioned() const;
bool isFixedPositioned() const;
bool isFloatingPositioned() const;
bool isLeftFloatingPositioned() const;
bool isRightFloatingPositioned() const;
bool hasFloatClear() const;
bool isFloatAvoider() const;
bool isFloatingOrOutOfFlowPositioned() const { return isFloatingPositioned() || isOutOfFlowPositioned(); }
const ContainerBox& containingBlock() const;
const ContainerBox& formattingContextRoot() const;
const InitialContainingBlock& initialContainingBlock() const;
bool isContainingBlockForInFlow() const;
bool isContainingBlockForFixedPosition() const;
bool isContainingBlockForOutOfFlowPosition() const;
bool isInFormattingContextOf(const ContainerBox&) const;
bool isAnonymous() const { return m_isAnonymous; }
// Block level elements generate block level boxes.
bool isBlockLevelBox() const;
// A block-level box that is also a block container.
bool isBlockBox() const;
// A block-level box is also a block container box unless it is a table box or the principal box of a replaced element.
bool isBlockContainer() const;
bool isInlineLevelBox() const;
bool isInlineBox() const;
bool isAtomicInlineLevelBox() const;
bool isInlineBlockBox() const;
bool isInlineTableBox() const;
bool isInitialContainingBlock() const { return baseTypeFlags().contains(InitialContainingBlockFlag); }
bool isLayoutContainmentBox() const;
bool isSizeContainmentBox() const;
bool isDocumentBox() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::Document; }
bool isBodyBox() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::Body; }
bool isTableWrapperBox() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::TableWrapperBox; }
bool isTableBox() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::TableBox; }
bool isTableCaption() const { return style().display() == DisplayType::TableCaption; }
bool isTableHeader() const { return style().display() == DisplayType::TableHeaderGroup; }
bool isTableBody() const { return style().display() == DisplayType::TableRowGroup; }
bool isTableFooter() const { return style().display() == DisplayType::TableFooterGroup; }
bool isTableRow() const { return style().display() == DisplayType::TableRow; }
bool isTableColumnGroup() const { return style().display() == DisplayType::TableColumnGroup; }
bool isTableColumn() const { return style().display() == DisplayType::TableColumn; }
bool isTableCell() const { return style().display() == DisplayType::TableCell; }
bool isInternalTableBox() const;
bool isFlexBox() const { return style().display() == DisplayType::Flex; }
bool isFlexItem() const;
bool isIFrame() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::IFrame; }
bool isImage() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::Image; }
bool isListMarker() const { return m_elementAttributes && (m_elementAttributes.value().elementType == ElementType::InsideListMarker || m_elementAttributes.value().elementType == ElementType::OutsideListMarker); }
bool isInsideListMarker() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::InsideListMarker; }
bool isOutsideListMarker() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::OutsideListMarker; }
bool isInternalRubyBox() const { return false; }
bool isIntegrationBlockContainer() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::IntegrationBlockContainer; }
bool isIntegrationRoot() const { return isIntegrationBlockContainer() && !m_parent; }
bool isIntegrationInlineBlock() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::IntegrationInlineBlock; }
const ContainerBox& parent() const { return *m_parent; }
const Box* nextSibling() const { return m_nextSibling.get(); }
const Box* nextInFlowSibling() const;
const Box* nextInFlowOrFloatingSibling() const;
const Box* previousSibling() const { return m_previousSibling.get(); }
const Box* previousInFlowSibling() const;
const Box* previousInFlowOrFloatingSibling() const;
bool isDescendantOf(const ContainerBox&) const;
// FIXME: This is currently needed for style updates.
Box* nextSibling() { return m_nextSibling.get(); }
bool isContainerBox() const { return baseTypeFlags().contains(ContainerBoxFlag); }
bool isInlineTextBox() const { return baseTypeFlags().contains(InlineTextBoxFlag); }
bool isLineBreakBox() const { return baseTypeFlags().contains(LineBreakBoxFlag); }
bool isReplacedBox() const { return baseTypeFlags().contains(ReplacedBoxFlag); }
bool isPaddingApplicable() const;
bool isOverflowVisible() const;
void updateStyle(const RenderStyle& newStyle, std::unique_ptr<RenderStyle>&& newFirstLineStyle);
const RenderStyle& style() const { return m_style; }
const RenderStyle& firstLineStyle() const { return hasRareData() && rareData().firstLineStyle ? *rareData().firstLineStyle : m_style; }
// FIXME: Find a better place for random DOM things.
void setRowSpan(size_t);
size_t rowSpan() const;
void setColumnSpan(size_t);
size_t columnSpan() const;
void setColumnWidth(LayoutUnit);
std::optional<LayoutUnit> columnWidth() const;
void setIsAnonymous() { m_isAnonymous = true; }
bool canCacheForLayoutState(const LayoutState&) const;
BoxGeometry* cachedGeometryForLayoutState(const LayoutState&) const;
void setCachedGeometryForLayoutState(LayoutState&, std::unique_ptr<BoxGeometry>) const;
protected:
Box(std::optional<ElementAttributes>, RenderStyle&&, std::unique_ptr<RenderStyle>&& firstLineStyle, OptionSet<BaseTypeFlag>);
private:
friend class ContainerBox;
void setParent(ContainerBox*);
void setNextSibling(Box*);
void setPreviousSibling(Box*);
class BoxRareData {
WTF_MAKE_FAST_ALLOCATED;
public:
BoxRareData() = default;
CellSpan tableCellSpan;
std::optional<LayoutUnit> columnWidth;
std::unique_ptr<RenderStyle> firstLineStyle;
};
bool hasRareData() const { return m_hasRareData; }
void setHasRareData(bool hasRareData) { m_hasRareData = hasRareData; }
const BoxRareData& rareData() const;
BoxRareData& ensureRareData();
void removeRareData();
OptionSet<BaseTypeFlag> baseTypeFlags() const { return OptionSet<BaseTypeFlag>::fromRaw(m_baseTypeFlags); }
typedef HashMap<const Box*, std::unique_ptr<BoxRareData>> RareDataMap;
static RareDataMap& rareDataMap();
RenderStyle m_style;
std::optional<ElementAttributes> m_elementAttributes;
CheckedPtr<ContainerBox> m_parent;
CheckedPtr<Box> m_previousSibling;
CheckedPtr<Box> m_nextSibling;
// First LayoutState gets a direct cache.
mutable WeakPtr<LayoutState> m_cachedLayoutState;
mutable std::unique_ptr<BoxGeometry> m_cachedGeometryForLayoutState;
unsigned m_baseTypeFlags : 6; // OptionSet<BaseTypeFlag>
bool m_hasRareData : 1;
bool m_isAnonymous : 1;
};
inline bool Box::isContainingBlockForInFlow() const
{
return isBlockContainer() || establishesFormattingContext();
}
inline bool Box::isContainingBlockForFixedPosition() const
{
return isInitialContainingBlock() || isLayoutContainmentBox() || style().hasTransform();
}
inline bool Box::isContainingBlockForOutOfFlowPosition() const
{
return isInitialContainingBlock() || isPositioned() || isLayoutContainmentBox() || style().hasTransform();
}
}
}
#define SPECIALIZE_TYPE_TRAITS_LAYOUT_BOX(ToValueTypeName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Layout::ToValueTypeName) \
static bool isType(const WebCore::Layout::Box& box) { return box.predicate; } \
SPECIALIZE_TYPE_TRAITS_END()
#endif