Back to index

lightning-sunbird  0.9+nobinonly
nsSpaceManager.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 // vim:cindent:ts=2:et:sw=2:
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #ifndef nsSpaceManager_h___
00039 #define nsSpaceManager_h___
00040 
00041 #include "prclist.h"
00042 #include "nsIntervalSet.h"
00043 #include "nsISupports.h"
00044 #include "nsCoord.h"
00045 #include "nsRect.h"
00046 
00047 class nsIPresShell;
00048 class nsIFrame;
00049 class nsVoidArray;
00050 struct nsSize;
00051 struct nsHTMLReflowState;
00052 class nsPresContext;
00053 
00054 #define NS_SPACE_MANAGER_CACHE_SIZE 4
00055 
00065 struct nsBandTrapezoid {
00066   enum State {Available, Occupied, OccupiedMultiple};
00067 
00068   nscoord   mTopY, mBottomY;            // top and bottom y-coordinates
00069   nscoord   mTopLeftX, mBottomLeftX;    // left edge x-coordinates
00070   nscoord   mTopRightX, mBottomRightX;  // right edge x-coordinates
00071   State     mState;                     // state of the space
00072   union {
00073     nsIFrame*          mFrame;  // single frame occupying the space
00074     const nsVoidArray* mFrames; // list of frames occupying the space
00075   };
00076 
00077   // Get the height of the trapezoid
00078   nscoord GetHeight() const {return mBottomY - mTopY;}
00079 
00080   // Get the bounding rect of the trapezoid
00081   inline void GetRect(nsRect& aRect) const;
00082 
00083   // Set the trapezoid from a rectangle
00084   inline void operator=(const nsRect& aRect);
00085 
00086   // Do these trapezoids have the same geometry, frame, and state?
00087   inline PRBool Equals(const nsBandTrapezoid& aTrap) const;
00088 
00089   // Do these trapezoids have the same geometry?
00090   inline PRBool EqualGeometry(const nsBandTrapezoid& aTrap) const;
00091 
00092   nsBandTrapezoid()
00093     : mTopY(0),
00094       mBottomY(0),
00095       mTopLeftX(0),
00096       mBottomLeftX(0),
00097       mTopRightX(0),
00098       mBottomRightX(0),
00099       mFrame(nsnull)
00100   {
00101   }
00102 };
00103 
00104 inline void nsBandTrapezoid::GetRect(nsRect& aRect) const
00105 {
00106   aRect.x = PR_MIN(mTopLeftX, mBottomLeftX);
00107   aRect.y = mTopY;
00108   aRect.width = PR_MAX(mTopRightX, mBottomRightX);
00109   if (NS_MAXSIZE != aRect.width) {
00110     aRect.width -= aRect.x;
00111   }
00112   aRect.height = (NS_MAXSIZE == mBottomY) ? NS_MAXSIZE : mBottomY - mTopY;
00113 }
00114 
00115 inline void nsBandTrapezoid::operator=(const nsRect& aRect)
00116 {
00117   mTopLeftX = mBottomLeftX = aRect.x;
00118   mTopRightX = mBottomRightX = aRect.XMost();
00119   mTopY = aRect.y;
00120   mBottomY = aRect.YMost();
00121 }
00122 
00123 inline PRBool nsBandTrapezoid::Equals(const nsBandTrapezoid& aTrap) const
00124 {
00125   return (
00126     mTopLeftX == aTrap.mTopLeftX &&
00127     mBottomLeftX == aTrap.mBottomLeftX &&
00128     mTopRightX == aTrap.mTopRightX &&
00129     mBottomRightX == aTrap.mBottomRightX &&
00130     mTopY == aTrap.mTopY &&
00131     mBottomY == aTrap.mBottomY &&
00132     mState == aTrap.mState &&
00133     mFrame == aTrap.mFrame    
00134   );
00135 }
00136 
00137 inline PRBool nsBandTrapezoid::EqualGeometry(const nsBandTrapezoid& aTrap) const
00138 {
00139   return (
00140     mTopLeftX == aTrap.mTopLeftX &&
00141     mBottomLeftX == aTrap.mBottomLeftX &&
00142     mTopRightX == aTrap.mTopRightX &&
00143     mBottomRightX == aTrap.mBottomRightX &&
00144     mTopY == aTrap.mTopY &&
00145     mBottomY == aTrap.mBottomY
00146   );
00147 }
00148 
00153 struct nsBandData {
00154   PRInt32 mCount; // [out] actual number of trapezoids in the band data
00155   PRInt32 mSize; // [in] the size of the array (number of trapezoids)
00156   nsBandTrapezoid* mTrapezoids; // [out] array of length 'size'
00157 };
00158 
00164 class nsSpaceManager {
00165 public:
00166   nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
00167   ~nsSpaceManager();
00168 
00169   void* operator new(size_t aSize) CPP_THROW_NEW;
00170   void operator delete(void* aPtr, size_t aSize);
00171 
00172   static void Shutdown();
00173 
00174   /*
00175    * Get the frame that's associated with the space manager. This frame
00176    * created the space manager, and the world coordinate space is
00177    * relative to this frame.
00178    *
00179    * You can use QueryInterface() on this frame to get any additional
00180    * interfaces.
00181    */
00182   nsIFrame* GetFrame() const { return mFrame; }
00183 
00189   void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
00190 
00196   void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
00197 
00204   PRBool XMost(nscoord& aXMost) const;
00205 
00211   PRBool YMost(nscoord& aYMost) const;
00212 
00236   nsresult GetBandData(nscoord       aYOffset,
00237                        const nsSize& aMaxSize,
00238                        nsBandData&   aBandData) const;
00239 
00251   nsresult AddRectRegion(nsIFrame*     aFrame,
00252                          const nsRect& aUnavailableSpace);
00253 
00265   nsresult RemoveTrailingRegions(nsIFrame* aFrameList);
00266 
00267 protected:
00276   nsresult RemoveRegion(nsIFrame* aFrame);
00277 
00278 public:
00282   void ClearRegions();
00283 
00284   PRBool HasAnyFloats() { return mFrameInfoMap != nsnull; }
00285 
00290   PRBool HasFloatDamage()
00291   {
00292     return !mFloatDamage.IsEmpty();
00293   }
00294 
00295   void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
00296   {
00297     mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
00298   }
00299 
00300   PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
00301   {
00302     return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
00303   }
00304 
00308   void PushState();
00309 
00314   void PopState();
00315 
00320   void DiscardState();
00321 
00327   nscoord GetLowestRegionTop();
00328 
00333   nscoord ClearFloats(nscoord aY, PRUint8 aBreakType);
00334 
00335 #ifdef DEBUG
00336 
00339   nsresult List(FILE* out);
00340 #endif
00341 
00342 protected:
00343   // Structure that maintains information about the region associated
00344   // with a particular frame
00345   struct FrameInfo {
00346     nsIFrame* const mFrame;
00347     nsRect          mRect;       // rectangular region
00348     FrameInfo*      mNext;
00349 
00350     FrameInfo(nsIFrame* aFrame, const nsRect& aRect);
00351 #ifdef NS_BUILD_REFCNT_LOGGING
00352     ~FrameInfo();
00353 #endif
00354   };
00355 
00356   // Structure that stores the current state of a frame manager for
00357   // Save/Restore purposes.
00358   struct SpaceManagerState {
00359     nscoord mX, mY;
00360     nsIFrame *mLastFrame;
00361     nscoord mLowestTop;
00362     SpaceManagerState *mNext;
00363   };
00364 
00365 public:
00366   // Doubly linked list of band rects
00367   struct BandRect : PRCListStr {
00368     nscoord   mLeft, mTop;
00369     nscoord   mRight, mBottom;
00370     PRInt32   mNumFrames;    // number of frames occupying this rect
00371     union {
00372       nsIFrame*    mFrame;   // single frame occupying the space
00373       nsVoidArray* mFrames;  // list of frames occupying the space
00374     };
00375 
00376     BandRect(nscoord aLeft, nscoord aTop,
00377              nscoord aRight, nscoord aBottom,
00378              nsIFrame*);
00379     BandRect(nscoord aLeft, nscoord aTop,
00380              nscoord aRight, nscoord aBottom,
00381              nsVoidArray*);
00382     ~BandRect();
00383 
00384     // List operations
00385     BandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
00386     BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
00387     void      InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
00388     void      InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
00389     void      Remove() {PR_REMOVE_LINK(this);}
00390 
00391     // Split the band rect into two vertically, with this band rect becoming
00392     // the top part, and a new band rect being allocated and returned for the
00393     // bottom part
00394     //
00395     // Does not insert the new band rect into the linked list
00396     BandRect* SplitVertically(nscoord aBottom);
00397 
00398     // Split the band rect into two horizontally, with this band rect becoming
00399     // the left part, and a new band rect being allocated and returned for the
00400     // right part
00401     //
00402     // Does not insert the new band rect into the linked list
00403     BandRect* SplitHorizontally(nscoord aRight);
00404 
00405     // Accessor functions
00406     PRBool  IsOccupiedBy(const nsIFrame*) const;
00407     void    AddFrame(const nsIFrame*);
00408     void    RemoveFrame(const nsIFrame*);
00409     PRBool  HasSameFrameList(const BandRect* aBandRect) const;
00410     PRInt32 Length() const;
00411   };
00412 
00413   // Circular linked list of band rects
00414   struct BandList : BandRect {
00415     BandList();
00416 
00417     // Accessors
00418     PRBool    IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
00419     BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
00420     BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}
00421 
00422     // Operations
00423     void      Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}
00424 
00425     // Remove and delete all the band rects in the list
00426     void      Clear();
00427   };
00428 
00429 protected:
00430   nsIFrame* const mFrame;     // frame associated with the space manager
00431   nscoord         mX, mY;     // translation from local to global coordinate space
00432   BandList        mBandList;  // header/sentinel for circular linked list of band rects
00433   nscoord         mLowestTop;  // the lowest *top*
00434   FrameInfo*      mFrameInfoMap;
00435   nsIntervalSet   mFloatDamage;
00436 
00437   SpaceManagerState *mSavedStates;
00438   SpaceManagerState mAutoState;
00439 
00440 protected:
00441   FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
00442   FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect& aRect);
00443   void       DestroyFrameInfo(FrameInfo*);
00444 
00445   void       ClearFrameInfo();
00446   void       ClearBandRects();
00447 
00448   BandRect*  GetNextBand(const BandRect* aBandRect) const;
00449   void       DivideBand(BandRect* aBand, nscoord aBottom);
00450   PRBool     CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
00451   PRBool     JoinBands(BandRect* aBand, BandRect* aPrevBand);
00452   void       AddRectToBand(BandRect* aBand, BandRect* aBandRect);
00453   void       InsertBandRect(BandRect* aBandRect);
00454 
00455   nsresult   GetBandAvailableSpace(const BandRect* aBand,
00456                                    nscoord         aY,
00457                                    const nsSize&   aMaxSize,
00458                                    nsBandData&     aAvailableSpace) const;
00459 
00460 private:
00461   static PRInt32 sCachedSpaceManagerCount;
00462   static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];
00463 
00464   nsSpaceManager(const nsSpaceManager&);  // no implementation
00465   void operator=(const nsSpaceManager&);  // no implementation
00466 };
00467 
00473 class nsAutoSpaceManager {
00474 public:
00475   nsAutoSpaceManager(nsHTMLReflowState& aReflowState)
00476     : mReflowState(aReflowState),
00477 #ifdef DEBUG
00478       mOwns(PR_TRUE),
00479 #endif
00480       mNew(nsnull),
00481       mOld(nsnull) {}
00482 
00483   ~nsAutoSpaceManager();
00484 
00490   nsresult
00491   CreateSpaceManagerFor(nsPresContext *aPresContext,
00492                         nsIFrame *aFrame);
00493 
00494 #ifdef DEBUG
00495 
00500   void DebugOrphanSpaceManager() { mOwns = PR_FALSE; }
00501 #endif
00502 
00503 protected:
00504   nsHTMLReflowState &mReflowState;
00505 #ifdef DEBUG
00506   PRBool mOwns;
00507 #endif
00508   nsSpaceManager *mNew;
00509   nsSpaceManager *mOld;
00510 };
00511 
00512 #endif /* nsSpaceManager_h___ */
00513