Bug 54488 - "[Mac] Non-draggable widgets in background windows should look disabled...
[mozilla-central.git] / layout / generic / nsSpaceManager.h
blob344cdff98e0b621f8888b632f2c6f10f09482675
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:cindent:ts=2:et:sw=2:
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
40 * class that manages regions of 2-D space, originally designed
41 * generally but actually specific to space occupied by floats
44 #ifndef nsSpaceManager_h___
45 #define nsSpaceManager_h___
47 #include "prclist.h"
48 #include "nsIntervalSet.h"
49 #include "nsISupports.h"
50 #include "nsCoord.h"
51 #include "nsRect.h"
52 #include "nsVoidArray.h"
54 class nsIPresShell;
55 class nsIFrame;
56 struct nsSize;
57 struct nsHTMLReflowState;
58 class nsPresContext;
60 #define NS_SPACE_MANAGER_CACHE_SIZE 4
62 /**
63 * Information about a particular trapezoid within a band. The space described
64 * by the trapezoid is in one of three states:
65 * <ul>
66 * <li>available
67 * <li>occupied by one frame
68 * <li>occupied by more than one frame
69 * </ul>
71 struct nsBandTrapezoid {
72 nscoord mTopY, mBottomY; // top and bottom y-coordinates
73 nscoord mTopLeftX, mBottomLeftX; // left edge x-coordinates
74 nscoord mTopRightX, mBottomRightX; // right edge x-coordinates
75 const nsSmallVoidArray* mFrames; // list of frames occupying the space
77 // Get the height of the trapezoid
78 nscoord GetHeight() const {return mBottomY - mTopY;}
80 // Get the bounding rect of the trapezoid
81 inline void GetRect(nsRect& aRect) const;
83 // Set the trapezoid from a rectangle
84 inline void operator=(const nsRect& aRect);
86 // Do these trapezoids have the same geometry?
87 inline PRBool EqualGeometry(const nsBandTrapezoid& aTrap) const;
89 nsBandTrapezoid()
90 : mTopY(0),
91 mBottomY(0),
92 mTopLeftX(0),
93 mBottomLeftX(0),
94 mTopRightX(0),
95 mBottomRightX(0),
96 mFrames(nsnull)
101 inline void nsBandTrapezoid::GetRect(nsRect& aRect) const
103 aRect.x = PR_MIN(mTopLeftX, mBottomLeftX);
104 aRect.y = mTopY;
105 aRect.width = PR_MAX(mTopRightX, mBottomRightX);
106 if (NS_MAXSIZE != aRect.width) {
107 aRect.width -= aRect.x;
109 aRect.height = (NS_MAXSIZE == mBottomY) ? NS_MAXSIZE : mBottomY - mTopY;
112 inline void nsBandTrapezoid::operator=(const nsRect& aRect)
114 mTopLeftX = mBottomLeftX = aRect.x;
115 mTopRightX = mBottomRightX = aRect.XMost();
116 mTopY = aRect.y;
117 mBottomY = aRect.YMost();
120 inline PRBool nsBandTrapezoid::EqualGeometry(const nsBandTrapezoid& aTrap) const
122 return (
123 mTopLeftX == aTrap.mTopLeftX &&
124 mBottomLeftX == aTrap.mBottomLeftX &&
125 mTopRightX == aTrap.mTopRightX &&
126 mBottomRightX == aTrap.mBottomRightX &&
127 mTopY == aTrap.mTopY &&
128 mBottomY == aTrap.mBottomY
133 * Structure used for describing the space within a band.
134 * @see #GetBandData()
136 struct nsBandData {
137 PRInt32 mCount; // [out] actual number of trapezoids in the band data
138 PRInt32 mSize; // [in] the size of the array (number of trapezoids)
139 nsBandTrapezoid* mTrapezoids; // [out] array of length 'size'
143 * Class for dealing with bands of available space. The space manager
144 * defines a coordinate space with an origin at (0, 0) that grows down
145 * and to the right.
147 class nsSpaceManager {
148 public:
149 nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
150 ~nsSpaceManager();
152 void* operator new(size_t aSize) CPP_THROW_NEW;
153 void operator delete(void* aPtr, size_t aSize);
155 static void Shutdown();
158 * Get the frame that's associated with the space manager. This frame
159 * created the space manager, and the world coordinate space is
160 * relative to this frame.
162 * You can use QueryInterface() on this frame to get any additional
163 * interfaces.
165 nsIFrame* GetFrame() const { return mFrame; }
168 * Translate the current origin by the specified (dx, dy). This
169 * creates a new local coordinate space relative to the current
170 * coordinate space.
172 void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
175 * Returns the current translation from local coordinate space to
176 * world coordinate space. This represents the accumulated calls to
177 * Translate().
179 void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
182 * Returns the x-most rect in the space manager, or 0 if there are no
183 * rects.
185 * @return PR_TRUE if there are bands and PR_FALSE if there are no bands
187 PRBool XMost(nscoord& aXMost) const;
190 * Returns the y-most of the bottommost band or 0 if there are no bands.
192 * @return PR_TRUE if there are bands and PR_FALSE if there are no bands
194 PRBool YMost(nscoord& aYMost) const;
197 * Returns a band starting at the specified y-offset. The band data
198 * indicates which parts of the band are available, and which parts
199 * are unavailable
201 * The band data that is returned is in the coordinate space of the
202 * local coordinate system.
204 * The local coordinate space origin, the y-offset, and the max size
205 * describe a rectangle that's used to clip the underlying band of
206 * available space, i.e.
207 * {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
208 * coordinate space
210 * @param aYOffset the y-offset of where the band begins. The coordinate is
211 * relative to the upper-left corner of the local coordinate space
212 * @param aMaxSize the size to use to constrain the band data
213 * @param aBandData [in,out] used to return the list of trapezoids that
214 * describe the available space and the unavailable space
215 * @return NS_OK if successful and NS_ERROR_FAILURE if the band data is not
216 * not large enough. The 'count' member of the band data struct
217 * indicates how large the array of trapezoids needs to be
219 nsresult GetBandData(nscoord aYOffset,
220 const nsSize& aMaxSize,
221 nsBandData& aBandData) const;
224 * Add a rectangular region of unavailable space. The space is
225 * relative to the local coordinate system.
227 * The region is tagged with a frame
229 * @param aFrame the frame used to identify the region. Must not be NULL
230 * @param aUnavailableSpace the bounding rect of the unavailable space
231 * @return NS_OK if successful
232 * NS_ERROR_FAILURE if there is already a region tagged with aFrame
234 nsresult AddRectRegion(nsIFrame* aFrame,
235 const nsRect& aUnavailableSpace);
238 * Remove the regions associated with this floating frame and its
239 * next-sibling list. Some of the frames may never have been added;
240 * we just skip those. This is not fully general; it only works as
241 * long as the N frames to be removed are the last N frames to have
242 * been added; if there's a frame in the middle of them that should
243 * not be removed, YOU LOSE.
245 * This can only be done at the end of the life of this space manager. The only
246 * methods it is safe to call after this are XMost() and YMost().
248 nsresult RemoveTrailingRegions(nsIFrame* aFrameList);
250 protected:
252 * Remove the region associated with aFrane.
254 * doesn't work in the general case!
256 * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
257 * tagged with aFrame
259 nsresult RemoveRegion(nsIFrame* aFrame);
261 public:
262 // Structure that stores the current state of a frame manager for
263 // Save/Restore purposes.
264 struct SavedState {
265 private:
266 nsIFrame *mLastFrame;
267 nscoord mX, mY;
268 nscoord mLowestTop;
269 nscoord mMaximalLeftYMost;
270 nscoord mMaximalRightYMost;
271 PRPackedBool mHaveCachedLeftYMost;
272 PRPackedBool mHaveCachedRightYMost;
274 friend class nsSpaceManager;
278 * Clears the list of regions representing the unavailable space.
280 void ClearRegions();
282 PRBool HasAnyFloats() { return mFrameInfoMap != nsnull; }
285 * Methods for dealing with the propagation of float damage during
286 * reflow.
288 PRBool HasFloatDamage()
290 return !mFloatDamage.IsEmpty();
293 void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
295 mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
298 PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
300 return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
304 * Saves the current state of the space manager into aState.
306 void PushState(SavedState* aState);
309 * Restores the space manager to the saved state.
311 * These states must be managed using stack discipline. PopState can only
312 * be used after PushState has been used to save the state, and it can only
313 * be used once --- although it can be omitted; saved states can be ignored.
314 * States must be popped in the reverse order they were pushed.
316 void PopState(SavedState* aState);
319 * Get the top of the last region placed into the space manager, to
320 * enforce the rule that a float can't be above an earlier float.
321 * Returns the minimum nscoord value if there are no regions.
323 nscoord GetLowestRegionTop();
326 * Return the coordinate of the lowest float matching aBreakType in this
327 * space manager. Returns aY if there are no matching floats.
329 nscoord ClearFloats(nscoord aY, PRUint8 aBreakType);
331 #ifdef DEBUG
333 * Dump the state of the spacemanager out to a file
335 nsresult List(FILE* out);
336 #endif
338 protected:
339 // Structure that maintains information about the region associated
340 // with a particular frame
341 struct FrameInfo {
342 nsIFrame* const mFrame;
343 nsRect mRect; // rectangular region
344 FrameInfo* mNext;
346 FrameInfo(nsIFrame* aFrame, const nsRect& aRect);
347 #ifdef NS_BUILD_REFCNT_LOGGING
348 ~FrameInfo();
349 #endif
352 public:
353 // Doubly linked list of band rects
354 struct BandRect : PRCListStr {
355 nscoord mLeft, mTop;
356 nscoord mRight, mBottom;
357 nsSmallVoidArray mFrames; // list of frames occupying the space
359 BandRect(nscoord aLeft, nscoord aTop,
360 nscoord aRight, nscoord aBottom,
361 nsIFrame* aFrame);
362 BandRect(nscoord aLeft, nscoord aTop,
363 nscoord aRight, nscoord aBottom,
364 nsSmallVoidArray& frames);
365 ~BandRect();
367 // List operations
368 BandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
369 BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
370 void InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
371 void InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
372 void Remove() {PR_REMOVE_LINK(this);}
374 // Split the band rect into two vertically, with this band rect becoming
375 // the top part, and a new band rect being allocated and returned for the
376 // bottom part
378 // Does not insert the new band rect into the linked list
379 BandRect* SplitVertically(nscoord aBottom);
381 // Split the band rect into two horizontally, with this band rect becoming
382 // the left part, and a new band rect being allocated and returned for the
383 // right part
385 // Does not insert the new band rect into the linked list
386 BandRect* SplitHorizontally(nscoord aRight);
388 // Accessor functions
389 PRBool IsOccupiedBy(const nsIFrame* aFrame) const {
390 return (mFrames.IndexOf((void*)aFrame) != -1);
392 void AddFrame(const nsIFrame* aFrame) {
393 mFrames.AppendElement((void*)aFrame);
395 void RemoveFrame(const nsIFrame* aFrame) {
396 mFrames.RemoveElement((void*)aFrame);
398 nsIFrame * FrameAt(PRInt32 index) {
399 return static_cast<nsIFrame*>(mFrames.FastElementAt(index));
401 PRBool HasSameFrameList(const BandRect* aBandRect) const;
402 PRInt32 Length() const;
405 // Circular linked list of band rects
406 struct BandList : BandRect {
407 BandList();
409 // Accessors
410 PRBool IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
411 BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
412 BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}
414 // Operations
415 void Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}
417 // Remove and delete all the band rects in the list
418 void Clear();
421 protected:
422 nsIFrame* const mFrame; // frame associated with the space manager
423 nscoord mX, mY; // translation from local to global coordinate space
424 BandList mBandList; // header/sentinel for circular linked list of band rects
425 nscoord mLowestTop; // the lowest *top*
426 FrameInfo* mFrameInfoMap;
427 nsIntervalSet mFloatDamage;
428 PRPackedBool mHaveCachedLeftYMost; // If true, mMaximalLeftYMost is set
429 PRPackedBool mHaveCachedRightYMost; // If true, mMaximalRightYMost is set
430 nscoord mMaximalLeftYMost; // The maximal YMost of our FrameInfo
431 // rects for left floats. Only makes
432 // sense when mHaveCachedLeftYMost is
433 // true.
434 nscoord mMaximalRightYMost; // The maximal YMost of our FrameInfo
435 // rects for right floats. Only makes
436 // sense when mHaveCachedLeftYMost is
437 // true.
438 // We keep track of the last BandRect* we worked with so that we can
439 // make use of locality of reference in situations where people want
440 // to do a bunch of operations in a row.
441 BandRect* mCachedBandPosition;
443 protected:
444 FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
445 FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect& aRect);
446 void DestroyFrameInfo(FrameInfo*);
448 void ClearFrameInfo();
449 void ClearBandRects();
451 BandRect* GetNextBand(const BandRect* aBandRect) const;
452 BandRect* GetPrevBand(const BandRect* aBandRect) const;
453 void DivideBand(BandRect* aBand, nscoord aBottom);
454 PRBool CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
455 PRBool JoinBands(BandRect* aBand, BandRect* aPrevBand);
456 void AddRectToBand(BandRect* aBand, BandRect* aBandRect);
457 void InsertBandRect(BandRect* aBandRect);
459 nsresult GetBandAvailableSpace(const BandRect* aBand,
460 nscoord aY,
461 const nsSize& aMaxSize,
462 nsBandData& aAvailableSpace) const;
464 // Return a band guaranteed to have its top at or above aYOffset or the first
465 // band if there is no band with its top above aYOffset. This method will
466 // use mCachedBandPosition to maybe get such a band that's not too far up.
467 // This function should not be called if there are no bands.
468 // This function never returns null.
469 BandRect* GuessBandWithTopAbove(nscoord aYOffset) const;
471 void SetCachedBandPosition(BandRect* aBandRect) {
472 NS_ASSERTION(!aBandRect ||
473 aBandRect == mBandList.Head() ||
474 aBandRect->Prev()->mBottom != aBandRect->mBottom,
475 "aBandRect should be first rect within its band");
476 mCachedBandPosition = aBandRect;
480 private:
481 static PRInt32 sCachedSpaceManagerCount;
482 static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];
484 nsSpaceManager(const nsSpaceManager&); // no implementation
485 void operator=(const nsSpaceManager&); // no implementation
489 * A helper class to manage maintenance of the space manager during
490 * nsBlockFrame::Reflow. It automatically restores the old space
491 * manager in the reflow state when the object goes out of scope.
493 class nsAutoSpaceManager {
494 public:
495 nsAutoSpaceManager(nsHTMLReflowState& aReflowState)
496 : mReflowState(aReflowState),
497 #ifdef DEBUG
498 mOwns(PR_TRUE),
499 #endif
500 mNew(nsnull),
501 mOld(nsnull) {}
503 ~nsAutoSpaceManager();
506 * Create a new space manager for the specified frame. This will
507 * `remember' the old space manager, and install the new space
508 * manager in the reflow state.
510 nsresult
511 CreateSpaceManagerFor(nsPresContext *aPresContext,
512 nsIFrame *aFrame);
514 #ifdef DEBUG
516 * `Orphan' any space manager that the nsAutoSpaceManager created;
517 * i.e., make it so that we don't destroy the space manager when we
518 * go out of scope.
520 void DebugOrphanSpaceManager() { mOwns = PR_FALSE; }
521 #endif
523 protected:
524 nsHTMLReflowState &mReflowState;
525 #ifdef DEBUG
526 PRBool mOwns;
527 #endif
528 nsSpaceManager *mNew;
529 nsSpaceManager *mOld;
532 #endif /* nsSpaceManager_h___ */