WebKit Bugzilla
Attachment 346142 Details for
Bug 188188
: [LFC] Add FormattingContext::mapToAncestor geometry mapping function
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
Patch.txt (text/plain), 17.37 KB, created by
zalan
on 2018-07-30 21:30:28 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
zalan
Created:
2018-07-30 21:30:28 PDT
Size:
17.37 KB
patch
obsolete
>diff --git a/Source/WebCore/layout/FloatingContext.cpp b/Source/WebCore/layout/FloatingContext.cpp >index df1dcf6a552..f1ee2db356c 100644 >--- a/Source/WebCore/layout/FloatingContext.cpp >+++ b/Source/WebCore/layout/FloatingContext.cpp >@@ -28,6 +28,7 @@ > > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > >+#include "DisplayBox.h" > #include "LayoutBox.h" > #include "LayoutContainer.h" > #include "LayoutContext.h" >@@ -38,29 +39,226 @@ namespace Layout { > > WTF_MAKE_ISO_ALLOCATED_IMPL(FloatingContext); > >-FloatingContext::FloatingContext(FloatingState& floatingState) >- : m_floatingState(floatingState) >+class FloatingPair { >+public: >+ FloatingPair(LayoutContext&, const FloatingState&); >+ >+ bool isEmpty() const { return !m_leftIndex && !m_rightIndex; } >+ const Display::Box* left() const; >+ const Display::Box* right() const; >+ bool intersects(const Display::Box::Rect&) const; >+ >+private: >+ const FloatingState& m_floatingState; >+ LayoutContext& m_layoutContext; >+ >+ std::optional<unsigned> m_leftIndex; >+ std::optional<unsigned> m_rightIndex; >+}; >+ >+class Iterator { >+public: >+ Iterator(const FloatingState&, LayoutUnit verticalPosition); >+ >+ std::optional<FloatingPair> current() const { return m_current; } >+ LayoutUnit verticalPosition() const { return m_verticalPosition; } >+ Iterator& operator++(); >+ >+private: >+ void adjustVerticalPosition(LayoutUnit verticalPosition); >+ void computeVerticalPosition(); >+ >+ const FloatingState& m_floatingState; >+ std::optional<FloatingPair> m_current; >+ LayoutUnit m_verticalPosition; >+}; >+ >+ >+FloatingContext::FloatingContext(const Container& formattingContextRoot, FloatingState& floatingState) >+ : m_formattingContextRoot(formattingContextRoot) >+ , m_floatingState(floatingState) > { >+ ASSERT(m_formattingContextRoot.establishesFormattingContext()); > } > >-Position FloatingContext::computePosition(const Box& layoutBox) >+Position FloatingContext::computePosition(const Box& layoutBox) const > { >+ ASSERT(layoutBox.isFloatingPositioned()); >+ >+ // 1. No floating box on the context yet -> align it with the containing block's left/right edge. >+ if (m_floatingState.isEmpty()) >+ return { alignWithContainingBlock(layoutBox), layoutContext().displayBoxForLayoutBox(layoutBox)->top() }; >+ >+ // 2. Find the top most postion where the float fits. >+ return floatingPosition(layoutBox); >+} >+ >+Position FloatingContext::floatingPosition(const Box& layoutBox) const >+{ >+ auto initialVerticalPosition = this->initialVerticalPosition(layoutBox); >+ auto boxSize = layoutContext().displayBoxForLayoutBox(layoutBox)->marginBox().size(); >+ >+ Iterator iterator(m_floatingState, initialVerticalPosition); >+ while (auto floatings = iterator.current()) { >+ auto top = iterator.verticalPosition(); >+ auto left = alignWithFloatings(*floatings,layoutBox); >+ >+ if (!floatings->intersects({ top, left, boxSize.width(), boxSize.height() })) >+ return { top, left }; >+ >+ ++iterator; >+ } >+ >+ // Passed the last floating, this box does not fit. >+ return { alignWithContainingBlock(layoutBox), initialVerticalPosition }; >+} >+ >+LayoutUnit FloatingContext::initialVerticalPosition(const Box& layoutBox) const >+{ >+ // Incoming float cannot be placed higher than existing floats. >+ >+ auto& displayBox = *layoutContext().displayBoxForLayoutBox(layoutBox); >+ >+ if (auto lastFloating = m_floatingState.last()) >+ return std::max(displayBox.top(), layoutContext().displayBoxForLayoutBox(*lastFloating)->top()); >+ >+ return displayBox.top(); >+} >+ >+LayoutUnit FloatingContext::alignWithContainingBlock(const Box& layoutBox) const >+{ >+ // Apparently there is no intrusive floatings for this floating box, push it to the left/right edge of its containing block's content box. >+ > auto& layoutContext = m_floatingState.layoutContext(); >- // 1. No floating box on the context yet -> align it with the containing block's left/right edge. >- if (m_floatingState.isEmpty()) { >- // Push the box to the left/right edge. >- auto* containingBlock = layoutBox.containingBlock(); >- auto* displayBox = layoutContext.displayBoxForLayoutBox(*containingBlock); >+ auto* containingBlock = layoutBox.containingBlock(); >+ ASSERT(containingBlock == &m_formattingContextRoot || containingBlock->isDescendantOf(m_formattingContextRoot)); >+ >+ auto* containgBlockDisplayBox = layoutContext.displayBoxForLayoutBox(*containingBlock); >+ >+ if (layoutBox.isLeftFloatingPositioned()) >+ return containgBlockDisplayBox->contentBoxLeft(); >+ >+ auto boxWidth = layoutContext.displayBoxForLayoutBox(layoutBox)->marginBox().width(); >+ return containgBlockDisplayBox->contentBoxRight() - boxWidth; >+} >+ >+LayoutUnit FloatingContext::alignWithFloatings(const FloatingPair& floatingPair, const Box& layoutBox) const >+{ >+ // Compute the new horizontal candidate position for the incoming float by taking both the contining block and the left/right floatings into account. >+ >+ auto& containingBlock = *layoutContext().displayBoxForLayoutBox(*layoutBox.containingBlock()); >+ auto containingBlockContentLeft = containingBlock.contentBoxLeft(); >+ >+ if (floatingPair.isEmpty()) { >+ ASSERT_NOT_REACHED(); >+ return containingBlockContentLeft; >+ } > >- if (layoutBox.isLeftFloatingPositioned()) >- return { displayBox->contentBoxLeft(), displayBox->contentBoxTop() }; >+ auto marginBoxWidth = layoutContext().displayBoxForLayoutBox(layoutBox)->marginBox().width(); >+ auto containingBlockContentRight = containingBlock.contentBoxRight(); > >- auto boxWidth = layoutContext.displayBoxForLayoutBox(layoutBox)->width(); >- return { displayBox->contentBoxRight() - boxWidth, displayBox->contentBoxTop() }; >+ if (layoutBox.isLeftFloatingPositioned()) { >+ if (auto* leftDisplayBox = floatingPair.left()) >+ return std::min(std::max(containingBlockContentLeft, leftDisplayBox->right()), containingBlockContentRight - marginBoxWidth); >+ >+ return containingBlockContentLeft; > } > >- ASSERT_NOT_IMPLEMENTED_YET(); >- return { }; >+ ASSERT(layoutBox.isRightFloatingPositioned()); >+ >+ if (auto* rightDisplayBox = floatingPair.right()) >+ return std::max(std::min(containingBlockContentRight, rightDisplayBox->left()) - marginBoxWidth, containingBlockContentLeft); >+ >+ return containingBlockContentRight - marginBoxWidth; >+} >+ >+static const Display::Box* floatingDisplayBox(unsigned index, const FloatingState::FloatingList& floatings, const LayoutContext& layoutContext) >+{ >+ RELEASE_ASSERT(index < floatings.size()); >+ return layoutContext.displayBoxForLayoutBox(*floatings[index]); >+} >+ >+const Display::Box* FloatingPair::left() const >+{ >+ if (!m_leftIndex) >+ return nullptr; >+ >+ return floatingDisplayBox(*m_leftIndex, m_floatingState.floatings().left, m_layoutContext); >+} >+ >+const Display::Box* FloatingPair::right() const >+{ >+ if (!m_rightIndex) >+ return nullptr; >+ >+ return floatingDisplayBox(*m_rightIndex, m_floatingState.floatings().right, m_layoutContext); >+} >+ >+bool FloatingPair::intersects(const Display::Box::Rect& rect) const >+{ >+ auto intersects = [&](const Display::Box* floating, const Display::Box::Rect& rect) { >+ if (!floating) >+ return false; >+ // FIXME: use margin box here. >+ return floating->rect().intersects(rect); >+ }; >+ >+ if (!m_leftIndex && !m_rightIndex) { >+ ASSERT_NOT_REACHED(); >+ return false; >+ } >+ >+ if (intersects(left(), rect)) >+ return true; >+ >+ if (intersects(right(), rect)) >+ return true; >+ >+ return false; >+} >+ >+Iterator::Iterator(const FloatingState& floatingState, LayoutUnit verticalPosition) >+ : m_floatingState(floatingState) >+{ >+ adjustVerticalPosition(verticalPosition); >+} >+ >+void Iterator::computeVerticalPosition() >+{ >+ ASSERT(m_current->left() || m_current->right()); >+ >+ std::optional<LayoutUnit> verticalPositionCandidate; >+ >+ if (auto* left = m_current->left()) >+ verticalPositionCandidate = left->bottom(); >+ >+ if (auto* right = m_current->right()) >+ verticalPositionCandidate = verticalPositionCandidate ? std::min(*verticalPositionCandidate, right->bottom()) : right->bottom(); >+ >+ m_verticalPosition = *verticalPositionCandidate; >+} >+ >+Iterator& Iterator::operator++() >+{ >+ if (!m_current) { >+ ASSERT_NOT_REACHED(); >+ return *this; >+ } >+ >+ // There has to be at least one float, otherwise m_current would be nullopt. >+ ASSERT(m_current->left() || m_current->right()); >+ >+ computeVerticalPosition(); >+ >+ if (m_current->left() && m_current->right()) { >+ >+ } >+ >+ return *this; >+} >+ >+void Iterator::adjustVerticalPosition(LayoutUnit) >+{ > } > > } >diff --git a/Source/WebCore/layout/FloatingContext.h b/Source/WebCore/layout/FloatingContext.h >index e471f4adbf1..de57fa1074e 100644 >--- a/Source/WebCore/layout/FloatingContext.h >+++ b/Source/WebCore/layout/FloatingContext.h >@@ -33,13 +33,11 @@ > > namespace WebCore { > >-namespace Display { >-class Box; >-} >- > namespace Layout { > > class Box; >+class Container; >+class FloatingPair; > class LayoutContext; > > // FloatingContext is responsible for adjusting the position of a box in the current formatting context >@@ -47,15 +45,22 @@ class LayoutContext; > class FloatingContext { > WTF_MAKE_ISO_ALLOCATED(FloatingContext); > public: >- FloatingContext(FloatingState&); >+ FloatingContext(const Container& formattingContextRoot, FloatingState&); > > FloatingState& floatingState() const { return m_floatingState; } > >- Position computePosition(const Box&); >+ Position computePosition(const Box&) const; > > private: > LayoutContext& layoutContext() const { return m_floatingState.layoutContext(); } > >+ Position floatingPosition(const Box&) const; >+ >+ LayoutUnit initialVerticalPosition(const Box&) const; >+ LayoutUnit alignWithContainingBlock(const Box&) const; >+ LayoutUnit alignWithFloatings(const FloatingPair&, const Box&) const; >+ >+ const Container& m_formattingContextRoot; > FloatingState& m_floatingState; > }; > >diff --git a/Source/WebCore/layout/FloatingState.h b/Source/WebCore/layout/FloatingState.h >index 9369985cf11..96f8873ef9d 100644 >--- a/Source/WebCore/layout/FloatingState.h >+++ b/Source/WebCore/layout/FloatingState.h >@@ -49,6 +49,14 @@ public: > > bool isEmpty() const { return m_leftFloatings.isEmpty() && m_rightFloatings.isEmpty(); } > >+ using FloatingList = Vector<WeakPtr<Box>>; >+ struct Floatings { >+ const FloatingList& left; >+ const FloatingList& right; >+ }; >+ const Floatings floatings() const { return { m_leftFloatings, m_rightFloatings }; } >+ const Box* last() const { return m_last.get(); } >+ > private: > friend class FloatingContext; > FloatingState(LayoutContext&); >@@ -57,9 +65,9 @@ private: > > LayoutContext& m_layoutContext; > >- using FloatingList = Vector<WeakPtr<Box>>; > FloatingList m_leftFloatings; > FloatingList m_rightFloatings; >+ WeakPtr<Box> m_last; > }; > > } >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >index faf1e897343..0210b75b30f 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >@@ -62,7 +62,7 @@ void BlockFormattingContext::layout(LayoutContext& layoutContext, FormattingStat > > auto& formattingRoot = downcast<Container>(root()); > LayoutQueue layoutQueue; >- FloatingContext floatingContext(formattingState.floatingState()); >+ FloatingContext floatingContext(formattingRoot, formattingState.floatingState()); > // This is a post-order tree traversal layout. > // The root container layout is done in the formatting context it lives in, not that one it creates, so let's start with the first child. > if (auto* firstChild = formattingRoot.firstInFlowOrFloatingChild()) >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.cpp b/Source/WebCore/layout/displaytree/DisplayBox.cpp >index b020c1e7283..74c09d4b2c4 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.cpp >+++ b/Source/WebCore/layout/displaytree/DisplayBox.cpp >@@ -36,6 +36,17 @@ namespace Display { > > WTF_MAKE_ISO_ALLOCATED_IMPL(Box); > >+Box::Rect::Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height) >+ : m_rect(left, top, width, height) >+{ >+#if !ASSERT_DISABLED >+ m_hasValidTop = true; >+ m_hasValidLeft = true; >+ m_hasValidWidth = true; >+ m_hasValidHeight = true; >+#endif >+} >+ > Box::Box(const RenderStyle& style) > : m_style(style) > { >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.h b/Source/WebCore/layout/displaytree/DisplayBox.h >index 13a3c74096f..f51b1a6fec5 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.h >+++ b/Source/WebCore/layout/displaytree/DisplayBox.h >@@ -53,6 +53,7 @@ public: > class Rect { > public: > Rect() = default; >+ Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height); > > LayoutUnit top() const; > LayoutUnit left() const; >@@ -82,6 +83,7 @@ public: > void moveVertically(LayoutUnit); > > void expand(LayoutUnit, LayoutUnit); >+ bool intersects(const Rect&) const; > > Rect clone() const; > operator LayoutRect() const; >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 3a6490c92cd..e5ed0b425ed 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,17 @@ >+2018-07-30 Zalan Bujtas <zalan@apple.com> >+ >+ [LFC] Add FormattingContext::mapToAncestor geometry mapping function >+ https://bugs.webkit.org/show_bug.cgi?id=188188 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * layout/FormattingContext.cpp: >+ (WebCore::Layout::FormattingContext::mapToAncestor): >+ * layout/FormattingContext.h: >+ * layout/displaytree/DisplayBox.cpp: >+ (WebCore::Display::Box::clone const): >+ * layout/displaytree/DisplayBox.h: >+ > 2018-07-29 Zalan Bujtas <zalan@apple.com> > > [LFC][Floating] Add basic left/right floating positioning. >diff --git a/Source/WebCore/layout/FormattingContext.cpp b/Source/WebCore/layout/FormattingContext.cpp >index f9604ead705..c36ba7c6503 100644 >--- a/Source/WebCore/layout/FormattingContext.cpp >+++ b/Source/WebCore/layout/FormattingContext.cpp >@@ -142,6 +142,26 @@ void FormattingContext::layoutOutOfFlowDescendants(LayoutContext& layoutContext, > LOG_WITH_STREAM(FormattingContextLayout, stream << "End: layout out-of-flow descendants -> context: " << &layoutContext << " root: " << &root()); > } > >+Display::Box FormattingContext::mapToAncestor(const LayoutContext& layoutContext, const Box& layoutBox, const Container& ancestor) >+{ >+ auto* displayBox = layoutContext.displayBoxForLayoutBox(layoutBox); >+ ASSERT(displayBox); >+ auto topLeft = displayBox->topLeft(); >+ >+ auto* containingBlock = layoutBox.containingBlock(); >+ for (; containingBlock && containingBlock != &ancestor; containingBlock = containingBlock->containingBlock()) >+ topLeft.moveBy(layoutContext.displayBoxForLayoutBox(*containingBlock)->topLeft()); >+ >+ if (!containingBlock) { >+ ASSERT_NOT_REACHED(); >+ return displayBox->clone(); >+ } >+ >+ auto mappedDisplayBox = displayBox->clone(); >+ mappedDisplayBox.setTopLeft(topLeft); >+ return mappedDisplayBox; >+} >+ > #ifndef NDEBUG > void FormattingContext::validateGeometryConstraintsAfterLayout(const LayoutContext& layoutContext) const > { >diff --git a/Source/WebCore/layout/FormattingContext.h b/Source/WebCore/layout/FormattingContext.h >index 3b5b855331f..ce201cff64d 100644 >--- a/Source/WebCore/layout/FormattingContext.h >+++ b/Source/WebCore/layout/FormattingContext.h >@@ -59,6 +59,8 @@ public: > }; > virtual InstrinsicWidthConstraints instrinsicWidthConstraints(LayoutContext&, const Box&) const = 0; > >+ static Display::Box mapToAncestor(const LayoutContext&, const Box&, const Container& ancestor); >+ > protected: > struct LayoutPair { > const Box& layoutBox; >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.cpp b/Source/WebCore/layout/displaytree/DisplayBox.cpp >index 74c09d4b2c4..3de06821c10 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.cpp >+++ b/Source/WebCore/layout/displaytree/DisplayBox.cpp >@@ -115,6 +115,22 @@ Box::Rect Box::contentBox() const > return contentBox; > } > >+Box Box::clone() const >+{ >+ Box box; >+ box.m_style = m_style; >+ >+ box.m_topLeft = m_topLeft; >+ box.m_contentWidth = m_contentWidth; >+ box.m_contentHeight = m_contentHeight; >+ box.m_verticalNonCollapsedMargin = m_verticalNonCollapsedMargin; >+ box.m_margin = m_margin; >+ box.m_border = m_border; >+ box.m_padding = m_padding; >+ >+ return box; >+} >+ > } > } > >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.h b/Source/WebCore/layout/displaytree/DisplayBox.h >index 59cc771a48b..30c75c10441 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.h >+++ b/Source/WebCore/layout/displaytree/DisplayBox.h >@@ -158,10 +158,14 @@ public: > Rect paddingBox() const; > Rect contentBox() const; > >+ Box clone() const; >+ > private: >+ Box() = default; > Box(const RenderStyle&); > > struct Style { >+ Style() = default; > Style(const RenderStyle&); > > BoxSizing boxSizing { BoxSizing::ContentBox }; >@@ -199,7 +203,7 @@ private: > void setHasValidContentWidth() { m_hasValidContentWidth = true; } > #endif > >- const Style m_style; >+ Style m_style; > > LayoutPoint m_topLeft; > LayoutUnit m_contentWidth;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188188
:
346142
|
346143
|
346251
|
346277