WebKit Bugzilla
Attachment 358670 Details for
Bug 192625
: [LFC][BFC][MarginCollapsing] Add support for peculiar cases.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-192625-20190108213249.patch (text/plain), 90.37 KB, created by
zalan
on 2019-01-08 21:32:59 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
zalan
Created:
2019-01-08 21:32:59 PST
Size:
90.37 KB
patch
obsolete
>Subversion Revision: 239675 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 3b718d102b27c05fb479747b9368f58f924e93e2..a869a7441adfefb870e7ef937b2dd2b849f3d889 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,89 @@ >+2019-01-07 Zalan Bujtas <zalan@apple.com> >+ >+ [LFC][BFC][MarginCollapsing] Add support for peculiar cases. >+ https://bugs.webkit.org/show_bug.cgi?id=192625 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Implement some of the more peculiar cases like margin collpasing through multiple boxes etc. >+ Add ~100 new passing cases. >+ >+ * layout/FormattingContextGeometry.cpp: >+ (WebCore::Layout::FormattingContext::Geometry::inlineReplacedHeightAndMargin): >+ * layout/LayoutState.h: >+ (WebCore::Layout::LayoutState::hasFormattingState const): >+ * layout/MarginTypes.h: >+ * layout/blockformatting/BlockFormattingContext.cpp: >+ (WebCore::Layout::BlockFormattingContext::computeEstimatedMarginBefore const): >+ (WebCore::Layout::BlockFormattingContext::computeEstimatedMarginBeforeForAncestors const): >+ (WebCore::Layout::hasPrecomputedMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::computeFloatingPosition const): >+ (WebCore::Layout::BlockFormattingContext::computePositionToAvoidFloats const): >+ (WebCore::Layout::BlockFormattingContext::computeVerticalPositionForFloatClear const): >+ (WebCore::Layout::BlockFormattingContext::computeHeightAndMargin const): >+ (WebCore::Layout::BlockFormattingContext::adjustedVerticalPositionAfterMarginCollapsing const): >+ * layout/blockformatting/BlockFormattingContext.h: >+ (WebCore::Layout::BlockFormattingContext::blockFormattingState const): >+ * layout/blockformatting/BlockFormattingContextGeometry.cpp: >+ (WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin): >+ (WebCore::Layout::BlockFormattingContext::Geometry::inFlowHeightAndMargin): >+ (WebCore::Layout::BlockFormattingContext::Geometry::estimatedMarginBefore): Deleted. >+ (WebCore::Layout::BlockFormattingContext::Geometry::estimatedMarginAfter): Deleted. >+ * layout/blockformatting/BlockFormattingContextQuirks.cpp: >+ (WebCore::Layout::BlockFormattingContext::Quirks::stretchedInFlowHeight): >+ (WebCore::Layout::BlockFormattingContext::Quirks::shouldIgnoreMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::Quirks::stretchedHeight): Deleted. >+ * layout/blockformatting/BlockFormattingState.h: >+ (WebCore::Layout::BlockFormattingState::setPositiveAndNegativeVerticalMargin): >+ (WebCore::Layout::BlockFormattingState::hasPositiveAndNegativeVerticalMargin const): >+ (WebCore::Layout::BlockFormattingState::positiveAndNegativeVerticalMargin const): >+ (WebCore::Layout::BlockFormattingState::setHasEstimatedMarginBefore): >+ (WebCore::Layout::BlockFormattingState::clearHasEstimatedMarginBefore): >+ (WebCore::Layout::BlockFormattingState::hasEstimatedMarginBefore const): >+ * layout/blockformatting/BlockMarginCollapse.cpp: >+ (WebCore::Layout::hasClearance): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithPreviousSiblingMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithFirstInFlowChildMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithSiblingMarginBeforeWithClearance): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithParentMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithLastInFlowChildMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithNextSiblingMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginsCollapseThrough): >+ (WebCore::Layout::computedPositiveAndNegativeMargin): >+ (WebCore::Layout::marginValue): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::updateCollapsedMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::positiveNegativeValues): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::positiveNegativeMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::positiveNegativeMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::estimatedMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::collapsedVerticalValues): >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::computedNonCollapsedMarginBefore): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::computedNonCollapsedMarginAfter): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::nonCollapsedMarginBefore): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::nonCollapsedMarginAfter): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::collapsedMarginBeforeFromFirstChild): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::collapsedMarginAfterFromLastChild): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithPreviousSibling): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithNextSibling): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBefore): Deleted. >+ (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfter): Deleted. >+ * layout/displaytree/DisplayBox.cpp: >+ (WebCore::Display::Box::Box): >+ * layout/displaytree/DisplayBox.h: >+ (WebCore::Display::Box::hasClearance const): >+ (WebCore::Display::Box::setEstimatedMarginBefore): >+ (WebCore::Display::Box::estimatedMarginBefore const): >+ (WebCore::Display::Box::setHasClearance): >+ (WebCore::Display::Box::invalidateEstimatedMarginBefore): >+ (WebCore::Display::Box::setVerticalMargin): >+ (WebCore::Display::Box::rectWithMargin const): >+ * layout/floats/FloatingContext.cpp: >+ (WebCore::Layout::FloatingContext::verticalPositionWithClearance const): >+ * layout/inlineformatting/InlineFormattingContext.cpp: >+ (WebCore::Layout::InlineFormattingContext::collectInlineContentForSubtree const): >+ > 2019-01-07 Zalan Bujtas <zalan@apple.com> > > [LFC][BFC] Margin collapsing should not be limited to in-flow non-replaced boxes. >diff --git a/Source/WebCore/layout/LayoutState.h b/Source/WebCore/layout/LayoutState.h >index 04775ab2bb668fc226a3fc1324042dbcf12fb33f..28446cf9add3e79869861c9cc79c6985bcd9f7ae 100644 >--- a/Source/WebCore/layout/LayoutState.h >+++ b/Source/WebCore/layout/LayoutState.h >@@ -75,6 +75,7 @@ public: > > FormattingState& formattingStateForBox(const Box&) const; > FormattingState& establishedFormattingState(const Box& formattingRoot) const; >+ bool hasFormattingState(const Box& formattingRoot) const { return m_formattingStates.contains(&formattingRoot); } > FormattingState& createFormattingStateForFormattingRootIfNeeded(const Box& formattingRoot); > > Display::Box& displayBoxForLayoutBox(const Box& layoutBox) const; >diff --git a/Source/WebCore/layout/MarginTypes.h b/Source/WebCore/layout/MarginTypes.h >index 4e1fc56d5562b1a726f27fe4858a1a87556474c9..ac4aa8bc5eedb9e571e1adae0ab3c6cdfbc1075d 100644 >--- a/Source/WebCore/layout/MarginTypes.h >+++ b/Source/WebCore/layout/MarginTypes.h >@@ -50,15 +50,15 @@ struct UsedVerticalMargin { > struct CollapsedValues { > Optional<LayoutUnit> before; > Optional<LayoutUnit> after; >+ bool isCollapsedThrough { false }; > }; > CollapsedValues collapsedValues() const { return m_collapsedValues; } > bool hasCollapsedValues() const { return m_collapsedValues.before || m_collapsedValues.after; } > void setCollapsedValues(CollapsedValues collapsedValues) { m_collapsedValues = collapsedValues; } > > UsedVerticalMargin(NonCollapsedValues, CollapsedValues); >- > UsedVerticalMargin() = default; >- ~UsedVerticalMargin() = default; >+ > private: > NonCollapsedValues m_nonCollapsedValues; > CollapsedValues m_collapsedValues; >@@ -74,6 +74,10 @@ struct UsedHorizontalMargin { > LayoutUnit end; > }; > >+struct EstimatedMarginBefore { >+ LayoutUnit usedValue; >+}; >+ > struct PositiveAndNegativeVerticalMargin { > struct Values { > Optional<LayoutUnit> positive; >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >index 2481116afd7ab140776de957af7762e8c09386eb..b24de9f68387e6f83fd302063e76cd08f607e312 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >@@ -187,11 +187,14 @@ void BlockFormattingContext::computeStaticPosition(const Box& layoutBox) const > void BlockFormattingContext::computeEstimatedMarginBefore(const Box& layoutBox) const > { > auto& layoutState = this->layoutState(); >- auto estimatedMarginBefore = Geometry::estimatedMarginBefore(layoutState, layoutBox); >+ auto estimatedMarginBefore = MarginCollapse::estimatedMarginBefore(layoutState, layoutBox); >+ blockFormattingState().setHasEstimatedMarginBefore(layoutBox); > > auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); >+ displayBox.setTop(adjustedVerticalPositionAfterMarginCollapsing(layoutBox, estimatedMarginBefore.usedValue)); >+#if !ASSERT_DISABLED > displayBox.setEstimatedMarginBefore(estimatedMarginBefore); >- displayBox.moveVertically(estimatedMarginBefore); >+#endif > } > > void BlockFormattingContext::computeEstimatedMarginBeforeForAncestors(const Box& layoutBox) const >@@ -208,12 +211,10 @@ void BlockFormattingContext::computeEstimatedMarginBeforeForAncestors(const Box& > // So when we get to the point where we intersect the box with the float to decide if the box needs to move, we don't yet have the final vertical position. > // > // The idea here is that as long as we don't cross the block formatting context boundary, we should be able to pre-compute the final top margin. >- auto& layoutState = this->layoutState(); >- >+ auto& formattingState = blockFormattingState(); > for (auto* ancestor = layoutBox.containingBlock(); ancestor && !ancestor->establishesBlockFormattingContext(); ancestor = ancestor->containingBlock()) { >- auto& displayBox = layoutState.displayBoxForLayoutBox(*ancestor); > // FIXME: with incremental layout, we might actually have a valid (non-estimated) margin top as well. >- if (displayBox.estimatedMarginBefore()) >+ if (formattingState.hasEstimatedMarginBefore(*ancestor)) > return; > > computeEstimatedMarginBefore(*ancestor); >@@ -238,10 +239,10 @@ void BlockFormattingContext::precomputeVerticalPositionForFormattingRootIfNeeded > } > > #ifndef NDEBUG >-static bool hasPrecomputedMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >+static bool hasPrecomputedMarginBefore(const BlockFormattingState& formattingState, const Box& layoutBox) > { > for (auto* ancestor = layoutBox.containingBlock(); ancestor && !ancestor->establishesBlockFormattingContext(); ancestor = ancestor->containingBlock()) { >- if (layoutState.displayBoxForLayoutBox(*ancestor).estimatedMarginBefore()) >+ if (formattingState.hasEstimatedMarginBefore(*ancestor)) > continue; > return false; > } >@@ -253,7 +254,7 @@ void BlockFormattingContext::computeFloatingPosition(const FloatingContext& floa > { > auto& layoutState = this->layoutState(); > ASSERT(layoutBox.isFloatingPositioned()); >- ASSERT(hasPrecomputedMarginBefore(layoutState, layoutBox)); >+ ASSERT(hasPrecomputedMarginBefore(blockFormattingState(), layoutBox)); > > auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); > // 8.3.1 Collapsing margins >@@ -273,7 +274,7 @@ void BlockFormattingContext::computePositionToAvoidFloats(const FloatingContext& > ASSERT(layoutBox.establishesBlockFormattingContext()); > ASSERT(!layoutBox.isFloatingPositioned()); > ASSERT(!layoutBox.hasFloatClear()); >- ASSERT(hasPrecomputedMarginBefore(layoutState, layoutBox)); >+ ASSERT(hasPrecomputedMarginBefore(blockFormattingState(), layoutBox)); > > if (floatingContext.floatingState().isEmpty()) > return; >@@ -292,7 +293,7 @@ void BlockFormattingContext::computeVerticalPositionForFloatClear(const Floating > // For formatting roots, we already precomputed final position. > if (!layoutBox.establishesFormattingContext()) > computeEstimatedMarginBeforeForAncestors(layoutBox); >- ASSERT(hasPrecomputedMarginBefore(layoutState, layoutBox)); >+ ASSERT(hasPrecomputedMarginBefore(blockFormattingState(), layoutBox)); > > if (auto verticalPositionWithClearance = floatingContext.verticalPositionWithClearance(layoutBox)) > layoutState.displayBoxForLayoutBox(layoutBox).setTop(*verticalPositionWithClearance); >@@ -371,15 +372,21 @@ void BlockFormattingContext::computeHeightAndMargin(const Box& layoutBox) const > } > } > >- auto collapsedMargin = UsedVerticalMargin::CollapsedValues { MarginCollapse::marginBefore(layoutState, layoutBox), MarginCollapse::marginAfter(layoutState, layoutBox) }; >+ auto collapsedMargin = MarginCollapse::collapsedVerticalValues(layoutState, layoutBox, heightAndMargin.nonCollapsedMargin); > auto verticalMargin = UsedVerticalMargin { heightAndMargin.nonCollapsedMargin, collapsedMargin }; > auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); >+ auto& formattingState = this->blockFormattingState(); >+ if (formattingState.hasEstimatedMarginBefore(layoutBox)) { >+ formattingState.clearHasEstimatedMarginBefore(layoutBox); >+ ASSERT(displayBox.estimatedMarginBefore()->usedValue == verticalMargin.before()); >+ } else >+ displayBox.setTop(adjustedVerticalPositionAfterMarginCollapsing(layoutBox, verticalMargin.before())); >+ > displayBox.setContentBoxHeight(heightAndMargin.height); > displayBox.setVerticalMargin(verticalMargin); >- >- // If this box has already been moved by the estimated vertical margin, no need to move it again. >- if (layoutBox.isFloatingPositioned() || !displayBox.estimatedMarginBefore()) >- displayBox.moveVertically(verticalMargin.before()); >+ // Adjust the previous sibling's margin bottom now that this box's vertical margin is computed. >+ if (MarginCollapse::marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, layoutBox)) >+ MarginCollapse::updateCollapsedMarginAfter(layoutState, *layoutBox.previousInFlowSibling(), verticalMargin); > } > > FormattingContext::InstrinsicWidthConstraints BlockFormattingContext::instrinsicWidthConstraints() const >@@ -446,6 +453,37 @@ FormattingContext::InstrinsicWidthConstraints BlockFormattingContext::instrinsic > return instrinsicWidthConstraints; > } > >+LayoutUnit BlockFormattingContext::adjustedVerticalPositionAfterMarginCollapsing(const Box& layoutBox, LayoutUnit marginBefore) const >+{ >+ // Now that we've computed the final margin before, let's shift the box's vertical position. >+ // 1. Check if the margin before collapses with the previous box's margin after. if not -> return previous box's bottom inlcuding margin after + marginBefore >+ // 2. Check if the previous box's margins collapse through. If not -> return previous box' bottom excluding margin after + marginBefore (they are supposed to be equal) >+ // 3. Go to previous box and start from step #1 until we hit the parent box. >+ auto& layoutState = this->layoutState(); >+ auto* currentLayoutBox = &layoutBox; >+ while (currentLayoutBox) { >+ if (!currentLayoutBox->previousInFlowSibling()) >+ break; >+ auto& previousInFlowSibling = *currentLayoutBox->previousInFlowSibling(); >+ if (!MarginCollapse::marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, *currentLayoutBox)) { >+ auto& previousDisplayBox = layoutState.displayBoxForLayoutBox(previousInFlowSibling); >+ return previousDisplayBox.rectWithMargin().bottom() + marginBefore; >+ } >+ >+ if (!MarginCollapse::marginsCollapseThrough(layoutState, previousInFlowSibling)) { >+ auto& previousDisplayBox = layoutState.displayBoxForLayoutBox(previousInFlowSibling); >+ return previousDisplayBox.bottom() + marginBefore; >+ } >+ currentLayoutBox = &previousInFlowSibling; >+ } >+ >+ auto containingBlockContentBoxTop = layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock()).contentBoxTop(); >+ if (MarginCollapse::marginBeforeCollapsesWithParentMarginBefore(layoutState, layoutBox) || MarginCollapse::marginBeforeCollapsesWithParentMarginAfter(layoutState, layoutBox)) >+ return containingBlockContentBoxTop; >+ >+ return containingBlockContentBoxTop + marginBefore; >+} >+ > } > } > >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContext.h b/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >index 21de3b49234e269c8ad54531277f1792a3345daf..500d0649c25e237ec00de72fbdeb92b05e758ed5 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >@@ -50,6 +50,8 @@ public: > void layout() const override; > > private: >+ BlockFormattingState& blockFormattingState() const { return downcast<BlockFormattingState>(formattingState()); } >+ > void layoutFormattingContextRoot(FloatingContext&, const Box&) const; > void placeInFlowPositionedChildren(const Container&) const; > >@@ -67,6 +69,7 @@ private: > void precomputeVerticalPositionForFormattingRootIfNeeded(const Box&) const; > > InstrinsicWidthConstraints instrinsicWidthConstraints() const override; >+ LayoutUnit adjustedVerticalPositionAfterMarginCollapsing(const Box&, LayoutUnit marginBefore) const; > > // This class implements positioning and sizing for boxes participating in a block formatting context. > class Geometry : public FormattingContext::Geometry { >@@ -79,9 +82,6 @@ private: > static bool instrinsicWidthConstraintsNeedChildrenWidth(const Box&); > static InstrinsicWidthConstraints instrinsicWidthConstraints(const LayoutState&, const Box&); > >- static LayoutUnit estimatedMarginBefore(const LayoutState&, const Box&); >- static LayoutUnit estimatedMarginAfter(const LayoutState&, const Box&); >- > private: > static HeightAndMargin inFlowNonReplacedHeightAndMargin(const LayoutState&, const Box&, Optional<LayoutUnit> usedHeight = { }); > static WidthAndMargin inFlowNonReplacedWidthAndMargin(const LayoutState&, const Box&, Optional<LayoutUnit> usedWidth = { }); >@@ -92,36 +92,38 @@ private: > // This class implements margin collapsing for block formatting context. > class MarginCollapse { > public: >- static LayoutUnit marginBefore(const LayoutState&, const Box&); >- static LayoutUnit marginAfter(const LayoutState&, const Box&); >- >- static bool marginBeforeCollapsesWithParentMarginAfter(const LayoutState&, const Box&); >- static bool marginAfterCollapsesWithParentMarginAfter(const LayoutState&, const Box&); >- >- private: >- static LayoutUnit collapsedMarginAfterFromLastChild(const LayoutState&, const Box&); >- static LayoutUnit nonCollapsedMarginAfter(const LayoutState&, const Box&); >- >- static LayoutUnit computedNonCollapsedMarginBefore(const LayoutState&, const Box&); >- static LayoutUnit computedNonCollapsedMarginAfter(const LayoutState&, const Box&); >+ static UsedVerticalMargin::CollapsedValues collapsedVerticalValues(const LayoutState&, const Box&, const UsedVerticalMargin::NonCollapsedValues&); > >- static LayoutUnit collapsedMarginBeforeFromFirstChild(const LayoutState&, const Box&); >- static LayoutUnit nonCollapsedMarginBefore(const LayoutState&, const Box&); >+ static EstimatedMarginBefore estimatedMarginBefore(const LayoutState&, const Box&); >+ static void updateCollapsedMarginAfter(const LayoutState&, const Box&, const UsedVerticalMargin& nextSiblingVerticalMargin); > > static bool marginBeforeCollapsesWithParentMarginBefore(const LayoutState&, const Box&); >- static bool marginBeforeCollapsesWithPreviousSibling(const Box&); >- static bool marginAfterCollapsesWithNextSibling(const Box&); >- static bool marginAfterCollapsesWithSiblingMarginBeforeWithClearance(const LayoutState&, const Box&); >+ static bool marginBeforeCollapsesWithFirstInFlowChildMarginBefore(const LayoutState&, const Box&); >+ static bool marginBeforeCollapsesWithParentMarginAfter(const LayoutState&, const Box&); >+ static bool marginBeforeCollapsesWithPreviousSiblingMarginAfter(const LayoutState&, const Box&); >+ >+ static bool marginAfterCollapsesWithParentMarginAfter(const LayoutState&, const Box&); >+ static bool marginAfterCollapsesWithLastInFlowChildMarginAfter(const LayoutState&, const Box&); > static bool marginAfterCollapsesWithParentMarginBefore(const LayoutState&, const Box&); >+ static bool marginAfterCollapsesWithNextSiblingMarginBefore(const LayoutState&, const Box&); >+ static bool marginAfterCollapsesWithSiblingMarginBeforeWithClearance(const LayoutState&, const Box&); >+ > static bool marginsCollapseThrough(const LayoutState&, const Box&); >+ >+ private: >+ enum class MarginType { Before, After }; >+ static PositiveAndNegativeVerticalMargin::Values positiveNegativeValues(const LayoutState&, const Box&, MarginType); >+ static PositiveAndNegativeVerticalMargin::Values positiveNegativeMarginBefore(const LayoutState&, const Box&, const UsedVerticalMargin::NonCollapsedValues&); >+ static PositiveAndNegativeVerticalMargin::Values positiveNegativeMarginAfter(const LayoutState&, const Box&, const UsedVerticalMargin::NonCollapsedValues&); > }; > > class Quirks { > public: > static bool needsStretching(const LayoutState&, const Box&); >- static HeightAndMargin stretchedHeight(const LayoutState&, const Box&, HeightAndMargin); >+ static HeightAndMargin stretchedInFlowHeight(const LayoutState&, const Box&, HeightAndMargin); > > static bool shouldIgnoreMarginBefore(const LayoutState&, const Box&); >+ static bool shouldIgnoreMarginAfter(const LayoutState&, const Box&); > }; > }; > >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >index 4cbbc63304013c08fd9979892d2959a3cf750578..4170eac90faf4def59957b40410f916bd4861982 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >@@ -99,7 +99,6 @@ HeightAndMargin BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMarg > }; > > auto heightAndMargin = compute(); >- > LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> inflow non-replaced -> height(" << heightAndMargin.height << "px) margin(" << heightAndMargin.nonCollapsedMargin.before << "px, " << heightAndMargin.nonCollapsedMargin.after << "px) -> layoutBox(" << &layoutBox << ")"); > return heightAndMargin; > } >@@ -257,7 +256,7 @@ HeightAndMargin BlockFormattingContext::Geometry::inFlowHeightAndMargin(const La > if (!Quirks::needsStretching(layoutState, layoutBox)) > return heightAndMargin; > >- heightAndMargin = Quirks::stretchedHeight(layoutState, layoutBox, heightAndMargin); >+ heightAndMargin = Quirks::stretchedInFlowHeight(layoutState, layoutBox, heightAndMargin); > > LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> inflow non-replaced -> streched to viewport -> height(" << heightAndMargin.height << "px) margin(" << heightAndMargin.nonCollapsedMargin.before << "px, " << heightAndMargin.nonCollapsedMargin.after << "px) -> layoutBox(" << &layoutBox << ")"); > return heightAndMargin; >@@ -318,30 +317,6 @@ FormattingContext::InstrinsicWidthConstraints BlockFormattingContext::Geometry:: > return { minimumIntrinsicWidth, maximumIntrinsicWidth }; > } > >-LayoutUnit BlockFormattingContext::Geometry::estimatedMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- // Can't estimate vertical margins for out of flow boxes (and we shouldn't need to do it for float boxes). >- ASSERT(layoutBox.isInFlow()); >- // Can't cross block formatting context boundary. >- ASSERT(!layoutBox.establishesBlockFormattingContext()); >- >- // Let's just use the normal path for now. >- return MarginCollapse::marginBefore(layoutState, layoutBox); >-} >- >-LayoutUnit BlockFormattingContext::Geometry::estimatedMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- // Can't estimate vertical margins for out of flow boxes (and we shouldn't need to do it for float boxes). >- ASSERT(layoutBox.isInFlow()); >- // Can't cross block formatting context boundary. >- ASSERT(!layoutBox.establishesBlockFormattingContext()); >- >- // Let's just use the normal path for now. >- return MarginCollapse::marginAfter(layoutState, layoutBox); >-} >- > } > } > >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp >index a107974d07ade4437165fa9c9795bb830a3afd54..71a1a79de6fe05079d50a3ae9931946282fbf051 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp >@@ -55,7 +55,6 @@ static bool hasMarginBeforeQuirkValue(const Box& layoutBox) > > bool BlockFormattingContext::Quirks::needsStretching(const LayoutState& layoutState, const Box& layoutBox) > { >- ASSERT(layoutBox.isInFlow()); > // In quirks mode, body stretches to html and html to the initial containing block (height: auto only). > if (!layoutState.inQuirksMode()) > return false; >@@ -66,8 +65,9 @@ bool BlockFormattingContext::Quirks::needsStretching(const LayoutState& layoutSt > return layoutBox.style().logicalHeight().isAuto(); > } > >-HeightAndMargin BlockFormattingContext::Quirks::stretchedHeight(const LayoutState& layoutState, const Box& layoutBox, HeightAndMargin heightAndMargin) >+HeightAndMargin BlockFormattingContext::Quirks::stretchedInFlowHeight(const LayoutState& layoutState, const Box& layoutBox, HeightAndMargin heightAndMargin) > { >+ ASSERT(layoutBox.isInFlow()); > ASSERT(layoutBox.isDocumentBox() || layoutBox.isBodyBox()); > > auto& documentBox = layoutBox.isDocumentBox() ? layoutBox : *layoutBox.parent(); >@@ -87,11 +87,12 @@ HeightAndMargin BlockFormattingContext::Quirks::stretchedHeight(const LayoutStat > // Here is the quirky part for body box: > // Stretch the body using the initial containing block's height and shrink it with document box's margin/border/padding. > // This looks extremely odd when html has non-auto height. >- auto verticalMargin = Geometry::estimatedMarginBefore(layoutState, documentBox) + Geometry::estimatedMarginAfter(layoutState, documentBox); >- strechedHeight -= verticalMargin; >+ auto documentBoxVerticalMargin = Geometry::computedVerticalMargin(layoutState, documentBox); >+ strechedHeight -= (documentBoxVerticalMargin.before.valueOr(0) + documentBoxVerticalMargin.after.valueOr(0)); > >- auto nonCollapsedValues = heightAndMargin.nonCollapsedMargin; >- totalVerticalMargin = nonCollapsedValues.before + nonCollapsedValues.after; >+ auto nonCollapsedMargin = heightAndMargin.nonCollapsedMargin; >+ auto collapsedMargin = MarginCollapse::collapsedVerticalValues(layoutState, layoutBox, nonCollapsedMargin); >+ totalVerticalMargin = collapsedMargin.before.valueOr(nonCollapsedMargin.before) + collapsedMargin.after.valueOr(nonCollapsedMargin.after); > } > > // Stretch but never overstretch with the margins. >@@ -109,6 +110,20 @@ bool BlockFormattingContext::Quirks::shouldIgnoreMarginBefore(const LayoutState& > return layoutState.inQuirksMode() && isQuirkContainer(*layoutBox.parent()) && hasMarginBeforeQuirkValue(layoutBox); > } > >+bool BlockFormattingContext::Quirks::shouldIgnoreMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >+{ >+ // Ignore maring after when the ignored margin before collapses through. >+ if (!shouldIgnoreMarginBefore(layoutState, layoutBox)) >+ return false; >+ >+ ASSERT(layoutBox.parent()); >+ auto& parent = *layoutBox.parent(); >+ if (parent.firstInFlowOrFloatingChild() != &layoutBox || parent.firstInFlowOrFloatingChild() != parent.lastInFlowOrFloatingChild()) >+ return false; >+ >+ return MarginCollapse::marginsCollapseThrough(layoutState, layoutBox); >+} >+ > } > } > >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingState.h b/Source/WebCore/layout/blockformatting/BlockFormattingState.h >index bb9669390ff9a2876fe714dc8544b01df6deaa84..bb456b5927fefe45c637831d5b24f717092bad2a 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingState.h >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingState.h >@@ -28,6 +28,7 @@ > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > > #include "FormattingState.h" >+#include "MarginTypes.h" > #include <wtf/IsoMalloc.h> > > namespace WebCore { >@@ -42,6 +43,18 @@ public: > virtual ~BlockFormattingState(); > > std::unique_ptr<FormattingContext> createFormattingContext(const Box& formattingContextRoot) override; >+ >+ void setPositiveAndNegativeVerticalMargin(const Box& layoutBox, PositiveAndNegativeVerticalMargin verticalMargin) { m_positiveAndNegativeVerticalMargin.set(&layoutBox, verticalMargin); } >+ bool hasPositiveAndNegativeVerticalMargin(const Box& layoutBox) const { return m_positiveAndNegativeVerticalMargin.contains(&layoutBox); } >+ PositiveAndNegativeVerticalMargin positiveAndNegativeVerticalMargin(const Box& layoutBox) const { return m_positiveAndNegativeVerticalMargin.get(&layoutBox); } >+ >+ void setHasEstimatedMarginBefore(const Box& layoutBox) { m_estimatedMarginBeforeList.add(&layoutBox); } >+ void clearHasEstimatedMarginBefore(const Box& layoutBox) { m_estimatedMarginBeforeList.remove(&layoutBox); } >+ bool hasEstimatedMarginBefore(const Box& layoutBox) const { return m_estimatedMarginBeforeList.contains(&layoutBox); } >+ >+private: >+ HashMap<const Box*, PositiveAndNegativeVerticalMargin> m_positiveAndNegativeVerticalMargin; >+ HashSet<const Box*> m_estimatedMarginBeforeList; > }; > > } >diff --git a/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp b/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp >index c71d39260a75588aa0ee8f261f24ae2194ee87b4..f9ab127f9aa48c20d0a7f4fa1e7b4c445ad44c1f 100644 >--- a/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp >@@ -70,12 +70,11 @@ static bool hasPaddingAfter(const Box& layoutBox) > return hasPadding(layoutBox.style().paddingAfter()); > } > >-static bool hasClearance(const Box& layoutBox) >+static bool hasClearance(const LayoutState& layoutState, const Box& layoutBox) > { > if (!layoutBox.hasFloatClear()) > return false; >- // FIXME >- return false; >+ return layoutState.displayBoxForLayoutBox(layoutBox).hasClearance(); > } > > static bool establishesBlockFormattingContext(const Box& layoutBox) >@@ -87,93 +86,6 @@ static bool establishesBlockFormattingContext(const Box& layoutBox) > return layoutBox.establishesBlockFormattingContext(); > } > >-static LayoutUnit marginValue(LayoutUnit currentMarginValue, LayoutUnit candidateMarginValue) >-{ >- if (!candidateMarginValue) >- return currentMarginValue; >- if (!currentMarginValue) >- return candidateMarginValue; >- // Both margins are positive. >- if (candidateMarginValue > 0 && currentMarginValue > 0) >- return std::max(candidateMarginValue, currentMarginValue); >- // Both margins are negative. >- if (candidateMarginValue < 0 && currentMarginValue < 0) >- return 0 - std::max(std::abs(candidateMarginValue.toFloat()), std::abs(currentMarginValue.toFloat())); >- // One of the margins is negative. >- return currentMarginValue + candidateMarginValue; >-} >- >-LayoutUnit BlockFormattingContext::MarginCollapse::computedNonCollapsedMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- >- return Geometry::computedVerticalMargin(layoutState, layoutBox).before.valueOr(0); >-} >- >-LayoutUnit BlockFormattingContext::MarginCollapse::computedNonCollapsedMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- >- return Geometry::computedVerticalMargin(layoutState, layoutBox).after.valueOr(0); >-} >- >-LayoutUnit BlockFormattingContext::MarginCollapse::nonCollapsedMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- >- // Non collapsed margin top includes collapsed margin from inflow first child. >- return marginValue(computedNonCollapsedMarginBefore(layoutState, layoutBox), collapsedMarginBeforeFromFirstChild(layoutState, layoutBox)); >-} >- >-LayoutUnit BlockFormattingContext::MarginCollapse::nonCollapsedMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- >- // Non collapsed margin bottom includes collapsed margin from inflow last child. >- return marginValue(computedNonCollapsedMarginAfter(layoutState, layoutBox), collapsedMarginAfterFromLastChild(layoutState, layoutBox)); >-} >- >-LayoutUnit BlockFormattingContext::MarginCollapse::collapsedMarginBeforeFromFirstChild(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- >- // Check if the first child collapses its margin top. >- if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild()) >- return 0; >- >- // Do not collapse margin with a box from a non-block formatting context <div><span>foobar</span></div>. >- if (layoutBox.establishesFormattingContext() && !layoutBox.establishesBlockFormattingContextOnly()) >- return 0; >- >- // FIXME: Take collapsed through margin into account. >- auto& firstInFlowChild = *downcast<Container>(layoutBox).firstInFlowChild(); >- if (!marginBeforeCollapsesWithParentMarginBefore(layoutState, firstInFlowChild)) >- return 0; >- // Collect collapsed margin top recursively. >- return marginValue(computedNonCollapsedMarginBefore(layoutState, firstInFlowChild), collapsedMarginBeforeFromFirstChild(layoutState, firstInFlowChild)); >-} >- >-LayoutUnit BlockFormattingContext::MarginCollapse::collapsedMarginAfterFromLastChild(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- >- // Check if the last child propagates its margin bottom. >- if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild()) >- return 0; >- >- // Do not collapse margin with a box from a non-block formatting context <div><span>foobar</span></div>. >- if (layoutBox.establishesFormattingContext() && !layoutBox.establishesBlockFormattingContextOnly()) >- return 0; >- >- // FIXME: Check for collapsed through margin. >- auto& lastInFlowChild = *downcast<Container>(layoutBox).lastInFlowChild(); >- if (!marginAfterCollapsesWithParentMarginAfter(layoutState, lastInFlowChild)) >- return 0; >- >- // Collect collapsed margin bottom recursively. >- return marginValue(computedNonCollapsedMarginAfter(layoutState, lastInFlowChild), collapsedMarginAfterFromLastChild(layoutState, lastInFlowChild)); >-} >- > bool BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarginAfter(const LayoutState& layoutState, const Box& layoutBox) > { > // 1. This is the last in-flow child and its margins collapse through and the margin after collapses with parent's margin after or >@@ -185,7 +97,7 @@ bool BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarg > return false; > if (currentBox == lastInFlowChild) > return marginAfterCollapsesWithParentMarginAfter(layoutState, *currentBox); >- if (!marginAfterCollapsesWithNextSibling(*currentBox)) >+ if (!marginAfterCollapsesWithNextSiblingMarginBefore(layoutState, *currentBox)) > return false; > } > ASSERT_NOT_REACHED(); >@@ -229,10 +141,86 @@ bool BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarg > return false; > > // ...and the child has no clearance. >- if (hasClearance(layoutBox)) >+ if (hasClearance(layoutState, layoutBox)) > return false; > >- if (BlockFormattingContext::Quirks::shouldIgnoreMarginBefore(layoutState, layoutBox)) >+ return true; >+} >+ >+bool BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithPreviousSiblingMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isBlockLevelBox()); >+ >+ if (!layoutBox.previousInFlowSibling()) >+ return false; >+ >+ auto& previousInFlowSibling = *layoutBox.previousInFlowSibling(); >+ >+ // Margins between a floated box and any other box do not collapse. >+ if (layoutBox.isFloatingPositioned() || previousInFlowSibling.isFloatingPositioned()) >+ return false; >+ >+ // Margins of absolutely positioned boxes do not collapse. >+ if ((layoutBox.isOutOfFlowPositioned() && !layoutBox.style().top().isAuto()) >+ || (previousInFlowSibling.isOutOfFlowPositioned() && !previousInFlowSibling.style().bottom().isAuto())) >+ return false; >+ >+ // Margins of inline-block boxes do not collapse. >+ if (layoutBox.isInlineBlockBox() || previousInFlowSibling.isInlineBlockBox()) >+ return false; >+ >+ // The bottom margin of an in-flow block-level element always collapses with the top margin of >+ // its next in-flow block-level sibling, unless that sibling has clearance. >+ if (hasClearance(layoutState, layoutBox)) >+ return false; >+ >+ return true; >+} >+ >+bool BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithFirstInFlowChildMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >+{ >+ if (layoutBox.isAnonymous()) >+ return false; >+ >+ ASSERT(layoutBox.isBlockLevelBox()); >+ // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children. >+ if (establishesBlockFormattingContext(layoutBox)) >+ return false; >+ >+ // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children. >+ if (establishesBlockFormattingContext(layoutBox)) >+ return false; >+ >+ // The top margin of an in-flow block element collapses with its first in-flow block-level >+ // child's top margin if the element has no top border... >+ if (hasBorderBefore(layoutBox)) >+ return false; >+ >+ // ...no top padding >+ if (hasPaddingBefore(layoutBox)) >+ return false; >+ >+ if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild()) >+ return false; >+ >+ auto& firstInFlowChild = *downcast<Container>(layoutBox).firstInFlowChild(); >+ if (!firstInFlowChild.isBlockLevelBox()) >+ return false; >+ >+ // ...and the child has no clearance. >+ if (hasClearance(layoutState, firstInFlowChild)) >+ return false; >+ >+ // Margins between a floated box and any other box do not collapse. >+ if (firstInFlowChild.isFloatingPositioned()) >+ return false; >+ >+ // Margins of absolutely positioned boxes do not collapse. >+ if (firstInFlowChild.isOutOfFlowPositioned()) >+ return false; >+ >+ // Margins of inline-block boxes do not collapse. >+ if (firstInFlowChild.isInlineBlockBox()) > return false; > > return true; >@@ -248,7 +236,7 @@ bool BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithSiblingMarg > for (auto* previousSibling = layoutBox.previousInFlowSibling(); previousSibling; previousSibling = previousSibling->previousInFlowSibling()) { > if (!marginsCollapseThrough(layoutState, *previousSibling)) > return false; >- if (hasClearance(*previousSibling)) >+ if (hasClearance(layoutState, *previousSibling)) > return true; > } > return false; >@@ -265,7 +253,7 @@ bool BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithParentMargi > return false; > if (currentBox == firstInFlowChild) > return marginBeforeCollapsesWithParentMarginBefore(layoutState, *currentBox); >- if (!marginBeforeCollapsesWithPreviousSibling(*currentBox)) >+ if (!marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, *currentBox)) > return false; > } > ASSERT_NOT_REACHED(); >@@ -324,44 +312,66 @@ bool BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithParentMargi > return true; > } > >-bool BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithPreviousSibling(const Box& layoutBox) >+bool BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithLastInFlowChildMarginAfter(const LayoutState& layoutState, const Box& layoutBox) > { > ASSERT(layoutBox.isBlockLevelBox()); > >- if (!layoutBox.previousInFlowSibling()) >+ // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children. >+ if (establishesBlockFormattingContext(layoutBox)) > return false; > >- auto& previousInFlowSibling = *layoutBox.previousInFlowSibling(); >+ if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild()) >+ return false; >+ >+ auto& lastInFlowChild = *downcast<Container>(layoutBox).lastInFlowChild(); >+ if (!lastInFlowChild.isBlockLevelBox()) >+ return false; >+ >+ // The bottom margin of an in-flow block box with a 'height' of 'auto' collapses with its last in-flow block-level child's bottom margin, if: >+ if (!layoutBox.style().height().isAuto()) >+ return false; >+ >+ // the box has no bottom padding, and >+ if (hasPaddingBefore(layoutBox)) >+ return false; >+ >+ // the box has no bottom border, and >+ if (hasBorderBefore(layoutBox)) >+ return false; >+ >+ // the child's bottom margin neither collapses with a top margin that has clearance... >+ if (marginAfterCollapsesWithSiblingMarginBeforeWithClearance(layoutState, lastInFlowChild)) >+ return false; >+ >+ // nor (if the box's min-height is non-zero) with the box's top margin. >+ auto computedMinHeight = layoutBox.style().logicalMinHeight(); >+ if (!computedMinHeight.isAuto() && computedMinHeight.value() >+ && (marginAfterCollapsesWithParentMarginBefore(layoutState, lastInFlowChild) || hasClearance(layoutState, lastInFlowChild))) >+ return false; > > // Margins between a floated box and any other box do not collapse. >- if (layoutBox.isFloatingPositioned() || previousInFlowSibling.isFloatingPositioned()) >+ if (lastInFlowChild.isFloatingPositioned()) > return false; > > // Margins of absolutely positioned boxes do not collapse. >- if ((layoutBox.isOutOfFlowPositioned() && !layoutBox.style().top().isAuto()) >- || (previousInFlowSibling.isOutOfFlowPositioned() && !previousInFlowSibling.style().bottom().isAuto())) >+ if (lastInFlowChild.isOutOfFlowPositioned()) > return false; > > // Margins of inline-block boxes do not collapse. >- if (layoutBox.isInlineBlockBox() || previousInFlowSibling.isInlineBlockBox()) >- return false; >- >- // The bottom margin of an in-flow block-level element always collapses with the top margin of >- // its next in-flow block-level sibling, unless that sibling has clearance. >- if (hasClearance(layoutBox)) >+ if (lastInFlowChild.isInlineBlockBox()) > return false; > > return true; > } > >-bool BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithNextSibling(const Box& layoutBox) >+bool BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithNextSiblingMarginBefore(const LayoutState& layoutState, const Box& layoutBox) > { > ASSERT(layoutBox.isBlockLevelBox()); > > if (!layoutBox.nextInFlowSibling()) > return false; > >- return marginBeforeCollapsesWithPreviousSibling(*layoutBox.nextInFlowSibling()); >+ return marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, *layoutBox.nextInFlowSibling()); > } > > bool BlockFormattingContext::MarginCollapse::marginsCollapseThrough(const LayoutState& layoutState, const Box& layoutBox) >@@ -387,77 +397,234 @@ bool BlockFormattingContext::MarginCollapse::marginsCollapseThrough(const Layout > if (!is<Container>(layoutBox)) > return true; > >- if (layoutBox.establishesInlineFormattingContext()) { >- if (downcast<InlineFormattingState>(layoutState.establishedFormattingState(layoutBox)).inlineRuns().isEmpty()) >- return false; >- } else { >- for (auto* inflowChild = downcast<Container>(layoutBox).firstInFlowChild(); inflowChild; inflowChild = inflowChild->nextInFlowSibling()) { >- if (!marginsCollapseThrough(layoutState, *inflowChild)) >- return true; >+ if (!downcast<Container>(layoutBox).hasInFlowChild()) >+ return !establishesBlockFormattingContext(layoutBox); >+ >+ if (Quirks::needsStretching(layoutState, layoutBox)) >+ return false; >+ >+ if (layoutBox.establishesFormattingContext()) { >+ if (layoutBox.establishesInlineFormattingContext()) { >+ // If we get here through margin estimation, we don't necessarily have an actual state for this layout box since >+ // we haven't started laying it out yet. >+ if (!layoutState.hasFormattingState(layoutBox)) >+ return false; >+ return downcast<InlineFormattingState>(layoutState.establishedFormattingState(layoutBox)).inlineRuns().isEmpty(); > } >+ >+ if (establishesBlockFormattingContext(layoutBox)) >+ return false; > } > >+ for (auto* inflowChild = downcast<Container>(layoutBox).firstInFlowChild(); inflowChild; inflowChild = inflowChild->nextInFlowSibling()) { >+ if (establishesBlockFormattingContext(*inflowChild)) >+ return false; >+ if (!marginsCollapseThrough(layoutState, *inflowChild)) >+ return false; >+ } > return true; > } > >-LayoutUnit BlockFormattingContext::MarginCollapse::marginBefore(const LayoutState& layoutState, const Box& layoutBox) >+static PositiveAndNegativeVerticalMargin::Values computedPositiveAndNegativeMargin(PositiveAndNegativeVerticalMargin::Values a, PositiveAndNegativeVerticalMargin::Values b) > { >- if (layoutBox.isAnonymous()) >- return 0; >+ PositiveAndNegativeVerticalMargin::Values computedValues; >+ if (a.positive && b.positive) >+ computedValues.positive = std::max(*a.positive, *b.positive); >+ else >+ computedValues.positive = a.positive ? a.positive : b.positive; >+ >+ if (a.negative && b.negative) >+ computedValues.negative = std::min(*a.negative, *b.negative); >+ else >+ computedValues.negative = a.negative ? a.negative : b.negative; >+ >+ return computedValues; >+} > >- ASSERT(layoutBox.isBlockLevelBox()); >+static PositiveAndNegativeVerticalMargin::Values computedPositiveAndNegativeMargin(PositiveAndNegativeVerticalMargin::Values a, Optional<LayoutUnit> marginValue) >+{ >+ if (!marginValue || !marginValue.value()) >+ return a; >+ if (*marginValue > 0) >+ return computedPositiveAndNegativeMargin(a, { marginValue, { } }); >+ if (*marginValue < 0) >+ return computedPositiveAndNegativeMargin(a, { { }, marginValue }); >+ ASSERT_NOT_REACHED(); >+ return { }; >+} >+ >+static Optional<LayoutUnit> marginValue(PositiveAndNegativeVerticalMargin::Values marginValues) >+{ >+ // When two or more margins collapse, the resulting margin width is the maximum of the collapsing margins' widths. >+ // In the case of negative margins, the maximum of the absolute values of the negative adjoining margins is deducted from the maximum >+ // of the positive adjoining margins. If there are no positive margins, the maximum of the absolute values of the adjoining margins is deducted from zero. >+ if (!marginValues.negative) >+ return marginValues.positive; >+ >+ if (!marginValues.positive) >+ return marginValues.negative; > >- // TODO: take _hasAdjoiningMarginBeforeAndAfter() into account. >- if (marginBeforeCollapsesWithParentMarginBefore(layoutState, layoutBox)) >- return 0; >- >- // FIXME: Find out the logic behind this. >- if (BlockFormattingContext::Quirks::shouldIgnoreMarginBefore(layoutState, layoutBox)) >- return 0; >- >- if (!marginBeforeCollapsesWithPreviousSibling(layoutBox)) { >- if (!marginsCollapseThrough(layoutState, layoutBox)) >- return nonCollapsedMarginBefore(layoutState, layoutBox); >- // Compute the collapsed through value. >- auto marginBefore = nonCollapsedMarginBefore(layoutState, layoutBox); >- auto marginAfter = nonCollapsedMarginAfter(layoutState, layoutBox); >- return marginValue(marginBefore, marginAfter); >+ return *marginValues.positive + *marginValues.negative; >+} >+ >+void BlockFormattingContext::MarginCollapse::updateCollapsedMarginAfter(const LayoutState& layoutState, const Box& layoutBox, const UsedVerticalMargin& nextSiblingVerticalMargin) >+{ >+ // 1. Get the margin before value from the next in-flow sibling. This is the same as this box's margin after value now since they are collapsed. >+ // 2. Update the collapsed margin after value as well as the positive/negative cache. >+ // 3. Check if the box's margins collapse through. >+ // 4. If so, update the collapsed margin before value as well as the positive/negative cache. >+ // 5. In case of collapsed through margins check if the before margin collapes with the previous inflow sibling's after margin. >+ // 6. If so, jump to #2. >+ if (!marginAfterCollapsesWithNextSiblingMarginBefore(layoutState, layoutBox)) >+ return; >+ >+ auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); >+ auto verticalMargin = displayBox.verticalMargin(); >+ auto verticalMarginAfter = nextSiblingVerticalMargin.before(); >+ Optional<LayoutUnit> verticalMarginBefore; >+ >+ auto marginsCollapseThrough = MarginCollapse::marginsCollapseThrough(layoutState, layoutBox); >+ if (marginsCollapseThrough) >+ verticalMarginBefore = verticalMarginAfter; >+ else if (verticalMargin.hasCollapsedValues()) >+ verticalMarginBefore = verticalMargin.collapsedValues().before; >+ >+ // Update vertical margin values. >+ verticalMargin.setCollapsedValues({ verticalMarginBefore, verticalMarginAfter }); >+ displayBox.setVerticalMargin(verticalMargin); >+ >+ // Update positive/negative cache. >+ auto& blockFormattingState = downcast<BlockFormattingState>(layoutState.formattingStateForBox(layoutBox)); >+ auto positiveNegativeMargin = blockFormattingState.positiveAndNegativeVerticalMargin(layoutBox); >+ auto nextSiblingPositiveNegativeMarginBefore = blockFormattingState.positiveAndNegativeVerticalMargin(*layoutBox.nextInFlowSibling()).before; >+ >+ positiveNegativeMargin.after = computedPositiveAndNegativeMargin(nextSiblingPositiveNegativeMarginBefore, positiveNegativeMargin.after); >+ if (marginsCollapseThrough) { >+ positiveNegativeMargin.before = computedPositiveAndNegativeMargin(positiveNegativeMargin.before, positiveNegativeMargin.after); >+ positiveNegativeMargin.after = positiveNegativeMargin.before; > } >+ blockFormattingState.setPositiveAndNegativeVerticalMargin(layoutBox, positiveNegativeMargin); >+ >+ if (!marginsCollapseThrough || !marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, layoutBox)) >+ return; >+ >+ updateCollapsedMarginAfter(layoutState, *layoutBox.previousInFlowSibling(), verticalMargin); >+} >+ >+PositiveAndNegativeVerticalMargin::Values BlockFormattingContext::MarginCollapse::positiveNegativeValues(const LayoutState& layoutState, const Box& layoutBox, MarginType marginType) >+{ >+ auto& blockFormattingState = downcast<BlockFormattingState>(layoutState.formattingStateForBox(layoutBox)); >+ if (blockFormattingState.hasPositiveAndNegativeVerticalMargin(layoutBox)) { >+ auto positiveAndNegativeVerticalMargin = blockFormattingState.positiveAndNegativeVerticalMargin(layoutBox); >+ return marginType == MarginType::Before ? positiveAndNegativeVerticalMargin.before : positiveAndNegativeVerticalMargin.after; >+ } >+ // This is the estimate path. We don't yet have positive/negative margin computed. >+ auto computedVerticalMargin = Geometry::computedVerticalMargin(layoutState, layoutBox); >+ auto nonCollapsedMargin = UsedVerticalMargin::NonCollapsedValues { computedVerticalMargin.before.valueOr(0), computedVerticalMargin.after.valueOr(0) }; >+ >+ if (marginType == MarginType::Before) >+ return positiveNegativeMarginBefore(layoutState, layoutBox, nonCollapsedMargin); >+ return positiveNegativeMarginAfter(layoutState, layoutBox, nonCollapsedMargin); >+} > >- // The bottom margin of an in-flow block-level element always collapses with the top margin of its next in-flow block-level sibling, >- // unless that sibling has clearance. >- auto* previousInFlowSibling = layoutBox.previousInFlowSibling(); >- if (!previousInFlowSibling) >- return nonCollapsedMarginBefore(layoutState, layoutBox); >+PositiveAndNegativeVerticalMargin::Values BlockFormattingContext::MarginCollapse::positiveNegativeMarginBefore(const LayoutState& layoutState, const Box& layoutBox, const UsedVerticalMargin::NonCollapsedValues& nonCollapsedValues) >+{ >+ auto firstChildCollapsedMarginBefore = [&]() -> PositiveAndNegativeVerticalMargin::Values { >+ if (!is<Container>(layoutBox)) >+ return { }; >+ auto* firstInFlowChild = downcast<Container>(layoutBox).firstInFlowChild(); >+ if (!firstInFlowChild) >+ return { }; >+ if (!marginBeforeCollapsesWithFirstInFlowChildMarginBefore(layoutState, layoutBox)) >+ return { }; >+ if (Quirks::shouldIgnoreMarginBefore(layoutState, *firstInFlowChild)) >+ return { }; >+ return positiveNegativeValues(layoutState, *firstInFlowChild, MarginType::Before); >+ }; >+ >+ auto previouSiblingCollapsedMarginAfter = [&]() -> PositiveAndNegativeVerticalMargin::Values { >+ auto* previousInFlowSibling = layoutBox.previousInFlowSibling(); >+ if (!previousInFlowSibling) >+ return { }; >+ if (!marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, layoutBox)) >+ return { }; >+ if (Quirks::shouldIgnoreMarginAfter(layoutState, *previousInFlowSibling)) >+ return { }; >+ return positiveNegativeValues(layoutState, *previousInFlowSibling, MarginType::After); >+ }; >+ >+ // 1. Gather positive and negative margin values from first child if margins are adjoining. >+ // 2. Gather positive and negative margin values from previous inflow sibling if margins are adjoining. >+ // 3. Compute min/max positive and negative collapsed margin values using non-collpased computed margin before. >+ auto collapsedMarginBefore = computedPositiveAndNegativeMargin(firstChildCollapsedMarginBefore(), previouSiblingCollapsedMarginAfter()); >+ return computedPositiveAndNegativeMargin(collapsedMarginBefore, nonCollapsedValues.before); >+} > >- auto previousSiblingMarginAfter = nonCollapsedMarginAfter(layoutState, *previousInFlowSibling); >- auto marginBefore = nonCollapsedMarginBefore(layoutState, layoutBox); >- return marginValue(marginBefore, previousSiblingMarginAfter); >+PositiveAndNegativeVerticalMargin::Values BlockFormattingContext::MarginCollapse::positiveNegativeMarginAfter(const LayoutState& layoutState, const Box& layoutBox, const UsedVerticalMargin::NonCollapsedValues& nonCollapsedValues) >+{ >+ auto lastChildCollapsedMarginAfter = [&]() -> PositiveAndNegativeVerticalMargin::Values { >+ if (!is<Container>(layoutBox)) >+ return { }; >+ auto* lastInFlowChild = downcast<Container>(layoutBox).lastInFlowChild(); >+ if (!lastInFlowChild) >+ return { }; >+ if (!marginAfterCollapsesWithLastInFlowChildMarginAfter(layoutState, layoutBox)) >+ return { }; >+ if (Quirks::shouldIgnoreMarginAfter(layoutState, *lastInFlowChild)) >+ return { }; >+ return positiveNegativeValues(layoutState, *lastInFlowChild, MarginType::After); >+ }; >+ >+ // We don't know yet the margin before value of the next sibling. Let's just pretend it does not have one and >+ // update it later when we compute the next sibling's margin before. See updateCollapsedMarginAfter. >+ return computedPositiveAndNegativeMargin(lastChildCollapsedMarginAfter(), nonCollapsedValues.after); > } > >-LayoutUnit BlockFormattingContext::MarginCollapse::marginAfter(const LayoutState& layoutState, const Box& layoutBox) >+EstimatedMarginBefore BlockFormattingContext::MarginCollapse::estimatedMarginBefore(const LayoutState& layoutState, const Box& layoutBox) > { > if (layoutBox.isAnonymous()) >- return 0; >+ return { }; > > ASSERT(layoutBox.isBlockLevelBox()); >+ // Can't estimate vertical margins for out of flow boxes (and we shouldn't need to do it for float boxes). >+ ASSERT(layoutBox.isInFlow()); >+ ASSERT(!layoutBox.replaced()); >+ // Can't cross block formatting context boundary. >+ ASSERT(!layoutBox.establishesBlockFormattingContext()); >+ >+ auto computedVerticalMargin = Geometry::computedVerticalMargin(layoutState, layoutBox); >+ auto nonCollapsedMargin = UsedVerticalMargin::NonCollapsedValues { computedVerticalMargin.before.valueOr(0), computedVerticalMargin.after.valueOr(0) }; > >- // TODO: take _hasAdjoiningMarginBeforeAndBottom() into account. >- if (marginAfterCollapsesWithParentMarginAfter(layoutState, layoutBox)) >- return 0; >+ if (!marginsCollapseThrough(layoutState, layoutBox)) >+ return { marginValue(positiveNegativeMarginBefore(layoutState, layoutBox, nonCollapsedMargin)).valueOr(0) }; >+ >+ return { marginValue(computedPositiveAndNegativeMargin(positiveNegativeMarginBefore(layoutState, layoutBox, nonCollapsedMargin), >+ positiveNegativeMarginAfter(layoutState, layoutBox, nonCollapsedMargin))).valueOr(0) }; >+} > >- if (marginsCollapseThrough(layoutState, layoutBox)) >- return 0; >+UsedVerticalMargin::CollapsedValues BlockFormattingContext::MarginCollapse::collapsedVerticalValues(const LayoutState& layoutState, const Box& layoutBox, const UsedVerticalMargin::NonCollapsedValues& nonCollapsedValues) >+{ >+ if (layoutBox.isAnonymous()) >+ return { }; > >- // Floats and out of flow positioned boxes do not collapse their margins. >- if (!marginAfterCollapsesWithNextSibling(layoutBox)) >- return nonCollapsedMarginAfter(layoutState, layoutBox); >+ ASSERT(layoutBox.isBlockLevelBox()); >+ // 1. Get min/max margin top values from the first in-flow child if we are collapsing margin top with it. >+ // 2. Get min/max margin top values from the previous in-flow sibling, if we are collapsing margin top with it. >+ // 3. Get this layout box's computed margin top value. >+ // 4. Update the min/max value and compute the final margin. >+ auto positiveNegativeMarginBefore = MarginCollapse::positiveNegativeMarginBefore(layoutState, layoutBox, nonCollapsedValues); >+ auto positiveNegativeMarginAfter = MarginCollapse::positiveNegativeMarginAfter(layoutState, layoutBox, nonCollapsedValues); >+ >+ auto marginsCollapseThrough = MarginCollapse::marginsCollapseThrough(layoutState, layoutBox); >+ if (marginsCollapseThrough) { >+ positiveNegativeMarginBefore = computedPositiveAndNegativeMargin(positiveNegativeMarginBefore, positiveNegativeMarginAfter); >+ positiveNegativeMarginAfter = positiveNegativeMarginBefore; >+ } > >- // The bottom margin of an in-flow block-level element always collapses with the top margin of its next in-flow block-level sibling, >- // unless that sibling has clearance. >- if (layoutBox.nextInFlowSibling()) >- return 0; >- return nonCollapsedMarginAfter(layoutState, layoutBox); >+ auto& blockFormattingState = downcast<BlockFormattingState>(layoutState.formattingStateForBox(layoutBox)); >+ blockFormattingState.setPositiveAndNegativeVerticalMargin(layoutBox, { positiveNegativeMarginBefore, positiveNegativeMarginAfter }); >+ >+ return { marginValue(positiveNegativeMarginBefore), marginValue(positiveNegativeMarginAfter), marginsCollapseThrough }; > } > > } >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.cpp b/Source/WebCore/layout/displaytree/DisplayBox.cpp >index 3140a55afab4cf12b3f55ffb7b1261f1d796f1ae..631ef71b983c715ad7e2ead54c0c152ec95102ea 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.cpp >+++ b/Source/WebCore/layout/displaytree/DisplayBox.cpp >@@ -60,7 +60,7 @@ Box::Box(const Box& other) > , m_horizontalMargin(other.m_horizontalMargin) > , m_verticalMargin(other.m_verticalMargin) > , m_horizontalComputedMargin(other.m_horizontalComputedMargin) >- , m_estimatedMarginBefore(other.m_estimatedMarginBefore) >+ , m_hasClearance(other.m_hasClearance) > , m_border(other.m_border) > , m_padding(other.m_padding) > #if !ASSERT_DISABLED >@@ -74,6 +74,7 @@ Box::Box(const Box& other) > , m_hasValidPadding(other.m_hasValidPadding) > , m_hasValidContentHeight(other.m_hasValidContentHeight) > , m_hasValidContentWidth(other.m_hasValidContentWidth) >+ , m_estimatedMarginBefore(other.m_estimatedMarginBefore) > #endif > { > } >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.h b/Source/WebCore/layout/displaytree/DisplayBox.h >index 31d86a6bfd33bb56d633f84465c69ab6ca429ee4..9aefb18d7759735820f34b0a0333302e5dc72719 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.h >+++ b/Source/WebCore/layout/displaytree/DisplayBox.h >@@ -136,21 +136,20 @@ public: > LayoutUnit width() const { return borderLeft() + paddingLeft().valueOr(0) + contentBoxWidth() + paddingRight().valueOr(0) + borderRight(); } > LayoutUnit height() const { return borderTop() + paddingTop().valueOr(0) + contentBoxHeight() + paddingBottom().valueOr(0) + borderBottom(); } > Rect rect() const { return { top(), left(), width(), height() }; } >- Rect rectWithMargin() const { return { top() - marginBefore(), left() - marginStart(), marginStart() + width() + marginEnd(), marginBefore() + height() + marginAfter() }; } >+ Rect rectWithMargin() const; > > Layout::UsedVerticalMargin verticalMargin() const; > LayoutUnit marginBefore() const; > LayoutUnit marginStart() const; > LayoutUnit marginAfter() const; > LayoutUnit marginEnd() const; >+ bool hasClearance() const { return m_hasClearance; } > > LayoutUnit nonCollapsedMarginBefore() const; > LayoutUnit nonCollapsedMarginAfter() const; > Optional<LayoutUnit> computedMarginStart() const; > Optional<LayoutUnit> computedMarginEnd() const; > >- Optional<LayoutUnit> estimatedMarginBefore() const { return m_estimatedMarginBefore; } >- > LayoutUnit borderTop() const; > LayoutUnit borderLeft() const; > LayoutUnit borderBottom() const; >@@ -175,6 +174,11 @@ public: > Rect paddingBox() const; > Rect contentBox() const; > >+#if !ASSERT_DISABLED >+ void setEstimatedMarginBefore(Layout::EstimatedMarginBefore marginBefore) { m_estimatedMarginBefore = marginBefore; } >+ Optional<Layout::EstimatedMarginBefore> estimatedMarginBefore() const { return m_estimatedMarginBefore; } >+#endif >+ > private: > struct Style { > Style(const RenderStyle&); >@@ -194,7 +198,7 @@ private: > void setHorizontalMargin(Layout::UsedHorizontalMargin); > void setVerticalMargin(Layout::UsedVerticalMargin); > void setHorizontalComputedMargin(Layout::ComputedHorizontalMargin); >- void setEstimatedMarginBefore(LayoutUnit marginBefore) { m_estimatedMarginBefore = marginBefore; } >+ void setHasClearance() { m_hasClearance = true; } > > void setBorder(Layout::Edges); > void setPadding(Optional<Layout::Edges>); >@@ -203,6 +207,7 @@ private: > void invalidateMargin(); > void invalidateBorder() { m_hasValidBorder = false; } > void invalidatePadding() { m_hasValidPadding = false; } >+ void invalidateEstimatedMarginBefore() { m_estimatedMarginBefore = { }; } > > void setHasValidTop() { m_hasValidTop = true; } > void setHasValidLeft() { m_hasValidLeft = true; } >@@ -227,7 +232,7 @@ private: > Layout::UsedHorizontalMargin m_horizontalMargin; > Layout::UsedVerticalMargin m_verticalMargin; > Layout::ComputedHorizontalMargin m_horizontalComputedMargin; >- Optional<LayoutUnit> m_estimatedMarginBefore; >+ bool m_hasClearance; > > Layout::Edges m_border; > Optional<Layout::Edges> m_padding; >@@ -243,6 +248,7 @@ private: > bool m_hasValidPadding { false }; > bool m_hasValidContentHeight { false }; > bool m_hasValidContentWidth { false }; >+ Optional<Layout::EstimatedMarginBefore> m_estimatedMarginBefore; > #endif > }; > >@@ -520,8 +526,8 @@ inline void Box::setVerticalMargin(Layout::UsedVerticalMargin margin) > #if !ASSERT_DISABLED > setHasValidVerticalMargin(); > setHasValidVerticalNonCollapsedMargin(); >+ invalidateEstimatedMarginBefore(); > #endif >- ASSERT(!m_estimatedMarginBefore || *m_estimatedMarginBefore == margin.before()); > m_verticalMargin = margin; > } > >@@ -549,6 +555,14 @@ inline void Box::setPadding(Optional<Layout::Edges> padding) > m_padding = padding; > } > >+inline Box::Rect Box::rectWithMargin() const >+{ >+ auto marginAfter = this->marginAfter(); >+ if (m_verticalMargin.collapsedValues().isCollapsedThrough) >+ marginAfter = 0; >+ return { top() - marginBefore(), left() - marginStart(), marginStart() + width() + marginEnd(), marginBefore() + height() + marginAfter }; >+} >+ > inline Layout::UsedVerticalMargin Box::verticalMargin() const > { > ASSERT(m_hasValidVerticalMargin); >diff --git a/Source/WebCore/layout/floats/FloatingContext.cpp b/Source/WebCore/layout/floats/FloatingContext.cpp >index 71d0539788988f741f04a0b7d63e63d65187fb28..4e9f2cc2c0186ab69fac969c17ff4aa73691ae9d 100644 >--- a/Source/WebCore/layout/floats/FloatingContext.cpp >+++ b/Source/WebCore/layout/floats/FloatingContext.cpp >@@ -183,34 +183,32 @@ Optional<Position> FloatingContext::verticalPositionWithClearance(const Box& lay > if (clearance <= 0) > return { }; > >+ displayBox.setHasClearance(); > // Clearance inhibits margin collapsing. Let's reset the relevant adjoining margins. > if (auto* previousInFlowSibling = layoutBox.previousInFlowSibling()) { > auto& previousInFlowDisplayBox = layoutState.displayBoxForLayoutBox(*previousInFlowSibling); >+ // Does this box with clearance actually collapse its margin before with the previous inflow box's margin after? >+ auto verticalMargin = displayBox.verticalMargin(); >+ if (verticalMargin.hasCollapsedValues() && verticalMargin.collapsedValues().before) { >+ // Reset previous bottom after and current margin before to non-collapsing. >+ auto previousVerticalMargin = previousInFlowDisplayBox.verticalMargin(); >+ ASSERT(previousVerticalMargin.hasCollapsedValues() && previousVerticalMargin.collapsedValues().after); > >- // Since the previous inflow sibling has already been laid out, its margin is collapsed by now. >- ASSERT(!previousInFlowDisplayBox.marginAfter()); >- auto collapsedMargin = displayBox.marginBefore(); >- >- // Reset previous bottom and current top margins to non-collapsing. >- auto previousVerticalMargin = previousInFlowDisplayBox.verticalMargin(); >- if (previousVerticalMargin.collapsedValues().after) { >+ auto collapsedMargin = *verticalMargin.collapsedValues().before; > previousVerticalMargin.setCollapsedValues({ previousVerticalMargin.collapsedValues().before, { } }); > previousInFlowDisplayBox.setVerticalMargin(previousVerticalMargin); >- } >- // FIXME: check if collapsing through has anything to do with this. >- auto verticalMargin = displayBox.verticalMargin(); >- if (verticalMargin.collapsedValues().before) { >+ > verticalMargin.setCollapsedValues({ { }, verticalMargin.collapsedValues().after }); > displayBox.setVerticalMargin(verticalMargin); >- } > >- auto nonCollapsedMargin = previousInFlowDisplayBox.marginAfter() + displayBox.marginBefore(); >- auto marginOffset = nonCollapsedMargin - collapsedMargin; >- // Move the box to the position where it would be with non-collapsed margins. >- rootRelativeTop += marginOffset; >+ auto nonCollapsedMargin = previousVerticalMargin.after() + verticalMargin.before(); >+ auto marginDifference = nonCollapsedMargin - collapsedMargin; >+ // Move the box to the position where it would be with non-collapsed margins. >+ rootRelativeTop += marginDifference; > >- // Having negative clearance is also normal. It just means that the box with the non-collapsed margins is now lower than it needs to be. >- clearance -= marginOffset; >+ // Having negative clearance is also normal. It just means that the box with the non-collapsed margins is now lower than it needs to be. >+ clearance -= marginDifference; >+ } > } > // Now adjust the box's position with the clearance. > rootRelativeTop += clearance; >diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >index 0c3f5c8d77a1e756f26bc7320959d3c99cd9b40c..e7e72b79aae85d41d9b10cc585ec029cadf2b2dc 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >@@ -157,7 +157,6 @@ void InlineFormattingContext::splitInlineRunIfNeeded(const InlineRun& inlineRun, > splitRuns.append(run); > > contentStart += runWidth + uncommitted->lastInlineItem->nonBreakableEnd(); >- remaningLength -= uncommitted->length; > > startPosition = 0; > uncommitted = { }; >@@ -183,7 +182,9 @@ void InlineFormattingContext::splitInlineRunIfNeeded(const InlineRun& inlineRun, > // #1 > if (detachingRules.containsAll({ InlineItem::DetachingRule::BreakAtStart, InlineItem::DetachingRule::BreakAtEnd })) { > commit(); >- uncommitted = Uncommitted { &inlineItem, &inlineItem, currentLength() }; >+ auto contentLength = currentLength(); >+ uncommitted = Uncommitted { &inlineItem, &inlineItem, contentLength }; >+ remaningLength -= contentLength; > commit(); > continue; > } >@@ -194,10 +195,12 @@ void InlineFormattingContext::splitInlineRunIfNeeded(const InlineRun& inlineRun, > > // Add current inline item to uncommitted. > // #3 and #4 >+ auto contentLength = currentLength(); > if (!uncommitted) > uncommitted = Uncommitted { &inlineItem, &inlineItem, 0 }; >- uncommitted->length += currentLength(); >+ uncommitted->length += contentLength; > uncommitted->lastInlineItem = &inlineItem; >+ remaningLength -= contentLength; > > // #3 > if (detachingRules.contains(InlineItem::DetachingRule::BreakAtEnd)) >@@ -441,11 +444,12 @@ void InlineFormattingContext::collectInlineContentForSubtree(const Box& root, In > if (root.establishesFormattingContext() && &root != &(this->root())) { > createAndAppendInlineItem(); > auto& inlineRun = *inlineFormattingState.inlineContent().last(); >+ auto computedHorizontalMargin = Geometry::computedHorizontalMargin(layoutState(), root); >+ auto horizontalMargin = UsedHorizontalMargin { computedHorizontalMargin.start.valueOr(0), computedHorizontalMargin.end.valueOr(0) }; > >- auto horizontalMargin = Geometry::computedHorizontalMargin(layoutState(), root); > inlineRun.addDetachingRule({ InlineItem::DetachingRule::BreakAtStart, InlineItem::DetachingRule::BreakAtEnd }); >- inlineRun.addNonBreakableStart(horizontalMargin.start.valueOr(0)); >- inlineRun.addNonBreakableEnd(horizontalMargin.end.valueOr(0)); >+ inlineRun.addNonBreakableStart(horizontalMargin.start); >+ inlineRun.addNonBreakableEnd(horizontalMargin.end); > // Skip formatting root subtree. They are not part of this inline formatting context. > return; > } >@@ -465,7 +469,9 @@ void InlineFormattingContext::collectInlineContentForSubtree(const Box& root, In > // FIXME: Revisit this when we figured out how inline boxes fit the display tree. > auto padding = Geometry::computedPadding(layoutState(), root); > auto border = Geometry::computedBorder(layoutState(), root); >- auto horizontalMargin = Geometry::computedHorizontalMargin(layoutState(), root); >+ auto computedHorizontalMargin = Geometry::computedHorizontalMargin(layoutState(), root); >+ auto horizontalMargin = UsedHorizontalMargin { computedHorizontalMargin.start.valueOr(0), computedHorizontalMargin.end.valueOr(0) }; >+ > // Setup breaking boundaries for this subtree. > auto* lastDescendantInlineBox = inlineFormattingState.lastInlineItem(); > // Empty container? >@@ -496,7 +502,7 @@ void InlineFormattingContext::collectInlineContentForSubtree(const Box& root, In > > ASSERT(firstDescendantInlineBox); > firstDescendantInlineBox->addDetachingRule(InlineItem::DetachingRule::BreakAtStart); >- auto startOffset = border.horizontal.left + horizontalMargin.start.valueOr(0); >+ auto startOffset = border.horizontal.left + horizontalMargin.start; > if (padding) > startOffset += padding->horizontal.left; > firstDescendantInlineBox->addNonBreakableStart(startOffset); >@@ -504,7 +510,7 @@ void InlineFormattingContext::collectInlineContentForSubtree(const Box& root, In > > if (rootBreaksAtEnd()) { > lastDescendantInlineBox->addDetachingRule(InlineItem::DetachingRule::BreakAtEnd); >- auto endOffset = border.horizontal.right + horizontalMargin.end.valueOr(0); >+ auto endOffset = border.horizontal.right + horizontalMargin.end; > if (padding) > endOffset += padding->horizontal.right; > lastDescendantInlineBox->addNonBreakableEnd(endOffset); >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 3e68f076c1e3ffc6d8e97632187f9ba97e3a8df2..406e1092682fd6e77b1c4ad62313929b9e090109 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,12 @@ >+2019-01-07 Zalan Bujtas <zalan@apple.com> >+ >+ [LFC][BFC][MarginCollapsing] Add support for peculiar cases. >+ https://bugs.webkit.org/show_bug.cgi?id=192625 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * LayoutReloaded/misc/LFC-passing-tests.txt: >+ > 2019-01-06 Fujii Hironori <Hironori.Fujii@sony.com> > > [Win][Clang] Fix compilation warnings of MiniBrowser >diff --git a/Tools/LayoutReloaded/misc/LFC-passing-tests.txt b/Tools/LayoutReloaded/misc/LFC-passing-tests.txt >index ff5eb38154b72ef8c8817fb2945f350ebb5d1012..225b7475da83aa5caae191ea591aa6251e69cf68 100644 >--- a/Tools/LayoutReloaded/misc/LFC-passing-tests.txt >+++ b/Tools/LayoutReloaded/misc/LFC-passing-tests.txt >@@ -4,23 +4,66 @@ fast/block/block-only/absolute-left-auto.html > fast/block/block-only/absolute-left-right-top-bottom-auto.html > fast/block/block-only/absolute-nested2.html > fast/block/block-only/absolute-nested.html >+fast/block/block-only/absolute-position-min-max-height.html >+fast/block/block-only/absolute-position-min-max-width.html >+fast/block/block-only/absolute-position-when-containing-block-is-not-in-the-formatting-context2.html > fast/block/block-only/absolute-position-when-containing-block-is-not-in-the-formatting-context.html > fast/block/block-only/absolute-simple.html > fast/block/block-only/absolute-width-shrink-to-fit.html > fast/block/block-only/absolute-width-stretch.html > fast/block/block-only/absolute-with-static-block-position-nested.html >+fast/block/block-only/almost-intruding-left-float-simple.html >+fast/block/block-only/body-height-with-auto-html-height-quirk2.html >+fast/block/block-only/body-height-with-auto-html-height-quirk.html >+fast/block/block-only/body-height-with-non-auto-html-height-quirk2.html >+fast/block/block-only/body-height-with-non-auto-html-height-quirk.html > fast/block/block-only/border-simple.html >+fast/block/block-only/collapsed-margin-with-min-height.html > fast/block/block-only/fixed-nested.html >+fast/block/block-only/float-and-siblings-with-margins.html >+fast/block/block-only/float-avoider-multiple-roots.html >+fast/block/block-only/float-avoider-simple-left.html >+fast/block/block-only/float-avoider-simple-right.html >+fast/block/block-only/float-avoider-with-margins.html >+fast/block/block-only/float-left-when-container-has-padding-margin.html >+fast/block/block-only/float-min-max-height.html >+fast/block/block-only/float-min-max-width.html >+fast/block/block-only/floating-and-next-previous-inflow-with-margin-with-no-border.html >+fast/block/block-only/floating-and-next-previous-inflow-with-margin.html >+fast/block/block-only/floating-box-clear-both-simple.html >+fast/block/block-only/floating-box-clear-right-simple.html >+fast/block/block-only/floating-box-left-and-right-multiple-with-top-offset.html >+fast/block/block-only/floating-box-left-and-right-multiple.html >+fast/block/block-only/floating-box-right-simple.html >+fast/block/block-only/floating-box-with-clear-siblings.html >+fast/block/block-only/floating-box-with-clear-simple.html >+fast/block/block-only/floating-box-with-new-formatting-context.html >+fast/block/block-only/floating-box-with-relative-positioned-sibling.html >+fast/block/block-only/floating-left-and-right-with-clearance.html >+fast/block/block-only/floating-left-right-simple.html >+fast/block/block-only/floating-left-right-with-all-margins.html >+fast/block/block-only/floating-lefts-and-rights-simple.html >+fast/block/block-only/floating-multiple-lefts-in-body.html >+fast/block/block-only/floating-multiple-lefts-multiple-lines.html >+fast/block/block-only/floating-multiple-lefts.html >+fast/block/block-only/floating-with-new-block-formatting-context.html >+fast/block/block-only/inflow-min-max-height.html >+fast/block/block-only/inflow-min-max-width.html > fast/block/block-only/margin-collapse-bottom-bottom.html > fast/block/block-only/margin-collapse-bottom-nested.html >+fast/block/block-only/margin-collapse-first-last-are-floating.html > fast/block/block-only/margin-collapse-simple.html > fast/block/block-only/margin-collapse-top-nested.html > fast/block/block-only/margin-collapse-when-child-has-padding-border.html >+fast/block/block-only/margin-collapse-with-block-formatting-context2.html >+fast/block/block-only/margin-collapse-with-block-formatting-context.html >+fast/block/block-only/margin-collapse-with-clearance.html > fast/block/block-only/margin-left-right-sizing-out-of-flow.html > fast/block/block-only/margin-left-right-sizing.html > fast/block/block-only/margin-propagation-simple-content-height.html > fast/block/block-only/margin-sibling-collapse-propagated.html > fast/block/block-only/margin-simple.html >+fast/block/block-only/min-max-height-percentage.html > fast/block/block-only/negative-margin-simple.html > fast/block/block-only/padding-nested.html > fast/block/block-only/padding-simple.html >@@ -31,80 +74,49 @@ fast/block/block-only/relative-position-when-containing-block-is-not-in-the-form > fast/block/block-only/relative-right.html > fast/block/block-only/relative-siblings.html > fast/block/block-only/relative-simple.html >-fast/block/block-only/absolute-position-when-containing-block-is-not-in-the-formatting-context2.html >-fast/block/block-only/margin-collapse-with-block-formatting-context.html >-fast/block/block-only/margin-collapse-with-block-formatting-context2.html >-fast/block/block-only/float-left-when-container-has-padding-margin.html >-fast/block/block-only/floating-box-left-and-right-multiple-with-top-offset.html >-fast/block/block-only/floating-box-left-and-right-multiple.html >-fast/block/block-only/floating-box-right-simple.html >-fast/block/block-only/floating-box-with-new-formatting-context.html >-fast/block/block-only/floating-box-with-relative-positioned-sibling.html >-fast/block/block-only/floating-left-right-simple.html >-fast/block/block-only/floating-left-right-with-all-margins.html >-fast/block/block-only/floating-lefts-and-rights-simple.html >-fast/block/block-only/floating-multiple-lefts-in-body.html >-fast/block/block-only/floating-multiple-lefts-multiple-lines.html >-fast/block/block-only/floating-multiple-lefts.html >-fast/block/block-only/floating-and-next-previous-inflow-with-margin.html >-fast/block/block-only/floating-and-next-previous-inflow-with-margin-with-no-border.html >-fast/block/block-only/floating-left-and-right-with-clearance.html >-fast/block/block-only/float-and-siblings-with-margins.html >-fast/block/block-only/margin-collapse-with-clearance.html >-fast/block/block-only/float-avoider-simple-left.html >-fast/block/block-only/float-avoider-simple-right.html >-fast/block/block-only/float-avoider-multiple-roots.html >-fast/block/block-only/float-avoider-with-margins.html >-fast/block/block-only/inflow-min-max-width.html >-fast/block/block-only/absolute-position-min-max-width.html >-fast/block/block-only/float-min-max-width.html >-fast/block/block-only/inflow-min-max-height.html >-fast/block/block-only/absolute-position-min-max-height.html >-fast/block/block-only/float-min-max-height.html >-fast/block/block-only/min-max-height-percentage.html >-fast/block/block-only/body-height-with-non-auto-html-height-quirk.html >-fast/block/block-only/body-height-with-non-auto-html-height-quirk2.html >-fast/block/block-only/body-height-with-auto-html-height-quirk.html >-fast/block/block-only/body-height-with-auto-html-height-quirk2.html >-fast/block/block-only/collapsed-margin-with-min-height.html >+fast/block/basic/002.html >+fast/block/basic/003.html >+fast/block/basic/006.html >+fast/block/basic/007.html >+fast/block/basic/008.html >+fast/block/basic/009.html >+fast/block/basic/012.html >+fast/block/basic/child-block-level-box-with-height-percent.html >+fast/block/basic/height-percentage-simple.html > fast/block/basic/inline-content-with-floating-image.html > fast/block/basic/inline-content-with-floating-images2.html >-fast/inline/simple-intruding-float1.html >-fast/inline/simple-intruding-floats2.html >-fast/inline/simple-intruding-floats3.html >-fast/inline/simple-inline-block.html >-fast/inline/simple-shrink-to-fit-inline-block.html >-fast/inline/simple-inline-inflow-positioned.html >-fast/inline/simple-inline-with-out-of-flow-descendant.html >-fast/inline/simple-inline-with-out-of-flow-descendant2.html >-fast/inline/inline-content-with-padding-left-right.html >-fast/inline/inline-content-with-border-left-right.html >-fast/inline/inline-content-with-margin-left-right.html >-fast/inline/inline-content-and-nested-formatting-root-with-margin-left-right.html >-fast/inline/inline-content-with-image-simple.html >-fast/inline/inline-content-with-float-and-margin.html >-fast/block/basic/height-percentage-simple.html >-fast/block/basic/child-block-level-box-with-height-percent.html >+fast/block/basic/percent-height-inside-anonymous-block.html > fast/block/basic/quirk-mode-percent-height.html >+fast/block/basic/quirk-percent-height-grandchild.html > fast/block/float/001.html > fast/block/float/007.html > fast/block/float/008.html > fast/block/float/009.html > fast/block/float/013.html > fast/block/float/019.html >-fast/block/basic/002.html >-fast/block/basic/003.html >-fast/block/basic/006.html >-fast/block/basic/007.html >-fast/block/basic/008.html >-fast/block/basic/009.html >-fast/block/basic/012.html >+fast/block/float/negative-margin-clear.html >+fast/block/float/overhanging-after-height-decrease-offsets.html >+fast/block/float/overhanging-after-height-decrease.html >+fast/block/float/overlapping-floats-with-overflow-hidden.html >+fast/block/float/previous-sibling-abspos-002.html >+fast/block/float/relative-painted-twice.html >+fast/block/float/avoidance-rtl.html >+fast/block/float/br-with-clear.html >+fast/block/float/clamped-right-float.html >+fast/block/float/float-on-zero-height-line.html >+fast/block/float/float-overhangs-root.html >+fast/block/float/float-with-anonymous-previous-sibling.html >+fast/block/float/floats-not-cleared-crash.html > fast/block/margin-collapse/002.html > fast/block/margin-collapse/003.html > fast/block/margin-collapse/026.html > fast/block/margin-collapse/027.html >+fast/block/margin-collapse/028.html >+fast/block/margin-collapse/029.html >+fast/block/margin-collapse/035.html > fast/block/margin-collapse/039.html > fast/block/margin-collapse/040.html >+fast/block/positioning/003.html > fast/block/positioning/004.html > fast/block/positioning/005.html > fast/block/positioning/006.html >@@ -145,8 +157,29 @@ fast/block/positioning/046.html > fast/block/positioning/049.html > fast/block/positioning/052.html > fast/block/positioning/054.html >+fast/block/positioning/060.html >+fast/block/positioning/absolute-positioning-no-scrollbar.html >+fast/block/positioning/change-containing-block-for-absolute-positioned.html >+fast/block/positioning/change-containing-block-for-fixed-positioned.html >+fast/block/positioning/complex-positioned-movement.html >+fast/block/positioning/fixed-position-detached-frame.html >+fast/block/positioning/fixed-position-stacking-context2.html >+fast/block/positioning/fixed-position-stacking-context.html >+fast/block/positioning/hiding-inside-relpositioned-inline.html >+fast/block/positioning/insert-positioned-in-anonymous-crash.html >+fast/block/positioning/leftmargin-topmargin.html >+fast/block/positioning/negative-rel-position.html >+fast/block/positioning/abs-inside-inline-rel.html >+fast/block/positioning/pref-width-change.html >+fast/block/positioning/relative-overflow-replaced-float.html >+fast/block/positioning/static-inline-position-dynamic.html > fast/block/inside-inlines/basic-float-intrusion.html > fast/block/inside-inlines/crash-on-first-line-change.html >+fast/block/lineboxcontain/replaced.html >+fast/block/collapse-anon-block-with-float-siblings-only.html >+fast/block/crash-when-anonymous-blocks-are-merged-with-simple-line-layout.html >+fast/block/crash-when-subtree-is-still-attached.html >+fast/block/geometry-map-assertion-with-tall-content.html > fast/borders/0px-borders-no-line-height.html > fast/borders/0px-borders.html > fast/borders/block-mask-overlay-image-outset.html >@@ -156,11 +189,8 @@ fast/borders/border-image-scaled-gradient.html > fast/borders/border-image-slice-omission.html > fast/borders/border-left-right-same-bottom-different-color.html > fast/borders/border-painting-dashed-at-all.html >-fast/borders/border-painting-dashed.html > fast/borders/border-painting-dotted-at-all.html >-fast/borders/border-painting-dotted.html > fast/borders/border-painting-double-at-all.html >-fast/borders/border-painting-double.html > fast/borders/border-painting-groove-at-all.html > fast/borders/border-painting-inset-at-all.html > fast/borders/border-painting-inset.html >@@ -169,4 +199,86 @@ fast/borders/border-painting-outset.html > fast/borders/border-painting-ridge-at-all.html > fast/borders/border-painting-solid-at-all.html > fast/borders/border-painting-solid.html >-fast/inline-block/004.html >+fast/borders/border-radius-inset-outset.html >+fast/borders/border-radius-on-html.html >+fast/borders/border-radius-on-subpixel-position-non-hidpi.html >+fast/borders/border-radius-percent.html >+fast/borders/border-radius-valid-border-clipping.html >+fast/borders/border-radius-wide-border-01.html >+fast/borders/border-radius-with-box-shadow-01.html >+fast/borders/border-radius-with-box-shadow.html >+fast/borders/border-shadow-large-radius.html >+fast/borders/borderRadiusAllStylesAllCorners.html >+fast/borders/borderRadiusArcs01.html >+fast/borders/borderRadiusDashed01.html >+fast/borders/borderRadiusDashed02.html >+fast/borders/borderRadiusDashed03.html >+fast/borders/borderRadiusDotted01.html >+fast/borders/borderRadiusDotted02.html >+fast/borders/borderRadiusDotted03.html >+fast/borders/borderRadiusDouble01.html >+fast/borders/borderRadiusDouble02.html >+fast/borders/borderRadiusDouble03.html >+fast/borders/borderRadiusGroove01.html >+fast/borders/borderRadiusGroove02.html >+fast/borders/borderRadiusInset01.html >+fast/borders/borderRadiusInvalidColor.html >+fast/borders/borderRadiusOutset01.html >+fast/borders/borderRadiusRidge01.html >+fast/borders/borderRadiusSolid01.html >+fast/borders/borderRadiusSolid02.html >+fast/borders/borderRadiusSolid03.html >+fast/borders/borderRadiusSolid04.html >+fast/borders/dashed-border-on-subpixel-position.html >+fast/borders/dotted-border-on-subpixel-position.html >+fast/borders/double-1px-border-assert.html >+fast/borders/empty-drawrect-assert-after-pixelsnap.html >+fast/borders/empty-outline-border-assert.html >+fast/borders/hidpi-3x-input-hairline-border.html >+fast/borders/hidpi-border-clipping-right-after-move.html >+fast/borders/hidpi-border-painting-groove.html >+fast/borders/hidpi-border-painting-ridge.html >+fast/borders/hidpi-border-radius-outer-border-goes-rectangle.html >+fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable.html >+fast/borders/hidpi-border-width-flooring.html >+fast/borders/hidpi-outline-hairline-painting.html >+fast/borders/hidpi-outline-on-subpixel-position.html >+fast/borders/hidpi-rounded-border-on-subpixel-position.html >+fast/borders/hidpi-simple-hairline-border-painting.html >+fast/borders/mixed-border-style2.html >+fast/borders/negative-border-width.html >+fast/borders/outline-offset-min-assert.html >+fast/borders/outline-offset-overflow.html >+fast/borders/webkit-border-radius.html >+fast/inline/absolute-positioned-block-in-centred-block.html >+fast/inline/absolute-positioned-inline-in-centred-block.html >+fast/inline/anonymous-block-with-empty-inline.html >+fast/inline/hidpi-outline-auto-negative-offset-with-border-radius.html >+fast/inline/hidpi-outline-auto-with-fractional-radius.html >+fast/inline/hidpi-outline-auto-with-one-focusring-rect.html >+fast/inline/hidpi-pixel-gap-between-adjacent-selection-inlines.html >+fast/inline/hidpi-select-inline-on-subpixel-position.html >+fast/inline/hidpi-selection-gap-on-subpixel-position.html >+fast/inline/hidpi-selection-gap-overlaps-inline-selection.html >+fast/inline/inline-body-with-scrollbar-crash.html >+fast/inline/inline-child-height-width-calc-crash.html >+fast/inline/inline-content-with-border-left-right.html >+fast/inline/inline-content-with-float-and-margin.html >+fast/inline/inline-content-with-image-simple.html >+fast/inline/inline-content-with-margin-left-right.html >+fast/inline/inline-content-with-padding-left-right.html >+fast/inline/inline-marquee-crash.html >+fast/inline/inline-padding-disables-text-quirk.html >+fast/inline/new-float-needs-layout-when-line-is-dirty.html >+fast/inline/percentage-margins.html >+fast/inline/simple-inline-block.html >+fast/inline/simple-inline-inflow-positioned.html >+fast/inline/simple-inline-with-out-of-flow-descendant2.html >+fast/inline/simple-inline-with-out-of-flow-descendant.html >+fast/inline/simple-intruding-float1.html >+fast/inline/simple-intruding-floats2.html >+fast/inline/simple-intruding-floats3.html >+fast/inline/simple-line-layout-16bit-content.html >+fast/inline/simple-shrink-to-fit-inline-block.html >+fast/inline/skipped-whitespace-boundingBox.html >+fast/inline/skipped-whitespace-client-rect.html
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 192625
:
357130
|
357423
|
358137
|
358138
|
358142
|
358143
|
358144
|
358455
|
358479
|
358589
| 358670