michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: Detailed Design Template michael@0: michael@0: michael@0: michael@0:

Gecko Layout Detailed Design Document

michael@0: michael@0:

Space Manager Detailed Design

michael@0: michael@0:

Overview

michael@0:

michael@0: The Space Manager and related classes and structures are an important of michael@0: the Gecko Layout system, specifically Block Layout.  See the High Level michael@0: Design document for an overview of the Space Manager, and as an introduction michael@0: to the classes, structures and algorithms container in this, the Detailed michael@0: Design Document. michael@0:

michael@0: michael@0: michael@0: michael@0:
michael@0:

nsSpaceManager

michael@0:

michael@0: The Space Manager is the central class is a group of classes that manage michael@0: the occupied and available space that exists in horizontal bands across michael@0: a canvas.  The primary goal of the Space Manager is to provide information michael@0: about those bands of space to support the CSS notion of floated elements. michael@0:

michael@0: michael@0:

michael@0: There are three important parts to the Space Manager API: the parts that michael@0: deal with the coordinate space of the Space Manager, the parts that deal with michael@0: the regions managed by the Space Manager, and the parts that manage float michael@0: impact intervals. michael@0:

michael@0: michael@0:

michael@0: The class nsSpaceManager is declared in the file michael@0: nsSpaceManger.h michael@0: .  The class is only used in the layout module and cannot be exported michael@0: outside of that module (nor does it need to be).  It is not a general michael@0: purpose class, and is not intended to be subclasses michael@0: . michael@0:

michael@0: michael@0:

michael@0: Here is the class declaration, taken from the source file as of 01.08.02 michael@0:

michael@0: michael@0: michael@0: michael@0:
/**
michael@0:  * Class for dealing with bands of available space. The space manager
michael@0:  * defines a coordinate space with an origin at (0, 0) that grows down
michael@0:  * and to the right.
michael@0:  */
michael@0: class nsSpaceManager {
michael@0: public:
michael@0:   nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
michael@0:   ~nsSpaceManager();
michael@0: 
michael@0:   void* operator new(size_t aSize);
michael@0:   void operator delete(void* aPtr, size_t aSize);
michael@0: 
michael@0:   static void Shutdown();
michael@0: 
michael@0:   /*
michael@0:    * Get the frame that's associated with the space manager. This frame
michael@0:    * created the space manager, and the world coordinate space is
michael@0:    * relative to this frame.
michael@0:    *
michael@0:    * You can use QueryInterface() on this frame to get any additional
michael@0:    * interfaces.
michael@0:    */
michael@0:   nsIFrame* GetFrame() const { return mFrame; }
michael@0: 
michael@0:   /**
michael@0:    * Translate the current origin by the specified (dx, dy). This
michael@0:    * creates a new local coordinate space relative to the current
michael@0:    * coordinate space.
michael@0:    */
michael@0:   void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
michael@0: 
michael@0:   /**
michael@0:    * Returns the current translation from local coordinate space to
michael@0:    * world coordinate space. This represents the accumulated calls to
michael@0:    * Translate().
michael@0:    */
michael@0:   void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
michael@0: 
michael@0:   /**
michael@0:    * Returns the y-most of the bottommost band or 0 if there are no bands.
michael@0:    *
michael@0:    * @return  PR_TRUE if there are bands and PR_FALSE if there are no bands
michael@0:    */
michael@0:   PRBool YMost(nscoord& aYMost) const;
michael@0: 
michael@0:   /**
michael@0:    * Returns a band starting at the specified y-offset. The band data
michael@0:    * indicates which parts of the band are available, and which parts
michael@0:    * are unavailable
michael@0:    *
michael@0:    * The band data that is returned is in the coordinate space of the
michael@0:    * local coordinate system.
michael@0:    *
michael@0:    * The local coordinate space origin, the y-offset, and the max size
michael@0:    * describe a rectangle that's used to clip the underlying band of
michael@0:    * available space, i.e.
michael@0:    * {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
michael@0:    * coordinate space
michael@0:    *
michael@0:    * @param   aYOffset the y-offset of where the band begins. The coordinate is
michael@0:    *            relative to the upper-left corner of the local coordinate space
michael@0:    * @param   aMaxSize the size to use to constrain the band data
michael@0:    * @param   aBandData [in,out] used to return the list of trapezoids that
michael@0:    *            describe the available space and the unavailable space
michael@0:    * @return  NS_OK if successful and NS_ERROR_FAILURE if the band data is not
michael@0:    *            not large enough. The 'count' member of the band data struct
michael@0:    *            indicates how large the array of trapezoids needs to be
michael@0:    */
michael@0:   nsresult GetBandData(nscoord       aYOffset,
michael@0:                        const nsSize& aMaxSize,
michael@0:                        nsBandData&   aBandData) const;
michael@0: 
michael@0:   /**
michael@0:    * Add a rectangular region of unavailable space. The space is
michael@0:    * relative to the local coordinate system.
michael@0:    *
michael@0:    * The region is tagged with a frame
michael@0:    *
michael@0:    * @param   aFrame the frame used to identify the region. Must not be NULL
michael@0:    * @param   aUnavailableSpace the bounding rect of the unavailable space
michael@0:    * @return  NS_OK if successful
michael@0:    *          NS_ERROR_FAILURE if there is already a region tagged with aFrame
michael@0:    */
michael@0:   nsresult AddRectRegion(nsIFrame*     aFrame,
michael@0:                          const nsRect& aUnavailableSpace);
michael@0: 
michael@0:   /**
michael@0:    * Resize the rectangular region associated with aFrame by the specified
michael@0:    * deltas. The height change always applies to the bottom edge or the existing
michael@0:    * rect. You specify whether the width change applies to the left or right edge
michael@0:    *
michael@0:    * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
michael@0:    * tagged with aFrame
michael@0:    */
michael@0:   enum AffectedEdge {LeftEdge, RightEdge};
michael@0:   nsresult ResizeRectRegion(nsIFrame*    aFrame,
michael@0:                             nscoord      aDeltaWidth,
michael@0:                             nscoord      aDeltaHeight,
michael@0:                             AffectedEdge aEdge = RightEdge);
michael@0: 
michael@0:   /**
michael@0:    * Offset the region associated with aFrame by the specified amount.
michael@0:    *
michael@0:    * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
michael@0:    * tagged with aFrame
michael@0:    */
michael@0:   nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);
michael@0: 
michael@0:   /**
michael@0:    * Remove the region associated with aFrane.
michael@0:    *
michael@0:    * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
michael@0:    * tagged with aFrame
michael@0:    */
michael@0:   nsresult RemoveRegion(nsIFrame* aFrame);
michael@0: 
michael@0:   /**
michael@0:    * Clears the list of regions representing the unavailable space.
michael@0:    */
michael@0:   void ClearRegions();
michael@0: 
michael@0:   /**
michael@0:    * Methods for dealing with the propagation of float damage during
michael@0:    * reflow.
michael@0:    */
michael@0:   PRBool HasFloatDamage()
michael@0:   {
michael@0:     return !mFloatDamage.IsEmpty();
michael@0:   }
michael@0: 
michael@0:   void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
michael@0:   {
michael@0:     mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
michael@0:   }
michael@0: 
michael@0:   PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
michael@0:   {
michael@0:     return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
michael@0:   }
michael@0: 
michael@0: #ifdef DEBUG
michael@0:   /**
michael@0:    * Dump the state of the spacemanager out to a file
michael@0:    */
michael@0:   nsresult List(FILE* out);
michael@0: 
michael@0:   void SizeOf(nsISizeOfHandler* aHandler, uint32_t* aResult) const;
michael@0: #endif
michael@0: 
michael@0: private:
michael@0:   // Structure that maintains information about the region associated
michael@0:   // with a particular frame
michael@0:   struct FrameInfo {
michael@0:     nsIFrame* const mFrame;
michael@0:     nsRect          mRect;       // rectangular region
michael@0:     FrameInfo*      mNext;
michael@0: 
michael@0:     FrameInfo(nsIFrame* aFrame, const nsRect& aRect);
michael@0: #ifdef NS_BUILD_REFCNT_LOGGING
michael@0:     ~FrameInfo();
michael@0: #endif
michael@0:   };
michael@0: 
michael@0:   // Doubly linked list of band rects
michael@0:   struct BandRect : PRCListStr {
michael@0:     nscoord   mLeft, mTop;
michael@0:     nscoord   mRight, mBottom;
michael@0:     int32_t   mNumFrames;    // number of frames occupying this rect
michael@0:     union {
michael@0:       nsIFrame*    mFrame;   // single frame occupying the space
michael@0:       nsVoidArray* mFrames;  // list of frames occupying the space
michael@0:     };
michael@0: 
michael@0:     BandRect(nscoord aLeft, nscoord aTop,
michael@0:              nscoord aRight, nscoord aBottom,
michael@0:              nsIFrame*);
michael@0:     BandRect(nscoord aLeft, nscoord aTop,
michael@0:              nscoord aRight, nscoord aBottom,
michael@0:              nsVoidArray*);
michael@0:     ~BandRect();
michael@0: 
michael@0:     // List operations
michael@0:     BandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
michael@0:     BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
michael@0:     void      InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
michael@0:     void      InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
michael@0:     void      Remove() {PR_REMOVE_LINK(this);}
michael@0: 
michael@0:     // Split the band rect into two vertically, with this band rect becoming
michael@0:     // the top part, and a new band rect being allocated and returned for the
michael@0:     // bottom part
michael@0:     //
michael@0:     // Does not insert the new band rect into the linked list
michael@0:     BandRect* SplitVertically(nscoord aBottom);
michael@0: 
michael@0:     // Split the band rect into two horizontally, with this band rect becoming
michael@0:     // the left part, and a new band rect being allocated and returned for the
michael@0:     // right part
michael@0:     //
michael@0:     // Does not insert the new band rect into the linked list
michael@0:     BandRect* SplitHorizontally(nscoord aRight);
michael@0: 
michael@0:     // Accessor functions
michael@0:     PRBool  IsOccupiedBy(const nsIFrame*) const;
michael@0:     void    AddFrame(const nsIFrame*);
michael@0:     void    RemoveFrame(const nsIFrame*);
michael@0:     PRBool  HasSameFrameList(const BandRect* aBandRect) const;
michael@0:     int32_t Length() const;
michael@0:   };
michael@0: 
michael@0:   // Circular linked list of band rects
michael@0:   struct BandList : BandRect {
michael@0:     BandList();
michael@0: 
michael@0:     // Accessors
michael@0:     PRBool    IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
michael@0:     BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
michael@0:     BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}
michael@0: 
michael@0:     // Operations
michael@0:     void      Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}
michael@0: 
michael@0:     // Remove and delete all the band rects in the list
michael@0:     void      Clear();
michael@0:   };
michael@0: 
michael@0: 
michael@0:   FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
michael@0:   FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect& aRect);
michael@0:   void       DestroyFrameInfo(FrameInfo*);
michael@0: 
michael@0:   void       ClearFrameInfo();
michael@0:   void       ClearBandRects();
michael@0: 
michael@0:   BandRect*  GetNextBand(const BandRect* aBandRect) const;
michael@0:   void       DivideBand(BandRect* aBand, nscoord aBottom);
michael@0:   PRBool     CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
michael@0:   PRBool     JoinBands(BandRect* aBand, BandRect* aPrevBand);
michael@0:   void       AddRectToBand(BandRect* aBand, BandRect* aBandRect);
michael@0:   void       InsertBandRect(BandRect* aBandRect);
michael@0: 
michael@0:   nsresult   GetBandAvailableSpace(const BandRect* aBand,
michael@0:                                    nscoord         aY,
michael@0:                                    const nsSize&   aMaxSize,
michael@0:                                    nsBandData&     aAvailableSpace) const;
michael@0: 
michael@0:   nsIFrame* const mFrame;     // frame associated with the space manager
michael@0:   nscoord         mX, mY;     // translation from local to global coordinate space
michael@0:   BandList        mBandList;  // header/sentinel for circular linked list of band rects
michael@0:   FrameInfo*      mFrameInfoMap;
michael@0:   nsIntervalSet   mFloatDamage;
michael@0: 
michael@0:   static int32_t sCachedSpaceManagerCount;
michael@0:   static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];
michael@0: 
michael@0:   nsSpaceManager(const nsSpaceManager&);  // no implementation
michael@0:   void operator=(const nsSpaceManager&);  // no implementation
michael@0: };
michael@0: 
michael@0: 
michael@0: michael@0:

