From f87dbaaa4efcabdc03de04e6594d0d73d27a3603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 13 Sep 2016 15:41:51 +0200 Subject: [PATCH] [Escher] handle redrawing of overlapping sister views Change-Id: I974c77f644834807bb206666748d2392c22fc516 --- escher/include/escher/view.h | 3 ++- escher/src/view.cpp | 52 ++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/escher/include/escher/view.h b/escher/include/escher/view.h index ada2f98c5..ccf45bb40 100644 --- a/escher/include/escher/view.h +++ b/escher/include/escher/view.h @@ -60,9 +60,10 @@ private: virtual View * subviewAtIndex(int index) = 0; virtual void layoutSubviews() = 0; virtual const Window * window() const; - void redraw(KDRect rect); + KDRect redraw(KDRect rect, KDRect forceRedrawRect = KDRectZero); KDPoint absoluteOrigin() const; KDRect absoluteVisibleFrame() const; + //KDRect areaNeedingRedraw() const; View * m_superview; KDRect m_dirtyRect; diff --git a/escher/src/view.cpp b/escher/src/view.cpp index 6f2f8aede..6a5cd662a 100644 --- a/escher/src/view.cpp +++ b/escher/src/view.cpp @@ -27,15 +27,32 @@ void View::markRectAsDirty(KDRect rect) { m_dirtyRect = m_dirtyRect.unionedWith(rect); } -void View::redraw(KDRect rect) { +KDRect View::redraw(KDRect rect, KDRect forceRedrawRect) { + /* View::redraw recursively redraws the rectangle 'rect' of the view and all + * its subviews. + * To optimize the function, we redraw only the union of the current dirty + * rectangle with a rectangle forced to be redrawn (forceRedrawRect). This + * rectangle is initially empty and recursively expands by unioning with the + * rectangles that are redrawn. This process handles the case when several + * sister views are overlapping (provided that the sister views are indexed in + * the right order). + */ if (window() == nullptr) { /* That view (and all of its subviews) is offscreen. That means so are all * of its subviews. So there's no point in drawing them. */ - return; + return KDRectZero; } - // First, let's draw our own content by calling drawRect - KDRect rectNeedingRedraw = rect.intersectedWith(m_dirtyRect); + /* First, for the current view, the rectangle to redraw is the union of the + * dirty rectangle and the rectangle forced to be redrawn. The rectangle to + * redraw must also be included in the current view bounds and in the + * rectangle rect. */ + KDRect rectNeedingRedraw = rect + .intersectedWith(m_dirtyRect) + .unionedWith(forceRedrawRect + .intersectedWith(bounds())); + + // This redraws the rectNeedingRedraw calling drawRect. if (!rectNeedingRedraw.isEmpty()) { KDPoint absOrigin = absoluteOrigin(); KDRect absRect = rectNeedingRedraw.translatedBy(absOrigin); @@ -45,6 +62,8 @@ void View::redraw(KDRect rect) { ctx->setClippingRect(absClippingRect); this->drawRect(ctx, rectNeedingRedraw); } + // This initiates the area that has been redrawn. + KDRect redrawnArea = rectNeedingRedraw; // Then, let's recursively draw our children over ourself for (uint8_t i=0; im_superview == this); - if (rect.intersects(subview->m_frame)) { - KDRect intersection = rect.intersectedWith(subview->m_frame); - // Let's express intersection in subview's coordinates - intersection = intersection.translatedBy(subview->m_frame.origin().opposite()); - subview->redraw(intersection); - } - } + // We transpose rect and forcedRedrawArea in the subview coordinates. + KDRect intersectionInSubview = rect + .intersectedWith(subview->m_frame) + .translatedBy(subview->m_frame.origin().opposite()); + KDRect forcedRedrawAreaInSubview = redrawnArea + .translatedBy(subview->m_frame.origin().opposite()); + // We redraw the current subview by passing the rectangle previously redrawn + // (by the parent view or previous sister views) as forced to be redraw. + KDRect subviewRedrawnArea = + subview->redraw(intersectionInSubview, forcedRedrawAreaInSubview); + + // We expand the redrawn area to include the area just drawn. + redrawnArea = redrawnArea.unionedWith(subviewRedrawnArea.translatedBy(subview->m_frame.origin())); + } // Eventually, mark that we don't need to be redrawn m_dirtyRect = KDRectZero; + + // The function returns the total area that have been redrawn. + return redrawnArea; } View * View::subview(int index) { @@ -95,6 +124,7 @@ void View::setFrame(KDRect frame) { * can either mark an area of our superview as dirty, or mark our whole frame * as dirty. We pick the second option because it is more efficient. */ markRectAsDirty(bounds()); + // FIXME: m_dirtyRect = bounds(); would be more correct (in case the view is being shrinked) layoutSubviews(); }