[patch] further reduce redraws from resizing tables
Hi, below is another patch to reduce the redraws caused by resizing tables. A new method Layout::queueDrawExcept(), that requests the drawing of a rectangle except another rectangle is added. It is then used in widget.cc to redraw the area that was previously occupied by a widget, but is no longer occupied after a resize or move. This makes it possible to redraw less when a table resizes. All in all it should reduce the flicker a bit when loading table based pages. Cheers, Johannes diff --git a/dw/layout.cc b/dw/layout.cc --- a/dw/layout.cc +++ b/dw/layout.cc @@ -610,11 +610,36 @@ void Layout::queueDraw (int x, int y, in area.width = width; area.height = height; + if (area.isEmpty ()) return; + for (container::typed::Iterator <View> it = views->iterator (); it.hasNext (); ) { View *view = it.getNext (); view->queueDraw (&area); } +} + +void Layout::queueDrawExcept (int x, int y, int width, int height, + int ex, int ey, int ewidth, int eheight) { + + if (x == ex && y == ey && width == ewidth && height == eheight) + return; + + // queueDraw() the four rectangles within rectangle (x, y, width, height) + // around rectangle (ex, ey, ewidth, eheight). + // Some or all of these may be empty. + + // upper left corner of the intersection rectangle + int ix1 = misc::max (x, ex); + int iy1 = misc::max (y, ey); + // lower right corner of the intersection rectangle + int ix2 = misc::min (x + width, ex + ewidth); + int iy2 = misc::min (y + height, ey + eheight); + + queueDraw (x, y, width, iy1 - y); + queueDraw (x, iy2, width, y + height - iy2); + queueDraw (x, iy1, ix1 - x, iy2 - iy1); + queueDraw (ix2, iy1, x + width - ix2, iy2 - iy1); } void Layout::queueResize (bool asap) diff --git a/dw/layout.hh b/dw/layout.hh --- a/dw/layout.hh +++ b/dw/layout.hh @@ -133,6 +133,8 @@ private: void updateCursor (); void updateBgColor (); void queueDraw (int x, int y, int width, int height); + void queueDrawExcept (int x, int y, int width, int height, + int ex, int ey, int ewidth, int eheight); void queueResize (bool asap); void removeWidget (); diff --git a/dw/table.cc b/dw/table.cc --- a/dw/table.cc +++ b/dw/table.cc @@ -61,6 +61,7 @@ Table::Table(bool limitTextWidth) hasColPercent = 0; colPercents = new misc::SimpleVector <float> (8); + redrawX = 0; redrawY = 0; } @@ -191,10 +192,11 @@ void Table::sizeAllocateImpl (core::Allo void Table::resizeDrawImpl () { + queueDrawArea (redrawX, 0, allocation.width - redrawX, getHeight ()); queueDrawArea (0, redrawY, allocation.width, getHeight () - redrawY); + redrawX = allocation.width; redrawY = getHeight (); } - void Table::setWidth (int width) { diff --git a/dw/table.hh b/dw/table.hh --- a/dw/table.hh +++ b/dw/table.hh @@ -378,7 +378,7 @@ private: int numRows, numCols, curRow, curCol; misc::SimpleVector<Child*> *children; - int redrawY; + int redrawX, redrawY; /** * \brief The extremes of all columns. @@ -437,11 +437,7 @@ private: void setCumHeight (int row, int value) { if (value != cumHeight->get (row)) { - if (row > 0) { - redrawY = misc::min ( redrawY, cumHeight->get (row - 1) ); - } else { - redrawY = 0; - } + redrawY = misc::min ( redrawY, value ); cumHeight->set (row, value); } } @@ -449,7 +445,7 @@ private: inline void setColWidth (int col, int value) { if (value != colWidths->get (col)) { - redrawY = 0; + redrawX = misc::min (redrawX, value); colWidths->set (col, value); } } diff --git a/dw/types.hh b/dw/types.hh --- a/dw/types.hh +++ b/dw/types.hh @@ -71,6 +71,7 @@ public: bool intersectsWith (Rectangle *otherRect, Rectangle *dest); bool isSubsetOf (Rectangle *otherRect); bool isPointWithin (int x, int y); + bool isEmpty () { return width <= 0 || height <= 0; }; }; /** diff --git a/dw/widget.cc b/dw/widget.cc --- a/dw/widget.cc +++ b/dw/widget.cc @@ -418,6 +418,18 @@ void Widget::sizeAllocate (Allocation *a // widget->allocation.x, widget->allocation.y, // widget->allocation.width, widget->allocation.ascent, // widget->allocation.descent); + + if (wasAllocated ()) { + layout->queueDrawExcept ( + this->allocation.x, + this->allocation.y, + this->allocation.width, + this->allocation.ascent + this->allocation.descent, + allocation->x, + allocation->y, + allocation->width, + allocation->ascent + allocation->descent); + } sizeAllocateImpl (allocation);
Hi Johannes, On Tue, Mar 11, 2008 at 07:27:01PM +0100, Johannes Hofmann wrote:
Hi,
below is another patch to reduce the redraws caused by resizing tables. A new method Layout::queueDrawExcept(), that requests the drawing of a rectangle except another rectangle is added. It is then used in widget.cc to redraw the area that was previously occupied by a widget, but is no longer occupied after a resize or move. This makes it possible to redraw less when a table resizes. All in all it should reduce the flicker a bit when loading table based pages.
On the topic of reducing the flicker, I'm far of an expert and please correct me if I'm wrong. AFAIU, the current design draws the background color before the widget content. This is: if you have an html page as big table, in dillo, it will become a table inside a textblock. When the textblock is asked to redraw, it will _erase_ the table with its background color and ask its child (the table) to redraw. Causing flicker. If this is true, a big gain could come from a different approach: just draw the surroundings of the widgets and ask the child widgets to redraw. This way widgets aren't erased beforehand, and can also decide not to redraw themselves when nothing has changed. I have worked a bit on this idea, and the attached patch mocks the idea hackishly. It draws the "padding" area of the CSS box (see the picture in namespacedw_1_1core_1_1style.html in dw docs) Please give it a review and share your comments, corrections and thoughts. -- Cheers Jorge.-
Hi Jorge, On Fri, Mar 14, 2008 at 06:53:08PM -0400, Jorge Arellano Cid wrote:
Hi Johannes,
On Tue, Mar 11, 2008 at 07:27:01PM +0100, Johannes Hofmann wrote:
Hi,
below is another patch to reduce the redraws caused by resizing tables. A new method Layout::queueDrawExcept(), that requests the drawing of a rectangle except another rectangle is added. It is then used in widget.cc to redraw the area that was previously occupied by a widget, but is no longer occupied after a resize or move. This makes it possible to redraw less when a table resizes. All in all it should reduce the flicker a bit when loading table based pages.
On the topic of reducing the flicker, I'm far of an expert and please correct me if I'm wrong. AFAIU, the current design draws the background color before the widget content.
This is: if you have an html page as big table, in dillo, it will become a table inside a textblock. When the textblock is asked to redraw, it will _erase_ the table with its background color and ask its child (the table) to redraw. Causing flicker.
Yes, that's true. In addition, before anything is drawn, the rectangle to be drawn is already cleared with the background color in FltkViewBase::draw() (the fillrect () calls).
If this is true, a big gain could come from a different approach: just draw the surroundings of the widgets and ask the child widgets to redraw.
This way widgets aren't erased beforehand, and can also decide not to redraw themselves when nothing has changed.
I have worked a bit on this idea, and the attached patch mocks the idea hackishly. It draws the "padding" area of the CSS box (see the picture in namespacedw_1_1core_1_1style.html in dw docs)
Please give it a review and share your comments, corrections and thoughts.
I've been thinking about something similar as well, but I don't think it will work out generally. The main problem is text drawing and maybe transparent widgets (don't know whether they exist already). Anyway, for drawing text, you need to erase the area first. Just comment out the fillrect () calls in FltkViewBase::draw() to see what I mean :-) Therefore, we will always have flicker, when drawing text. The good news is that all the flicker can be avoided easily with some double buffering technique. And from dillo1 we even know that this is not necessarily slow :-) So for me the flicker itself is not that much of a problem. It may be an indicator for unnecessary redraws, which should be avoided to save CPU power. But I think current cvs is already pretty good in this regard. So I would propose to start to think about efficient double buffering similar to what I had posted in http://lists.auriga.wearlab.de/pipermail/dillo-dev/2007-November/003379.html but platform independent using fltk2 support. Cheers, Johannes
Hi, On Sat, Mar 15, 2008 at 07:58:34PM +0100, Johannes Hofmann wrote:
Hi Jorge,
On Fri, Mar 14, 2008 at 06:53:08PM -0400, Jorge Arellano Cid wrote:
Hi Johannes,
On Tue, Mar 11, 2008 at 07:27:01PM +0100, Johannes Hofmann wrote:
Hi,
below is another patch to reduce the redraws caused by resizing tables. A new method Layout::queueDrawExcept(), that requests the drawing of a rectangle except another rectangle is added. It is then used in widget.cc to redraw the area that was previously occupied by a widget, but is no longer occupied after a resize or move. This makes it possible to redraw less when a table resizes. All in all it should reduce the flicker a bit when loading table based pages.
On the topic of reducing the flicker, I'm far of an expert and please correct me if I'm wrong. AFAIU, the current design draws the background color before the widget content.
This is: if you have an html page as big table, in dillo, it will become a table inside a textblock. When the textblock is asked to redraw, it will _erase_ the table with its background color and ask its child (the table) to redraw. Causing flicker.
Yes, that's true. In addition, before anything is drawn, the rectangle to be drawn is already cleared with the background color in FltkViewBase::draw() (the fillrect () calls).
Oh, I haven't noticed those calls.
If this is true, a big gain could come from a different approach: just draw the surroundings of the widgets and ask the child widgets to redraw.
This way widgets aren't erased beforehand, and can also decide not to redraw themselves when nothing has changed.
I have worked a bit on this idea, and the attached patch mocks the idea hackishly. It draws the "padding" area of the CSS box (see the picture in namespacedw_1_1core_1_1style.html in dw docs)
Please give it a review and share your comments, corrections and thoughts.
I've been thinking about something similar as well, but I don't think it will work out generally. The main problem is text drawing and maybe transparent widgets (don't know whether they exist already).
Probably drawing text over a background image qualifies as "transparent text widget".
Anyway, for drawing text, you need to erase the area first. Just comment out the fillrect () calls in FltkViewBase::draw() to see what I mean :-)
Yes, I did. Quite clear example.
Therefore, we will always have flicker, when drawing text.
The good news is that all the flicker can be avoided easily with some double buffering technique. And from dillo1 we even know that this is not necessarily slow :-)
So for me the flicker itself is not that much of a problem. It may be an indicator for unnecessary redraws, which should be avoided to save CPU power. But I think current cvs is already pretty good in this regard.
That makes me happy, because since the queueDrawExcept() patch, flickering has reduced even more. I'm yet to test on a slow system though.
So I would propose to start to think about efficient double buffering similar to what I had posted in http://lists.auriga.wearlab.de/pipermail/dillo-dev/2007-November/003379.html but platform independent using fltk2 support.
Sure, and we still have the reosurce of tunning the refresh rate as in formerly proposed patches. I agree with your proposal. And if someday (soon I hope) we start working together with the FLTK guys, they will have lots of advice on how to tune things up. -- Cheers Jorge.-
On Tue, Mar 11, 2008 at 07:27:01PM +0100, Johannes Hofmann wrote:
Hi,
below is another patch to reduce the redraws caused by resizing tables. A new method Layout::queueDrawExcept(), that requests the drawing of a rectangle except another rectangle is added. It is then used in widget.cc to redraw the area that was previously occupied by a widget, but is no longer occupied after a resize or move. This makes it possible to redraw less when a table resizes. All in all it should reduce the flicker a bit when loading table based pages.
Committed! -- Cheers Jorge.-
participants (2)
-
jcid@dillo.org
-
Johannes.Hofmann@gmx.de