WebKit Bugzilla
Attachment 356727 Details for
Bug 192465
: [BFC][MarginCollapsing] Extend margin collapsing rules.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-192465-20181206074546.patch (text/plain), 22.25 KB, created by
zalan
on 2018-12-06 07:45:54 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
zalan
Created:
2018-12-06 07:45:54 PST
Size:
22.25 KB
patch
obsolete
>Subversion Revision: 238931 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 74455e715effc97c8b19d47a3e60b700d7e01217..1b2ec7b6f8bb6a5d039bcfb85aa996a4d0a39d92 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,35 @@ >+2018-12-06 Zalan Bujtas <zalan@apple.com> >+ >+ [BFC][MarginCollapsing] Extend margin collapsing rules. >+ https://bugs.webkit.org/show_bug.cgi?id=192465 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add some missing collapsing rules. >+ >+ * layout/blockformatting/BlockFormattingContext.h: >+ * layout/blockformatting/BlockFormattingContextGeometry.cpp: >+ (WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin): >+ * layout/blockformatting/BlockMarginCollapse.cpp: >+ (WebCore::Layout::hasClearance): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::marginTopCollapsesWithSibling): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::marginBottomCollapsesWithSibling): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::marginTopCollapsesWithParent): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::marginBottomCollapsesWithParent): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::marginsCollapseThrough): >+ (WebCore::Layout::marginValue): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::collapsedMarginTopFromFirstChild): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::marginTop): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::marginBottom): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::marginTopCollapsesWithParentMarginBottom): >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::collapsedMarginBottomFromLastChild): >+ (WebCore::Layout::isMarginTopCollapsedWithSibling): Deleted. >+ (WebCore::Layout::isMarginBottomCollapsedWithSibling): Deleted. >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::isMarginTopCollapsedWithParent): Deleted. >+ (WebCore::Layout::isMarginBottomCollapsedThrough): Deleted. >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::isMarginBottomCollapsedWithParent): Deleted. >+ (WebCore::Layout::BlockFormattingContext::Geometry::MarginCollapse::isMarginTopCollapsedWithParentMarginBottom): Deleted. >+ > 2018-12-06 Zalan Bujtas <zalan@apple.com> > > [LFC][BFC][MarginCollapsing] HeightAndMargin::margin is always the non-collapsed margin value. >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContext.h b/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >index e677e0174f0ed58c162fb6b713de096b11f0fd30..40e7b21c532a5d8c911a8feb324b9250e64db8d9 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >@@ -89,8 +89,8 @@ private: > static LayoutUnit marginTop(const LayoutState&, const Box&); > static LayoutUnit marginBottom(const LayoutState&, const Box&); > >- static bool isMarginBottomCollapsedWithParent(const Box&); >- static bool isMarginTopCollapsedWithParentMarginBottom(const Box&); >+ static bool marginBottomCollapsesWithParent(const Box&); >+ static bool marginTopCollapsesWithParentMarginBottom(const Box&); > > private: > static LayoutUnit collapsedMarginBottomFromLastChild(const LayoutState&, const Box&); >@@ -102,7 +102,10 @@ private: > static LayoutUnit collapsedMarginTopFromFirstChild(const LayoutState&, const Box&); > static LayoutUnit nonCollapsedMarginTop(const LayoutState&, const Box&); > >- static bool isMarginTopCollapsedWithParent(const LayoutState&, const Box&); >+ static bool marginTopCollapsesWithParent(const LayoutState&, const Box&); >+ static bool marginTopCollapsesWithSibling(const Box&); >+ static bool marginBottomCollapsesWithSibling(const Box&); >+ static bool marginsCollapseThrough(const Box&); > }; > > static HeightAndMargin inFlowNonReplacedHeightAndMargin(const LayoutState&, const Box&, std::optional<LayoutUnit> usedHeight = { }); >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >index 3b09f30cf1b69c837adbe3b8183802eca86408c4..815f33258aefce822b5a1982a4de6ced91f6055c 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >@@ -84,14 +84,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::isMarginBottomCollapsedWithParent(*lastInFlowChild)) { >+ if (!MarginCollapse::marginBottomCollapsesWithParent(*lastInFlowChild)) { > auto& lastInFlowDisplayBox = layoutState.displayBoxForLayoutBox(*lastInFlowChild); > return { lastInFlowDisplayBox.bottom() + lastInFlowDisplayBox.marginBottom() - 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::isMarginTopCollapsedWithParentMarginBottom(*inFlowChild)) >+ while (inFlowChild && MarginCollapse::marginTopCollapsesWithParentMarginBottom(*inFlowChild)) > inFlowChild = inFlowChild->previousInFlowSibling(); > if (inFlowChild) { > auto& inFlowDisplayBox = layoutState.displayBoxForLayoutBox(*inFlowChild); >diff --git a/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp b/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp >index bf1a08ccb659e5735937c76e822e87dba889e486..6f8020bce8ec83f54f6d331b71a9178cc531cd57 100644 >--- a/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp >@@ -78,53 +78,73 @@ static bool establishesBlockFormattingContext(const Box& layoutBox) > return layoutBox.establishesBlockFormattingContext(); > } > >-static LayoutUnit marginValue(LayoutUnit currentMarginValue, LayoutUnit candidateMarginValue) >+static bool hasClearance(const Box&) > { >- 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; >+ // FIXME: Use computed clearance for float avoiding block boxes. >+ return false; > } > >-static bool isMarginTopCollapsedWithSibling(const Box& layoutBox) >+bool BlockFormattingContext::Geometry::MarginCollapse::marginTopCollapsesWithSibling(const Box& layoutBox) > { > ASSERT(layoutBox.isBlockLevelBox()); > >- if (layoutBox.isFloatingPositioned()) >+ if (!layoutBox.previousInFlowSibling()) > return false; > >- if (!layoutBox.isPositioned() || layoutBox.isInFlowPositioned()) >- return true; >+ auto& previousInFlowSibling = *layoutBox.previousInFlowSibling(); > >- // Out of flow positioned. >- ASSERT(layoutBox.isOutOfFlowPositioned()); >- return layoutBox.style().top().isAuto(); >+ // 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(layoutBox)) >+ return false; >+ >+ return true; > } > >-static bool isMarginBottomCollapsedWithSibling(const Box& layoutBox) >+bool BlockFormattingContext::Geometry::MarginCollapse::marginBottomCollapsesWithSibling(const Box& layoutBox) > { > ASSERT(layoutBox.isBlockLevelBox()); > >- if (layoutBox.isFloatingPositioned()) >+ if (!layoutBox.nextInFlowSibling()) > return false; > >- if (!layoutBox.isPositioned() || layoutBox.isInFlowPositioned()) >- return true; >+ auto& nextInFlowSibling = *layoutBox.nextInFlowSibling(); >+ >+ // Margins between a floated box and any other box do not collapse. >+ if (layoutBox.isFloatingPositioned() || nextInFlowSibling.isFloatingPositioned()) >+ return false; >+ >+ // Margins of absolutely positioned boxes do not collapse. >+ if ((layoutBox.isOutOfFlowPositioned() && !layoutBox.style().bottom().isAuto()) >+ || (nextInFlowSibling.isOutOfFlowPositioned() && !nextInFlowSibling.style().top().isAuto())) >+ return false; >+ >+ // Margins of inline-block boxes do not collapse. >+ if (layoutBox.isInlineBlockBox() || nextInFlowSibling.isInlineBlockBox()) >+ return false; > >- // Out of flow positioned. >- ASSERT(layoutBox.isOutOfFlowPositioned()); >- return layoutBox.style().bottom().isAuto(); >+ // 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(nextInFlowSibling)) >+ return false; >+ >+ return true; > } > >-bool BlockFormattingContext::Geometry::MarginCollapse::isMarginTopCollapsedWithParent(const LayoutState& layoutState, const Box& layoutBox) >+bool BlockFormattingContext::Geometry::MarginCollapse::marginTopCollapsesWithParent(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 >@@ -133,7 +153,16 @@ bool BlockFormattingContext::Geometry::MarginCollapse::isMarginTopCollapsedWithP > > ASSERT(layoutBox.isBlockLevelBox()); > >- if (layoutBox.isFloatingOrOutOfFlowPositioned()) >+ // Margins between a floated box and any other box do not collapse. >+ if (layoutBox.isFloatingPositioned()) >+ return false; >+ >+ // Margins of absolutely positioned boxes do not collapse. >+ if (layoutBox.isOutOfFlowPositioned()) >+ return false; >+ >+ // Margins of inline-block boxes do not collapse. >+ if (layoutBox.isInlineBlockBox()) > return false; > > // Only the first inlflow child collapses with parent. >@@ -141,46 +170,126 @@ bool BlockFormattingContext::Geometry::MarginCollapse::isMarginTopCollapsedWithP > return false; > > auto& parent = *layoutBox.parent(); >- // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children >+ // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children. > if (establishesBlockFormattingContext(parent)) > 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(parent)) > return false; > >+ // ...no top padding > if (hasPaddingBefore(parent)) > return false; > >+ // ...and the child has no clearance. >+ if (hasClearance(layoutBox)) >+ return false; >+ > if (BlockFormattingContext::Quirks::shouldIgnoreMarginTop(layoutState, layoutBox)) > return false; > > return true; > } > >-static bool isMarginBottomCollapsedThrough(const Box& layoutBox) >+bool BlockFormattingContext::Geometry::MarginCollapse::marginBottomCollapsesWithParent(const Box& layoutBox) > { >+ // last inflow box to parent. >+ // https://www.w3.org/TR/CSS21/box.html#collapsing-margins >+ if (layoutBox.isAnonymous()) >+ return false; >+ > ASSERT(layoutBox.isBlockLevelBox()); > >- // If the top and bottom margins of a box are adjoining, then it is possible for margins to collapse through it. >+ // Margins between a floated box and any other box do not collapse. >+ if (layoutBox.isFloatingPositioned()) >+ return false; >+ >+ // Margins of absolutely positioned boxes do not collapse. >+ if (layoutBox.isOutOfFlowPositioned()) >+ return false; >+ >+ // Margins of inline-block boxes do not collapse. >+ if (layoutBox.isInlineBlockBox()) >+ return false; >+ >+ // Only the last inlflow child collapses with parent. >+ if (layoutBox.nextInFlowSibling()) >+ return false; >+ >+ auto& parent = *layoutBox.parent(); >+ // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children. >+ if (establishesBlockFormattingContext(parent)) >+ 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 (!parent.style().height().isAuto()) >+ return false; >+ >+ // the box has no bottom padding, and >+ if (hasPaddingBefore(parent)) >+ return false; >+ >+ // the box has no bottom border, and >+ if (hasBorderBefore(parent)) >+ return false; >+ >+ // 1. 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. >+ >+ // 2. If the top margin of a box with non-zero computed 'min-height' and 'auto' computed 'height' collapses with the bottom >+ // margin of its last in-flow child, then the child's bottom margin does not collapse with the parent's bottom margin >+ >+ // FIXME: ^^ >+ >+ return true; >+} >+ >+bool BlockFormattingContext::Geometry::MarginCollapse::marginsCollapseThrough(const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isBlockLevelBox()); >+ >+ // A box's own margins collapse if the 'min-height' property is zero, and it has neither top or bottom borders nor top or bottom padding, >+ // and it has a 'height' of either 0 or 'auto', and it does not contain a line box, and all of its in-flow children's margins (if any) collapse. > if (hasBorderBefore(layoutBox) || hasBorderAfter(layoutBox)) > return false; > > if (hasPaddingBefore(layoutBox) || hasPaddingAfter(layoutBox)) > return false; > >+ // FIXME: Check for computed 0 height. > if (!layoutBox.style().height().isAuto() || !layoutBox.style().minHeight().isAuto()) > return false; > > if (!is<Container>(layoutBox)) > return true; > >+ // FIXME: Check if the inflow block children have collapsed margins > auto& container = downcast<Container>(layoutBox); > if (container.hasInFlowOrFloatingChild()) > return false; > >+ // FIXME: Check if there's no line box (inline formatting context). > return true; > } > >+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::collapsedMarginTopFromFirstChild(const LayoutState& layoutState, const Box& layoutBox) > { > ASSERT(layoutBox.isBlockLevelBox()); >@@ -195,7 +304,7 @@ LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::collapsedMarginTopF > > // FIXME: Take collapsed through margin into account. > auto& firstInFlowChild = *downcast<Container>(layoutBox).firstInFlowChild(); >- if (!isMarginTopCollapsedWithParent(layoutState, firstInFlowChild)) >+ if (!marginTopCollapsesWithParent(layoutState, firstInFlowChild)) > return 0; > // Collect collapsed margin top recursively. > return marginValue(computedNonCollapsedMarginTop(layoutState, firstInFlowChild), collapsedMarginTopFromFirstChild(layoutState, firstInFlowChild)); >@@ -209,20 +318,6 @@ LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::nonCollapsedMarginT > return marginValue(computedNonCollapsedMarginTop(layoutState, layoutBox), collapsedMarginTopFromFirstChild(layoutState, layoutBox)); > } > >-/*static bool hasAdjoiningMarginTopAndBottom(const Box&) >-{ >- // Two margins are adjoining if and only if: >- // 1. both belong to in-flow block-level boxes that participate in the same block formatting context >- // 2. no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.) >- // 3. both belong to vertically-adjacent box edges, i.e. form one of the following pairs: >- // top margin of a box and top margin of its first in-flow child >- // bottom margin of box and top margin of its next in-flow following sibling >- // bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height >- // top and bottom margins of a box that does not establish a new block formatting context and that has zero computed 'min-height', >- // zero or 'auto' computed 'height', and no in-flow children >- // A collapsed margin is considered adjoining to another margin if any of its component margins is adjoining to that margin. >- return false; >-}*/ > LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::computedNonCollapsedMarginTop(const LayoutState& layoutState, const Box& layoutBox) > { > ASSERT(layoutBox.isBlockLevelBox()); >@@ -245,15 +340,15 @@ LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::marginTop(const Lay > ASSERT(layoutBox.isBlockLevelBox()); > > // TODO: take _hasAdjoiningMarginTopAndBottom() into account. >- if (isMarginTopCollapsedWithParent(layoutState, layoutBox)) >+ if (marginTopCollapsesWithParent(layoutState, layoutBox)) > return 0; > > // FIXME: Find out the logic behind this. > if (BlockFormattingContext::Quirks::shouldIgnoreMarginTop(layoutState, layoutBox)) > return 0; > >- if (!isMarginTopCollapsedWithSibling(layoutBox)) { >- if (!isMarginBottomCollapsedThrough(layoutBox)) >+ if (!marginTopCollapsesWithSibling(layoutBox)) { >+ if (!marginsCollapseThrough(layoutBox)) > return nonCollapsedMarginTop(layoutState, layoutBox); > // Compute the collapsed through value. > auto marginTop = nonCollapsedMarginTop(layoutState, layoutBox); >@@ -280,14 +375,14 @@ LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::marginBottom(const > ASSERT(layoutBox.isBlockLevelBox()); > > // TODO: take _hasAdjoiningMarginTopAndBottom() into account. >- if (isMarginBottomCollapsedWithParent(layoutBox)) >+ if (marginBottomCollapsesWithParent(layoutBox)) > return 0; > >- if (isMarginBottomCollapsedThrough(layoutBox)) >+ if (marginsCollapseThrough(layoutBox)) > return 0; > > // Floats and out of flow positioned boxes do not collapse their margins. >- if (!isMarginBottomCollapsedWithSibling(layoutBox)) >+ if (!marginBottomCollapsesWithSibling(layoutBox)) > return nonCollapsedMarginBottom(layoutState, layoutBox); > > // The bottom margin of an in-flow block-level element always collapses with the top margin of its next in-flow block-level sibling, >@@ -297,43 +392,7 @@ LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::marginBottom(const > return nonCollapsedMarginBottom(layoutState, layoutBox); > } > >-bool BlockFormattingContext::Geometry::MarginCollapse::isMarginBottomCollapsedWithParent(const Box& layoutBox) >-{ >- // last inflow box to parent. >- // https://www.w3.org/TR/CSS21/box.html#collapsing-margins >- if (layoutBox.isAnonymous()) >- return false; >- >- ASSERT(layoutBox.isBlockLevelBox()); >- >- if (layoutBox.isFloatingOrOutOfFlowPositioned()) >- return false; >- >- if (isMarginBottomCollapsedThrough(layoutBox)) >- return false; >- >- // Only the last inlflow child collapses with parent. >- if (layoutBox.nextInFlowSibling()) >- return false; >- >- auto& parent = *layoutBox.parent(); >- // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children >- if (establishesBlockFormattingContext(parent)) >- return false; >- >- if (hasBorderBefore(parent)) >- return false; >- >- if (hasPaddingBefore(parent)) >- return false; >- >- if (!parent.style().height().isAuto()) >- return false; >- >- return true; >-} >- >-bool BlockFormattingContext::Geometry::MarginCollapse::isMarginTopCollapsedWithParentMarginBottom(const Box&) >+bool BlockFormattingContext::Geometry::MarginCollapse::marginTopCollapsesWithParentMarginBottom(const Box&) > { > return false; > } >@@ -352,7 +411,7 @@ LayoutUnit BlockFormattingContext::Geometry::MarginCollapse::collapsedMarginBott > > // FIXME: Check for collapsed through margin. > auto& lastInFlowChild = *downcast<Container>(layoutBox).lastInFlowChild(); >- if (!isMarginBottomCollapsedWithParent(lastInFlowChild)) >+ if (!marginBottomCollapsesWithParent(lastInFlowChild)) > return 0; > > // Collect collapsed margin bottom recursively.
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
Flags:
koivisto
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 192465
: 356727