Public API

michael@0: michael@0:

Life Cycle:

michael@0:

michael@0: The Constructor requires a Presentation Shell, used for arena allocations michael@0: mostly, and a frame that this Space Manager is rooted on.  The coordinate michael@0: space of this Space Manager is relative to the frame passed in to the constructor. michael@0:

michael@0: michael@0:
  nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
michael@0:   ~nsSpaceManager();
michael@0: 
michael@0:

michael@0: Operators 'new' and 'delete' are overridden to support a recycler.  Space michael@0: Manager instances come and go pretty frequently, and this recycler prevents michael@0: excessive heap allocations and the performance penalties associated with michael@0: it. The #define NS_SPACE_MANAGER_CACHE_SIZE is used to control the number michael@0: of Space Manager instances that can be present in the recycler, currently michael@0: 4.  If more than NS_SPACE_MANAGER_CACHE_SIZE are allocated at a time, michael@0: then standard allocation is used. michael@0:

michael@0: michael@0:
michael@0:   void* operator new(size_t aSize);
michael@0:   void operator delete(void* aPtr, size_t aSize);
michael@0: 
michael@0: 
michael@0:

michael@0: A Static method is used to shutdown the Space Manager recycling.  This michael@0: method deletes all of the Space Mangers inthe recycler,and prevents further michael@0: recycling.  It is meant to be called only when the layout module is being michael@0: terminated. michael@0:

michael@0: michael@0:
  static void Shutdown();
michael@0: 
michael@0: 
michael@0: michael@0:

Origin / Coordinate Space Translation

michael@0: michael@0:
  /**
michael@0:    * Translate the current origin by the specified (dx, dy). This
michael@0:    * creates a new local coordinate space relative to the current
michael@0:    * coordinate space.
michael@0:    */
michael@0:   void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
michael@0: 
michael@0:   /**
michael@0:    * Returns the current translation from local coordinate space to
michael@0:    * world coordinate space. This represents the accumulated calls to
michael@0:    * Translate().
michael@0:    */
michael@0:   void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
michael@0: 
michael@0:   /**
michael@0:    * Returns the y-most of the bottommost band or 0 if there are no bands.
michael@0:    *
michael@0:    * @return  PR_TRUE if there are bands and PR_FALSE if there are no bands
michael@0:    */
michael@0:   PRBool YMost(nscoord& aYMost) const;
michael@0: 
michael@0: michael@0:

Region Management

michael@0: michael@0:
  /**
michael@0:    * Returns a band starting at the specified y-offset. The band data
michael@0:    * indicates which parts of the band are available, and which parts
michael@0:    * are unavailable
michael@0:    *
michael@0:    * The band data that is returned is in the coordinate space of the
michael@0:    * local coordinate system.
michael@0:    *
michael@0:    * The local coordinate space origin, the y-offset, and the max size
michael@0:    * describe a rectangle that's used to clip the underlying band of
michael@0:    * available space, i.e.
michael@0:    * {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
michael@0:    * coordinate space
michael@0:    *
michael@0:    * @param   aYOffset the y-offset of where the band begins. The coordinate is
michael@0:    *            relative to the upper-left corner of the local coordinate space
michael@0:    * @param   aMaxSize the size to use to constrain the band data
michael@0:    * @param   aBandData [in,out] used to return the list of trapezoids that
michael@0:    *            describe the available space and the unavailable space
michael@0:    * @return  NS_OK if successful and NS_ERROR_FAILURE if the band data is not
michael@0:    *            not large enough. The 'count' member of the band data struct
michael@0:    *            indicates how large the array of trapezoids needs to be
michael@0:    */
michael@0:   nsresult GetBandData(nscoord       aYOffset,
michael@0:                        const nsSize& aMaxSize,
michael@0:                        nsBandData&   aBandData) const;
michael@0: 
michael@0:   /**
michael@0:    * Add a rectangular region of unavailable space. The space is
michael@0:    * relative to the local coordinate system.
michael@0:    *
michael@0:    * The region is tagged with a frame
michael@0:    *
michael@0:    * @param   aFrame the frame used to identify the region. Must not be NULL
michael@0:    * @param   aUnavailableSpace the bounding rect of the unavailable space
michael@0:    * @return  NS_OK if successful
michael@0:    *          NS_ERROR_FAILURE if there is already a region tagged with aFrame
michael@0:    */
michael@0:   nsresult AddRectRegion(nsIFrame*     aFrame,
michael@0:                          const nsRect& aUnavailableSpace);
michael@0: 
michael@0:   /**
michael@0:    * Resize the rectangular region associated with aFrame by the specified
michael@0:    * deltas. The height change always applies to the bottom edge or the existing
michael@0:    * rect. You specify whether the width change applies to the left or right edge
michael@0:    *
michael@0:    * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
michael@0:    * tagged with aFrame
michael@0:    */
michael@0:   enum AffectedEdge {LeftEdge, RightEdge};
michael@0:   nsresult ResizeRectRegion(nsIFrame*    aFrame,
michael@0:                             nscoord      aDeltaWidth,
michael@0:                             nscoord      aDeltaHeight,
michael@0:                             AffectedEdge aEdge = RightEdge);
michael@0: 
michael@0:   /**
michael@0:    * Offset the region associated with aFrame by the specified amount.
michael@0:    *
michael@0:    * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
michael@0:    * tagged with aFrame
michael@0:    */
michael@0:   nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);
michael@0: 
michael@0:   /**
michael@0:    * Remove the region associated with aFrane.
michael@0:    *
michael@0:    * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
michael@0:    * tagged with aFrame
michael@0:    */
michael@0:   nsresult RemoveRegion(nsIFrame* aFrame);
michael@0: 
michael@0:   /**
michael@0:    * Clears the list of regions representing the unavailable space.
michael@0:    */
michael@0:   void ClearRegions();
michael@0: 
michael@0: michael@0:

