From f0c3c996cd92350f083210e5cc0d161abbbc3aa1 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 7 Jun 2008 23:09:21 +0000 Subject: [PATCH] * Decouple local and user clipping into normal local clipping and a user clipping region pointer. * Provide _ScreenClipping() that only includes local and screen clipping but not user clipping. * Provide ScreenAndUserClipping() that returns screen clipping if no user clipping is present, or returns a combined region that is then cached. * Adapt all places where the former methods are used and decide which one to use depending on the relevance of user clipping. User clipping is now ignored for background clearing and when determining whether or not to call Draw() on a view. This should make Haiku behaviourally compatible with BeOS (confirmed by the ClippingAndRedraw test app) and should also fix the Firefox redraw issues. Stephan please review! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25854 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/View.cpp | 127 ++++++++++++++++++++--------- src/servers/app/View.h | 15 +++- src/servers/app/Window.cpp | 5 +- src/servers/app/WorkspacesView.cpp | 2 +- 4 files changed, 105 insertions(+), 44 deletions(-) diff --git a/src/servers/app/View.cpp b/src/servers/app/View.cpp index 081c0a6bc7..546ca2cac4 100644 --- a/src/servers/app/View.cpp +++ b/src/servers/app/View.cpp @@ -109,7 +109,9 @@ View::View(IntRect frame, IntPoint scrollingOffset, const char* name, fLocalClipping((BRect)Bounds()), fScreenClipping(), - fScreenClippingValid(false) + fScreenClippingValid(false), + fUserClipping(NULL), + fScreenAndUserClipping(NULL) { if (fDrawState) fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); @@ -1121,19 +1123,19 @@ View::CopyBits(IntRect src, IntRect dst, BRegion& windowContentClipping) // move src rect to destination here for efficiency reasons visibleSrc.OffsetBy(xOffset, yOffset); - // we need to interstect the copyRegion too times, onces + // we need to interstect the copyRegion two times, onces // at the source and once at the destination (here done // the other way arround but it doesn't matter) // the reason for this is that we are not supposed to visually // copy children in the source rect and neither to copy onto // children in the destination rect... copyRegion->Set((clipping_rect)visibleSrc); - copyRegion->IntersectWith(&ScreenClipping(&windowContentClipping)); - // note that fScreenClipping is used directly from hereon + copyRegion->IntersectWith(&ScreenAndUserClipping(&windowContentClipping)); + // note that fScreenAndUserClipping is used directly from hereon // because it is now up to date copyRegion->OffsetBy(-xOffset, -yOffset); - copyRegion->IntersectWith(&fScreenClipping); + copyRegion->IntersectWith(fScreenAndUserClipping); // do the actual blit fWindow->CopyContents(copyRegion, xOffset, yOffset); @@ -1155,7 +1157,7 @@ View::CopyBits(IntRect src, IntRect dst, BRegion& windowContentClipping) // exclude the part that we could copy dirty->Exclude(copyRegion); - dirty->IntersectWith(&fScreenClipping); + dirty->IntersectWith(fScreenAndUserClipping); fWindow->MarkContentDirty(*dirty); fWindow->RecycleRegion(dirty); @@ -1242,7 +1244,8 @@ View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, if (fViewBitmap != NULL || fViewColor != B_TRANSPARENT_COLOR) { // we can only draw within our own area - BRegion* redraw = fWindow->GetRegion(ScreenClipping(windowContentClipping)); + BRegion* redraw = fWindow->GetRegion( + _ScreenClipping(windowContentClipping)); if (!redraw) return; // add the current clipping @@ -1478,7 +1481,7 @@ View::AddTokensForViewsInRegion(BMessage* message, BRegion& region, if (!fVisible) return; - if (region.Intersects(ScreenClipping(windowContentClipping).Frame())) + if (region.Intersects(_ScreenClipping(windowContentClipping).Frame())) message->AddInt32("_token", fToken); for (View* child = FirstChild(); child; child = child->NextSibling()) { @@ -1500,7 +1503,7 @@ View::AddTokensForViewsInRegion(BPrivate::PortLink& link, BRegion& region, if (!region.Intersects((clipping_rect)screenBounds)) return; - if (region.Intersects(ScreenClipping(windowContentClipping).Frame())) + if (region.Intersects(_ScreenClipping(windowContentClipping).Frame())) link.Attach(fToken); for (View* child = FirstChild(); child; child = child->NextSibling()) { @@ -1525,6 +1528,19 @@ View::PrintToStream() const printf(" fScreenClipping:\n"); fScreenClipping.PrintToStream(); printf(" valid: %d\n", fScreenClippingValid); + + printf(" fUserClipping:\n"); + if (fUserClipping != NULL) + fUserClipping->PrintToStream(); + else + printf(" none\n"); + + printf(" fScreenAndUserClipping:\n"); + if (fScreenAndUserClipping != NULL) + fScreenAndUserClipping->PrintToStream(); + else + printf(" invalid\n"); + printf(" state:\n"); printf(" user clipping: %d\n", fDrawState->HasClipping()); BPoint origin = fDrawState->CombinedOrigin(); @@ -1572,45 +1588,44 @@ View::RebuildClipping(bool deep) // hand, views for which this feature is actually used will // probably not have any children, so it is not that expensive // after all - BRegion* screenUserClipping = fWindow->GetRegion(); - if (!screenUserClipping) - return; - fDrawState->GetCombinedClippingRegion(screenUserClipping); - fLocalClipping.IntersectWith(screenUserClipping); - fWindow->RecycleRegion(screenUserClipping); + if (fUserClipping == NULL) { + fUserClipping = new (nothrow) BRegion; + if (fUserClipping == NULL) + return; + } + + fDrawState->GetCombinedClippingRegion(fUserClipping); + } else { + delete fUserClipping; + fUserClipping = NULL; } + delete fScreenAndUserClipping; + fScreenAndUserClipping = NULL; fScreenClippingValid = false; } BRegion& -View::ScreenClipping(BRegion* windowContentClipping, bool force) const +View::ScreenAndUserClipping(BRegion* windowContentClipping, bool force) const { - if (!fScreenClippingValid || force) { - fScreenClipping = fLocalClipping; - ConvertToScreen(&fScreenClipping); + // no user clipping - return screen clipping directly + if (fUserClipping == NULL) + return _ScreenClipping(windowContentClipping, force); - // see if parts of our bounds are hidden underneath - // the parent, the local clipping does not account for this - IntRect clippedBounds = Bounds(); - ConvertToVisibleInTopView(&clippedBounds); - if (clippedBounds.Width() < fScreenClipping.Frame().Width() - || clippedBounds.Height() < fScreenClipping.Frame().Height()) { - BRegion* temp = fWindow->GetRegion(); - if (temp) { - temp->Set((clipping_rect)clippedBounds); - fScreenClipping.IntersectWith(temp); - fWindow->RecycleRegion(temp); - } - } + // combined screen and user clipping already valid + if (fScreenAndUserClipping != NULL) + return *fScreenAndUserClipping; - fScreenClipping.IntersectWith(windowContentClipping); - fScreenClippingValid = true; - } -//printf("###View(%s)::ScreenClipping():\n", Name()); -//fScreenClipping.PrintToStream(); - return fScreenClipping; + // build a new combined user and screen clipping + fScreenAndUserClipping = new (nothrow) BRegion(*fUserClipping); + if (fScreenAndUserClipping == NULL) + return fScreenClipping; + + ConvertToScreen(fScreenAndUserClipping); + fScreenAndUserClipping->IntersectWith( + &_ScreenClipping(windowContentClipping, force)); + return *fScreenAndUserClipping; } @@ -1633,6 +1648,8 @@ View::InvalidateScreenClipping() // if (!fScreenClippingValid) // return; + delete fScreenAndUserClipping; + fScreenAndUserClipping = NULL; fScreenClippingValid = false; // invalidate the childrens screen clipping as well for (View* child = FirstChild(); child; child = child->NextSibling()) { @@ -1641,11 +1658,43 @@ View::InvalidateScreenClipping() } +BRegion& +View::_ScreenClipping(BRegion* windowContentClipping, bool force) const +{ + if (!fScreenClippingValid || force) { + fScreenClipping = fLocalClipping; + ConvertToScreen(&fScreenClipping); + + // see if parts of our bounds are hidden underneath + // the parent, the local clipping does not account for this + IntRect clippedBounds = Bounds(); + ConvertToVisibleInTopView(&clippedBounds); + if (clippedBounds.Width() < fScreenClipping.Frame().Width() + || clippedBounds.Height() < fScreenClipping.Frame().Height()) { + BRegion* temp = fWindow->GetRegion(); + if (temp) { + temp->Set((clipping_rect)clippedBounds); + fScreenClipping.IntersectWith(temp); + fWindow->RecycleRegion(temp); + } + } + + fScreenClipping.IntersectWith(windowContentClipping); + fScreenClippingValid = true; + } + + return fScreenClipping; +} + + void View::_MoveScreenClipping(int32 x, int32 y, bool deep) { - if (fScreenClippingValid) + if (fScreenClippingValid) { fScreenClipping.OffsetBy(x, y); + delete fScreenAndUserClipping; + fScreenAndUserClipping = NULL; + } if (deep) { // move the childrens screen clipping as well diff --git a/src/servers/app/View.h b/src/servers/app/View.h index 42abbac8cb..f2157b6bb9 100644 --- a/src/servers/app/View.h +++ b/src/servers/app/View.h @@ -225,11 +225,17 @@ class View { // clipping void RebuildClipping(bool deep); - BRegion& ScreenClipping(BRegion* windowContentClipping, + BRegion& ScreenAndUserClipping( + BRegion* windowContentClipping, bool force = false) const; void InvalidateScreenClipping(); inline bool IsScreenClippingValid() const - { return fScreenClippingValid; } + { + return fScreenClippingValid + && (fUserClipping == NULL + || (fUserClipping != NULL + && fScreenAndUserClipping != NULL)); + } // debugging void PrintToStream() const; @@ -239,6 +245,8 @@ class View { #endif protected: + BRegion& _ScreenClipping(BRegion* windowContentClipping, + bool force = false) const; void _MoveScreenClipping(int32 x, int32 y, bool deep); Overlay* _Overlay() const; @@ -285,6 +293,9 @@ class View { mutable BRegion fScreenClipping; mutable bool fScreenClippingValid; + + BRegion* fUserClipping; + mutable BRegion* fScreenAndUserClipping; }; #endif // VIEW_H diff --git a/src/servers/app/Window.cpp b/src/servers/app/Window.cpp index 52a96d138c..2ee518314b 100644 --- a/src/servers/app/Window.cpp +++ b/src/servers/app/Window.cpp @@ -581,7 +581,7 @@ Window::GetEffectiveDrawingRegion(View* view, BRegion& region) if (!fContentRegionValid) _UpdateContentRegion(); - region.IntersectWith(&view->ScreenClipping(&fContentRegion)); + region.IntersectWith(&view->ScreenAndUserClipping(&fContentRegion)); } @@ -706,7 +706,8 @@ Window::InvalidateView(View* view, BRegion& viewRegion) view->ConvertToScreen(&viewRegion); viewRegion.IntersectWith(&VisibleContentRegion()); if (viewRegion.CountRects() > 0) { - viewRegion.IntersectWith(&view->ScreenClipping(&fContentRegion)); + viewRegion.IntersectWith( + &view->ScreenAndUserClipping(&fContentRegion)); //fDrawingEngine->FillRegion(viewRegion, rgb_color{ 0, 255, 0, 255 }); //snooze(10000); diff --git a/src/servers/app/WorkspacesView.cpp b/src/servers/app/WorkspacesView.cpp index 336cba536d..20500bb94a 100644 --- a/src/servers/app/WorkspacesView.cpp +++ b/src/servers/app/WorkspacesView.cpp @@ -325,7 +325,7 @@ WorkspacesView::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, BRegion* windowContentClipping, bool deep) { // we can only draw within our own area - BRegion redraw(ScreenClipping(windowContentClipping)); + BRegion redraw(ScreenAndUserClipping(windowContentClipping)); // add the current clipping redraw.IntersectWith(effectiveClipping);