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
This commit is contained in:
Adi Oanca
2005-06-15 20:36:43 +00:00
parent 4399fd6025
commit d41a1e80b8
4 changed files with 561 additions and 7 deletions
+459 -6
View File
@@ -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 &reg, 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(&regZ);
// intersect that with this'(not lay's) fullVisible region
regZ.IntersectWith(&fFullVisible);
reg.Include(&regZ);
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 &reg, 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 &reg)
{
// 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 &reg)
{
// 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
+31
View File
@@ -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 &region);
virtual void get_user_regions(BRegion &reg);
void clear_visible_regions();
void resize_layer_frame_by(float x, float y);
void rezize_layer_redraw_more(BRegion &reg, float dx, float dy);
void resize_layer_full_update_on_resize(BRegion &reg, float dx, float dy);
#endif
protected:
+56 -1
View File
@@ -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 &region)
{
region.Exclude(&fDecRegion);
return true;
}
void WinBorder::get_user_regions(BRegion &reg)
{
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
+15
View File
@@ -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 &region);
virtual void get_user_regions(BRegion &reg);
BRegion fDecRegion;
bool fRebuildDecRegion;
#endif
protected:
friend class Layer;
friend class ServerWindow;