Commit 6d92520b authored by mitz@apple.com's avatar mitz@apple.com

WebCore:

        Reviewed by Dave Hyatt.

        - fix https://bugs.webkit.org/show_bug.cgi?id=15384
          Div does not notice when grandparent changes height

        Test: fast/block/basic/quirk-percent-height-grandchild.html

        - fix https://bugs.webkit.org/show_bug.cgi?id=20714
          Resizing Gmail inbox vertically results in whitespace at the bottom of the window

        Test: fast/replaced/percent-height-in-anonymous-block.html

        Added a two-way mapping between boxes with percentage heights and
        their non-parent ancestors up to the one the height is computed relative
        to. In quirks mode (the first bug), this can be any number of containing
        block with auto height. In strict mode (the second bug) this can be
        the containing block of an anonymous block containing a replaced
        element.

        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::~RenderBlock): Added code to remove the all the
        mapping to/from this block to percentage-height descendants.
        (WebCore::RenderBlock::layoutBlockChildren): Added code to mark
        percentage-height descendants (and their containing block ancestry chain
        up to this block) for layout. This ensures that those descendants whose
        height depends on the height of this block (or an ancestor) are updated.
        (WebCore::RenderBlock::addPercentHeightDescendant): Added. Establishes
        a two-way mapping between this block and the given box.
        (WebCore::RenderBlock::removePercentHeightDescendant): Added. Removes
        all the mapping to/from this box.
        * rendering/RenderBlock.h:
        * rendering/RenderBox.cpp:
        (WebCore::RenderBox::setStyle): Added calls to
        removePercentHeightDescendant() when style changes and the box
        previously had a percentage height. An exception is when the style
        change does not require layout, in which case the box still has
        a percentage height and the mappings are valid. In all other cases,
        any required mappings will be (re-)established during layout.
        (WebCore::RenderBox::destroy): Added a call to
        removePercentHeightDescendant.
        (WebCore::RenderBox::calcPercentageHeight): Added code that, in quirks
        mode, if a higher-than-parent containing block is affecting the box's
        height, creates a mapping between the box and that block.
        (WebCore::RenderBox::calcReplacedHeightUsing): Changed to skip over
        anonymous containing blocks, if any, and when that happens, use
        addPercentHeightDescendant() to ensure that the non-anonymous block
        is aware of the dependent percent-height box.

LayoutTests:

        Reviewed by Dave Hyatt.

        - test for https://bugs.webkit.org/show_bug.cgi?id=15384
          Div does not notice when grandparent changes height

        - test for https://bugs.webkit.org/show_bug.cgi?id=20714
          Resizing Gmail inbox vertically results in whitespace at the bottom of the window

        * fast/block/basic/quirk-percent-height-grandchild.html: Added.
        * fast/replaced/percent-height-in-anonymous-block.html: Added.
        * platform/mac/fast/block/basic/quirk-percent-height-grandchild-expected.checksum: Added.
        * platform/mac/fast/block/basic/quirk-percent-height-grandchild-expected.png: Added.
        * platform/mac/fast/block/basic/quirk-percent-height-grandchild-expected.txt: Added.
        * platform/mac/fast/replaced/percent-height-in-anonymous-block-expected.checksum: Added.
        * platform/mac/fast/replaced/percent-height-in-anonymous-block-expected.png: Added.
        * platform/mac/fast/replaced/percent-height-in-anonymous-block-expected.txt: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36513 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 5e82be48
2008-09-16 Dan Bernstein <mitz@apple.com>
Reviewed by Dave Hyatt.
- test for https://bugs.webkit.org/show_bug.cgi?id=15384
Div does not notice when grandparent changes height
- test for https://bugs.webkit.org/show_bug.cgi?id=20714
Resizing Gmail inbox vertically results in whitespace at the bottom of the window
* fast/block/basic/quirk-percent-height-grandchild.html: Added.
* fast/replaced/percent-height-in-anonymous-block.html: Added.
* platform/mac/fast/block/basic/quirk-percent-height-grandchild-expected.checksum: Added.
* platform/mac/fast/block/basic/quirk-percent-height-grandchild-expected.png: Added.
* platform/mac/fast/block/basic/quirk-percent-height-grandchild-expected.txt: Added.
* platform/mac/fast/replaced/percent-height-in-anonymous-block-expected.checksum: Added.
* platform/mac/fast/replaced/percent-height-in-anonymous-block-expected.png: Added.
* platform/mac/fast/replaced/percent-height-in-anonymous-block-expected.txt: Added.
2008-09-15 Rob Buis <buis@kde.org>
Reviewed by Eric.
......
<html>
<head>
<script>
function test()
{
document.getElementById("target").style.height = "100px";
}
</script>
</head>
<body>
<div style="height: 50px; background: red; width: 100px;" id="target">
<div>
<div style="height:100%; background: green;"></div>
</div>
</div>
</body>
<script>
document.body.offsetTop;
test();
</script>
</html>
<!DOCTYPE HTML>
<html>
<head>
<script>
function test()
{
document.getElementById("target").style.height = "100px";
}
</script>
</head>
<body>
<div style="height: 50px; background: red; width: 100px;" id="target">
<div style="height: 100%">
<div></div>
<iframe style="vertical-align: bottom; width: 100%; height:100%; background: green; border: 0;"></iframe>
</div>
</div>
</body>
<script>
document.body.offsetTop;
test();
</script>
</html>
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x584
RenderBlock {DIV} at (0,0) size 100x100 [bgcolor=#FF0000]
RenderBlock {DIV} at (0,0) size 100x100
RenderBlock {DIV} at (0,0) size 100x100 [bgcolor=#008000]
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x116
RenderBlock {HTML} at (0,0) size 800x116
RenderBody {BODY} at (8,8) size 784x100
RenderBlock {DIV} at (0,0) size 100x100 [bgcolor=#FF0000]
RenderBlock {DIV} at (0,0) size 100x100
RenderBlock {DIV} at (0,0) size 100x0
RenderBlock (anonymous) at (0,0) size 100x100
RenderPartObject {IFRAME} at (0,0) size 100x100 [bgcolor=#008000]
layer at (0,0) size 100x100
RenderView at (0,0) size 100x100
layer at (0,0) size 100x100
RenderBlock {HTML} at (0,0) size 100x100
RenderBody {BODY} at (8,8) size 84x84
RenderText {#text} at (0,0) size 0x0
2008-09-16 Dan Bernstein <mitz@apple.com>
Reviewed by Dave Hyatt.
- fix https://bugs.webkit.org/show_bug.cgi?id=15384
Div does not notice when grandparent changes height
Test: fast/block/basic/quirk-percent-height-grandchild.html
- fix https://bugs.webkit.org/show_bug.cgi?id=20714
Resizing Gmail inbox vertically results in whitespace at the bottom of the window
Test: fast/replaced/percent-height-in-anonymous-block.html
Added a two-way mapping between boxes with percentage heights and
their non-parent ancestors up to the one the height is computed relative
to. In quirks mode (the first bug), this can be any number of containing
block with auto height. In strict mode (the second bug) this can be
the containing block of an anonymous block containing a replaced
element.
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::~RenderBlock): Added code to remove the all the
mapping to/from this block to percentage-height descendants.
(WebCore::RenderBlock::layoutBlockChildren): Added code to mark
percentage-height descendants (and their containing block ancestry chain
up to this block) for layout. This ensures that those descendants whose
height depends on the height of this block (or an ancestor) are updated.
(WebCore::RenderBlock::addPercentHeightDescendant): Added. Establishes
a two-way mapping between this block and the given box.
(WebCore::RenderBlock::removePercentHeightDescendant): Added. Removes
all the mapping to/from this box.
* rendering/RenderBlock.h:
* rendering/RenderBox.cpp:
(WebCore::RenderBox::setStyle): Added calls to
removePercentHeightDescendant() when style changes and the box
previously had a percentage height. An exception is when the style
change does not require layout, in which case the box still has
a percentage height and the mappings are valid. In all other cases,
any required mappings will be (re-)established during layout.
(WebCore::RenderBox::destroy): Added a call to
removePercentHeightDescendant.
(WebCore::RenderBox::calcPercentageHeight): Added code that, in quirks
mode, if a higher-than-parent containing block is affecting the box's
height, creates a mapping between the box and that block.
(WebCore::RenderBox::calcReplacedHeightUsing): Changed to skip over
anonymous containing blocks, if any, and when that happens, use
addPercentHeightDescendant() to ensure that the non-anonymous block
is aware of the dependent percent-height box.
2008-09-16 Dirk Schulze <vbs85@gmx.de>
Reviewed by Oliver Hunt and Alp Toker.
......
......@@ -65,6 +65,12 @@ struct ColumnInfo {
typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
static ColumnInfoMap* gColumnInfoMap = 0;
typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
// Our MarginInfo state used when laying out block children.
RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom)
{
......@@ -119,6 +125,25 @@ RenderBlock::~RenderBlock()
if (m_hasColumns)
delete gColumnInfoMap->take(this);
if (gPercentHeightDescendantsMap) {
if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
HashSet<RenderBox*>::iterator end = descendantSet->end();
for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
ASSERT(containerSet);
if (!containerSet)
continue;
ASSERT(containerSet->contains(this));
containerSet->remove(this);
if (containerSet->isEmpty()) {
gPercentHeightContainerMap->remove(*descendant);
delete containerSet;
}
}
delete descendantSet;
}
}
}
void RenderBlock::setStyle(RenderStyle* _style)
......@@ -1196,6 +1221,24 @@ void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInf
void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom)
{
if (gPercentHeightDescendantsMap) {
if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
HashSet<RenderBox*>::iterator end = descendants->end();
for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
RenderBox* box = *it;
while (box != this) {
if (box->normalChildNeedsLayout())
break;
box->setChildNeedsLayout(true, false);
box = box->containingBlock();
ASSERT(box);
if (!box)
break;
}
}
}
}
int top = borderTop() + paddingTop();
int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
......@@ -2361,6 +2404,61 @@ void RenderBlock::newLine(EClear clear)
m_height = newY;
}
void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
{
if (!gPercentHeightDescendantsMap) {
gPercentHeightDescendantsMap = new PercentHeightDescendantsMap;
gPercentHeightContainerMap = new PercentHeightContainerMap;
}
HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this);
if (!descendantSet) {
descendantSet = new HashSet<RenderBox*>;
gPercentHeightDescendantsMap->set(this, descendantSet);
}
bool added = descendantSet->add(descendant).second;
if (!added) {
ASSERT(gPercentHeightContainerMap->get(descendant));
ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this));
return;
}
HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant);
if (!containerSet) {
containerSet = new HashSet<RenderBlock*>;
gPercentHeightContainerMap->set(descendant, containerSet);
}
ASSERT(!containerSet->contains(this));
containerSet->add(this);
}
void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
{
if (!gPercentHeightContainerMap)
return;
HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant);
if (!containerSet)
return;
HashSet<RenderBlock*>::iterator end = containerSet->end();
for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
RenderBlock* container = *it;
HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container);
ASSERT(descendantSet);
if (!descendantSet)
continue;
ASSERT(descendantSet->contains(descendant));
descendantSet->remove(descendant);
if (descendantSet->isEmpty()) {
gPercentHeightDescendantsMap->remove(container);
delete descendantSet;
}
}
delete containerSet;
}
int
RenderBlock::leftOffset() const
{
......
......@@ -118,6 +118,9 @@ public:
void removePositionedObject(RenderObject*);
virtual void removePositionedObjects(RenderBlock*);
void addPercentHeightDescendant(RenderBox*);
static void removePercentHeightDescendant(RenderBox*);
virtual void positionListMarker() { }
virtual void borderFitAdjust(int& x, int& w) const; // Shrink the box in which the border paints if border-fit is set.
......
......@@ -83,6 +83,9 @@ void RenderBox::setStyle(RenderStyle* newStyle)
RenderObject::setStyle(newStyle);
if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent()))
RenderBlock::removePercentHeightDescendant(this);
// The root and the RenderView always paint their backgrounds/borders.
if (isRoot() || isRenderView())
setHasBoxDecorations(true);
......@@ -186,6 +189,9 @@ void RenderBox::destroy()
if (m_layer)
m_layer->clearClipRect();
if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
RenderBlock::removePercentHeightDescendant(this);
RenderObject::destroy();
}
......@@ -1516,8 +1522,10 @@ int RenderBox::calcPercentageHeight(const Length& height)
// block that may have a specified height and then use it. In strict mode, this violates the
// specification, which states that percentage heights just revert to auto if the containing
// block has an auto height.
while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->height().isAuto())
while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->height().isAuto()) {
cb = cb->containingBlock();
cb->addPercentHeightDescendant(this);
}
}
// A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
......@@ -1620,6 +1628,11 @@ int RenderBox::calcReplacedHeightUsing(Length height) const
case Percent:
{
RenderObject* cb = isPositioned() ? container() : containingBlock();
while (cb->isAnonymous()) {
cb = cb->containingBlock();
static_cast<RenderBlock*>(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
}
if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
ASSERT(cb->isRenderBlock());
RenderBlock* block = static_cast<RenderBlock*>(cb);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment