* 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
This commit is contained in:
Michael Lotz
2008-06-07 23:09:21 +00:00
parent 680a35bbdb
commit f0c3c996cd
4 changed files with 105 additions and 44 deletions
+88 -39
View File
@@ -109,7 +109,9 @@ View::View(IntRect frame, IntPoint scrollingOffset, const char* name,
fLocalClipping((BRect)Bounds()), fLocalClipping((BRect)Bounds()),
fScreenClipping(), fScreenClipping(),
fScreenClippingValid(false) fScreenClippingValid(false),
fUserClipping(NULL),
fScreenAndUserClipping(NULL)
{ {
if (fDrawState) if (fDrawState)
fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 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 // move src rect to destination here for efficiency reasons
visibleSrc.OffsetBy(xOffset, yOffset); 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 // at the source and once at the destination (here done
// the other way arround but it doesn't matter) // the other way arround but it doesn't matter)
// the reason for this is that we are not supposed to visually // the reason for this is that we are not supposed to visually
// copy children in the source rect and neither to copy onto // copy children in the source rect and neither to copy onto
// children in the destination rect... // children in the destination rect...
copyRegion->Set((clipping_rect)visibleSrc); copyRegion->Set((clipping_rect)visibleSrc);
copyRegion->IntersectWith(&ScreenClipping(&windowContentClipping)); copyRegion->IntersectWith(&ScreenAndUserClipping(&windowContentClipping));
// note that fScreenClipping is used directly from hereon // note that fScreenAndUserClipping is used directly from hereon
// because it is now up to date // because it is now up to date
copyRegion->OffsetBy(-xOffset, -yOffset); copyRegion->OffsetBy(-xOffset, -yOffset);
copyRegion->IntersectWith(&fScreenClipping); copyRegion->IntersectWith(fScreenAndUserClipping);
// do the actual blit // do the actual blit
fWindow->CopyContents(copyRegion, xOffset, yOffset); fWindow->CopyContents(copyRegion, xOffset, yOffset);
@@ -1155,7 +1157,7 @@ View::CopyBits(IntRect src, IntRect dst, BRegion& windowContentClipping)
// exclude the part that we could copy // exclude the part that we could copy
dirty->Exclude(copyRegion); dirty->Exclude(copyRegion);
dirty->IntersectWith(&fScreenClipping); dirty->IntersectWith(fScreenAndUserClipping);
fWindow->MarkContentDirty(*dirty); fWindow->MarkContentDirty(*dirty);
fWindow->RecycleRegion(dirty); fWindow->RecycleRegion(dirty);
@@ -1242,7 +1244,8 @@ View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
if (fViewBitmap != NULL || fViewColor != B_TRANSPARENT_COLOR) { if (fViewBitmap != NULL || fViewColor != B_TRANSPARENT_COLOR) {
// we can only draw within our own area // we can only draw within our own area
BRegion* redraw = fWindow->GetRegion(ScreenClipping(windowContentClipping)); BRegion* redraw = fWindow->GetRegion(
_ScreenClipping(windowContentClipping));
if (!redraw) if (!redraw)
return; return;
// add the current clipping // add the current clipping
@@ -1478,7 +1481,7 @@ View::AddTokensForViewsInRegion(BMessage* message, BRegion& region,
if (!fVisible) if (!fVisible)
return; return;
if (region.Intersects(ScreenClipping(windowContentClipping).Frame())) if (region.Intersects(_ScreenClipping(windowContentClipping).Frame()))
message->AddInt32("_token", fToken); message->AddInt32("_token", fToken);
for (View* child = FirstChild(); child; child = child->NextSibling()) { 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)) if (!region.Intersects((clipping_rect)screenBounds))
return; return;
if (region.Intersects(ScreenClipping(windowContentClipping).Frame())) if (region.Intersects(_ScreenClipping(windowContentClipping).Frame()))
link.Attach<int32>(fToken); link.Attach<int32>(fToken);
for (View* child = FirstChild(); child; child = child->NextSibling()) { for (View* child = FirstChild(); child; child = child->NextSibling()) {
@@ -1525,6 +1528,19 @@ View::PrintToStream() const
printf(" fScreenClipping:\n"); printf(" fScreenClipping:\n");
fScreenClipping.PrintToStream(); fScreenClipping.PrintToStream();
printf(" valid: %d\n", fScreenClippingValid); 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(" state:\n");
printf(" user clipping: %d\n", fDrawState->HasClipping()); printf(" user clipping: %d\n", fDrawState->HasClipping());
BPoint origin = fDrawState->CombinedOrigin(); BPoint origin = fDrawState->CombinedOrigin();
@@ -1572,45 +1588,44 @@ View::RebuildClipping(bool deep)
// hand, views for which this feature is actually used will // hand, views for which this feature is actually used will
// probably not have any children, so it is not that expensive // probably not have any children, so it is not that expensive
// after all // after all
BRegion* screenUserClipping = fWindow->GetRegion(); if (fUserClipping == NULL) {
if (!screenUserClipping) fUserClipping = new (nothrow) BRegion;
return; if (fUserClipping == NULL)
fDrawState->GetCombinedClippingRegion(screenUserClipping); return;
fLocalClipping.IntersectWith(screenUserClipping); }
fWindow->RecycleRegion(screenUserClipping);
fDrawState->GetCombinedClippingRegion(fUserClipping);
} else {
delete fUserClipping;
fUserClipping = NULL;
} }
delete fScreenAndUserClipping;
fScreenAndUserClipping = NULL;
fScreenClippingValid = false; fScreenClippingValid = false;
} }
BRegion& BRegion&
View::ScreenClipping(BRegion* windowContentClipping, bool force) const View::ScreenAndUserClipping(BRegion* windowContentClipping, bool force) const
{ {
if (!fScreenClippingValid || force) { // no user clipping - return screen clipping directly
fScreenClipping = fLocalClipping; if (fUserClipping == NULL)
ConvertToScreen(&fScreenClipping); return _ScreenClipping(windowContentClipping, force);
// see if parts of our bounds are hidden underneath // combined screen and user clipping already valid
// the parent, the local clipping does not account for this if (fScreenAndUserClipping != NULL)
IntRect clippedBounds = Bounds(); return *fScreenAndUserClipping;
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); // build a new combined user and screen clipping
fScreenClippingValid = true; fScreenAndUserClipping = new (nothrow) BRegion(*fUserClipping);
} if (fScreenAndUserClipping == NULL)
//printf("###View(%s)::ScreenClipping():\n", Name()); return fScreenClipping;
//fScreenClipping.PrintToStream();
return fScreenClipping; ConvertToScreen(fScreenAndUserClipping);
fScreenAndUserClipping->IntersectWith(
&_ScreenClipping(windowContentClipping, force));
return *fScreenAndUserClipping;
} }
@@ -1633,6 +1648,8 @@ View::InvalidateScreenClipping()
// if (!fScreenClippingValid) // if (!fScreenClippingValid)
// return; // return;
delete fScreenAndUserClipping;
fScreenAndUserClipping = NULL;
fScreenClippingValid = false; fScreenClippingValid = false;
// invalidate the childrens screen clipping as well // invalidate the childrens screen clipping as well
for (View* child = FirstChild(); child; child = child->NextSibling()) { 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 void
View::_MoveScreenClipping(int32 x, int32 y, bool deep) View::_MoveScreenClipping(int32 x, int32 y, bool deep)
{ {
if (fScreenClippingValid) if (fScreenClippingValid) {
fScreenClipping.OffsetBy(x, y); fScreenClipping.OffsetBy(x, y);
delete fScreenAndUserClipping;
fScreenAndUserClipping = NULL;
}
if (deep) { if (deep) {
// move the childrens screen clipping as well // move the childrens screen clipping as well
+13 -2
View File
@@ -225,11 +225,17 @@ class View {
// clipping // clipping
void RebuildClipping(bool deep); void RebuildClipping(bool deep);
BRegion& ScreenClipping(BRegion* windowContentClipping, BRegion& ScreenAndUserClipping(
BRegion* windowContentClipping,
bool force = false) const; bool force = false) const;
void InvalidateScreenClipping(); void InvalidateScreenClipping();
inline bool IsScreenClippingValid() const inline bool IsScreenClippingValid() const
{ return fScreenClippingValid; } {
return fScreenClippingValid
&& (fUserClipping == NULL
|| (fUserClipping != NULL
&& fScreenAndUserClipping != NULL));
}
// debugging // debugging
void PrintToStream() const; void PrintToStream() const;
@@ -239,6 +245,8 @@ class View {
#endif #endif
protected: protected:
BRegion& _ScreenClipping(BRegion* windowContentClipping,
bool force = false) const;
void _MoveScreenClipping(int32 x, int32 y, void _MoveScreenClipping(int32 x, int32 y,
bool deep); bool deep);
Overlay* _Overlay() const; Overlay* _Overlay() const;
@@ -285,6 +293,9 @@ class View {
mutable BRegion fScreenClipping; mutable BRegion fScreenClipping;
mutable bool fScreenClippingValid; mutable bool fScreenClippingValid;
BRegion* fUserClipping;
mutable BRegion* fScreenAndUserClipping;
}; };
#endif // VIEW_H #endif // VIEW_H
+3 -2
View File
@@ -581,7 +581,7 @@ Window::GetEffectiveDrawingRegion(View* view, BRegion& region)
if (!fContentRegionValid) if (!fContentRegionValid)
_UpdateContentRegion(); _UpdateContentRegion();
region.IntersectWith(&view->ScreenClipping(&fContentRegion)); region.IntersectWith(&view->ScreenAndUserClipping(&fContentRegion));
} }
@@ -706,7 +706,8 @@ Window::InvalidateView(View* view, BRegion& viewRegion)
view->ConvertToScreen(&viewRegion); view->ConvertToScreen(&viewRegion);
viewRegion.IntersectWith(&VisibleContentRegion()); viewRegion.IntersectWith(&VisibleContentRegion());
if (viewRegion.CountRects() > 0) { if (viewRegion.CountRects() > 0) {
viewRegion.IntersectWith(&view->ScreenClipping(&fContentRegion)); viewRegion.IntersectWith(
&view->ScreenAndUserClipping(&fContentRegion));
//fDrawingEngine->FillRegion(viewRegion, rgb_color{ 0, 255, 0, 255 }); //fDrawingEngine->FillRegion(viewRegion, rgb_color{ 0, 255, 0, 255 });
//snooze(10000); //snooze(10000);
+1 -1
View File
@@ -325,7 +325,7 @@ WorkspacesView::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
BRegion* windowContentClipping, bool deep) BRegion* windowContentClipping, bool deep)
{ {
// we can only draw within our own area // we can only draw within our own area
BRegion redraw(ScreenClipping(windowContentClipping)); BRegion redraw(ScreenAndUserClipping(windowContentClipping));
// add the current clipping // add the current clipping
redraw.IntersectWith(effectiveClipping); redraw.IntersectWith(effectiveClipping);