Diff
Modified: trunk/Source/WebCore/ChangeLog (239772 => 239773)
--- trunk/Source/WebCore/ChangeLog 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/ChangeLog 2019-01-09 16:08:05 UTC (rev 239773)
@@ -1,3 +1,89 @@
+2019-01-09 Zalan Bujtas <za...@apple.com>
+
+ [LFC][BFC][MarginCollapsing] Add support for peculiar cases.
+ https://bugs.webkit.org/show_bug.cgi?id=192625
+
+ Reviewed by Antti Koivisto.
+
+ 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-09 Carlos Garcia Campos <cgar...@igalia.com>
REGRESSION(r239156): [FreeType] fixed width, and synthetic bold/italic not correctly applied since r239156
Modified: trunk/Source/WebCore/layout/LayoutState.h (239772 => 239773)
--- trunk/Source/WebCore/layout/LayoutState.h 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/LayoutState.h 2019-01-09 16:08:05 UTC (rev 239773)
@@ -75,6 +75,7 @@
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;
Modified: trunk/Source/WebCore/layout/MarginTypes.h (239772 => 239773)
--- trunk/Source/WebCore/layout/MarginTypes.h 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/MarginTypes.h 2019-01-09 16:08:05 UTC (rev 239773)
@@ -50,6 +50,7 @@
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; }
@@ -56,9 +57,8 @@
void setCollapsedValues(CollapsedValues collapsedValues) { m_collapsedValues = collapsedValues; }
UsedVerticalMargin(NonCollapsedValues, CollapsedValues);
+ UsedVerticalMargin() = default;
- UsedVerticalMargin() = default;
- ~UsedVerticalMargin() = default;
private:
NonCollapsedValues m_nonCollapsedValues;
CollapsedValues m_collapsedValues;
@@ -74,6 +74,10 @@
LayoutUnit end;
};
+struct EstimatedMarginBefore {
+ LayoutUnit usedValue;
+};
+
struct PositiveAndNegativeVerticalMargin {
struct Values {
Optional<LayoutUnit> positive;
Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp (239772 => 239773)
--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp 2019-01-09 16:08:05 UTC (rev 239773)
@@ -187,11 +187,14 @@
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 @@
// 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 @@
}
#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 @@
{
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 @@
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 @@
// 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 @@
}
}
- 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,7 +453,38 @@
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;
}
+
}
+}
#endif
Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h (239772 => 239773)
--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h 2019-01-09 16:08:05 UTC (rev 239773)
@@ -50,6 +50,8 @@
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 @@
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 @@
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 @@
// 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 UsedVerticalMargin::CollapsedValues collapsedVerticalValues(const LayoutState&, const Box&, const UsedVerticalMargin::NonCollapsedValues&);
+ 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 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:
- 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 LayoutUnit collapsedMarginBeforeFromFirstChild(const LayoutState&, const Box&);
- static LayoutUnit nonCollapsedMarginBefore(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&);
+ 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&);
};
};
Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp (239772 => 239773)
--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp 2019-01-09 16:08:05 UTC (rev 239773)
@@ -99,7 +99,6 @@
};
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 @@
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,31 +317,7 @@
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);
}
-}
-}
-
#endif
Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp (239772 => 239773)
--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp 2019-01-09 16:08:05 UTC (rev 239773)
@@ -55,7 +55,6 @@
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 @@
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 @@
// 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,7 +110,21 @@
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);
}
+
}
+}
#endif
Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingState.h (239772 => 239773)
--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingState.h 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingState.h 2019-01-09 16:08:05 UTC (rev 239773)
@@ -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 @@
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;
};
}
Modified: trunk/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp (239772 => 239773)
--- trunk/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp 2019-01-09 16:08:05 UTC (rev 239773)
@@ -70,12 +70,11 @@
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 @@
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 @@
return false;
if (currentBox == lastInFlowChild)
return marginAfterCollapsesWithParentMarginAfter(layoutState, *currentBox);
- if (!marginAfterCollapsesWithNextSibling(*currentBox))
+ if (!marginAfterCollapsesWithNextSiblingMarginBefore(layoutState, *currentBox))
return false;
}
ASSERT_NOT_REACHED();
@@ -229,15 +141,91 @@
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;
+}
+
bool BlockFormattingContext::MarginCollapse::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
@@ -248,7 +236,7 @@
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 @@
return false;
if (currentBox == firstInFlowChild)
return marginBeforeCollapsesWithParentMarginBefore(layoutState, *currentBox);
- if (!marginBeforeCollapsesWithPreviousSibling(*currentBox))
+ if (!marginBeforeCollapsesWithPreviousSiblingMarginAfter(layoutState, *currentBox))
return false;
}
ASSERT_NOT_REACHED();
@@ -324,37 +312,59 @@
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())
+ if (lastInFlowChild.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))
- return false;
-
return true;
}
-bool BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithNextSibling(const Box& layoutBox)
+bool BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithNextSiblingMarginBefore(const LayoutState& layoutState, const Box& layoutBox)
{
ASSERT(layoutBox.isBlockLevelBox());
@@ -361,7 +371,7 @@
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 @@
if (!is<Container>(layoutBox))
return true;
- if (layoutBox.establishesInlineFormattingContext()) {
- if (downcast<InlineFormattingState>(layoutState.establishedFormattingState(layoutBox)).inlineRuns().isEmpty())
+ 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;
- } else {
- for (auto* inflowChild = downcast<Container>(layoutBox).firstInFlowChild(); inflowChild; inflowChild = inflowChild->nextInFlowSibling()) {
- if (!marginsCollapseThrough(layoutState, *inflowChild))
- return true;
- }
}
+ 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;
- ASSERT(layoutBox.isBlockLevelBox());
+ if (a.negative && b.negative)
+ computedValues.negative = std::min(*a.negative, *b.negative);
+ else
+ computedValues.negative = a.negative ? a.negative : b.negative;
- // TODO: take _hasAdjoiningMarginBeforeAndAfter() into account.
- if (marginBeforeCollapsesWithParentMarginBefore(layoutState, layoutBox))
- return 0;
+ return computedValues;
+}
- // FIXME: Find out the logic behind this.
- if (BlockFormattingContext::Quirks::shouldIgnoreMarginBefore(layoutState, layoutBox))
- return 0;
+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 { };
+}
- 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);
+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;
+
+ 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);
- // 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::MarginCollapse::marginAfter(const LayoutState& layoutState, const Box& layoutBox)
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
- // 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 marginsCollapseThrough = MarginCollapse::marginsCollapseThrough(layoutState, layoutBox);
+ if (marginsCollapseThrough) {
+ positiveNegativeMarginBefore = computedPositiveAndNegativeMargin(positiveNegativeMarginBefore, positiveNegativeMarginAfter);
+ positiveNegativeMarginAfter = positiveNegativeMarginBefore;
+ }
+
+ auto& blockFormattingState = downcast<BlockFormattingState>(layoutState.formattingStateForBox(layoutBox));
+ blockFormattingState.setPositiveAndNegativeVerticalMargin(layoutBox, { positiveNegativeMarginBefore, positiveNegativeMarginAfter });
+
+ return { marginValue(positiveNegativeMarginBefore), marginValue(positiveNegativeMarginAfter), marginsCollapseThrough };
}
}
Modified: trunk/Source/WebCore/layout/displaytree/DisplayBox.cpp (239772 => 239773)
--- trunk/Source/WebCore/layout/displaytree/DisplayBox.cpp 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/displaytree/DisplayBox.cpp 2019-01-09 16:08:05 UTC (rev 239773)
@@ -60,7 +60,7 @@
, 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 @@
, m_hasValidPadding(other.m_hasValidPadding)
, m_hasValidContentHeight(other.m_hasValidContentHeight)
, m_hasValidContentWidth(other.m_hasValidContentWidth)
+ , m_estimatedMarginBefore(other.m_estimatedMarginBefore)
#endif
{
}
Modified: trunk/Source/WebCore/layout/displaytree/DisplayBox.h (239772 => 239773)
--- trunk/Source/WebCore/layout/displaytree/DisplayBox.h 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/displaytree/DisplayBox.h 2019-01-09 16:08:05 UTC (rev 239773)
@@ -136,7 +136,7 @@
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;
@@ -143,6 +143,7 @@
LayoutUnit marginStart() const;
LayoutUnit marginAfter() const;
LayoutUnit marginEnd() const;
+ bool hasClearance() const { return m_hasClearance; }
LayoutUnit nonCollapsedMarginBefore() const;
LayoutUnit nonCollapsedMarginAfter() const;
@@ -149,8 +150,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
bool m_hasValidPadding { false };
bool m_hasValidContentHeight { false };
bool m_hasValidContentWidth { false };
+ Optional<Layout::EstimatedMarginBefore> m_estimatedMarginBefore;
#endif
};
@@ -520,8 +526,8 @@
#if !ASSERT_DISABLED
setHasValidVerticalMargin();
setHasValidVerticalNonCollapsedMargin();
+ invalidateEstimatedMarginBefore();
#endif
- ASSERT(!m_estimatedMarginBefore || *m_estimatedMarginBefore == margin.before());
m_verticalMargin = margin;
}
@@ -549,6 +555,14 @@
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);
Modified: trunk/Source/WebCore/layout/floats/FloatingContext.cpp (239772 => 239773)
--- trunk/Source/WebCore/layout/floats/FloatingContext.cpp 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/floats/FloatingContext.cpp 2019-01-09 16:08:05 UTC (rev 239773)
@@ -183,34 +183,32 @@
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;
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp (239772 => 239773)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2019-01-09 16:08:05 UTC (rev 239773)
@@ -157,7 +157,6 @@
splitRuns.append(run);
contentStart += runWidth + uncommitted->lastInlineItem->nonBreakableEnd();
- remaningLength -= uncommitted->length;
startPosition = 0;
uncommitted = { };
@@ -183,7 +182,9 @@
// #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 @@
// 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 @@
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 @@
// 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 @@
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 @@
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);
Modified: trunk/Tools/ChangeLog (239772 => 239773)
--- trunk/Tools/ChangeLog 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Tools/ChangeLog 2019-01-09 16:08:05 UTC (rev 239773)
@@ -1,3 +1,12 @@
+2019-01-09 Zalan Bujtas <za...@apple.com>
+
+ [LFC][BFC][MarginCollapsing] Add support for peculiar cases.
+ https://bugs.webkit.org/show_bug.cgi?id=192625
+
+ Reviewed by Antti Koivisto.
+
+ * LayoutReloaded/misc/LFC-passing-tests.txt:
+
2019-01-09 Michael Catanzaro <mcatanz...@igalia.com>
[WPE][GTK] Purge use of g_assert() under TestWebKitAPI
Modified: trunk/Tools/LayoutReloaded/misc/LFC-passing-tests.txt (239772 => 239773)
--- trunk/Tools/LayoutReloaded/misc/LFC-passing-tests.txt 2019-01-09 15:30:58 UTC (rev 239772)
+++ trunk/Tools/LayoutReloaded/misc/LFC-passing-tests.txt 2019-01-09 16:08:05 UTC (rev 239773)
@@ -4,23 +4,66 @@
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,61 +74,20 @@
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
@@ -92,19 +94,29 @@
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/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-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-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