* 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

View File

@ -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<int32>(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)
if (fUserClipping == NULL) {
fUserClipping = new (nothrow) BRegion;
if (fUserClipping == NULL)
return;
fDrawState->GetCombinedClippingRegion(screenUserClipping);
fLocalClipping.IntersectWith(screenUserClipping);
fWindow->RecycleRegion(screenUserClipping);
}
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();
// 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

View File

@ -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

View File

@ -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);

View File

@ -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);