| /* |
| * 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. |
| */ |
| |
| #include "config.h" |
| #include "LayoutState.h" |
| |
| #include "BlockFormattingState.h" |
| #include "InlineContentCache.h" |
| #include "LayoutBox.h" |
| #include "LayoutBoxGeometry.h" |
| #include "LayoutContainingBlockChainIterator.h" |
| #include "LayoutElementBox.h" |
| #include "LayoutInitialContainingBlock.h" |
| #include "RenderBox.h" |
| #include "Settings.h" |
| #include "TableFormattingState.h" |
| #include <wtf/TZoneMallocInlines.h> |
| |
| namespace WebCore { |
| namespace Layout { |
| |
| WTF_MAKE_TZONE_ALLOCATED_IMPL(LayoutState); |
| |
| LayoutState::LayoutState(const Document& document, const ElementBox& rootContainer, Type type, FormattingContextLayoutFunction&& formattingContextLayoutFunction, FormattingContextLogicalWidthFunction&& formattingContextLogicalWidthFunction , FormattingContextLogicalHeightFunction&& formattingContextLogicalHeightFunction, FormattingContextLayoutForBlockInInlineFunction&& formattingContextLayoutForBlockInInlineFunction) |
| : m_type(type) |
| , m_isTextShapingAcrossInlineBoxesEnabled(document.settings().textShapingAcrossInlineBoxes()) |
| , m_rootContainer(rootContainer) |
| , m_securityOrigin(document.securityOrigin()) |
| , m_formattingContextLayoutFunction(WTF::move(formattingContextLayoutFunction)) |
| , m_formattingContextLogicalWidthFunction(WTF::move(formattingContextLogicalWidthFunction)) |
| , m_formattingContextLogicalHeightFunction(WTF::move(formattingContextLogicalHeightFunction)) |
| , m_formattingContextLayoutForBlockInInlineFunction(WTF::move(formattingContextLayoutForBlockInInlineFunction)) |
| { |
| // It makes absolutely no sense to construct a dedicated layout state for a non-formatting context root (layout would be a no-op). |
| ASSERT(root().establishesFormattingContext()); |
| |
| updateQuirksMode(document); |
| } |
| |
| LayoutState::~LayoutState() = default; |
| |
| void LayoutState::updateQuirksMode(const Document& document) |
| { |
| auto quirksMode = [&] { |
| if (document.inLimitedQuirksMode()) |
| return LayoutState::QuirksMode::Limited; |
| if (document.inQuirksMode()) |
| return LayoutState::QuirksMode::Yes; |
| return LayoutState::QuirksMode::No; |
| }; |
| setQuirksMode(quirksMode()); |
| } |
| |
| BoxGeometry& LayoutState::geometryForRootBox() |
| { |
| return ensureGeometryForBox(root()); |
| } |
| |
| BoxGeometry& LayoutState::ensureGeometryForBoxSlow(const Box& layoutBox) |
| { |
| if (m_type == Type::Primary) [[likely]] { |
| #if ASSERT_ENABLED |
| ASSERT(!layoutBox.m_cachedGeometryForPrimaryLayoutState); |
| ASSERT(!layoutBox.m_primaryLayoutState); |
| layoutBox.m_primaryLayoutState = this; |
| #endif |
| layoutBox.m_cachedGeometryForPrimaryLayoutState = makeUnique<BoxGeometry>(); |
| return *layoutBox.m_cachedGeometryForPrimaryLayoutState; |
| } |
| |
| return *m_layoutBoxToBoxGeometry.ensure(&layoutBox, [] { |
| return makeUnique<BoxGeometry>(); |
| }).iterator->value; |
| } |
| |
| bool LayoutState::hasFormattingState(const ElementBox& formattingContextRoot) const |
| { |
| ASSERT(formattingContextRoot.establishesFormattingContext()); |
| return m_blockFormattingStates.contains(formattingContextRoot) || m_tableFormattingStates.contains(formattingContextRoot); |
| } |
| |
| FormattingState& LayoutState::formattingStateForFormattingContext(const ElementBox& formattingContextRoot) const |
| { |
| ASSERT(formattingContextRoot.establishesFormattingContext()); |
| |
| if (formattingContextRoot.establishesBlockFormattingContext()) |
| return formattingStateForBlockFormattingContext(formattingContextRoot); |
| |
| if (formattingContextRoot.establishesTableFormattingContext()) |
| return formattingStateForTableFormattingContext(formattingContextRoot); |
| |
| CRASH(); |
| } |
| |
| BlockFormattingState& LayoutState::formattingStateForBlockFormattingContext(const ElementBox& blockFormattingContextRoot) const |
| { |
| ASSERT(blockFormattingContextRoot.establishesBlockFormattingContext()); |
| return *m_blockFormattingStates.get(blockFormattingContextRoot); |
| } |
| |
| TableFormattingState& LayoutState::formattingStateForTableFormattingContext(const ElementBox& tableFormattingContextRoot) const |
| { |
| ASSERT(tableFormattingContextRoot.establishesTableFormattingContext()); |
| return *m_tableFormattingStates.get(tableFormattingContextRoot); |
| } |
| |
| InlineContentCache& LayoutState::inlineContentCache(const ElementBox& formattingContextRoot) |
| { |
| ASSERT(formattingContextRoot.establishesInlineFormattingContext()); |
| return *m_inlineContentCaches.ensure(formattingContextRoot, [&] { return makeUnique<InlineContentCache>(); }).iterator->value; |
| } |
| |
| BlockFormattingState& LayoutState::ensureBlockFormattingState(const ElementBox& formattingContextRoot) |
| { |
| ASSERT(formattingContextRoot.establishesBlockFormattingContext()); |
| return *m_blockFormattingStates.ensure(formattingContextRoot, [&] { return makeUnique<BlockFormattingState>(*this, formattingContextRoot); }).iterator->value; |
| } |
| |
| TableFormattingState& LayoutState::ensureTableFormattingState(const ElementBox& formattingContextRoot) |
| { |
| ASSERT(formattingContextRoot.establishesTableFormattingContext()); |
| return *m_tableFormattingStates.ensure(formattingContextRoot, [&] { return makeUnique<TableFormattingState>(*this, formattingContextRoot); }).iterator->value; |
| } |
| |
| void LayoutState::destroyBlockFormattingState(const ElementBox& formattingContextRoot) |
| { |
| ASSERT(formattingContextRoot.establishesBlockFormattingContext()); |
| m_blockFormattingStates.remove(formattingContextRoot); |
| } |
| |
| void LayoutState::destroyInlineContentCache(const ElementBox& formattingContextRoot) |
| { |
| ASSERT(formattingContextRoot.establishesInlineFormattingContext()); |
| m_inlineContentCaches.remove(formattingContextRoot); |
| } |
| |
| void LayoutState::layoutWithFormattingContextForBox(const ElementBox& box, std::optional<LayoutUnit> widthConstraint, std::optional<LayoutUnit> heightConstraint) const |
| { |
| const_cast<LayoutState&>(*this).m_formattingContextLayoutFunction(box, widthConstraint, heightConstraint, const_cast<LayoutState&>(*this)); |
| } |
| |
| LayoutUnit LayoutState::logicalWidthWithFormattingContextForBox(const ElementBox& box, LayoutIntegration::LogicalWidthType logicalWidthType) const |
| { |
| return const_cast<LayoutState&>(*this).m_formattingContextLogicalWidthFunction(box, logicalWidthType); |
| } |
| |
| LayoutUnit LayoutState::logicalHeightWithFormattingContextForBox(const ElementBox& box, LayoutIntegration::LogicalHeightType logicalHeightType) const |
| { |
| return const_cast<LayoutState&>(*this).m_formattingContextLogicalHeightFunction(box, logicalHeightType); |
| } |
| |
| void LayoutState::layoutWithFormattingContextForBlockInInline(const Layout::ElementBox& block, LayoutPoint blockLineLogicalTopLeft, const InlineLayoutState& inlineLayoutState) const |
| { |
| const_cast<LayoutState&>(*this).m_formattingContextLayoutForBlockInInlineFunction(block, blockLineLogicalTopLeft, const_cast<InlineLayoutState&>(inlineLayoutState), const_cast<LayoutState&>(*this)); |
| } |
| |
| } |
| } |
| |