From d41a1e80b8bab52b8cb07aba5320399970d37cd3 Mon Sep 17 00:00:00 2001 From: Adi Oanca Date: Wed, 15 Jun 2005 20:36:43 +0000 Subject: [PATCH] Integrated the new clipping code. It compiles but it does not work yet. Do not worry, it's guarded by a #define :-) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13161 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/Layer.cpp | 465 +++++++++++++++++++++++++++++++++- src/servers/app/Layer.h | 31 +++ src/servers/app/WinBorder.cpp | 57 ++++- src/servers/app/WinBorder.h | 15 ++ 4 files changed, 561 insertions(+), 7 deletions(-) diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp index b784744a13..bf715adb1c 100644 --- a/src/servers/app/Layer.cpp +++ b/src/servers/app/Layer.cpp @@ -271,6 +271,10 @@ Layer::RemoveChild(Layer *layer) layer->fUpperSibling = NULL; layer->fLowerSibling = NULL; +#ifdef NEW_CLIPPING + layer->clear_visible_regions(); +#endif + // 2) Iterate over all of the removed-layer's descendants and unset the // root layer, server window, and all redraw-related regions @@ -924,12 +928,11 @@ Layer::IsHidden(void) const { if (fHidden) return true; - else { - if (fParent) + + if (fParent) return fParent->IsHidden(); - } - return false; + return fHidden; } @@ -1564,7 +1567,8 @@ Layer::ConvertToScreen2(BRect* rect) const { if (GetRootLayer()) if (fParent) { - rect->OffsetBy(-fOrigin.x, -fOrigin.y); + BPoint origin = BoundsOrigin(); + rect->OffsetBy(-origin.x, -origin.y); rect->OffsetBy(fFrame.left, fFrame.top); fParent->ConvertToScreen2(rect); @@ -1576,11 +1580,460 @@ Layer::ConvertToScreen2(BRegion* reg) const { if (GetRootLayer()) if (fParent) { - reg->OffsetBy(-fOrigin.x, -fOrigin.y); + BPoint origin = BoundsOrigin(); + reg->OffsetBy(-origin.x, -origin.y); reg->OffsetBy(fFrame.left, fFrame.top); fParent->ConvertToScreen2(reg); } } + +void +Layer::do_Hide() +{ + fHidden = true; + + if (fParent && !fParent->IsHidden() && GetRootLayer()) { + // save fullVisible so we know what to invalidate + BRegion invalid(fFullVisible); + + clear_visible_regions(); + + if (invalid.Frame().IsValid()) + fParent->do_Invalidate(invalid, this); + } +} + +void +Layer::do_Show() +{ + fHidden = false; + + if (fParent && !fParent->IsHidden() && GetRootLayer()) { + BRegion invalid; + + get_user_regions(invalid); + + if (invalid.CountRects() > 0) + fParent->do_Invalidate(invalid, this); + } +} + +void +Layer::do_Invalidate(const BRegion &invalid, const Layer *startFrom) +{ + BRegion localVisible(fFullVisible); + localVisible.IntersectWith(&invalid); + rebuild_visible_regions(invalid, localVisible, + startFrom? startFrom: BottomChild()); + + // add localVisible to our RootLayer's redraw region. + GetRootLayer()->fRedrawReg.Include(&localVisible); +// TODO: --- + GetRootLayer()->RequestDraw(GetRootLayer()->fRedrawReg, BottomChild()); +// GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? +} + +inline void +Layer::resize_layer_frame_by(float x, float y) +{ + uint16 rm = fResizeMode & 0x0000FFFF; + BRect newFrame = fFrame; + + if ((rm & 0x0F00U) == _VIEW_LEFT_ << 8) + newFrame.left += 0.0f; + else if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8) + newFrame.left += x; + else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8) + newFrame.left += x/2; + + if ((rm & 0x000FU) == _VIEW_LEFT_) + newFrame.right += 0.0f; + else if ((rm & 0x000FU) == _VIEW_RIGHT_) + newFrame.right += x; + else if ((rm & 0x000FU) == _VIEW_CENTER_) + newFrame.right += x/2; + + if ((rm & 0xF000U) == _VIEW_TOP_ << 12) + newFrame.top += 0.0f; + else if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12) + newFrame.top += y; + else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12) + newFrame.top += y/2; + + if ((rm & 0x00F0U) == _VIEW_TOP_ << 4) + newFrame.bottom += 0.0f; + else if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4) + newFrame.bottom += y; + else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4) + newFrame.bottom += y/2; + + if (newFrame != fFrame) { + float dx, dy; + + dx = newFrame.Width() - fFrame.Width(); + dy = newFrame.Height() - fFrame.Height(); + + fFrame = newFrame; + + if (dx != 0.0f || dy != 0.0f) { + // call hook function + ResizedByHook(dx, dy, true); // automatic + + for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) + lay->resize_layer_frame_by(dx, dy); + } + else + MovedByHook(dx, dy); + } +} + +inline void +Layer::rezize_layer_redraw_more(BRegion ®, float dx, float dy) +{ + if (dx == 0 && dy == 0) + return; + + for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) { + uint16 rm = lay->fResizeMode & 0x0000FFFF; + + if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) { + // NOTE: this is not exactly corect, but it works :-) + // Normaly we shoud've used the lay's old, required region - the one returned + // from get_user_region() with the old frame, and the current one. lay->Bounds() + // works for the moment so we leave it like this. + + // calculate the old bounds. + BRect oldBounds(lay->Bounds()); + if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT) + oldBounds.right -=dx; + if ((rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) + oldBounds.bottom -=dy; + + // compute the region that became visible because we got bigger OR smaller. + BRegion regZ(lay->Bounds()); + regZ.Include(oldBounds); + regZ.Exclude(oldBounds&lay->Bounds()); + + lay->ConvertToScreen2(®Z); + + // intersect that with this'(not lay's) fullVisible region + regZ.IntersectWith(&fFullVisible); + reg.Include(®Z); + + lay->rezize_layer_redraw_more(reg, + (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0, + (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0); + + // above, OR this: + // reg.Include(&lay->fFullVisible); + } + else + if (((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0) || + ((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0) || + ((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0)|| + ((rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER && dy != 0)) + { + reg.Include(&lay->fFullVisible); + } + } +} + +inline void +Layer::resize_layer_full_update_on_resize(BRegion ®, float dx, float dy) +{ + if (dx == 0 && dy == 0) + return; + + for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) { + uint16 rm = lay->fResizeMode & 0x0000FFFF; + + if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) { + if (lay->fFlags & B_FULL_UPDATE_ON_RESIZE && lay->fVisible.CountRects() > 0) + reg.Include(&lay->fVisible); + + lay->resize_layer_full_update_on_resize(reg, + (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0, + (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0); + } + } +} + +void +Layer::do_ResizeBy(float dx, float dy) +{ + fFrame.Set(fFrame.left, fFrame.top, fFrame.right+dx, fFrame.bottom+dy); + + // resize children using their resize_mask. + for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) + lay->resize_layer_frame_by(dx, dy); + + // call hook function + if (dx != 0.0f || dy != 0.0f) + ResizedByHook(dx, dy, false); // manual + + if (!IsHidden() && GetRootLayer()) { + BRegion oldFullVisible(fFullVisible); + // this is required to invalidate the old border + BRegion oldVisible(fVisible); + + // in case they moved, bottom, right and center aligned layers must be redrawn + BRegion redrawMore; + rezize_layer_redraw_more(redrawMore, dx, dy); + + // we'll invalidate the old area and the new, maxmial one. + BRegion invalid; + get_user_regions(invalid); + invalid.Include(&fFullVisible); + + clear_visible_regions(); + + fParent->do_RebuildVisibleRegions(invalid, this); + + // done rebuilding regions, now redraw regions that became visible + + // what's invalid, are the differences between to old and the new fullVisible region + // 1) in case we grow. + BRegion redrawReg(fFullVisible); + redrawReg.Exclude(&oldFullVisible); + // 2) in case we shrink + BRegion redrawReg2(oldFullVisible); + redrawReg2.Exclude(&fFullVisible); + // 3) combine. + redrawReg.Include(&redrawReg2); + + // for center, right and bottom alligned layers, redraw their old positions + redrawReg.Include(&redrawMore); + + // layers that had their frame modified must be entirely redrawn. + rezize_layer_redraw_more(redrawReg, dx, dy); + + // add redrawReg to our RootLayer's redraw region. + GetRootLayer()->fRedrawReg.Include(&redrawReg); + // include layer's visible region in case we want a full update on resize + if (fFlags & B_FULL_UPDATE_ON_RESIZE && fVisible.Frame().IsValid()) { + resize_layer_full_update_on_resize(GetRootLayer()->fRedrawReg, dx, dy); + + GetRootLayer()->fRedrawReg.Include(&fVisible); + GetRootLayer()->fRedrawReg.Include(&oldVisible); + } + // clear canvas and set invalid regions for affected WinBorders +// TODO: --- + GetRootLayer()->RequestDraw(GetRootLayer()->fRedrawReg, BottomChild()); +// GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? + } +} + +void Layer::do_MoveBy(float dx, float dy) +{ + if (dx == 0.0f && dy == 0.0f) + return; + +// fFrame.Set(fFrame.left+dx, fFrame.top+dy, fFrame.right+dx, fFrame.bottom+dy); + fFrame.OffsetBy(dx, dy); + + // call hook function + MovedByHook(dx, dy); + + if (!IsHidden() && GetRootLayer()) { + BRegion oldFullVisible(fFullVisible); + + // we'll invalidate the old position and the new, maxmial one. + BRegion invalid; + get_user_regions(invalid); + invalid.Include(&fFullVisible); + + clear_visible_regions(); + + fParent->do_RebuildVisibleRegions(invalid, this); + + // done rebuilding regions, now copy common parts and redraw regions that became visible + + // include the actual and the old fullVisible regions. later, we'll exclude the common parts. + BRegion redrawReg(fFullVisible); + redrawReg.Include(&oldFullVisible); + + // offset to layer's new location so that we can calculate the common region. + oldFullVisible.OffsetBy(dx, dy); + + // finally we have the region that needs to be redrawn. + redrawReg.Exclude(&oldFullVisible); + + // by intersecting the old fullVisible offseted to layer's new location, with the current + // fullVisible, we'll have the common region which can be copied using HW acceleration. + oldFullVisible.IntersectWith(&fFullVisible); + + // offset back and instruct the HW to do the actual copying. + oldFullVisible.OffsetBy(-dx, -dy); +// TODO: uncomment!!! +// GetRootLayer()->CopyRegion(&oldFullVisible, dx, dy); + + // add redrawReg to our RootLayer's redraw region. + GetRootLayer()->fRedrawReg.Include(&redrawReg); +// TODO: --- + GetRootLayer()->RequestDraw(GetRootLayer()->fRedrawReg, BottomChild()); +// GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? + } +} + +void +Layer::do_ScrollBy(float dx, float dy) +{ + fLayerData->OffsetOrigin(BPoint(dx, dy)); +// fOrigin.Set(fOrigin.x + dx, fOrigin.y + dy); + + if (!IsHidden() && GetRootLayer()) { + // set the region to be invalidated. + BRegion invalid(fFullVisible); + + clear_visible_regions(); + + rebuild_visible_regions(invalid, invalid, BottomChild()); + + // for the moment we say that the whole surface needs to be redraw. + BRegion redrawReg(fFullVisible); + + // offset old region so that we can start comparing. + invalid.OffsetBy(dx, dy); + + // compute the common region. we'll use HW acc to copy this to the new location. + invalid.IntersectWith(&fFullVisible); +// TODO: uncomment!!! +// GetRootLayer()->CopyRegion(&invalid, -dx, -dy); + + // common region goes back to its original location. then, by excluding + // it from curent fullVisible we'll obtain the region that needs to be redrawn. + invalid.OffsetBy(-dx, -dy); + redrawReg.Exclude(&invalid); + + GetRootLayer()->fRedrawReg.Include(&redrawReg); +// TODO: --- + GetRootLayer()->RequestDraw(GetRootLayer()->fRedrawReg, BottomChild()); +// GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? + } + + if (dx != 0.0f || dy != 0.0f) + ScrolledByHook(dx, dy); +} +void +Layer::get_user_regions(BRegion ®) +{ + // 1) set to frame in screen coords + BRect screenFrame(Bounds()); + ConvertToScreen2(&screenFrame); + reg.Set(screenFrame); + + // 2) intersect with screen region + BRegion screenReg(GetRootLayer()->Bounds()); + reg.IntersectWith(&screenReg); + +// TODO: you MUST at some point uncomment this block! +/* + // 3) impose user constrained regions + LayerData *stackData = fLayerData; + while (stackData) + { + // transform in screen coords + BRegion screenReg(stackData->ClippingRegion()); + ConvertToScreen2(&screenReg); + reg.IntersectWith(&screenReg); + stackData = stackData->prevState; + } +*/ +} + +void +Layer::do_RebuildVisibleRegions(const BRegion &invalid, const Layer *startFrom) +{ + BRegion localVisible(fFullVisible); + localVisible.IntersectWith(&invalid); + rebuild_visible_regions(invalid, localVisible, startFrom); +} + +void +Layer::rebuild_visible_regions(const BRegion &invalid, + const BRegion &parentLocalVisible, + const Layer *startFrom) +{ + // no point in continuing if this layer is hidden. starting from here, all + // descendants have (and will have) invalid visible regions. + if (fHidden) + return; + + // no need to go deeper if the parent doesn't have a visible region anymore + // and our fullVisible region is also empty. + if (!parentLocalVisible.Frame().IsValid() && !(fFullVisible.CountRects() > 0)) + return; + + bool fullRebuild = false; + + // intersect maximum wanted region with the invalid region + BRegion common; + get_user_regions(common); + common.IntersectWith(&invalid); + + // if the resulted region is not valid, this layer is not in the catchment area + // of the region being invalidated + if (!common.CountRects() > 0) + return; + + // now intersect with parent's visible part of the region that was/is invalidated + common.IntersectWith(&parentLocalVisible); + + // exclude the invalid region + fFullVisible.Exclude(&invalid); + fVisible.Exclude(&invalid); + + // put in what's really visible + fFullVisible.Include(&common); + + // this is to allow a layer to hide some parts of itself so children + // won't take them. + BRegion unalteredVisible(common); + bool altered = alter_visible_for_children(common); + + for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) { + if (lay == startFrom) + fullRebuild = true; + + if (fullRebuild) + lay->rebuild_visible_regions(invalid, common, lay->BottomChild()); + + // to let children know much they can take from parent's visible region + common.Exclude(&lay->fFullVisible); + // we've hidden some parts of our visible region from our children, + // and we must be in sysnc with this region too... + if (altered) + unalteredVisible.Exclude(&lay->fFullVisible); + } + + // the visible region of this layer is what left after all its children took + // what they could. + if (altered) + fVisible.Include(&unalteredVisible); + else + fVisible.Include(&common); +} + +bool +Layer::alter_visible_for_children(BRegion ®) +{ + // Empty Hook function + return false; +} + +void +Layer::clear_visible_regions() +{ + // OPT: maybe we should uncomment these lines for performance + //if (fFullVisible.CountRects() <= 0) + // return; + + fVisible.MakeEmpty(); + fFullVisible.MakeEmpty(); + for (Layer *child = BottomChild(); child; child = UpperSibling()) + child->clear_visible_regions(); +} + #endif diff --git a/src/servers/app/Layer.h b/src/servers/app/Layer.h index b0997c51f3..e4cd05577c 100644 --- a/src/servers/app/Layer.h +++ b/src/servers/app/Layer.h @@ -41,6 +41,8 @@ #include "RGBColor.h" #include "ServerWindow.h" +//#define NEW_CLIPPING 1 + enum { B_LAYER_NONE = 1, B_LAYER_MOVE = 2, @@ -207,8 +209,37 @@ class Layer { inline const ServerBitmap* OverlayBitmap() const { return fOverlayBitmap; } #ifdef NEW_CLIPPING + virtual void MovedByHook(float dx, float dy) { } + virtual void ResizedByHook(float dx, float dy, bool automatic) { } + virtual void ScrolledByHook(float dx, float dy) { } + void ConvertToScreen2(BRect* rect) const; void ConvertToScreen2(BRegion* reg) const; + bool IsVisuallyHidden() const; + private: + void do_Hide(); + void do_Show(); + void do_RebuildVisibleRegions(const BRegion &invalid, + const Layer *startFrom); + void do_MoveBy(float dx, float dy); + void do_ResizeBy(float dx, float dy); + void do_ScrollBy(float dx, float dy); + + void do_Invalidate( const BRegion &invalid, + const Layer *startFrom = NULL); + + void rebuild_visible_regions(const BRegion &invalid, + const BRegion &parentLocalVisible, + const Layer *startFrom); + + virtual bool alter_visible_for_children(BRegion ®ion); + virtual void get_user_regions(BRegion ®); + + void clear_visible_regions(); + void resize_layer_frame_by(float x, float y); + void rezize_layer_redraw_more(BRegion ®, float dx, float dy); + void resize_layer_full_update_on_resize(BRegion ®, float dx, float dy); + #endif protected: diff --git a/src/servers/app/WinBorder.cpp b/src/servers/app/WinBorder.cpp index ca01e21d8c..657945294e 100644 --- a/src/servers/app/WinBorder.cpp +++ b/src/servers/app/WinBorder.cpp @@ -127,7 +127,9 @@ WinBorder::WinBorder(const BRect &r, fAdFlags = fAdFlags | B_LAYER_CHILDREN_DEPENDANT; fFlags = B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE; fEventMask = B_POINTER_EVENTS; - +#ifdef NEW_CLIPPING + fRebuildDecRegion = true; +#endif QuietlySetFeel(wfeel); if (fFeel != B_NO_BORDER_WINDOW_LOOK) { @@ -612,4 +614,57 @@ WinBorder::_ActionFor(const PointerEvent& event) const return DEC_NONE; } +#ifdef NEW_CLIPPING +void WinBorder::MovedByHook(float dx, float dy) +{ + fDecRegion.OffsetBy(dx, dy); +} +void WinBorder::ResizedByHook(float dx, float dy, bool automatic) +{ + fRebuildDecRegion = true; +} + +void WinBorder::set_decorator_region(BRect bounds) +{ + fRebuildDecRegion = false; + + fDecRegion.MakeEmpty(); + // NOTE: frame is in screen coords + fDecRegion.Include(BRect(bounds.left-4, bounds.top-4, bounds.right+4, bounds.top-1)); + fDecRegion.Include(BRect(bounds.left-4, bounds.bottom+1, bounds.right+4, bounds.bottom+4)); + fDecRegion.Include(BRect(bounds.left-4, bounds.top, bounds.left-1, bounds.bottom)); + fDecRegion.Include(BRect(bounds.right+1, bounds.top, bounds.right+4, bounds.bottom)); + + // tab + fDecRegion.Include(BRect(bounds.left-4, bounds.top-4-10, bounds.left+bounds.Width()/2, bounds.top-4)); + + // resize rect + fDecRegion.Include(BRect(bounds.right-10, bounds.bottom-10, bounds.right, bounds.bottom)); +} + +bool WinBorder::alter_visible_for_children(BRegion ®ion) +{ + region.Exclude(&fDecRegion); + return true; +} + +void WinBorder::get_user_regions(BRegion ®) +{ + if (fRebuildDecRegion) + { + set_decorator_region(Bounds()); + ConvertToScreen2(&fDecRegion); + } + + BRect screenFrame(Bounds()); + ConvertToScreen2(&screenFrame); + reg.Set(screenFrame); + + BRegion screenReg(GetRootLayer()->Bounds()); + + reg.IntersectWith(&screenReg); + + reg.Include(&fDecRegion); +} +#endif \ No newline at end of file diff --git a/src/servers/app/WinBorder.h b/src/servers/app/WinBorder.h index f4b3818a1a..1b6546eae7 100644 --- a/src/servers/app/WinBorder.h +++ b/src/servers/app/WinBorder.h @@ -123,6 +123,21 @@ class WinBorder : public Layer { FMWList fFMWList; +#ifdef NEW_CLIPPING + public: + virtual void MovedByHook(float dx, float dy); + virtual void ResizedByHook(float dx, float dy, bool automatic); + + private: + void set_decorator_region(BRect frame); + virtual bool alter_visible_for_children(BRegion ®ion); + virtual void get_user_regions(BRegion ®); + + BRegion fDecRegion; + bool fRebuildDecRegion; + +#endif + protected: friend class Layer; friend class ServerWindow;