Commit bb7981f7 authored by hyatt's avatar hyatt

Break up painting and hit testing of children into helper methods and...

        Break up painting and hit testing of children into helper methods and add multi-column versions for both.
        
        Make incremental repainting able to invalidate the right spot in multiple column layouts so that e.g., link
        hover works.

        Turn off selection gap filling in columns for now until it can be made to work correctly.

        Improve the column balancing heuristic by adding in the block's lineHeight/2 to each column initially to
        account for column break adjustments that shrink the columns slightly.  Avoid clipping of the last column's
        contents by ensuring it gets all the remaining available height.

        Reviewed by mitz

        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::paintColumns):
        (WebCore::RenderBlock::paintContents):
        (WebCore::RenderBlock::paintObject):
        (WebCore::RenderBlock::fillSelectionGaps):
        (WebCore::RenderBlock::nodeAtPoint):
        (WebCore::RenderBlock::hitTestColumns):
        (WebCore::RenderBlock::layoutColumns):
        (WebCore::RenderBlock::adjustRepaintRectForColumns):
        * rendering/RenderBlock.h:
        * rendering/RenderBox.cpp:
        (WebCore::RenderBox::computeAbsoluteRepaintRect):
        * rendering/RenderFlow.cpp:
        (WebCore::RenderFlow::getAbsoluteRepaintRect):



git-svn-id: svn://svn.chromium.org/blink/trunk@18732 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent de087914
2007-01-09 David Hyatt <hyatt@apple.com>
Break up painting and hit testing of children into helper methods and add multi-column versions for both.
Make incremental repainting able to invalidate the right spot in multiple column layouts so that e.g., link
hover works.
Turn off selection gap filling in columns for now until it can be made to work correctly.
Improve the column balancing heuristic by adding in the block's lineHeight/2 to each column initially to
account for column break adjustments that shrink the columns slightly. Avoid clipping of the last column's
contents by ensuring it gets all the remaining available height.
Reviewed by mitz
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::paintColumns):
(WebCore::RenderBlock::paintContents):
(WebCore::RenderBlock::paintObject):
(WebCore::RenderBlock::fillSelectionGaps):
(WebCore::RenderBlock::nodeAtPoint):
(WebCore::RenderBlock::hitTestColumns):
(WebCore::RenderBlock::layoutColumns):
(WebCore::RenderBlock::adjustRepaintRectForColumns):
* rendering/RenderBlock.h:
* rendering/RenderBox.cpp:
(WebCore::RenderBox::computeAbsoluteRepaintRect):
* rendering/RenderFlow.cpp:
(WebCore::RenderFlow::getAbsoluteRepaintRect):
2007-01-09 Remi Zara <remi_zara@mac.com>
Reviewed by Darin and Eric.
......
......@@ -1301,6 +1301,44 @@ void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
return paintObject(paintInfo, tx, ty);
}
void RenderBlock::paintColumns(PaintInfo& paintInfo, int tx, int ty)
{
// We need to do multiple passes, breaking up our child painting into strips.
GraphicsContext* context = paintInfo.context;
int currXOffset = 0;
int currYOffset = 0;
int colGap = columnGap();
for (unsigned i = 0; i < m_columnCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
IntRect colRect = m_columnRects->at(i);
colRect.move(tx, ty);
context->save();
// Each strip pushes a clip, since column boxes are specified as being
// like overflow:hidden.
context->clip(colRect);
// Adjust tx and ty to change where we paint.
PaintInfo info(paintInfo);
info.rect.intersect(colRect);
// Adjust our x and y when painting.
int finalX = tx + currXOffset;
int finalY = ty + currYOffset;
paintContents(info, finalX, finalY);
// Move to the next position.
if (style()->direction() == LTR)
currXOffset += colRect.width() + colGap;
else
currXOffset -= (colRect.width() + colGap);
currYOffset -= colRect.height();
context->restore();
}
}
void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty)
{
// Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
......@@ -1309,50 +1347,10 @@ void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty)
if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
return;
if (!hasColumns()) {
if (childrenInline())
paintLines(paintInfo, tx, ty);
else
paintChildren(paintInfo, tx, ty);
} else {
// We need to do multiple passes, breaking up our child painting into strips.
GraphicsContext* context = paintInfo.context;
int currXOffset = 0;
int currYOffset = 0;
int colGap = columnGap();
for (unsigned i = 0; i < m_columnCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
IntRect colRect = m_columnRects->at(i);
colRect.move(tx, ty);
context->save();
// Each strip pushes a clip, since column boxes are specified as being
// like overflow:hidden.
context->clip(colRect);
// Adjust tx and ty to change where we paint.
PaintInfo info(paintInfo);
info.rect.intersect(colRect);
// Adjust our x and y when painting.
int finalX = tx + currXOffset;
int finalY = ty + currYOffset;
if (childrenInline())
paintLines(paintInfo, finalX, finalY);
else
paintChildren(paintInfo, finalX, finalY);
// Move to the next position.
if (style()->direction() == LTR)
currXOffset += colRect.width() + colGap;
else
currXOffset -= (colRect.width() + colGap);
currYOffset -= colRect.height();
context->restore();
}
}
if (childrenInline())
paintLines(paintInfo, tx, ty);
else
paintChildren(paintInfo, tx, ty);
}
void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
......@@ -1426,8 +1424,12 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
m_layer->subtractScrollOffset(scrolledX, scrolledY);
// 2. paint contents
if (paintPhase != PaintPhaseSelfOutline)
paintContents(paintInfo, scrolledX, scrolledY);
if (paintPhase != PaintPhaseSelfOutline) {
if (hasColumns())
paintColumns(paintInfo, scrolledX, scrolledY);
else
paintContents(paintInfo, scrolledX, scrolledY);
}
// 3. paint selection
// FIXME: Make this work with multi column layouts. For now don't fill gaps.
......@@ -1584,8 +1586,16 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int
// FIXME: overflow: auto/scroll regions need more math here, since painting in the border box is different from painting in the padding box (one is scrolled, the other is
// fixed).
GapRects result;
if (!isBlockFlow())
if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
return result;
if (hasColumns()) {
// FIXME: We should learn how to gap fill multiple columns eventually.
lastTop = (ty - blockY) + height();
lastLeft = leftSelectionOffset(rootBlock, height());
lastRight = rightSelectionOffset(rootBlock, height());
return result;
}
if (childrenInline())
result = fillInlineSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo);
......@@ -2628,7 +2638,13 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
int scrolledY = ty;
if (hasOverflowClip())
m_layer->subtractScrollOffset(scrolledX, scrolledY);
if (hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
// Hit test contents if we don't have columns.
if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
return true;
// Hit test our columns if we do have them.
if (hasColumns() && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
return true;
// Hit test floats.
......@@ -2662,6 +2678,39 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
return false;
}
bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
{
// We need to do multiple passes, breaking up our hit testing into strips.
// We can always go left to right, since column contents are clipped (meaning that there
// can't be any overlap).
int currXOffset = 0;
int currYOffset = 0;
int colGap = columnGap();
for (unsigned i = 0; i < m_columnCount; i++) {
IntRect colRect = m_columnRects->at(i);
colRect.move(tx, ty);
if (colRect.contains(x, y)) {
// The point is inside this column.
// Adjust tx and ty to change where we hit test.
int finalX = tx + currXOffset;
int finalY = ty + currYOffset;
return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction);
}
// Move to the next position.
if (style()->direction() == LTR)
currXOffset += colRect.width() + colGap;
else
currXOffset -= (colRect.width() + colGap);
currYOffset -= colRect.height();
}
return false;
}
bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
{
if (childrenInline() && !isTable()) {
......@@ -2900,7 +2949,8 @@ void RenderBlock::layoutColumns()
// Fill the columns in to the available height. Attempt to balance the height of the columns
int availableHeight = contentHeight();
int colHeight = availableHeight / m_columnCount;
int colHeight = availableHeight / m_columnCount + lineHeight(false) / 2; // Add in half our line-height to help with best-guess initial balancing.
int colGap = columnGap();
// Compute a collection of column rects.
......@@ -2918,6 +2968,10 @@ void RenderBlock::layoutColumns()
int colCount = m_columnCount;
int maxColBottom = borderTop() + paddingTop();
for (unsigned i = 0; i < m_columnCount; i++) {
// The last column just gets all the remaining space.
if (i == m_columnCount - 1)
colHeight = availableHeight;
// This represents the real column position.
IntRect colRect(currX, top, m_columnWidth, colHeight);
......@@ -2943,14 +2997,13 @@ void RenderBlock::layoutColumns()
currX -= (m_columnWidth + colGap);
currY += colRect.height();
availableHeight -= colRect.height();
maxColBottom = max(colRect.bottom(), maxColBottom);
m_columnRects->append(colRect);
}
// FIXME: We should be prepared to grow the last column to accommodate clipped out content if the amount of growth would be pretty small.
m_overflowHeight = maxColBottom;
int toAdd = borderBottom() + paddingBottom();
if (includeHorizontalScrollbarSize())
......@@ -2962,6 +3015,41 @@ void RenderBlock::layoutColumns()
v->setTruncatedAt(0);
}
void RenderBlock::adjustRepaintRectForColumns(IntRect& r) const
{
// Just bail if we have no columns.
if (!hasColumns())
return;
// Begin with a result rect that is empty.
IntRect result;
// Determine which columns we intersect.
int currXOffset = 0;
int currYOffset = 0;
int colGap = columnGap();
for (unsigned i = 0; i < m_columnCount; i++) {
IntRect colRect = m_columnRects->at(i);
IntRect repaintRect = r;
repaintRect.move(currXOffset, currYOffset);
repaintRect.intersect(colRect);
result.unite(repaintRect);
// Move to the next position.
if (style()->direction() == LTR)
currXOffset += colRect.width() + colGap;
else
currXOffset -= (colRect.width() + colGap);
currYOffset -= colRect.height();
}
r = result;
}
void RenderBlock::calcMinMaxWidth()
{
ASSERT( !minMaxKnown() );
......
......@@ -142,6 +142,7 @@ public:
virtual void paintObject(PaintInfo&, int tx, int ty);
void paintFloats(PaintInfo&, int tx, int ty, bool paintSelection = false);
void paintContents(PaintInfo&, int tx, int ty);
void paintColumns(PaintInfo&, int tx, int ty);
void paintChildren(PaintInfo&, int tx, int ty);
void paintEllipsisBoxes(PaintInfo&, int tx, int ty);
void paintSelection(PaintInfo&, int tx, int ty);
......@@ -190,6 +191,7 @@ public:
int leftOffset(int y) const { return leftRelOffset(y, leftOffset(), true); }
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
virtual bool hitTestColumns(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
virtual bool hitTestContents(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
virtual bool isPointInScrollbar(HitTestResult&, int x, int y, int tx, int ty);
......@@ -279,7 +281,8 @@ public:
void clearTruncation();
virtual bool hasColumns() const { return m_columnCount > 1; }
void adjustRepaintRectForColumns(IntRect&) const;
protected:
void newLine();
virtual bool hasLineIfEmpty() const;
......
......@@ -914,6 +914,17 @@ void RenderBox::computeAbsoluteRepaintRect(IntRect& r, bool f)
RenderObject* o = container();
if (o) {
if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
RenderBlock* cb = static_cast<RenderBlock*>(o);
if (cb->hasColumns()) {
IntRect repaintRect(x, y, r.width(), r.height());
cb->adjustRepaintRectForColumns(repaintRect);
x = repaintRect.x();
y = repaintRect.y();
r = repaintRect;
}
}
if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isInlineFlow()) {
// When we have an enclosing relpositioned inline, we need to add in the offset of the first line
// box from the rest of the content, but only in the cases where we know we're positioned
......@@ -944,6 +955,7 @@ void RenderBox::computeAbsoluteRepaintRect(IntRect& r, bool f)
if (!hasStaticY())
y += sy;
}
// <body> may not have overflow, since it might be applying its overflow value to the
// scrollbars.
if (o->hasOverflowClip()) {
......
......@@ -468,6 +468,9 @@ IntRect RenderFlow::getAbsoluteRepaintRect()
}
IntRect r(-ow + left, -ow + top, width() + ow * 2, height() + ow * 2);
if (cb->hasColumns())
cb->adjustRepaintRectForColumns(r);
if (cb->hasOverflowClip()) {
// cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
// layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
......
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