Float Impact

michael@0: michael@0:
  /**
michael@0:    * Methods for dealing with the propagation of float damage during
michael@0:    * reflow.
michael@0:    */
michael@0:   PRBool HasFloatDamage()
michael@0:   {
michael@0:     return !mFloatDamage.IsEmpty();
michael@0:   }
michael@0: 
michael@0:   void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
michael@0:   {
michael@0:     mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
michael@0:   }
michael@0: 
michael@0:   PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
michael@0:   {
michael@0:     return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
michael@0:   }
michael@0: 
michael@0: michael@0:

Debug Only Methods

michael@0: michael@0:
  /**
michael@0:    * Dump the state of the spacemanager out to a file
michael@0:    */
michael@0:   nsresult List(FILE* out);
michael@0: 
michael@0:   void SizeOf(nsISizeOfHandler* aHandler, uint32_t* aResult) const;
michael@0: 
michael@0: 
michael@0: michael@0:

Unused / Obsolete Methods

michael@0: michael@0:
  /*
michael@0:    * Get the frame that's associated with the space manager. This frame
michael@0:    * created the space manager, and the world coordinate space is
michael@0:    * relative to this frame.
michael@0:    *
michael@0:    * You can use QueryInterface() on this frame to get any additional
michael@0:    * interfaces.
michael@0:    */
michael@0:    nsIFrame* GetFrame() const { return mFrame; }
michael@0: 
michael@0: 
michael@0: michael@0:

Implementation Notes

michael@0: michael@0:

michael@0: michael@0:

Algorithm 1: GetBandData

michael@0:

michael@0: GetBandData is used to provide information to clients about what space if michael@0: available and unavailable in a band of space.  The client provides a michael@0: vertical offset, the yOffset, that corresponds to the band that is of interest. michael@0:  This will be the y offset of the frame that is being reflowed.  The michael@0: caller also provides a collection of BandData objects (an array) and the michael@0: number of items that the collection can handle.  If the collection is michael@0: too small, then an error is returned and the count is updated to indicate michael@0: the size required. michael@0:

michael@0: michael@0:

michael@0: The algorithm to provide the band data is as follows: michael@0:

michael@0: michael@0:
GetBandAvailableSpace:
michael@0: This method is called from GetBandData only. It walks all of the bands in michael@0: the space manager and determines which bands intersect with the band passed michael@0: in, and if within those bands there are regions that are available or occupied. michael@0: michael@0: michael@0: michael@0:

Algorithm 2: AddRectRegion

michael@0: Clients call into this method to notify the Space Manager that a new frame michael@0: is occupying some space. michael@0: michael@0: michael@0:
InsertBandRect:
michael@0: Internal method to insert a band rect into the BandList in the correct location. michael@0: There are several cases it has to handle, as specified in the source file michael@0: comments: michael@0: michael@0:
// When comparing a rect to a band there are seven cases to consider.
michael@0: // 'R' is the rect and 'B' is the band.
michael@0: //
michael@0: //      Case 1              Case 2              Case 3              Case 4
michael@0: //      ------              ------              ------              ------
michael@0: // +-----+             +-----+                      +-----+             +-----+
michael@0: // |  R  |             |  R  |  +-----+    +-----+  |     |             |     |
michael@0: // +-----+             +-----+  |     |    |  R  |  |  B  |             |  B  |
michael@0: //          +-----+             |  B  |    +-----+  |     |    +-----+  |     |
michael@0: //          |     |             |     |             +-----+    |  R  |  +-----+
michael@0: //          |  B  |             +-----+                        +-----+
michael@0: //          |     |
michael@0: //          +-----+
michael@0: //
michael@0: //
michael@0: //
michael@0: //      Case 5              Case 6              Case 7
michael@0: //      ------              ------              ------
michael@0: //          +-----+    +-----+  +-----+    +-----+
michael@0: //          |     |    |  R  |  |  B  |    |     |  +-----+
michael@0: //          |  B  |    +-----+  +-----+    |  R  |  |  B  |
michael@0: //          |     |                        |     |  +-----+
michael@0: //          +-----+                        +-----+
michael@0: // +-----+
michael@0: // |  R  |
michael@0: // +-----+
michael@0: //
michael@0: 
michael@0: michael@0: This algorithm is pretty confusing - basically what needs to happen is michael@0: that rects and bands need to be divided up so that complicated cases like michael@0: #2, #4, and #7, are reduced to simpler cases where the rects is totally above, michael@0: below, or between a band rect.  From the current implementation, it michael@0: might be worth verifying that the final result of the inserts is a correctly michael@0: ordered liest of bandRects (debug mode only). michael@0: michael@0: michael@0:

Algorithm 3: RemoveRegion

michael@0: When a float is removed, the Space Manager is notified by a call to RemoveRegion, michael@0: passing in the frame that is being removed. michael@0: michael@0: michael@0: michael@0:
michael@0: michael@0:
michael@0:

Cross-Component Algorithms

michael@0: michael@0:
michael@0: michael@0: michael@0: michael@0:
michael@0:

Tech Notes

michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: