Several fixes preparing for the incremental repainting patch to be enabled.
(1) Make layers update their positions after layout instead of during layout or
during painting.
(2) Fix a regression from the overflow:hidden body quirk landing. Make sure repaint()
understands that quirk exists and avoids clipping when it shouldn't.
(3) Fix a regression from the scrollbar improvements. The vertical scrollbar repainted
on every layout.
(4) Make sure outside list bullets are repainted when a list item needs to repaint.
(5) A whole bunch of INCREMENTAL_REPAINTING code that isn't turned on yet.
Reviewed by kocienda
* khtml/khtmlview.cpp:
(KHTMLViewPrivate::KHTMLViewPrivate):
(KHTMLViewPrivate::reset):
(KHTMLView::resetScrollBars):
(KHTMLView::needsFullRepaint):
* khtml/khtmlview.h:
* khtml/rendering/bidi.cpp:
(khtml::RenderBlock::layoutInlineChildren):
* khtml/rendering/render_block.cpp:
(khtml::RenderBlock::layoutBlock):
(khtml::RenderBlock::layoutBlockChildren):
(khtml::RenderBlock::getAbsoluteRepaintRectIncludingFloats):
(khtml::RenderBlock::repaintFloatingDescendants):
(khtml::RenderBlock::repaintObjectsBeforeLayout):
* khtml/rendering/render_block.h:
* khtml/rendering/render_box.cpp:
(RenderBox::computeAbsoluteRepaintRect):
(RenderBox::repaintDuringLayoutIfMoved):
* khtml/rendering/render_box.h:
* khtml/rendering/render_canvas.cpp:
(RenderCanvas::layout):
* khtml/rendering/render_canvas.h:
(khtml::RenderCanvas::hasOverhangingFloats):
* khtml/rendering/render_flexbox.cpp:
(khtml::RenderFlexibleBox::layoutBlock):
(khtml::RenderFlexibleBox::layoutHorizontalBox):
(khtml::RenderFlexibleBox::layoutVerticalBox):
(khtml::RenderFlexibleBox::placeChild):
* khtml/rendering/render_flexbox.h:
* khtml/rendering/render_flow.cpp:
(RenderFlow::getAbsoluteRepaintRect):
* khtml/rendering/render_image.cpp:
(RenderImage::setPixmap):
(RenderImage::layout):
* khtml/rendering/render_layer.cpp:
(RenderLayer::RenderLayer):
(RenderLayer::computeRepaintRects):
(RenderLayer::updateLayerPositions):
(RenderLayer::updateLayerPosition):
(RenderLayer::checkScrollbarsAfterLayout):
(RenderLayer::paintLayer):
(RenderLayer::calculateClipRects):
(RenderLayer::calculateRects):
* khtml/rendering/render_layer.h:
(khtml::RenderLayer::relativePositionOffset):
* khtml/rendering/render_list.cpp:
(RenderListItem::getAbsoluteRepaintRect):
* khtml/rendering/render_list.h:
(khtml::RenderListMarker::listImage):
* khtml/rendering/render_object.cpp:
(RenderObject::repaint):
(RenderObject::repaintRectangle):
(RenderObject::repaintAfterLayoutIfNeeded):
(RenderObject::repaintDuringLayoutIfMoved):
(RenderObject::repaintFloatingDescendants):
(RenderObject::checkForRepaintDuringLayout):
(RenderObject::repaintObjectsBeforeLayout):
(RenderObject::getAbsoluteRepaintRectIncludingFloats):
(RenderObject::container):
* khtml/rendering/render_object.h:
* khtml/rendering/render_table.cpp:
(RenderTable::layout):
* kwq/KWQKHTMLPart.mm:
(KWQKHTMLPart::passWidgetMouseDownEventToWidget):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@5141 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/khtml/khtmlview.cpp b/WebCore/khtml/khtmlview.cpp
index 64165db..003009e 100644
--- a/WebCore/khtml/khtmlview.cpp
+++ b/WebCore/khtml/khtmlview.cpp
@@ -99,6 +99,9 @@
complete = false;
mousePressed = false;
tooltip = 0;
+#ifdef INCREMENTAL_REPAINTING
+ doFullRepaint = true;
+#endif
#if APPLE_CHANGES
vmode = hmode = QScrollView::Auto;
firstLayout = true;
@@ -149,6 +152,9 @@
layoutTimerId = 0;
complete = false;
mousePressed = false;
+#ifdef INCREMENTAL_REPAINTING
+ doFullRepaint = true;
+#endif
layoutSchedulingEnabled = true;
layoutSuppressed = false;
#if APPLE_CHANGES
@@ -166,7 +172,10 @@
bool borderTouched:1;
bool borderStart:1;
bool scrollBarMoved:1;
-
+#ifdef INCREMENTAL_REPAINTING
+ bool doFullRepaint:1;
+#endif
+
QScrollView::ScrollBarMode vmode;
QScrollView::ScrollBarMode hmode;
#if !APPLE_CHANGES
@@ -292,6 +301,7 @@
void KHTMLView::resetScrollBars()
{
// Reset the document's scrollbars back to our defaults before we yield the floor.
+ d->firstLayout = true;
suppressScrollBars(true);
QScrollView::setVScrollBarMode(d->vmode);
QScrollView::setHScrollBarMode(d->hmode);
@@ -487,6 +497,13 @@
return d->layoutSuppressed;
}
+#ifdef INCREMENTAL_REPAINTING
+bool KHTMLView::needsFullRepaint() const
+{
+ return d->doFullRepaint;
+}
+#endif
+
void KHTMLView::layout()
{
if (d->layoutSuppressed)
@@ -495,7 +512,7 @@
d->layoutSchedulingEnabled=false;
killTimer(d->layoutTimerId);
d->layoutTimerId = 0;
-
+
DOM::DocumentImpl* document = m_part->xmlDocImpl();
if (!document) {
_width = visibleWidth();
@@ -506,11 +523,6 @@
if (!root)
return;
-#if APPLE_CHANGES
- // Now set up our scrollbar state for the layout.
- suppressScrollBars(true);
-#endif
-
ScrollBarMode hMode = d->hmode;
ScrollBarMode vMode = d->vmode;
@@ -527,34 +539,64 @@
}
}
-#if APPLE_CHANGES
- if (d->firstLayout) {
- d->firstLayout = false;
-
- // Set the initial vMode to AlwaysOn if we're auto.
- if (vMode == Auto)
- QScrollView::setVScrollBarMode(AlwaysOn); // This causes a vertical scrollbar to appear.
- // Set the initial hMode to AlwaysOff if we're auto.
- if (hMode == Auto)
- QScrollView::setHScrollBarMode(AlwaysOff); // This causes a horizontal scrollbar to disappear.
- }
-
- if (hMode == vMode)
- QScrollView::setScrollBarsMode(hMode);
- else {
- QScrollView::setHScrollBarMode(hMode);
- QScrollView::setVScrollBarMode(vMode);
- }
+#if INCREMENTAL_REPAINTING
+ d->doFullRepaint = d->firstLayout || root->printingMode();
+#endif
- suppressScrollBars(false, true);
+#if APPLE_CHANGES
+ // Now set our scrollbar state for the layout.
+ ScrollBarMode currentHMode = hScrollBarMode();
+ ScrollBarMode currentVMode = vScrollBarMode();
+
+ if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
+ suppressScrollBars(true);
+ if (d->firstLayout) {
+ d->firstLayout = false;
+
+ // Set the initial vMode to AlwaysOn if we're auto.
+ if (vMode == Auto)
+ QScrollView::setVScrollBarMode(AlwaysOn); // This causes a vertical scrollbar to appear.
+ // Set the initial hMode to AlwaysOff if we're auto.
+ if (hMode == Auto)
+ QScrollView::setHScrollBarMode(AlwaysOff); // This causes a horizontal scrollbar to disappear.
+ }
+
+ if (hMode == vMode)
+ QScrollView::setScrollBarsMode(hMode);
+ else {
+ QScrollView::setHScrollBarMode(hMode);
+ QScrollView::setVScrollBarMode(vMode);
+ }
+
+ suppressScrollBars(false, true);
+ }
#else
QScrollView::setHScrollBarMode(hMode);
QScrollView::setVScrollBarMode(vMode);
#endif
-
+
+#ifdef INCREMENTAL_REPAINTING
+ int oldHeight = _height;
+ int oldWidth = _width;
+#endif
+
_height = visibleHeight();
_width = visibleWidth();
+#ifdef INCREMENTAL_REPAINTING
+ if (oldHeight != _height || oldWidth != _width)
+ d->doFullRepaint = true;
+#endif
+
+ RenderLayer* layer = root->layer();
+
+#ifdef INCREMENTAL_REPAINTING
+ if (!d->doFullRepaint) {
+ layer->computeRepaintRects();
+ root->repaintObjectsBeforeLayout();
+ }
+#endif
+
root->layout();
//kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
@@ -562,8 +604,15 @@
d->layoutSchedulingEnabled=true;
d->layoutSuppressed = false;
- resizeContents(root->docWidth(), root->docHeight());
-
+ resizeContents(layer->width(), layer->height());
+
+ // Now update the positions of all layers.
+#ifdef INCREMENTAL_REPAINTING
+ layer->updateLayerPositions(layer, d->doFullRepaint);
+#else
+ layer->updateLayerPositions();
+#endif
+
#ifdef INCREMENTAL_REPAINTING
if (root->needsLayout()) {
#else
diff --git a/WebCore/khtml/khtmlview.h b/WebCore/khtml/khtmlview.h
index b140d72..7eca5e4 100644
--- a/WebCore/khtml/khtmlview.h
+++ b/WebCore/khtml/khtmlview.h
@@ -32,6 +32,9 @@
class QPainter;
class QRect;
+// Uncomment to enable INCREMENTAL_REPAINTING
+//#define INCREMENTAL_REPAINTING
+
namespace DOM {
class HTMLDocumentImpl;
class DocumentImpl;
@@ -152,6 +155,10 @@
void layout();
bool inLayout() const;
+
+#ifdef INCREMENTAL_REPAINTING
+ bool needsFullRepaint() const;
+#endif
#if APPLE_CHANGES
void resetScrollBars();
diff --git a/WebCore/khtml/rendering/bidi.cpp b/WebCore/khtml/rendering/bidi.cpp
index 88c0ac1..cb00da7 100644
--- a/WebCore/khtml/rendering/bidi.cpp
+++ b/WebCore/khtml/rendering/bidi.cpp
@@ -1301,10 +1301,18 @@
else
o->layoutIfNeeded();
}
- else if(o->isText()) // FIXME: Should be able to combine deleteLineBoxes/Runs
+ else if(o->isText()) { // FIXME: Should be able to combine deleteLineBoxes/Runs
static_cast<RenderText *>(o)->deleteRuns();
- else if (o->isInlineFlow() && !endOfInline)
+#ifdef INCREMENTAL_REPAINTING
+ o->setNeedsLayout(false);
+#endif
+ }
+ else if (o->isInlineFlow() && !endOfInline) {
static_cast<RenderFlow*>(o)->deleteLineBoxes();
+#ifdef INCREMENTAL_REPAINTING
+ o->setNeedsLayout(false);
+#endif
+ }
o = Bidinext( this, o, bidi, false, &endOfInline);
}
diff --git a/WebCore/khtml/rendering/render_block.cpp b/WebCore/khtml/rendering/render_block.cpp
index d63d016..07b9ae1 100644
--- a/WebCore/khtml/rendering/render_block.cpp
+++ b/WebCore/khtml/rendering/render_block.cpp
@@ -413,12 +413,10 @@
}
#ifdef INCREMENTAL_REPAINTING
- // FIXME: For now, if we have dirty inline children, we just always repaint.
- if (normalChildNeedsLayout() && childrenInline())
- repaint();
-
QRect oldBounds, oldFullBounds;
- getAbsoluteRepaintRectIncludingDescendants(oldBounds, oldFullBounds);
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint)
+ getAbsoluteRepaintRectIncludingFloats(oldBounds, oldFullBounds);
#endif
int oldWidth = m_width;
@@ -539,7 +537,7 @@
#ifdef INCREMENTAL_REPAINTING
// Repaint with our new bounds if they are different from our old bounds.
- if (!isCanvas())
+ if (checkForRepaint)
repaintAfterLayoutIfNeeded(oldBounds, oldFullBounds);
#endif
@@ -1064,12 +1062,12 @@
treatCompactAsBlock = false;
}
+#ifdef INCREMENTAL_REPAINTING
// If the child moved, we have to repaint it as well as any floating/positioned
// descendants. An exception is if we need a layout. In this case, we know we're going to
// repaint ourselves (and the child) anyway.
-#ifdef INCREMENTAL_REPAINTING
- if (!selfNeedsLayout())
- child->repaintIfMoved(oldChildX, oldChildY);
+ if (!selfNeedsLayout() && checkForRepaintDuringLayout())
+ child->repaintDuringLayoutIfMoved(oldChildX, oldChildY);
#endif
child = child->nextSibling();
@@ -1136,58 +1134,57 @@
}
#ifdef INCREMENTAL_REPAINTING
-void RenderBlock::getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& fullBounds)
+void RenderBlock::getAbsoluteRepaintRectIncludingFloats(QRect& bounds, QRect& fullBounds)
{
bounds = fullBounds = getAbsoluteRepaintRect();
- if (m_positionedObjects) {
- RenderObject* r;
- QPtrListIterator<RenderObject> it(*m_positionedObjects);
- for ( ; (r = it.current()); ++it ) {
- QRect childRect, childFullRect;
- r->getAbsoluteRepaintRectIncludingDescendants(childRect, childFullRect);
- fullBounds = fullBounds.unite(childFullRect);
- }
- }
// Include any overhanging floats (if we know we're the one to paint them).
if (hasOverhangingFloats()) {
FloatingObject* r;
QPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it) {
- // Only repaint the object if our noPaint flag isn't set.
- if (!r->noPaint) {
+ // Only repaint the object if our noPaint flag isn't set and if it isn't in
+ // its own layer.
+ if (!r->noPaint && !r->node->layer()) {
QRect childRect, childFullRect;
- r->node->getAbsoluteRepaintRectIncludingDescendants(childRect, childFullRect);
+ r->node->getAbsoluteRepaintRectIncludingFloats(childRect, childFullRect);
fullBounds = fullBounds.unite(childFullRect);
}
}
}
}
-void RenderBlock::repaintPositionedAndFloatingDescendants()
+void RenderBlock::repaintFloatingDescendants()
{
- if (m_positionedObjects) {
- RenderObject* r;
- QPtrListIterator<RenderObject> it(*m_positionedObjects);
- for ( ; (r = it.current()); ++it ) {
- r->repaint();
- r->repaintPositionedAndFloatingDescendants();
- }
- }
-
// Repaint any overhanging floats (if we know we're the one to paint them).
if (hasOverhangingFloats()) {
FloatingObject* r;
QPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it) {
- // Only repaint the object if our noPaint flag isn't set.
- if (!r->noPaint) {
+ // Only repaint the object if our noPaint flag isn't set and if it isn't in
+ // its own layer.
+ if (!r->noPaint && !r->node->layer()) {
r->node->repaint();
- r->node->repaintPositionedAndFloatingDescendants();
+ r->node->repaintFloatingDescendants();
}
}
}
}
+
+void RenderBlock::repaintObjectsBeforeLayout()
+{
+ RenderFlow::repaintObjectsBeforeLayout();
+ if (!needsLayout())
+ return;
+
+ // Walk our positioned objects.
+ if (m_positionedObjects) {
+ RenderObject* r;
+ QPtrListIterator<RenderObject> it(*m_positionedObjects);
+ for ( ; (r = it.current()); ++it )
+ r->repaintObjectsBeforeLayout();
+ }
+}
#endif
void RenderBlock::paint(QPainter* p, int _x, int _y, int _w, int _h, int _tx, int _ty, PaintAction paintAction)
diff --git a/WebCore/khtml/rendering/render_block.h b/WebCore/khtml/rendering/render_block.h
index 7081eb9..ef31ffb 100644
--- a/WebCore/khtml/rendering/render_block.h
+++ b/WebCore/khtml/rendering/render_block.h
@@ -94,8 +94,9 @@
virtual void removeChild(RenderObject *oldChild);
#ifdef INCREMENTAL_REPAINTING
- virtual void repaintPositionedAndFloatingDescendants();
- virtual void getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& fullBounds);
+ virtual void repaintObjectsBeforeLayout();
+ virtual void repaintFloatingDescendants();
+ virtual void getAbsoluteRepaintRectIncludingFloats(QRect& bounds, QRect& fullBounds);
#endif
virtual void setStyle(RenderStyle* _style);
diff --git a/WebCore/khtml/rendering/render_box.cpp b/WebCore/khtml/rendering/render_box.cpp
index f14e972..be1f323 100644
--- a/WebCore/khtml/rendering/render_box.cpp
+++ b/WebCore/khtml/rendering/render_box.cpp
@@ -587,19 +587,25 @@
// is translated, but the render box isn't, so we need to do this to get the
// right dirty rect. Since this is called from RenderObject::setStyle, the relative position
// flag on the RenderObject has been cleared, so use the one on the style().
+#ifdef INCREMENTAL_REPAINTING
+ if (style()->position() == RELATIVE && m_layer)
+ m_layer->relativePositionOffset(x,y);
+#else
if (style()->position() == RELATIVE)
relativePositionOffset(x,y);
+#endif
if (style()->position()==FIXED)
f = true;
RenderObject* o = container();
if (o) {
- if (o->style()->hidesOverflow()) {
+ // <body> may not have a layer, since it might be applying its overflow value to the
+ // scrollbars.
+ if (o->style()->hidesOverflow() && o->layer()) {
int ow = o->style() ? o->style()->outlineWidth() : 0;
QRect boxRect(-ow, -ow, o->width()+ow*2, o->height()+ow*2);
- if (o->layer())
- o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
+ o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
QRect repaintRect(x, y, r.width(), r.height());
if (!repaintRect.intersects(boxRect)) {
r = QRect();
@@ -616,11 +622,8 @@
}
#ifdef INCREMENTAL_REPAINTING
-void RenderBox::repaintIfMoved(int oldX, int oldY)
+void RenderBox::repaintDuringLayoutIfMoved(int oldX, int oldY)
{
- if (isCanvas())
- return;
-
int newX = m_x;
int newY = m_y;
if (oldX != newX || oldY != newY) {
@@ -628,10 +631,10 @@
// since the object may not have gotten a layout.
m_x = oldX; m_y = oldY;
repaint();
- repaintPositionedAndFloatingDescendants();
+ repaintFloatingDescendants();
m_x = newX; m_y = newY;
repaint();
- repaintPositionedAndFloatingDescendants();
+ repaintFloatingDescendants();
}
}
#endif
diff --git a/WebCore/khtml/rendering/render_box.h b/WebCore/khtml/rendering/render_box.h
index fbdf67e..3df449b 100644
--- a/WebCore/khtml/rendering/render_box.h
+++ b/WebCore/khtml/rendering/render_box.h
@@ -90,7 +90,7 @@
virtual void computeAbsoluteRepaintRect(QRect& r, bool f=false);
#ifdef INCREMENTAL_REPAINTING
- virtual void repaintIfMoved(int oldX, int oldY);
+ virtual void repaintDuringLayoutIfMoved(int oldX, int oldY);
#endif
virtual void setPixmap(const QPixmap &, const QRect&, CachedImage *);
diff --git a/WebCore/khtml/rendering/render_canvas.cpp b/WebCore/khtml/rendering/render_canvas.cpp
index c1e6912..ed9eaa8 100644
--- a/WebCore/khtml/rendering/render_canvas.cpp
+++ b/WebCore/khtml/rendering/render_canvas.cpp
@@ -127,10 +127,6 @@
{
KHTMLAssert(!view()->inLayout());
-#ifdef INCREMENTAL_REPAINTING
- QRect oldBounds(m_x, m_y, m_width, m_height);
-#endif
-
if (m_printingMode)
m_minWidth = m_width;
@@ -182,12 +178,6 @@
layer()->setHeight(QMAX(doch, m_height));
layer()->setWidth(QMAX(docw, m_width));
-
-#ifdef INCREMENTAL_REPAINTING
- QRect newBounds(m_x, m_y, m_width, m_height);
- if (oldBounds != newBounds)
- repaint();
-#endif
setNeedsLayout(false);
}
diff --git a/WebCore/khtml/rendering/render_canvas.h b/WebCore/khtml/rendering/render_canvas.h
index 04350bc..d48d9e0 100644
--- a/WebCore/khtml/rendering/render_canvas.h
+++ b/WebCore/khtml/rendering/render_canvas.h
@@ -50,6 +50,8 @@
KHTMLView *view() const { return m_view; }
+ virtual bool hasOverhangingFloats() { return false; }
+
virtual QRect getAbsoluteRepaintRect();
virtual void computeAbsoluteRepaintRect(QRect& r, bool f=false);
virtual void repaintViewRectangle(const QRect& r, bool immediate = false);
diff --git a/WebCore/khtml/rendering/render_flexbox.cpp b/WebCore/khtml/rendering/render_flexbox.cpp
index 76bcb2c..70cb001 100644
--- a/WebCore/khtml/rendering/render_flexbox.cpp
+++ b/WebCore/khtml/rendering/render_flexbox.cpp
@@ -246,6 +246,13 @@
setNeedsLayout(false);
return;
}
+
+#ifdef INCREMENTAL_REPAINTING
+ QRect oldBounds;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint)
+ oldBounds = getAbsoluteRepaintRect();
+#endif
int oldWidth = m_width;
int oldHeight = m_height;
@@ -320,6 +327,12 @@
if (style()->scrollsOverflow() && m_layer)
m_layer->checkScrollbarsAfterLayout();
+#ifdef INCREMENTAL_REPAINTING
+ // Repaint with our new bounds if they are different from our old bounds.
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldBounds);
+#endif
+
setNeedsLayout(false);
}
@@ -375,7 +388,7 @@
while (child) {
// make sure we relayout children if we need it.
if ( relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
- child->setNeedsLayout(true);
+ child->setChildNeedsLayout(true);
if (child->isPositioned()) {
child = iterator.next();
@@ -439,7 +452,7 @@
int oldChildHeight = child->height();
static_cast<RenderBox*>(child)->calcHeight();
if (oldChildHeight != child->height())
- child->setNeedsLayout(true);
+ child->setChildNeedsLayout(true);
child->layoutIfNeeded();
// We can place the child now, using our value of box-align.
@@ -457,9 +470,9 @@
childY += child->marginTop();
break;
}
-
- // Place the child.
- child->setPos(xPos, childY);
+
+ placeChild(child, xPos, childY);
+
xPos += child->width() + child->marginRight();
child = iterator.next();
@@ -592,7 +605,8 @@
offset += remainingSpace/totalChildren;
remainingSpace -= (remainingSpace/totalChildren);
totalChildren--;
- child->setPos(child->xPos()+offset, child->yPos());
+
+ placeChild(child, child->xPos()+offset, child->yPos());
child = iterator.next();
}
}
@@ -608,7 +622,7 @@
child = iterator.next();
continue;
}
- child->setPos(child->xPos()+offset, child->yPos());
+ placeChild(child, child->xPos()+offset, child->yPos());
child = iterator.next();
}
}
@@ -644,7 +658,7 @@
// We always have to lay out flexible objects again, since the flex distribution
// may have changed, and we need to reallocate space.
if (!relayoutChildren)
- child->setNeedsLayout(true);
+ child->setChildNeedsLayout(true);
haveFlex = true;
unsigned int flexGroup = child->style()->boxFlexGroup();
if (lowestFlexGroup == 0)
@@ -720,7 +734,7 @@
}
// Place the child.
- child->setPos(childX, m_height);
+ placeChild(child, childX, m_height);
m_height += child->height() + child->marginBottom();
// See if this child has made our overflow need to grow.
@@ -869,7 +883,7 @@
offset += remainingSpace/totalChildren;
remainingSpace -= (remainingSpace/totalChildren);
totalChildren--;
- child->setPos(child->xPos(), child->yPos()+offset);
+ placeChild(child, child->xPos(), child->yPos()+offset);
child = iterator.next();
}
}
@@ -885,7 +899,7 @@
child = iterator.next();
continue;
}
- child->setPos(child->xPos(), child->yPos()+offset);
+ placeChild(child, child->xPos(), child->yPos()+offset);
child = iterator.next();
}
}
@@ -897,6 +911,22 @@
m_height = oldHeight;
}
+void RenderFlexibleBox::placeChild(RenderObject* child, int x, int y)
+{
+#ifdef INCREMENTAL_REPAINTING
+ int oldChildX = child->xPos();
+ int oldChildY = child->yPos();
+#endif
+ // Place the child.
+ child->setPos(x, y);
+#ifdef INCREMENTAL_REPAINTING
+ // If the child moved, we have to repaint it as well as any floating/positioned
+ // descendants. An exception is if we need a layout. In this case, we know we're going to
+ // repaint ourselves (and the child) anyway.
+ if (!selfNeedsLayout() && checkForRepaintDuringLayout()) child->repaintDuringLayoutIfMoved(oldChildX, oldChildY);
+#endif
+}
+
const char *RenderFlexibleBox::renderName() const
{
if (isFloating())
diff --git a/WebCore/khtml/rendering/render_flexbox.h b/WebCore/khtml/rendering/render_flexbox.h
index b562cc6..4dd7d6c 100644
--- a/WebCore/khtml/rendering/render_flexbox.h
+++ b/WebCore/khtml/rendering/render_flexbox.h
@@ -47,6 +47,8 @@
virtual bool isStretchingChildren() const { return m_stretchingChildren; }
virtual const char *renderName() const;
+
+ void placeChild(RenderObject* child, int x, int y);
protected:
bool hasMultipleLines() { return style()->boxLines() == MULTIPLE; }
diff --git a/WebCore/khtml/rendering/render_flow.cpp b/WebCore/khtml/rendering/render_flow.cpp
index 951f9d5..b273f05 100644
--- a/WebCore/khtml/rendering/render_flow.cpp
+++ b/WebCore/khtml/rendering/render_flow.cpp
@@ -242,6 +242,13 @@
int ow = style() ? style()->outlineWidth() : 0;
if (isCompact())
left -= m_x;
+#ifdef INCREMENTAL_REPAINTING
+ if (style()->position() == RELATIVE && m_layer)
+ m_layer->relativePositionOffset(left, top);
+#else
+ if (style()->position() == RELATIVE)
+ relativePositionOffset(left, top);
+#endif
QRect r(-ow+left, -ow+top, width()+ow*2, height()+ow*2);
containingBlock()->computeAbsoluteRepaintRect(r);
return r;
diff --git a/WebCore/khtml/rendering/render_image.cpp b/WebCore/khtml/rendering/render_image.cpp
index eabdbfb..583fd84 100644
--- a/WebCore/khtml/rendering/render_image.cpp
+++ b/WebCore/khtml/rendering/render_image.cpp
@@ -164,6 +164,13 @@
setMinMaxKnown(false);
}
else {
+#if APPLE_CHANGES
+ // FIXME: We always just do a complete repaint, since we always pass in the full pixmap
+ // rect at the moment anyway.
+ resizeCache = QPixmap();
+ repaintRectangle(QRect(borderLeft()+paddingLeft(), borderTop()+paddingTop(), contentWidth(), contentHeight()));
+#else
+ // FIXME: This code doesn't handle scaling properly, since it doesn't scale |r|.
bool completeRepaint = !resizeCache.isNull();
int cHeight = contentHeight();
int scaledHeight = intrinsicHeight() ? ((o->valid_rect().height()*cHeight)/intrinsicHeight()) : 0;
@@ -181,6 +188,7 @@
repaintRectangle(QRect(r.x() + borderLeft() + paddingLeft(), r.y() + borderTop() + paddingTop(),
r.width(), r.height()));
}
+#endif
}
}
@@ -351,8 +359,11 @@
KHTMLAssert(needsLayout());
KHTMLAssert( minMaxKnown() );
-#ifdef INCREMENTAL_PAINTING
- QRect oldBounds(getAbsoluteRepaintRect());
+#ifdef INCREMENTAL_REPAINTING
+ QRect oldBounds;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint)
+ oldBounds = getAbsoluteRepaintRect();
#endif
short oldwidth = m_width;
@@ -386,8 +397,9 @@
if ( m_width != oldwidth || m_height != oldheight )
resizeCache = QPixmap();
-#ifdef INCREMENTAL_PAINTING
- repaintAfterLayoutIfNeeded(oldBounds, oldBounds);
+#ifdef INCREMENTAL_REPAINTING
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldBounds);
#endif
setNeedsLayout(false);
diff --git a/WebCore/khtml/rendering/render_layer.cpp b/WebCore/khtml/rendering/render_layer.cpp
index 2aba1fb..f7dde5d 100644
--- a/WebCore/khtml/rendering/render_layer.cpp
+++ b/WebCore/khtml/rendering/render_layer.cpp
@@ -45,7 +45,7 @@
#include <kdebug.h>
#include <assert.h>
#include "khtmlview.h"
-#include "render_block.h"
+#include "render_canvas.h"
#include "render_arena.h"
#include "xml/dom_docimpl.h"
@@ -76,6 +76,10 @@
m_next( 0 ),
m_first( 0 ),
m_last( 0 ),
+#ifdef INCREMENTAL_REPAINTING
+m_relX( 0 ),
+m_relY( 0 ),
+#endif
m_x( 0 ),
m_y( 0 ),
m_width( 0 ),
@@ -105,6 +109,57 @@
delete m_negZOrderList;
}
+#ifdef INCREMENTAL_REPAINTING
+void RenderLayer::computeRepaintRects()
+{
+ // FIXME: Child object could override visibility.
+ if (m_object->style()->visibility() == VISIBLE)
+ m_object->getAbsoluteRepaintRectIncludingFloats(m_repaintRect, m_fullRepaintRect);
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ child->computeRepaintRects();
+}
+#endif
+
+#ifdef INCREMENTAL_REPAINTING
+void RenderLayer::updateLayerPositions(RenderLayer* rootLayer, bool doFullRepaint, bool checkForRepaint)
+#else
+void RenderLayer::updateLayerPositions()
+#endif
+{
+#ifdef INCREMENTAL_REPAINTING
+ if (doFullRepaint) {
+ m_object->repaint();
+ checkForRepaint = doFullRepaint = false;
+ }
+#endif
+
+ updateLayerPosition(); // For relpositioned layers or non-positioned layers,
+ // we need to keep in sync, since we may have shifted relative
+ // to our parent layer.
+
+#ifdef INCREMENTAL_REPAINTING
+ if (m_hBar || m_vBar) {
+ // Need to position the scrollbars.
+ int x = 0;
+ int y = 0;
+ convertToLayerCoords(rootLayer, x, y);
+ QRect layerBounds = QRect(x,y,width(),height());
+ positionScrollbars(layerBounds);
+ }
+
+ // FIXME: Child object could override visibility.
+ if (checkForRepaint && (m_object->style()->visibility() == VISIBLE))
+ m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_fullRepaintRect);
+#endif
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+#ifdef INCREMENTAL_REPAINTING
+ child->updateLayerPositions(rootLayer, doFullRepaint, checkForRepaint);
+#else
+ child->updateLayerPositions();
+#endif
+}
+
void RenderLayer::updateLayerPosition()
{
// The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we
@@ -126,9 +181,17 @@
}
}
+#ifdef INCREMENTAL_REPAINTING
+ m_relX = m_relY = 0;
+ if (m_object->isRelPositioned()) {
+ static_cast<RenderBox*>(m_object)->relativePositionOffset(m_relX, m_relY);
+ x += m_relX; y += m_relY;
+ }
+#else
if (m_object->isRelPositioned())
static_cast<RenderBox*>(m_object)->relativePositionOffset(x, y);
-
+#endif
+
// Subtract our parent's scroll offset.
if (parent())
parent()->subtractScrollOffset(x, y);
@@ -501,8 +564,6 @@
void
RenderLayer::checkScrollbarsAfterLayout()
{
- updateLayerPosition();
-
int rightPos = m_object->rightmostPosition();
int bottomPos = m_object->lowestPosition();
@@ -516,8 +577,8 @@
if (bottomPos - m_object->borderTop() > m_scrollHeight)
m_scrollHeight = bottomPos - m_object->borderTop();
- bool needHorizontalBar = rightPos > width();
- bool needVerticalBar = bottomPos > height();
+ bool needHorizontalBar = rightPos > m_object->overflowWidth(false);
+ bool needVerticalBar = bottomPos > m_object->overflowHeight(false);
bool haveHorizontalBar = m_hBar;
bool haveVerticalBar = m_vBar;
@@ -643,9 +704,11 @@
x - renderer()->xPos(), y - renderer()->yPos(),
PaintActionElementBackground);
+#ifndef INCREMENTAL_REPAINTING
// Position our scrollbars.
positionScrollbars(layerBounds);
-
+#endif
+
#if APPLE_CHANGES
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
// z-index. We paint after we painted the background/border, so that the scrollbars will
@@ -797,10 +860,6 @@
{
if (parent())
parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
-
- updateLayerPosition(); // For relpositioned layers or non-positioned layers,
- // we need to keep in sync, since we may have shifted relative
- // to our parent layer.
// A fixed object is essentially the root of its containing block hierarchy, so when
// we encounter such an object, we reset our clip rects to the fixedClipRect.
@@ -842,8 +901,6 @@
if (parent())
parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
- updateLayerPosition();
-
int x = 0;
int y = 0;
convertToLayerCoords(rootLayer, x, y);
diff --git a/WebCore/khtml/rendering/render_layer.h b/WebCore/khtml/rendering/render_layer.h
index 6408fd2..8d0a77f 100644
--- a/WebCore/khtml/rendering/render_layer.h
+++ b/WebCore/khtml/rendering/render_layer.h
@@ -53,6 +53,9 @@
class QScrollBar;
template <class T> class QPtrVector;
+// Uncomment to enable incremental painting
+//#define INCREMENTAL_REPAINTING 1
+
namespace khtml {
class RenderStyle;
class RenderTable;
@@ -150,6 +153,15 @@
void updateScrollPositionFromScrollbars();
void updateLayerPosition();
+#ifdef INCREMENTAL_REPAINTING
+ void updateLayerPositions(RenderLayer* rootLayer, bool doFullRepaint, bool checkForRepaint=true);
+ void computeRepaintRects();
+ void relativePositionOffset(int& relX, int& relY) {
+ relX += m_relX; relY += m_relY;
+ }
+#else
+ void updateLayerPositions();
+#endif
// Get the enclosing stacking context for this layer. A stacking context is a layer
// that has a non-auto z-index.
@@ -225,7 +237,16 @@
RenderLayer* m_first;
RenderLayer* m_last;
-
+
+#ifdef INCREMENTAL_REPAINTING
+ QRect m_repaintRect; // Cached repaint rects. Used by layout.
+ QRect m_fullRepaintRect;
+
+ // Our current relative position offset.
+ int m_relX;
+ int m_relY;
+#endif
+
// Our (x,y) coordinates are in our parent layer's coordinate space.
short m_x;
int m_y;
diff --git a/WebCore/khtml/rendering/render_list.cpp b/WebCore/khtml/rendering/render_list.cpp
index 087bddb..1f59192 100644
--- a/WebCore/khtml/rendering/render_list.cpp
+++ b/WebCore/khtml/rendering/render_list.cpp
@@ -289,6 +289,41 @@
RenderBlock::paintObject(p, _x, _y, _w, _h, _tx, _ty, paintAction);
}
+QRect RenderListItem::getAbsoluteRepaintRect()
+{
+ QRect result = RenderBlock::getAbsoluteRepaintRect();
+ if (m_marker && !m_marker->isInside()) {
+ // This can be a sloppy and imprecise offset as long as it's always too big.
+ int pixHeight = style()->htmlFont().getFontDef().computedPixelSize();
+ int offset = pixHeight*2/3;
+ int xoff = 0;
+ if (style()->direction() == LTR)
+ xoff = -7 - offset;
+ else
+ xoff = offset;
+
+ if (m_marker->listImage() && !m_marker->listImage()->isErrorImage()) {
+ // For OUTSIDE bullets shrink back to only a 0.3em margin. 0.67 em is too
+ // much. This brings the margin back to MacIE/Gecko/WinIE levels.
+ // For LTR don't forget to add in the width of the image to the offset as
+ // well (you are moving the image left, so you have to also add in the width
+ // of the image's border box as well). -dwh
+ if (style()->direction() == LTR)
+ xoff -= m_marker->listImage()->pixmap().width() - pixHeight*1/3;
+ else
+ xoff -= pixHeight*1/3;
+ }
+
+ if (xoff < 0) {
+ result.setX(result.x() + xoff);
+ result.setWidth(result.width() - xoff);
+ }
+ else
+ result.setWidth(result.width() + xoff);
+ }
+ return result;
+}
+
// -----------------------------------------------------------
RenderListMarker::RenderListMarker(DocumentImpl* document)
diff --git a/WebCore/khtml/rendering/render_list.h b/WebCore/khtml/rendering/render_list.h
index 7d80fc5..4074315 100644
--- a/WebCore/khtml/rendering/render_list.h
+++ b/WebCore/khtml/rendering/render_list.h
@@ -63,6 +63,8 @@
virtual short baselinePosition(bool b, bool isRootLineBox=false) const;
virtual bool isListMarker() const { return true; }
+
+ CachedImage* listImage() const { return m_listImage; }
RenderListItem* listItem() { return m_listItem; }
void setListItem(RenderListItem* listItem) { m_listItem = listItem; }
@@ -103,6 +105,8 @@
virtual void layout( );
virtual void calcMinMaxWidth();
+
+ virtual QRect getAbsoluteRepaintRect();
void updateMarkerLocation();
diff --git a/WebCore/khtml/rendering/render_object.cpp b/WebCore/khtml/rendering/render_object.cpp
index 2ffbf95..51f69ce 100644
--- a/WebCore/khtml/rendering/render_object.cpp
+++ b/WebCore/khtml/rendering/render_object.cpp
@@ -909,7 +909,12 @@
void RenderObject::repaint(bool immediate)
{
- RenderCanvas* c = canvas();
+ // Can't use canvas(), since we might be unrooted.
+ RenderObject* o = this;
+ while ( o->parent() ) o = o->parent();
+ if (!o->isCanvas())
+ return;
+ RenderCanvas* c = static_cast<RenderCanvas*>(o);
if (c->printingMode())
return; // Don't repaint if we're printing.
c->repaintViewRectangle(getAbsoluteRepaintRect(), immediate);
@@ -917,7 +922,12 @@
void RenderObject::repaintRectangle(const QRect& r, bool immediate)
{
- RenderCanvas* c = canvas();
+ // Can't use canvas(), since we might be unrooted.
+ RenderObject* o = this;
+ while ( o->parent() ) o = o->parent();
+ if (!o->isCanvas())
+ return;
+ RenderCanvas* c = static_cast<RenderCanvas*>(o);
if (c->printingMode())
return; // Don't repaint if we're printing.
QRect absRect(r);
@@ -928,11 +938,8 @@
#ifdef INCREMENTAL_REPAINTING
void RenderObject::repaintAfterLayoutIfNeeded(const QRect& oldBounds, const QRect& oldFullBounds)
{
- if (!isFloatingOrPositioned() && parent() && parent()->selfNeedsLayout())
- return;
-
QRect newBounds, newFullBounds;
- getAbsoluteRepaintRectIncludingDescendants(newBounds, newFullBounds);
+ getAbsoluteRepaintRectIncludingFloats(newBounds, newFullBounds);
if (newBounds != oldBounds || selfNeedsLayout()) {
RenderObject* c = canvas();
if (!c || !c->isCanvas())
@@ -946,13 +953,35 @@
}
}
-void RenderObject::repaintIfMoved(int x, int y)
+void RenderObject::repaintDuringLayoutIfMoved(int x, int y)
{
}
-void RenderObject::repaintPositionedAndFloatingDescendants()
+void RenderObject::repaintFloatingDescendants()
{
}
+
+bool RenderObject::checkForRepaintDuringLayout() const
+{
+ return !document()->view()->needsFullRepaint() && !layer();
+}
+
+void RenderObject::repaintObjectsBeforeLayout()
+{
+ if (!needsLayout())
+ return;
+
+ // FIXME: For now we just always repaint blocks with inline children, regardless of whether
+ // they're really dirty or not.
+ if (selfNeedsLayout() || (isRenderBlock() && !isTable() && normalChildNeedsLayout() && childrenInline()))
+ repaint();
+
+ for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
+ if (!current->isPositioned()) // RenderBlock subclass method handles walking the positioned objects.
+ current->repaintObjectsBeforeLayout();
+ }
+}
+
#endif
QRect RenderObject::getAbsoluteRepaintRect()
@@ -963,7 +992,7 @@
}
#ifdef INCREMENTAL_REPAINTING
-void RenderObject::getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& fullBounds)
+void RenderObject::getAbsoluteRepaintRectIncludingFloats(QRect& bounds, QRect& fullBounds)
{
bounds = fullBounds = getAbsoluteRepaintRect();
}
@@ -1342,16 +1371,6 @@
return o;
}
-#if 0 /// this method is unused
-void RenderObject::invalidateLayout()
-{
- kdDebug() << "RenderObject::invalidateLayout " << renderName() << endl;
- setNeedsLayout(true);
- if (m_parent && !m_parent->needsLayout())
- m_parent->invalidateLayout();
-}
-#endif
-
void RenderObject::removeFromObjectLists()
{
if (isFloating()) {
diff --git a/WebCore/khtml/rendering/render_object.h b/WebCore/khtml/rendering/render_object.h
index b41470d..3c30e24 100644
--- a/WebCore/khtml/rendering/render_object.h
+++ b/WebCore/khtml/rendering/render_object.h
@@ -585,10 +585,15 @@
virtual void repaintAfterLayoutIfNeeded(const QRect& oldBounds, const QRect& oldFullBounds);
// Repaint only if the object moved.
- virtual void repaintIfMoved(int oldX, int oldY);
+ virtual void repaintDuringLayoutIfMoved(int oldX, int oldY);
- // Called to repaint a block's positioned objects and floats.
- virtual void repaintPositionedAndFloatingDescendants();
+ // Called to repaint a block's floats.
+ virtual void repaintFloatingDescendants();
+
+ // Called before layout to repaint all dirty children (with selfNeedsLayout() set).
+ virtual void repaintObjectsBeforeLayout();
+
+ bool checkForRepaintDuringLayout() const;
#endif
// Returns the rect that should be repainted whenever this object changes. The rect is in the view's
@@ -596,7 +601,7 @@
virtual QRect getAbsoluteRepaintRect();
#ifdef INCREMENTAL_REPAINTING
- virtual void getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& boundsWithChildren);
+ virtual void getAbsoluteRepaintRectIncludingFloats(QRect& bounds, QRect& boundsWithChildren);
#endif
// Given a rect in the object's coordinate space, this method converts the rectangle to the view's
diff --git a/WebCore/khtml/rendering/render_table.cpp b/WebCore/khtml/rendering/render_table.cpp
index 407dc09..aa2813c 100644
--- a/WebCore/khtml/rendering/render_table.cpp
+++ b/WebCore/khtml/rendering/render_table.cpp
@@ -43,6 +43,8 @@
#include <kdebug.h>
#include <assert.h>
+#include "khtmlview.h"
+
using namespace khtml;
using namespace DOM;
@@ -220,15 +222,16 @@
setNeedsLayout(false);
return;
}
-
- //kdDebug( 6040 ) << renderName() << "(Table)"<< this << " ::layout0() width=" << width() << ", needsLayout=" << needsLayout() << endl;
#ifdef INCREMENTAL_REPAINTING
- // FIXME: We should be smarter about this, but for now just always repaint a table whenever it
- // does a layout.
- repaint();
+ QRect oldBounds, oldFullBounds;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint)
+ getAbsoluteRepaintRectIncludingFloats(oldBounds, oldFullBounds);
#endif
+ //kdDebug( 6040 ) << renderName() << "(Table)"<< this << " ::layout0() width=" << width() << ", needsLayout=" << needsLayout() << endl;
+
m_height = 0;
initMaxMarginValues();
@@ -367,9 +370,9 @@
layoutPositionedObjects( true );
#ifdef INCREMENTAL_REPAINTING
- // FIXME: We should be smarter about this, but for now just always repaint a table whenever it
- // does a layout.
- repaint();
+ // Repaint with our new bounds if they are different from our old bounds.
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldFullBounds);
#endif
setNeedsLayout(false);