WebKit Bugzilla
Attachment 358455 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-20190105212144.patch (text/plain), 92.56 KB, created by
zalan
on 2019-01-05 21:21:52 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
zalan
Created:
2019-01-05 21:21:52 PST
Size:
92.56 KB
patch
obsolete
>Subversion Revision: 239660 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 55b71dc9deb21074a32e10417dfd9dbcea258561..576fd3f25c1eb0c21479608f1feaf3d941af79a2 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,117 @@ >+2018-12-29 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. >+ >+ * Sources.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ * layout/FormattingContext.cpp: >+ (WebCore::Layout::FormattingContext::FormattingContext): >+ (WebCore::Layout::FormattingContext::formattingState const): Deleted. >+ * layout/FormattingContext.h: >+ * layout/FormattingContextGeometry.cpp: >+ (WebCore::Layout::FormattingContext::Geometry::computedMinHeight): >+ (WebCore::Layout::FormattingContext::Geometry::floatingNonReplacedWidthAndMargin): >+ (WebCore::Layout::FormattingContext::Geometry::floatingReplacedWidthAndMargin): >+ (WebCore::Layout::FormattingContext::Geometry::inlineReplacedHeightAndMargin): >+ (WebCore::Layout::FormattingContext::Geometry::computedNonCollapsedHorizontalMargin): >+ (WebCore::Layout::FormattingContext::Geometry::computedNonCollapsedVerticalMargin): >+ (WebCore::Layout::FormattingContext::Geometry::computedNonCollapsedHorizontalMarginValue): Deleted. >+ (WebCore::Layout::FormattingContext::Geometry::computedNonCollapsedVerticalMarginValue): Deleted. >+ * layout/FormattingContextQuirks.cpp: >+ (WebCore::Layout::FormattingContext::Quirks::heightValueOfNearestContainingBlockWithFixedHeight): >+ * layout/LayoutState.h: >+ (WebCore::Layout::LayoutState::hasFormattingState const): >+ * layout/MarginTypes.h: >+ * layout/blockformatting/BlockFormattingContext.cpp: >+ (WebCore::Layout::BlockFormattingContext::formattingState const): >+ (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::Geometry::inFlowNonReplacedHeightAndMargin): >+ (WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedWidthAndMargin): >+ (WebCore::Layout::BlockFormattingContext::Geometry::inFlowReplacedWidthAndMargin): >+ * 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/BlockMargin.cpp: Added. >+ (WebCore::Layout::hasBorder): >+ (WebCore::Layout::hasPadding): >+ (WebCore::Layout::hasBorderBefore): >+ (WebCore::Layout::hasBorderAfter): >+ (WebCore::Layout::hasPaddingBefore): >+ (WebCore::Layout::hasPaddingAfter): >+ (WebCore::Layout::hasClearance): >+ (WebCore::Layout::establishesBlockFormattingContext): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginBeforeCollapsesWithParentMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginBeforeCollapsesWithParentMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginBeforeCollapsesWithPreviousSiblingMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginBeforeCollapsesWithFirstInFlowChildMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginAfterCollapsesWithSiblingMarginBeforeWithClearance): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginAfterCollapsesWithParentMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginAfterCollapsesWithParentMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginAfterCollapsesWithLastInFlowChildMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginAfterCollapsesWithNextSiblingMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::Margin::marginsCollapseThrough): >+ (WebCore::Layout::computedPositiveAndNegativeMargin): >+ (WebCore::Layout::marginValue): >+ (WebCore::Layout::BlockFormattingContext::Margin::updateCollapsedMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::Margin::positiveNegativeValues): >+ (WebCore::Layout::BlockFormattingContext::Margin::positiveNegativeMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::Margin::positiveNegativeMarginAfter): >+ (WebCore::Layout::BlockFormattingContext::Margin::estimatedMarginBefore): >+ (WebCore::Layout::BlockFormattingContext::Margin::vertical): >+ * layout/blockformatting/BlockMarginCollapse.cpp: Removed. >+ * 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::formattingState const): >+ (WebCore::Layout::InlineFormattingContext::splitInlineRunIfNeeded const): >+ (WebCore::Layout::InlineFormattingContext::createFinalRuns const): >+ (WebCore::Layout::InlineFormattingContext::postProcessInlineRuns const): >+ (WebCore::Layout::InlineFormattingContext::layoutInlineContent const): >+ (WebCore::Layout::InlineFormattingContext::placeInFlowPositionedChildren const): >+ (WebCore::Layout::InlineFormattingContext::collectInlineContentForSubtree const): >+ (WebCore::Layout::InlineFormattingContext::instrinsicWidthConstraints const): >+ * layout/inlineformatting/InlineFormattingContext.h: >+ (WebCore::Layout::InlineFormattingContext::inlineFormattingState const): Deleted. >+ * layout/inlineformatting/InlineFormattingContextGeometry.cpp: >+ (WebCore::Layout::InlineFormattingContext::Geometry::inlineBlockWidthAndMargin): >+ > 2019-01-05 Youenn Fablet <youenn@apple.com> > > Service Worker fetch should obey its referrer policy >diff --git a/Source/WebCore/layout/FormattingContextGeometry.cpp b/Source/WebCore/layout/FormattingContextGeometry.cpp >index cca6ef9a1d933efa3f0adff03a8f99be96ee6e4e..00e425f51059907f085f8748a9c27c68c07fb590 100644 >--- a/Source/WebCore/layout/FormattingContextGeometry.cpp >+++ b/Source/WebCore/layout/FormattingContextGeometry.cpp >@@ -785,6 +785,7 @@ HeightAndMargin FormattingContext::Geometry::inlineReplacedHeightAndMargin(const > // #1 > auto computedVerticalMargin = Geometry::computedVerticalMargin(layoutState, layoutBox); > auto usedVerticalMargin = UsedVerticalMargin::NonCollapsedValues { computedVerticalMargin.before.valueOr(0), computedVerticalMargin.after.valueOr(0) }; >+ > auto& style = layoutBox.style(); > auto replaced = layoutBox.replaced(); > >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..720e6d3e16af9074a6eeb2935f334f0db5537aba 100644 >--- a/Source/WebCore/layout/MarginTypes.h >+++ b/Source/WebCore/layout/MarginTypes.h >@@ -50,6 +50,7 @@ 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; } >@@ -59,6 +60,7 @@ struct UsedVerticalMargin { > > UsedVerticalMargin() = default; > ~UsedVerticalMargin() = default; >+ > private: > NonCollapsedValues m_nonCollapsedValues; > CollapsedValues m_collapsedValues; >@@ -74,6 +76,10 @@ struct UsedHorizontalMargin { > LayoutUnit end; > }; > >+struct EstimatedMarginBefore { >+ LayoutUnit computedValue; >+}; >+ > struct PositiveAndNegativeVerticalMargin { > struct Values { > Optional<LayoutUnit> positive; >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >index a73a5771c0480d83efbe67257c82203721cde6b8..b4f2a7afeff9650b7615df71f15e9b1c1b2df1f9 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >@@ -186,12 +186,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 = Margin::estimatedMarginBefore(layoutState(), layoutBox); >+ blockFormattingState().setHasEstimatedMarginBefore(layoutBox); > >- auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); >+ auto& displayBox = layoutState().displayBoxForLayoutBox(layoutBox); >+#if !ASSERT_DISABLED > displayBox.setEstimatedMarginBefore(estimatedMarginBefore); >- displayBox.moveVertically(estimatedMarginBefore); >+#endif >+ displayBox.setTop(adjustedVerticalPositionAfterMarginCollapsing(layoutBox, estimatedMarginBefore.computedValue)); > } > > void BlockFormattingContext::computeEstimatedMarginBeforeForAncestors(const Box& layoutBox) const >@@ -208,12 +210,11 @@ 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); >@@ -372,12 +373,15 @@ void BlockFormattingContext::computeHeightAndMargin(const Box& layoutBox) const > } > > auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); >+ auto& formattingState = this->blockFormattingState(); >+ if (formattingState.hasEstimatedMarginBefore(layoutBox)) { >+ formattingState.clearHasEstimatedMarginBefore(layoutBox); >+ ASSERT(layoutState.displayBoxForLayoutBox(layoutBox).estimatedMarginBefore()->computedValue == heightAndMargin.usedMargin.before()); >+ } else >+ displayBox.setTop(adjustedVerticalPositionAfterMarginCollapsing(layoutBox, heightAndMargin.usedMargin.before())); >+ > displayBox.setContentBoxHeight(heightAndMargin.height); > displayBox.setVerticalMargin(heightAndMargin.usedMargin); >- >- // 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(heightAndMargin.usedMargin.before()); > } > > FormattingContext::InstrinsicWidthConstraints BlockFormattingContext::instrinsicWidthConstraints() const >@@ -444,6 +448,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 (!Margin::marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, *currentLayoutBox)) { >+ auto& previousDisplayBox = layoutState.displayBoxForLayoutBox(previousInFlowSibling); >+ return previousDisplayBox.rectWithMargin().bottom() + marginBefore; >+ } >+ >+ if (!Margin::marginsCollapseThrough(layoutState, previousInFlowSibling)) { >+ auto& previousDisplayBox = layoutState.displayBoxForLayoutBox(previousInFlowSibling); >+ return previousDisplayBox.bottom() + marginBefore; >+ } >+ currentLayoutBox = &previousInFlowSibling; >+ } >+ >+ auto containingBlockContentBoxTop = layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock()).contentBoxTop(); >+ if (Margin::marginBeforeCollapsesWithParentMarginBefore(layoutState, layoutBox) || Margin::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 68041d4908567fb889340d6b53b7e3f2082ec180..081db774466b66fa7b3a7b43b7cf35bb389da6ce 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,49 +82,47 @@ 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: >- // 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 HeightAndMargin inFlowNonReplacedHeightAndMargin(const LayoutState&, const Box&, Optional<LayoutUnit> usedHeight = { }); >+ static WidthAndMargin inFlowNonReplacedWidthAndMargin(const LayoutState&, const Box&, Optional<LayoutUnit> usedWidth = { }); >+ static WidthAndMargin inFlowReplacedWidthAndMargin(const LayoutState&, const Box&, Optional<LayoutUnit> usedWidth = { }); >+ static Point staticPositionForOutOfFlowPositioned(const LayoutState&, const Box&); >+ }; > >- static bool marginBeforeCollapsesWithParentMarginAfter(const LayoutState&, const Box&); >- static bool marginAfterCollapsesWithParentMarginAfter(const LayoutState&, const Box&); >+ class Margin { >+ public: >+ static UsedVerticalMargin::CollapsedValues vertical(const LayoutState&, const Box&); > >- private: >- static LayoutUnit collapsedMarginAfterFromLastChild(const LayoutState&, const Box&); >- static LayoutUnit nonCollapsedMarginAfter(const LayoutState&, const Box&); >+ static EstimatedMarginBefore estimatedMarginBefore(const LayoutState&, const Box&); >+ static void updateCollapsedMarginAfter(const LayoutState&, const Box&, const UsedVerticalMargin& nextSiblingVerticalMargin); > >- static LayoutUnit computedNonCollapsedMarginBefore(const LayoutState&, const Box&); >- static LayoutUnit computedNonCollapsedMarginAfter(const LayoutState&, const Box&); >+ static bool marginBeforeCollapsesWithParentMarginBefore(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 LayoutUnit collapsedMarginBeforeFromFirstChild(const LayoutState&, const Box&); >- static LayoutUnit nonCollapsedMarginBefore(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 marginBeforeCollapsesWithParentMarginBefore(const LayoutState&, const Box&); >- static bool marginBeforeCollapsesWithPreviousSibling(const Box&); >- static bool marginAfterCollapsesWithNextSibling(const Box&); >- static bool marginAfterCollapsesWithSiblingMarginBeforeWithClearance(const LayoutState&, const Box&); >- static bool marginAfterCollapsesWithParentMarginBefore(const LayoutState&, const Box&); >- static bool marginsCollapseThrough(const LayoutState&, const Box&); >- }; >+ static bool marginsCollapseThrough(const LayoutState&, const Box&); > >- static HeightAndMargin inFlowNonReplacedHeightAndMargin(const LayoutState&, const Box&, Optional<LayoutUnit> usedHeight = { }); >- static WidthAndMargin inFlowNonReplacedWidthAndMargin(const LayoutState&, const Box&, Optional<LayoutUnit> usedWidth = { }); >- static WidthAndMargin inFlowReplacedWidthAndMargin(const LayoutState&, const Box&, Optional<LayoutUnit> usedWidth = { }); >- static Point staticPositionForOutOfFlowPositioned(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&); >+ static PositiveAndNegativeVerticalMargin::Values positiveNegativeMarginAfter(const LayoutState&, const Box&); > }; > > 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 fc75b5307c3e343f0244943896c29c7b1631bd9f..6197b462362ea721401a2e2cd0f55d2558e8ced1 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >@@ -60,7 +60,7 @@ HeightAndMargin BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMarg > auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); > auto computedVerticalMargin = Geometry::computedVerticalMargin(layoutState, layoutBox); > auto nonCollapsedMargin = UsedVerticalMargin::NonCollapsedValues { computedVerticalMargin.before.valueOr(0), computedVerticalMargin.after.valueOr(0) }; >- auto collapsedMargin = UsedVerticalMargin::CollapsedValues { MarginCollapse::marginBefore(layoutState, layoutBox), MarginCollapse::marginAfter(layoutState, layoutBox) }; >+ auto collapsedMargin = Margin::vertical(layoutState, layoutBox); > auto borderAndPaddingTop = displayBox.borderTop() + displayBox.paddingTop().valueOr(0); > > auto height = usedHeight ? usedHeight.value() : computedHeightValue(layoutState, layoutBox, HeightType::Normal); >@@ -81,14 +81,14 @@ HeightAndMargin BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMarg > // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin... > auto* lastInFlowChild = downcast<Container>(layoutBox).lastInFlowChild(); > ASSERT(lastInFlowChild); >- if (!MarginCollapse::marginAfterCollapsesWithParentMarginAfter(layoutState, *lastInFlowChild)) { >+ if (!Margin::marginAfterCollapsesWithParentMarginAfter(layoutState, *lastInFlowChild)) { > auto& lastInFlowDisplayBox = layoutState.displayBoxForLayoutBox(*lastInFlowChild); > return { lastInFlowDisplayBox.bottom() + lastInFlowDisplayBox.marginAfter() - borderAndPaddingTop, { nonCollapsedMargin, collapsedMargin } }; > } > > // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin > auto* inFlowChild = lastInFlowChild; >- while (inFlowChild && MarginCollapse::marginBeforeCollapsesWithParentMarginAfter(layoutState, *inFlowChild)) >+ while (inFlowChild && Margin::marginBeforeCollapsesWithParentMarginAfter(layoutState, *inFlowChild)) > inFlowChild = inFlowChild->previousInFlowSibling(); > if (inFlowChild) { > auto& inFlowDisplayBox = layoutState.displayBoxForLayoutBox(*inFlowChild); >@@ -100,6 +100,9 @@ HeightAndMargin BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMarg > }; > > auto heightAndMargin = compute(); >+ // Adjust the previous sibling's margin bottom now that this box's vertical margin is computed. >+ if (Margin::marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, layoutBox)) >+ Margin::updateCollapsedMarginAfter(layoutState, *layoutBox.previousInFlowSibling(), heightAndMargin.usedMargin); > > LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> inflow non-replaced -> height(" << heightAndMargin.height << "px) margin(" << heightAndMargin.usedMargin.before() << "px, " << heightAndMargin.usedMargin.after() << "px) -> layoutBox(" << &layoutBox << ")"); > return heightAndMargin; >@@ -258,7 +261,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.usedMargin.before() << "px, " << heightAndMargin.usedMargin.after() << "px) -> layoutBox(" << &layoutBox << ")"); > return heightAndMargin; >@@ -319,30 +322,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 f3ebd2d7cf135a87131aa64b428c65eda0810370..9c0ccf44ed0b17842e104394bceee270593cdfe8 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp >@@ -66,8 +66,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(); >@@ -88,17 +89,11 @@ 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; >- >- // This quirk happens when the body height is 0 which means its vertical margins collapse through (top and bottom margins are adjoining). >- // However now that we stretch the body they don't collapse through anymore, so we need to use the non-collapsed values instead. >- if (heightAndMargin.height) >- totalVerticalMargin = heightAndMargin.usedMargin.before() + heightAndMargin.usedMargin.after(); >- else { >- auto nonCollapsedValues = heightAndMargin.usedMargin.nonCollapsedValues(); >- totalVerticalMargin = nonCollapsedValues.before + nonCollapsedValues.after; >- } >+ auto documentBoxVerticalMargin = Geometry::computedVerticalMargin(layoutState, documentBox); >+ strechedHeight -= (documentBoxVerticalMargin.before.valueOr(0) + documentBoxVerticalMargin.after.valueOr(0)); >+ >+ auto bodyBoxVerticalMargin = heightAndMargin.usedMargin; >+ totalVerticalMargin = bodyBoxVerticalMargin.before() + bodyBoxVerticalMargin.after(); > } > > // Stretch but never overstretch with the margins. >@@ -116,6 +111,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 Margin::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 f798af3ded84bb72242b5825c8294448da691812..041dd63f4e0182e9e0a2e73edcc0272f5e65c7d4 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,94 +86,7 @@ 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::Geometry::MarginCollapse::computedNonCollapsedMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- >- return computedVerticalMargin(layoutState, layoutBox).before.valueOr(0); >-} >- >-LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::computedNonCollapsedMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isBlockLevelBox()); >- >- return computedVerticalMargin(layoutState, layoutBox).after.valueOr(0); >-} >- >-LayoutUnit BlockFormattingContext::Geometry::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::Geometry::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::Geometry::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::Geometry::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::Geometry::MarginCollapse::marginBeforeCollapsesWithParentMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >+bool BlockFormattingContext::Margin::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 > // 2. This box's margin after collapses with the next sibling's margin before and that sibling collapses through and >@@ -185,14 +97,14 @@ bool BlockFormattingContext::Geometry::MarginCollapse::marginBeforeCollapsesWith > return false; > if (currentBox == lastInFlowChild) > return marginAfterCollapsesWithParentMarginAfter(layoutState, *currentBox); >- if (!marginAfterCollapsesWithNextSibling(*currentBox)) >+ if (!marginAfterCollapsesWithNextSiblingMarginBefore(layoutState, *currentBox)) > return false; > } > ASSERT_NOT_REACHED(); > return false; > } > >-bool BlockFormattingContext::Geometry::MarginCollapse::marginBeforeCollapsesWithParentMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >+bool BlockFormattingContext::Margin::marginBeforeCollapsesWithParentMarginBefore(const LayoutState& layoutState, const Box& layoutBox) > { > // The first inflow child could propagate its top margin to parent. > // https://www.w3.org/TR/CSS21/box.html#collapsing-margins >@@ -229,16 +141,92 @@ bool BlockFormattingContext::Geometry::MarginCollapse::marginBeforeCollapsesWith > return false; > > // ...and the child has no clearance. >- if (hasClearance(layoutBox)) >+ if (hasClearance(layoutState, layoutBox)) >+ return false; >+ >+ return true; >+} >+ >+bool BlockFormattingContext::Margin::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::Margin::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; > >- if (BlockFormattingContext::Quirks::shouldIgnoreMarginBefore(layoutState, layoutBox)) >+ // 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; > } > >-bool BlockFormattingContext::Geometry::MarginCollapse::marginAfterCollapsesWithSiblingMarginBeforeWithClearance(const LayoutState& layoutState, const Box& layoutBox) >+bool BlockFormattingContext::Margin::marginAfterCollapsesWithSiblingMarginBeforeWithClearance(const LayoutState& layoutState, const Box& layoutBox) > { > // If the top and bottom margins of an element with clearance are adjoining, its margins collapse with the adjoining margins > // of following siblings but that resulting margin does not collapse with the bottom margin of the parent block. >@@ -248,13 +236,13 @@ bool BlockFormattingContext::Geometry::MarginCollapse::marginAfterCollapsesWithS > 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; > } > >-bool BlockFormattingContext::Geometry::MarginCollapse::marginAfterCollapsesWithParentMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >+bool BlockFormattingContext::Margin::marginAfterCollapsesWithParentMarginBefore(const LayoutState& layoutState, const Box& layoutBox) > { > // 1. This is the first in-flow child and its margins collapse through and the margin before collapses with parent's margin before or > // 2. This box's margin before collapses with the previous sibling's margin after and that sibling collapses through and >@@ -265,14 +253,14 @@ bool BlockFormattingContext::Geometry::MarginCollapse::marginAfterCollapsesWithP > return false; > if (currentBox == firstInFlowChild) > return marginBeforeCollapsesWithParentMarginBefore(layoutState, *currentBox); >- if (!marginBeforeCollapsesWithPreviousSibling(*currentBox)) >+ if (!marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, *currentBox)) > return false; > } > ASSERT_NOT_REACHED(); > return false; > } > >-bool BlockFormattingContext::Geometry::MarginCollapse::marginAfterCollapsesWithParentMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >+bool BlockFormattingContext::Margin::marginAfterCollapsesWithParentMarginAfter(const LayoutState& layoutState, const Box& layoutBox) > { > if (layoutBox.isAnonymous()) > return false; >@@ -324,47 +312,69 @@ bool BlockFormattingContext::Geometry::MarginCollapse::marginAfterCollapsesWithP > return true; > } > >-bool BlockFormattingContext::Geometry::MarginCollapse::marginBeforeCollapsesWithPreviousSibling(const Box& layoutBox) >+bool BlockFormattingContext::Margin::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::Geometry::MarginCollapse::marginAfterCollapsesWithNextSibling(const Box& layoutBox) >+bool BlockFormattingContext::Margin::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::Geometry::MarginCollapse::marginsCollapseThrough(const LayoutState& layoutState, const Box& layoutBox) >+bool BlockFormattingContext::Margin::marginsCollapseThrough(const LayoutState& layoutState, const Box& layoutBox) > { > ASSERT(layoutBox.isBlockLevelBox()); > >@@ -387,77 +397,219 @@ bool BlockFormattingContext::Geometry::MarginCollapse::marginsCollapseThrough(co > if (!is<Container>(layoutBox)) > return true; > >+ if (!downcast<Container>(layoutBox).hasInFlowChild()) >+ return true; >+ >+ if (Quirks::needsStretching(layoutState, layoutBox)) >+ return false; >+ > if (layoutBox.establishesInlineFormattingContext()) { >- if (downcast<InlineFormattingState>(layoutState.establishedFormattingState(layoutBox)).inlineRuns().isEmpty()) >+ // 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(); >+ } >+ >+ for (auto* inflowChild = downcast<Container>(layoutBox).firstInFlowChild(); inflowChild; inflowChild = inflowChild->nextInFlowSibling()) { >+ if (establishesBlockFormattingContext(*inflowChild)) >+ return false; >+ if (!marginsCollapseThrough(layoutState, *inflowChild)) > return false; >- } else { >- for (auto* inflowChild = downcast<Container>(layoutBox).firstInFlowChild(); inflowChild; inflowChild = inflowChild->nextInFlowSibling()) { >- if (!marginsCollapseThrough(layoutState, *inflowChild)) >- return true; >- } > } >- > return true; > } > >-LayoutUnit BlockFormattingContext::Geometry::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; > >- // 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); >+ if (!marginValues.positive) >+ return marginValues.negative; >+ >+ return *marginValues.positive + *marginValues.negative; >+} >+ >+void BlockFormattingContext::Margin::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 = Margin::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); > >- // 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); >+ if (!marginsCollapseThrough || !marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, layoutBox)) >+ return; > >- auto previousSiblingMarginAfter = nonCollapsedMarginAfter(layoutState, *previousInFlowSibling); >- auto marginBefore = nonCollapsedMarginBefore(layoutState, layoutBox); >- return marginValue(marginBefore, previousSiblingMarginAfter); >+ updateCollapsedMarginAfter(layoutState, *layoutBox.previousInFlowSibling(), verticalMargin); > } > >-LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::marginAfter(const LayoutState& layoutState, const Box& layoutBox) >+PositiveAndNegativeVerticalMargin::Values BlockFormattingContext::Margin::positiveNegativeValues(const LayoutState& layoutState, const Box& layoutBox, MarginType marginType) >+{ >+ auto& blockFormattingState = downcast<BlockFormattingState>(layoutState.formattingStateForBox(layoutBox)); >+ auto hasPrecomputedValue = blockFormattingState.hasPositiveAndNegativeVerticalMargin(layoutBox); >+ if (marginType == MarginType::Before) >+ return hasPrecomputedValue ? blockFormattingState.positiveAndNegativeVerticalMargin(layoutBox).before : positiveNegativeMarginBefore(layoutState, layoutBox); >+ return hasPrecomputedValue ? blockFormattingState.positiveAndNegativeVerticalMargin(layoutBox).after : positiveNegativeMarginAfter(layoutState, layoutBox); >+} >+ >+PositiveAndNegativeVerticalMargin::Values BlockFormattingContext::Margin::positiveNegativeMarginBefore(const LayoutState& layoutState, const Box& layoutBox) >+{ >+ 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()); >+ auto nonCollapsedMarginBefore = Geometry::computedVerticalMargin(layoutState, layoutBox).before; >+ return computedPositiveAndNegativeMargin(collapsedMarginBefore, nonCollapsedMarginBefore); >+} >+ >+PositiveAndNegativeVerticalMargin::Values BlockFormattingContext::Margin::positiveNegativeMarginAfter(const LayoutState& layoutState, const Box& layoutBox) >+{ >+ 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. >+ auto nonCollapsedMarginAfter = Geometry::computedVerticalMargin(layoutState, layoutBox).after; >+ return computedPositiveAndNegativeMargin(lastChildCollapsedMarginAfter(), nonCollapsedMarginAfter); >+} >+ >+EstimatedMarginBefore BlockFormattingContext::Margin::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()); >+ // Can't cross block formatting context boundary. >+ ASSERT(!layoutBox.establishesBlockFormattingContext()); >+ >+ if (!marginsCollapseThrough(layoutState, layoutBox)) >+ return { marginValue(positiveNegativeMarginBefore(layoutState, layoutBox)).valueOr(0) }; >+ >+ return { marginValue(computedPositiveAndNegativeMargin(positiveNegativeMarginBefore(layoutState, layoutBox), positiveNegativeMarginAfter(layoutState, layoutBox))).valueOr(0) }; >+} > >- // TODO: take _hasAdjoiningMarginBeforeAndBottom() into account. >- if (marginAfterCollapsesWithParentMarginAfter(layoutState, layoutBox)) >- return 0; >+UsedVerticalMargin::CollapsedValues BlockFormattingContext::Margin::vertical(const LayoutState& layoutState, const Box& layoutBox) >+{ >+ if (layoutBox.isAnonymous()) >+ return { }; > >- if (marginsCollapseThrough(layoutState, layoutBox)) >- return 0; >+ 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 = Margin::positiveNegativeMarginBefore(layoutState, layoutBox); >+ auto positiveNegativeMarginAfter = Margin::positiveNegativeMarginAfter(layoutState, layoutBox); >+ >+ auto marginsCollapseThrough = Margin::marginsCollapseThrough(layoutState, layoutBox); >+ if (marginsCollapseThrough) { >+ positiveNegativeMarginBefore = computedPositiveAndNegativeMargin(positiveNegativeMarginBefore, positiveNegativeMarginAfter); >+ positiveNegativeMarginAfter = positiveNegativeMarginBefore; >+ } > >- // Floats and out of flow positioned boxes do not collapse their margins. >- if (!marginAfterCollapsesWithNextSibling(layoutBox)) >- return nonCollapsedMarginAfter(layoutState, layoutBox); >+ auto& blockFormattingState = downcast<BlockFormattingState>(layoutState.formattingStateForBox(layoutBox)); >+ blockFormattingState.setPositiveAndNegativeVerticalMargin(layoutBox, { positiveNegativeMarginBefore, positiveNegativeMarginAfter }); > >- // 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); >+ 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 e0aaf59defd03d5d3193a924e99e5399856aacc5..1c416806c70effd0ff4d2d85e27631ac25cf9c65 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >@@ -466,6 +466,7 @@ void InlineFormattingContext::collectInlineContentForSubtree(const Box& root, In > auto padding = Geometry::computedPadding(layoutState(), root); > auto border = Geometry::computedBorder(layoutState(), root); > auto horizontalMargin = Geometry::computedHorizontalMargin(layoutState(), root); >+ > // Setup breaking boundaries for this subtree. > auto* lastDescendantInlineBox = inlineFormattingState.lastInlineItem(); > // Empty container? >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 97104d3ce906a86ca50eee55ee6a2dfd9a226035..00fe94589ce868eeddaaea66b2551b2f56d0eec4 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,12 @@ >+2018-12-29 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-05 Oriol Brufau <obrufau@igalia.com> > > [GTK] Add python3-setuptools, libunistring-dev, bison and flex dependencies >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