Changeset 142974 in webkit


Ignore:
Timestamp:
Feb 15, 2013 2:22:27 AM (11 years ago)
Author:
commit-queue@webkit.org
Message:

Implement the -webkit-margin-collapse properties correct rendering
https://bugs.webkit.org/show_bug.cgi?id=108168

Patch by Andrei Bucur <abucur@adobe.com> on 2013-02-15
Reviewed by David Hyatt.

Source/WebCore:

The patch implements the correct behavior for the -webkit-margin-collapse properties:

  • a value of "discard" on a margin will truncate all the margins collapsing with it;
  • a value of "separate" will prevent the margin to collapse;
  • a value of "collapse" is the default collapse behavior.

The implementation is aware of multiple writing-modes:

  • if the writing mode of a child is parallel with the writing mode of the container and has the same direction,

the -webkit-margin-collapse properties on the child are left as is;

  • if the writing mode of a child is parallel with the writing mode of the container but has a different direction,

the -webkit-margin-collapse properties on the child are reversed;

  • if the writing mode of a child is perpendicular on the writing mode of the container,

the -webkit-margin-collapse properties on the child are ignored;

  1. The "discard" value implementation

There are two new bits (before and after) added on the RenderBlockRareData structure specifying if the margins
of the block will be discarded or not. We can't rely only on the value from style() because
it's possible a block to discard it's margins because it has collapsed with a children that
specified "discard" for -webkit-margin-collapse. However, the bits are set only if it is
required.
Another bit is added on the MarginInfo structure specifying if the margin has to be discarded or not. When
collapsing at the before side of a block it will hold information if the container block needs to discard
or not. If the collapsing happens between siblings/with after side of the container it will tell if the previous
child discards the margin or not. The self collapsing blocks are a special case. If any of its margins
discards then both its margins discard and all the other margins collapsing with it.
To ensure an optimal behavior it is asserted margin values can't be set on the MarginInfo object if the
discard flag is active. If this happens it may indicate someone ignored the possibility of the margin being
discarded altogether and incorrectly updated the margin values.
Float clearing also needs to change because it may force margins to stop collapsing. If this happens the discard
flags and margins needs to be restored to their values before the collapse.

  1. The "separate" value implementation

The implementation for separate was not changed too much. I've added new accessor methods for the property
that take writing mode into consideration and I've removed some code that didn't work correctly in layoutBlockChild.
The problem was the marginInfo structure was cleared if the child was specifying the "separate" value for before.
This is wrong because you lose the margin information of the previous child/before side.

Tests: fast/block/margin-collapse/webkit-margin-collapse-container.html

fast/block/margin-collapse/webkit-margin-collapse-floats.html
fast/block/margin-collapse/webkit-margin-collapse-siblings-bt.html
fast/block/margin-collapse/webkit-margin-collapse-siblings.html

  • rendering/RenderBlock.cpp:

(WebCore::RenderBlock::MarginInfo::MarginInfo):
(WebCore::RenderBlock::layoutBlock):
(WebCore::RenderBlock::collapseMargins):
(WebCore::RenderBlock::clearFloatsIfNeeded):
(WebCore::RenderBlock::marginBeforeEstimateForChild):
(WebCore::RenderBlock::estimateLogicalTopPosition):
(WebCore::RenderBlock::setCollapsedBottomMargin):
(WebCore::RenderBlock::handleAfterSideOfBlock):
(WebCore::RenderBlock::layoutBlockChild):
(WebCore::RenderBlock::setMustDiscardMarginBefore):
(WebCore):
(WebCore::RenderBlock::setMustDiscardMarginAfter):
(WebCore::RenderBlock::mustDiscardMarginBefore):
(WebCore::RenderBlock::mustDiscardMarginAfter):
(WebCore::RenderBlock::mustDiscardMarginBeforeForChild):
(WebCore::RenderBlock::mustDiscardMarginAfterForChild):
(WebCore::RenderBlock::mustSeparateMarginBeforeForChild):
(WebCore::RenderBlock::mustSeparateMarginAfterForChild):

  • rendering/RenderBlock.h:

(RenderBlock):
(WebCore::RenderBlock::initMaxMarginValues):
(MarginInfo):
(WebCore::RenderBlock::MarginInfo::setPositiveMargin):
(WebCore::RenderBlock::MarginInfo::setNegativeMargin):
(WebCore::RenderBlock::MarginInfo::setPositiveMarginIfLarger):
(WebCore::RenderBlock::MarginInfo::setNegativeMarginIfLarger):
(WebCore::RenderBlock::MarginInfo::setMargin):
(WebCore::RenderBlock::MarginInfo::setCanCollapseMarginAfterWithChildren):
(WebCore::RenderBlock::MarginInfo::setDiscardMargin):
(WebCore::RenderBlock::MarginInfo::discardMargin):
(WebCore::RenderBlock::RenderBlockRareData::RenderBlockRareData):
(WebCore::RenderBlock::RenderBlockRareData::positiveMarginBeforeDefault):
(RenderBlockRareData):

  • rendering/style/RenderStyle.h:

LayoutTests:

Four new tests covering the -webkit-margin-collapse property basic behavior: collapsing
between a block container and its children, collapsing between sibling boxes in both TTB
and BTT direction. The last test verifies if a container's before margin correctly resets
the discard value after a clear of the child that initally caused it.

  • fast/block/margin-collapse/webkit-margin-collapse-container-expected.html: Added.
  • fast/block/margin-collapse/webkit-margin-collapse-container.html: Added.
  • fast/block/margin-collapse/webkit-margin-collapse-floats-expected.html: Added.
  • fast/block/margin-collapse/webkit-margin-collapse-floats.html: Added.
  • fast/block/margin-collapse/webkit-margin-collapse-siblings-bt-expected.html: Added.
  • fast/block/margin-collapse/webkit-margin-collapse-siblings-bt.html: Added.
  • fast/block/margin-collapse/webkit-margin-collapse-siblings-expected.html: Added.
  • fast/block/margin-collapse/webkit-margin-collapse-siblings.html: Added.
Location:
trunk
Files:
8 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r142971 r142974  
     12013-02-15  Andrei Bucur  <abucur@adobe.com>
     2
     3        Implement the -webkit-margin-collapse properties correct rendering
     4        https://bugs.webkit.org/show_bug.cgi?id=108168
     5
     6        Reviewed by David Hyatt.
     7
     8        Four new tests covering the -webkit-margin-collapse property basic behavior: collapsing
     9        between a block container and its children, collapsing between sibling boxes in both TTB
     10        and BTT direction. The last test verifies if a container's before margin correctly resets
     11        the discard value after a clear of the child that initally caused it.
     12
     13        * fast/block/margin-collapse/webkit-margin-collapse-container-expected.html: Added.
     14        * fast/block/margin-collapse/webkit-margin-collapse-container.html: Added.
     15        * fast/block/margin-collapse/webkit-margin-collapse-floats-expected.html: Added.
     16        * fast/block/margin-collapse/webkit-margin-collapse-floats.html: Added.
     17        * fast/block/margin-collapse/webkit-margin-collapse-siblings-bt-expected.html: Added.
     18        * fast/block/margin-collapse/webkit-margin-collapse-siblings-bt.html: Added.
     19        * fast/block/margin-collapse/webkit-margin-collapse-siblings-expected.html: Added.
     20        * fast/block/margin-collapse/webkit-margin-collapse-siblings.html: Added.
     21
    1222013-02-15  KwangYong Choi  <ky0.choi@samsung.com>
    223
  • trunk/Source/WebCore/ChangeLog

    r142969 r142974  
     12013-02-15  Andrei Bucur  <abucur@adobe.com>
     2
     3        Implement the -webkit-margin-collapse properties correct rendering
     4        https://bugs.webkit.org/show_bug.cgi?id=108168
     5
     6        Reviewed by David Hyatt.
     7
     8        The patch implements the correct behavior for the -webkit-margin-collapse properties:
     9        - a value of "discard" on a margin will truncate all the margins collapsing with it;
     10        - a value of "separate" will prevent the margin to collapse;
     11        - a value of "collapse" is the default collapse behavior.
     12
     13        The implementation is aware of multiple writing-modes:
     14        - if the writing mode of a child is parallel with the writing mode of the container and has the same direction,
     15        the -webkit-margin-collapse properties on the child are left as is;
     16        - if the writing mode of a child is parallel with the writing mode of the container but has a different direction,
     17        the -webkit-margin-collapse properties on the child are reversed;
     18        - if the writing mode of a child is perpendicular on the writing mode of the container,
     19        the -webkit-margin-collapse properties on the child are ignored;
     20
     21        I. The "discard" value implementation
     22        There are two new bits (before and after) added on the RenderBlockRareData structure specifying if the margins
     23        of the block will be discarded or not. We can't rely only on the value from style() because
     24        it's possible a block to discard it's margins because it has collapsed with a children that
     25        specified "discard" for -webkit-margin-collapse. However, the bits are set only if it is
     26        required.
     27        Another bit is added on the MarginInfo structure specifying if the margin has to be discarded or not. When
     28        collapsing at the before side of a block it will hold information if the container block needs to discard
     29        or not. If the collapsing happens between siblings/with after side of the container it will tell if the previous
     30        child discards the margin or not. The self collapsing blocks are a special case. If any of its margins
     31        discards then both its margins discard and all the other margins collapsing with it.
     32        To ensure an optimal behavior it is asserted margin values can't be set on the MarginInfo object if the
     33        discard flag is active. If this happens it may indicate someone ignored the possibility of the margin being
     34        discarded altogether and incorrectly updated the margin values.
     35        Float clearing also needs to change because it may force margins to stop collapsing. If this happens the discard
     36        flags and margins needs to be restored to their values before the collapse.
     37
     38        II. The "separate" value implementation
     39        The implementation for separate was not changed too much. I've added new accessor methods for the property
     40        that take writing mode into consideration and I've removed some code that didn't work correctly in layoutBlockChild.
     41        The problem was the marginInfo structure was cleared if the child was specifying the "separate" value for before.
     42        This is wrong because you lose the margin information of the previous child/before side.
     43
     44        Tests: fast/block/margin-collapse/webkit-margin-collapse-container.html
     45               fast/block/margin-collapse/webkit-margin-collapse-floats.html
     46               fast/block/margin-collapse/webkit-margin-collapse-siblings-bt.html
     47               fast/block/margin-collapse/webkit-margin-collapse-siblings.html
     48
     49        * rendering/RenderBlock.cpp:
     50        (WebCore::RenderBlock::MarginInfo::MarginInfo):
     51        (WebCore::RenderBlock::layoutBlock):
     52        (WebCore::RenderBlock::collapseMargins):
     53        (WebCore::RenderBlock::clearFloatsIfNeeded):
     54        (WebCore::RenderBlock::marginBeforeEstimateForChild):
     55        (WebCore::RenderBlock::estimateLogicalTopPosition):
     56        (WebCore::RenderBlock::setCollapsedBottomMargin):
     57        (WebCore::RenderBlock::handleAfterSideOfBlock):
     58        (WebCore::RenderBlock::layoutBlockChild):
     59        (WebCore::RenderBlock::setMustDiscardMarginBefore):
     60        (WebCore):
     61        (WebCore::RenderBlock::setMustDiscardMarginAfter):
     62        (WebCore::RenderBlock::mustDiscardMarginBefore):
     63        (WebCore::RenderBlock::mustDiscardMarginAfter):
     64        (WebCore::RenderBlock::mustDiscardMarginBeforeForChild):
     65        (WebCore::RenderBlock::mustDiscardMarginAfterForChild):
     66        (WebCore::RenderBlock::mustSeparateMarginBeforeForChild):
     67        (WebCore::RenderBlock::mustSeparateMarginAfterForChild):
     68        * rendering/RenderBlock.h:
     69        (RenderBlock):
     70        (WebCore::RenderBlock::initMaxMarginValues):
     71        (MarginInfo):
     72        (WebCore::RenderBlock::MarginInfo::setPositiveMargin):
     73        (WebCore::RenderBlock::MarginInfo::setNegativeMargin):
     74        (WebCore::RenderBlock::MarginInfo::setPositiveMarginIfLarger):
     75        (WebCore::RenderBlock::MarginInfo::setNegativeMarginIfLarger):
     76        (WebCore::RenderBlock::MarginInfo::setMargin):
     77        (WebCore::RenderBlock::MarginInfo::setCanCollapseMarginAfterWithChildren):
     78        (WebCore::RenderBlock::MarginInfo::setDiscardMargin):
     79        (WebCore::RenderBlock::MarginInfo::discardMargin):
     80        (WebCore::RenderBlock::RenderBlockRareData::RenderBlockRareData):
     81        (WebCore::RenderBlock::RenderBlockRareData::positiveMarginBeforeDefault):
     82        (RenderBlockRareData):
     83        * rendering/style/RenderStyle.h:
     84
    1852013-02-14  Yury Semikhatsky  <yurys@chromium.org>
    286
  • trunk/Source/WebCore/rendering/RenderBlock.cpp

    r142922 r142974  
    170170    , m_marginAfterQuirk(false)
    171171    , m_determinedMarginBeforeQuirk(false)
     172    , m_discardMargin(false)
    172173{
    173174    RenderStyle* blockStyle = block->style();
     
    187188        (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
    188189   
    189     m_quirkContainer = block->isTableCell() || block->isBody() || blockStyle->marginBeforeCollapse() == MDISCARD
    190         || blockStyle->marginAfterCollapse() == MDISCARD;
    191 
    192     m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : LayoutUnit();
    193     m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : LayoutUnit();
     190    m_quirkContainer = block->isTableCell() || block->isBody();
     191
     192    m_discardMargin = m_canCollapseMarginBeforeWithChildren && block->mustDiscardMarginBefore();
     193
     194    m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxPositiveMarginBefore() : LayoutUnit();
     195    m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxNegativeMarginBefore() : LayoutUnit();
    194196}
    195197
     
    15271529        initMaxMarginValues();
    15281530       
    1529         setMarginBeforeQuirk(styleToUse->marginBefore().quirk());
    1530         setMarginAfterQuirk(styleToUse->marginAfter().quirk());
     1531        setMarginBeforeQuirk(styleToUse->isMarginBeforeQuirk());
     1532        setMarginAfterQuirk(styleToUse->isMarginAfterQuirk());
    15311533        setPaginationStrut(0);
    15321534    }
     
    19581960LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
    19591961{
     1962    bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
     1963    bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
     1964    bool childIsSelfCollapsing = child->isSelfCollapsingBlock();
     1965
     1966    // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
     1967    childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
     1968
    19601969    // Get the four margin values for the child and cache them.
    19611970    const MarginValues childMargins = marginValuesForChild(child);
     
    19671976    // For self-collapsing blocks, collapse our bottom margins into our
    19681977    // top to get new posTop and negTop values.
    1969     if (child->isSelfCollapsingBlock()) {
     1978    if (childIsSelfCollapsing) {
    19701979        posTop = max(posTop, childMargins.positiveMarginAfter());
    19711980        negTop = max(negTop, childMargins.negativeMarginAfter());
     
    19741983    // See if the top margin is quirky. We only care if this child has
    19751984    // margins that will collapse with us.
    1976     bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
     1985    bool topQuirk = child->isMarginBeforeQuirk();
    19771986
    19781987    if (marginInfo.canCollapseWithMarginBefore()) {
    1979         // This child is collapsing with the top of the
    1980         // block.  If it has larger margin values, then we need to update
    1981         // our own maximal values.
    1982         if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
    1983             setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
    1984 
    1985         // The minute any of the margins involved isn't a quirk, don't
    1986         // collapse it away, even if the margin is smaller (www.webreference.com
    1987         // has an example of this, a <dt> with 0.8em author-specified inside
    1988         // a <dl> inside a <td>.
    1989         if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
    1990             setMarginBeforeQuirk(false);
    1991             marginInfo.setDeterminedMarginBeforeQuirk(true);
    1992         }
    1993 
    1994         if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
    1995             // We have no top margin and our top child has a quirky margin.
    1996             // We will pick up this quirky margin and pass it through.
    1997             // This deals with the <td><div><p> case.
    1998             // Don't do this for a block that split two inlines though.  You do
    1999             // still apply margins in this case.
    2000             setMarginBeforeQuirk(true);
     1988        if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
     1989            // This child is collapsing with the top of the
     1990            // block. If it has larger margin values, then we need to update
     1991            // our own maximal values.
     1992            if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
     1993                setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
     1994
     1995            // The minute any of the margins involved isn't a quirk, don't
     1996            // collapse it away, even if the margin is smaller (www.webreference.com
     1997            // has an example of this, a <dt> with 0.8em author-specified inside
     1998            // a <dl> inside a <td>.
     1999            if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
     2000                setMarginBeforeQuirk(false);
     2001                marginInfo.setDeterminedMarginBeforeQuirk(true);
     2002            }
     2003
     2004            if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
     2005                // We have no top margin and our top child has a quirky margin.
     2006                // We will pick up this quirky margin and pass it through.
     2007                // This deals with the <td><div><p> case.
     2008                // Don't do this for a block that split two inlines though. You do
     2009                // still apply margins in this case.
     2010                setMarginBeforeQuirk(true);
     2011        } else
     2012            // The before margin of the container will also discard all the margins it is collapsing with.
     2013            setMustDiscardMarginBefore();
     2014    }
     2015
     2016    // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
     2017    if (childDiscardMarginBefore) {
     2018        marginInfo.setDiscardMargin(true);
     2019        marginInfo.clearMargin();
    20012020    }
    20022021
     
    20062025    LayoutUnit beforeCollapseLogicalTop = logicalHeight();
    20072026    LayoutUnit logicalTop = beforeCollapseLogicalTop;
    2008     if (child->isSelfCollapsingBlock()) {
    2009         // This child has no height.  We need to compute our
    2010         // position before we collapse the child's margins together,
    2011         // so that we can get an accurate position for the zero-height block.
    2012         LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
    2013         LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
    2014         marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
    2015        
    2016         // Now collapse the child's margins together, which means examining our
    2017         // bottom margin values as well.
    2018         marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
    2019         marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
    2020 
    2021         if (!marginInfo.canCollapseWithMarginBefore())
    2022             // We need to make sure that the position of the self-collapsing block
    2023             // is correct, since it could have overflowing content
    2024             // that needs to be positioned correctly (e.g., a block that
    2025             // had a specified height of 0 but that actually had subcontent).
    2026             logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
    2027     }
    2028     else {
    2029         if (child->style()->marginBeforeCollapse() == MSEPARATE) {
     2027    if (childIsSelfCollapsing) {
     2028        // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
     2029        // Also, the child's top position equals the logical height of the container.
     2030        if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
     2031            // This child has no height. We need to compute our
     2032            // position before we collapse the child's margins together,
     2033            // so that we can get an accurate position for the zero-height block.
     2034            LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
     2035            LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
     2036            marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
     2037           
     2038            // Now collapse the child's margins together, which means examining our
     2039            // bottom margin values as well.
     2040            marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
     2041            marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
     2042
     2043            if (!marginInfo.canCollapseWithMarginBefore())
     2044                // We need to make sure that the position of the self-collapsing block
     2045                // is correct, since it could have overflowing content
     2046                // that needs to be positioned correctly (e.g., a block that
     2047                // had a specified height of 0 but that actually had subcontent).
     2048                logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
     2049        }
     2050    } else {
     2051        if (mustSeparateMarginBeforeForChild(child)) {
     2052            ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
    20302053            setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
    20312054            logicalTop = logicalHeight();
    2032         }
    2033         else if (!marginInfo.atBeforeSideOfBlock() ||
    2034             (!marginInfo.canCollapseMarginBeforeWithChildren()
    2035              && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
     2055        } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
     2056            || (!marginInfo.canCollapseMarginBeforeWithChildren()
     2057            && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk())))) {
    20362058            // We're collapsing with a previous sibling's margins and not
    20372059            // with the top of the block.
     
    20402062        }
    20412063
    2042         marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
    2043         marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
     2064        marginInfo.setDiscardMargin(childDiscardMarginAfter);
     2065       
     2066        if (!marginInfo.discardMargin()) {
     2067            marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
     2068            marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
     2069        } else
     2070            marginInfo.clearMargin();
    20442071
    20452072        if (marginInfo.margin())
    2046             marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
     2073            marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk());
    20472074    }
    20482075   
     
    20802107
    20812108    if (child->isSelfCollapsingBlock()) {
     2109        bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
     2110
    20822111        // For self-collapsing blocks that clear, they can still collapse their
    20832112        // margins with following siblings.  Reset the current margins to represent
    20842113        // the self-collapsing block's margins only.
    2085         MarginValues childMargins = marginValuesForChild(child);
    2086         marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
    2087         marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
     2114        // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
     2115        if (!childDiscardMargin) {
     2116            MarginValues childMargins = marginValuesForChild(child);
     2117            marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
     2118            marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
     2119        } else
     2120            marginInfo.clearMargin();
     2121        marginInfo.setDiscardMargin(childDiscardMargin);
    20882122
    20892123        // CSS2.1 states:
     
    21182152        setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
    21192153        marginInfo.setAtBeforeSideOfBlock(false);
     2154
     2155        // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
     2156        setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD);
    21202157    }
    21212158
     
    21292166}
    21302167
    2131 void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const
    2132 {
    2133     // FIXME: We should deal with the margin-collapse-* style extensions that prevent collapsing and that discard margins.
     2168void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
     2169{
    21342170    // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
    2135     if (document()->inQuirksMode() && child->isMarginBeforeQuirk() && (isTableCell() || isBody()))
    2136         return;
     2171    // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
     2172    // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
     2173    if ((document()->inQuirksMode() && child->isMarginBeforeQuirk() && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE)
     2174        return;
     2175
     2176    // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
     2177    // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
     2178    if (child->style()->marginBeforeCollapse() == MDISCARD) {
     2179        positiveMarginBefore = 0;
     2180        negativeMarginBefore = 0;
     2181        discardMarginBefore = true;
     2182        return;
     2183    }
    21372184
    21382185    LayoutUnit beforeChildMargin = marginBeforeForChild(child);
     
    21642211    if (grandchildBox->needsLayout()) {
    21652212        grandchildBox->computeAndSetBlockDirectionMargins(this);
    2166         grandchildBox->setMarginBeforeQuirk(grandchildBox->style()->marginBefore().quirk());
    2167         grandchildBox->setMarginAfterQuirk(grandchildBox->style()->marginAfter().quirk());
     2213        grandchildBox->setMarginBeforeQuirk(grandchildBox->style()->isMarginBeforeQuirk());
     2214        grandchildBox->setMarginAfterQuirk(grandchildBox->style()->isMarginAfterQuirk());
    21682215    }
    21692216
    21702217    // Collapse the margin of the grandchild box with our own to produce an estimate.
    2171     childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore);
     2218    childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
    21722219}
    21732220
     
    21802227        LayoutUnit positiveMarginBefore = 0;
    21812228        LayoutUnit negativeMarginBefore = 0;
     2229        bool discardMarginBefore = false;
    21822230        if (child->selfNeedsLayout()) {
    21832231            // Try to do a basic estimation of how the collapse is going to go.
    2184             marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore);
     2232            marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
    21852233        } else {
    21862234            // Use the cached collapsed margin values from a previous layout. Most of the time they
     
    21892237            positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
    21902238            negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
     2239            discardMarginBefore = mustDiscardMarginBeforeForChild(child);
    21912240        }
    21922241
    21932242        // Collapse the result with our current margins.
    2194         logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
     2243        if (!discardMarginBefore)
     2244            logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
    21952245    }
    21962246
     
    22672317{
    22682318    if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
     2319        // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
     2320        // Don't update the max margin values because we won't need them anyway.
     2321        if (marginInfo.discardMargin()) {
     2322            setMustDiscardMarginAfter();
     2323            return;
     2324        }
     2325
    22692326        // Update our max pos/neg bottom margins, since we collapsed our bottom margins
    22702327        // with our children.
     
    22892346    // Don't do this for ordinary anonymous blocks as only the enclosing box should add in
    22902347    // its margin.
    2291     if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
     2348    if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
    22922349        && (!isAnonymousBlock() || isAnonymousColumnsBlock() || isAnonymousColumnSpanBlock())
    2293         && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
     2350        && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk())))
    22942351        setLogicalHeight(logicalHeight() + marginInfo.margin());
    22952352       
     
    24162473    child->computeAndSetBlockDirectionMargins(this);
    24172474
    2418     // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
    2419     RenderStyle* childStyle = child->style();
    2420     if (childStyle->marginBeforeCollapse() == MSEPARATE) {
    2421         marginInfo.setAtBeforeSideOfBlock(false);
    2422         marginInfo.clearMargin();
    2423     }
    2424 
    24252475    // Try to guess our correct logical top position.  In most cases this guess will
    24262476    // be correct.  Only if we're wrong (when we compute the real logical top position)
     
    25162566    // Update our height now that the child has been placed in the correct position.
    25172567    setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
    2518     if (childStyle->marginAfterCollapse() == MSEPARATE) {
     2568    if (mustSeparateMarginAfterForChild(child)) {
    25192569        setLogicalHeight(logicalHeight() + marginAfterForChild(child));
    25202570        marginInfo.clearMargin();
     
    68206870}
    68216871
     6872void RenderBlock::setMustDiscardMarginBefore(bool value)
     6873{
     6874    if (style()->marginBeforeCollapse() == MDISCARD) {
     6875        ASSERT(value);
     6876        return;
     6877    }
     6878   
     6879    if (!m_rareData && !value)
     6880        return;
     6881
     6882    if (!m_rareData)
     6883        m_rareData = adoptPtr(new RenderBlockRareData(this));
     6884
     6885    m_rareData->m_discardMarginBefore = value;
     6886}
     6887
     6888void RenderBlock::setMustDiscardMarginAfter(bool value)
     6889{
     6890    if (style()->marginAfterCollapse() == MDISCARD) {
     6891        ASSERT(value);
     6892        return;
     6893    }
     6894
     6895    if (!m_rareData && !value)
     6896        return;
     6897
     6898    if (!m_rareData)
     6899        m_rareData = adoptPtr(new RenderBlockRareData(this));
     6900
     6901    m_rareData->m_discardMarginAfter = value;
     6902}
     6903
     6904bool RenderBlock::mustDiscardMarginBefore() const
     6905{
     6906    return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore);
     6907}
     6908
     6909bool RenderBlock::mustDiscardMarginAfter() const
     6910{
     6911    return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter);
     6912}
     6913
     6914bool RenderBlock::mustDiscardMarginBeforeForChild(const RenderBox* child) const
     6915{
     6916    ASSERT(!child->selfNeedsLayout());
     6917    if (!child->isWritingModeRoot())
     6918        return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
     6919    if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
     6920        return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
     6921
     6922    // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
     6923    // In case the boxes are perpendicular we assume the property is not specified.
     6924    return false;
     6925}
     6926
     6927bool RenderBlock::mustDiscardMarginAfterForChild(const RenderBox* child) const
     6928{
     6929    ASSERT(!child->selfNeedsLayout());
     6930    if (!child->isWritingModeRoot())
     6931        return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
     6932    if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
     6933        return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
     6934
     6935    // FIXME: See |mustDiscardMarginBeforeForChild| above.
     6936    return false;
     6937}
     6938
     6939bool RenderBlock::mustSeparateMarginBeforeForChild(const RenderBox* child) const
     6940{
     6941    ASSERT(!child->selfNeedsLayout());
     6942    const RenderStyle* childStyle = child->style();
     6943    if (!child->isWritingModeRoot())
     6944        return childStyle->marginBeforeCollapse() == MSEPARATE;
     6945    if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
     6946        return childStyle->marginAfterCollapse() == MSEPARATE;
     6947
     6948    // FIXME: See |mustDiscardMarginBeforeForChild| above.
     6949    return false;
     6950}
     6951
     6952bool RenderBlock::mustSeparateMarginAfterForChild(const RenderBox* child) const
     6953{
     6954    ASSERT(!child->selfNeedsLayout());
     6955    const RenderStyle* childStyle = child->style();
     6956    if (!child->isWritingModeRoot())
     6957        return childStyle->marginAfterCollapse() == MSEPARATE;
     6958    if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
     6959        return childStyle->marginBeforeCollapse() == MSEPARATE;
     6960
     6961    // FIXME: See |mustDiscardMarginBeforeForChild| above.
     6962    return false;
     6963}
     6964
    68226965void RenderBlock::setPaginationStrut(LayoutUnit strut)
    68236966{
  • trunk/Source/WebCore/rendering/RenderBlock.h

    r142527 r142974  
    456456    void setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg);
    457457
     458    void setMustDiscardMarginBefore(bool = true);
     459    void setMustDiscardMarginAfter(bool = true);
     460
     461    bool mustDiscardMarginBefore() const;
     462    bool mustDiscardMarginAfter() const;
     463
     464    bool mustDiscardMarginBeforeForChild(const RenderBox*) const;
     465    bool mustDiscardMarginAfterForChild(const RenderBox*) const;
     466
     467    bool mustSeparateMarginBeforeForChild(const RenderBox*) const;
     468    bool mustSeparateMarginAfterForChild(const RenderBox*) const;
     469
    458470    void initMaxMarginValues()
    459471    {
     
    462474                                                 RenderBlockRareData::positiveMarginAfterDefault(this), RenderBlockRareData::negativeMarginAfterDefault(this));
    463475            m_rareData->m_paginationStrut = 0;
     476
     477            m_rareData->m_discardMarginBefore = false;
     478            m_rareData->m_discardMarginAfter = false;
    464479        }
    465480    }
     
    950965        bool m_determinedMarginBeforeQuirk : 1;
    951966
     967        bool m_discardMargin : 1;
     968
    952969        // These flags track the previous maximal positive and negative margins.
    953970        LayoutUnit m_positiveMargin;
     
    967984        void setMarginAfterQuirk(bool b) { m_marginAfterQuirk = b; }
    968985        void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; }
    969         void setPositiveMargin(LayoutUnit p) { m_positiveMargin = p; }
    970         void setNegativeMargin(LayoutUnit n) { m_negativeMargin = n; }
     986        void setPositiveMargin(LayoutUnit p) { ASSERT(!m_discardMargin); m_positiveMargin = p; }
     987        void setNegativeMargin(LayoutUnit n) { ASSERT(!m_discardMargin); m_negativeMargin = n; }
    971988        void setPositiveMarginIfLarger(LayoutUnit p)
    972989        {
     990            ASSERT(!m_discardMargin);
    973991            if (p > m_positiveMargin)
    974992                m_positiveMargin = p;
     
    976994        void setNegativeMarginIfLarger(LayoutUnit n)
    977995        {
     996            ASSERT(!m_discardMargin);
    978997            if (n > m_negativeMargin)
    979998                m_negativeMargin = n;
    980999        }
    9811000
    982         void setMargin(LayoutUnit p, LayoutUnit n) { m_positiveMargin = p; m_negativeMargin = n; }
     1001        void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_positiveMargin = p; m_negativeMargin = n; }
     1002        void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; }
     1003        void setDiscardMargin(bool value) { m_discardMargin = value; }
    9831004
    9841005        bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; }
     
    9871008        bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; }
    9881009        bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; }
    989         void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; }
    9901010        bool quirkContainer() const { return m_quirkContainer; }
    9911011        bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; }
     
    9941014        LayoutUnit positiveMargin() const { return m_positiveMargin; }
    9951015        LayoutUnit negativeMargin() const { return m_negativeMargin; }
     1016        bool discardMargin() const { return m_discardMargin; }
    9961017        LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; }
    9971018    };
     
    10111032    LayoutUnit clearFloatsIfNeeded(RenderBox* child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos);
    10121033    LayoutUnit estimateLogicalTopPosition(RenderBox* child, const MarginInfo&, LayoutUnit& estimateWithoutPagination);
    1013     void marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const;
     1034    void marginBeforeEstimateForChild(RenderBox*, LayoutUnit&, LayoutUnit&, bool&) const;
    10141035    void determineLogicalLeftPositionForChild(RenderBox* child);
    10151036    void handleAfterSideOfBlock(LayoutUnit top, LayoutUnit bottom, MarginInfo&);
     
    11731194            , m_pageLogicalOffset(0)
    11741195            , m_lineGridBox(0)
     1196            , m_lineBreakToAvoidWidow(0)
    11751197            , m_shouldBreakAtLineToAvoidWidow(false)
    1176             , m_lineBreakToAvoidWidow(0)
     1198            , m_discardMarginBefore(false)
     1199            , m_discardMarginAfter(false)
    11771200        {
    11781201        }
     
    11821205            return std::max<LayoutUnit>(block->marginBefore(), 0);
    11831206        }
    1184        
    11851207        static LayoutUnit negativeMarginBeforeDefault(const RenderBlock* block)
    11861208        {
     
    12021224        RootInlineBox* m_lineGridBox;
    12031225
    1204         bool m_shouldBreakAtLineToAvoidWidow;
    12051226        RootInlineBox* m_lineBreakToAvoidWidow;
     1227        bool m_shouldBreakAtLineToAvoidWidow : 1;
     1228        bool m_discardMarginBefore : 1;
     1229        bool m_discardMarginAfter : 1;
    12061230     };
    12071231
  • trunk/Source/WebCore/rendering/style/RenderStyle.h

    r142893 r142974  
    378378    bool hasPadding() const { return surround->padding.nonZero(); }
    379379    bool hasOffset() const { return surround->offset.nonZero(); }
     380    bool isMarginBeforeQuirk() const { return marginBefore().quirk(); }
     381    bool isMarginAfterQuirk() const { return marginAfter().quirk(); }
    380382
    381383    bool hasBackgroundImage() const { return m_background->background().hasImage(); }
Note: See TracChangeset for help on using the changeset viewer.