Bug 54488 - "[Mac] Non-draggable widgets in background windows should look disabled...
[mozilla-central.git] / layout / generic / nsSpaceManager.cpp
blobe48151e9bb2c7a789a3f02d5260bb353d454e82c
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Pierre Phaneuf <pp@ludusdesign.com>
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 #include "nsSpaceManager.h"
45 #include "nsPoint.h"
46 #include "nsRect.h"
47 #include "nsSize.h"
48 #include <stdlib.h>
49 #include "nsVoidArray.h"
50 #include "nsIFrame.h"
51 #include "nsString.h"
52 #include "nsIPresShell.h"
53 #include "nsMemory.h"
54 #include "nsHTMLReflowState.h"
55 #include "nsHashSets.h"
56 #ifdef DEBUG
57 #include "nsIFrameDebug.h"
58 #endif
60 /////////////////////////////////////////////////////////////////////////////
61 // BandList
63 PRInt32 nsSpaceManager::sCachedSpaceManagerCount = 0;
64 void* nsSpaceManager::sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];
66 #define NSCOORD_MIN (-2147483647 - 1) /* minimum signed value */
68 nsSpaceManager::BandList::BandList()
69 : nsSpaceManager::BandRect(NSCOORD_MIN, NSCOORD_MIN, NSCOORD_MIN, NSCOORD_MIN, (nsIFrame*)nsnull)
71 PR_INIT_CLIST(this);
74 void
75 nsSpaceManager::BandList::Clear()
77 if (!IsEmpty()) {
78 BandRect* bandRect = Head();
80 while (bandRect != this) {
81 BandRect* nxt = bandRect->Next();
83 delete bandRect;
84 bandRect = nxt;
87 PR_INIT_CLIST(this);
91 /////////////////////////////////////////////////////////////////////////////
93 // PresShell Arena allocate callback (for nsIntervalSet use below)
94 PR_STATIC_CALLBACK(void*)
95 PSArenaAllocCB(size_t aSize, void* aClosure)
97 return static_cast<nsIPresShell*>(aClosure)->AllocateFrame(aSize);
100 // PresShell Arena free callback (for nsIntervalSet use below)
101 PR_STATIC_CALLBACK(void)
102 PSArenaFreeCB(size_t aSize, void* aPtr, void* aClosure)
104 static_cast<nsIPresShell*>(aClosure)->FreeFrame(aSize, aPtr);
107 /////////////////////////////////////////////////////////////////////////////
108 // nsSpaceManager
110 nsSpaceManager::nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame)
111 : mFrame(aFrame),
112 mLowestTop(NSCOORD_MIN),
113 mFloatDamage(PSArenaAllocCB, PSArenaFreeCB, aPresShell),
114 mHaveCachedLeftYMost(PR_TRUE),
115 mHaveCachedRightYMost(PR_TRUE),
116 mMaximalLeftYMost(nscoord_MIN),
117 mMaximalRightYMost(nscoord_MIN),
118 mCachedBandPosition(nsnull)
120 MOZ_COUNT_CTOR(nsSpaceManager);
121 mX = mY = 0;
122 mFrameInfoMap = nsnull;
125 void
126 nsSpaceManager::ClearFrameInfo()
128 while (mFrameInfoMap) {
129 FrameInfo* next = mFrameInfoMap->mNext;
130 delete mFrameInfoMap;
131 mFrameInfoMap = next;
135 nsSpaceManager::~nsSpaceManager()
137 MOZ_COUNT_DTOR(nsSpaceManager);
138 mBandList.Clear();
139 ClearFrameInfo();
142 // static
143 void* nsSpaceManager::operator new(size_t aSize) CPP_THROW_NEW
145 if (sCachedSpaceManagerCount > 0) {
146 // We have cached unused instances of this class, return a cached
147 // instance in stead of always creating a new one.
148 return sCachedSpaceManagers[--sCachedSpaceManagerCount];
151 // The cache is empty, this means we haveto create a new instance using
152 // the global |operator new|.
153 return nsMemory::Alloc(aSize);
156 void
157 nsSpaceManager::operator delete(void* aPtr, size_t aSize)
159 if (!aPtr)
160 return;
161 // This space manager is no longer used, if there's still room in
162 // the cache we'll cache this space manager, unless the layout
163 // module was already shut down.
165 if (sCachedSpaceManagerCount < NS_SPACE_MANAGER_CACHE_SIZE &&
166 sCachedSpaceManagerCount >= 0) {
167 // There's still space in the cache for more instances, put this
168 // instance in the cache in stead of deleting it.
170 sCachedSpaceManagers[sCachedSpaceManagerCount++] = aPtr;
171 return;
174 // The cache is full, or the layout module has been shut down,
175 // delete this space manager.
176 nsMemory::Free(aPtr);
180 /* static */
181 void nsSpaceManager::Shutdown()
183 // The layout module is being shut down, clean up the cache and
184 // disable further caching.
186 PRInt32 i;
188 for (i = 0; i < sCachedSpaceManagerCount; i++) {
189 void* spaceManager = sCachedSpaceManagers[i];
190 if (spaceManager)
191 nsMemory::Free(spaceManager);
194 // Disable further caching.
195 sCachedSpaceManagerCount = -1;
198 PRBool
199 nsSpaceManager::XMost(nscoord& aXMost) const
201 nscoord xMost = 0;
202 for (FrameInfo* fi = mFrameInfoMap; fi; fi = fi->mNext) {
203 xMost = PR_MAX(xMost, fi->mRect.XMost());
205 aXMost = xMost;
206 return !mBandList.IsEmpty();
209 PRBool
210 nsSpaceManager::YMost(nscoord& aYMost) const
212 PRBool result;
214 if (mBandList.IsEmpty()) {
215 aYMost = 0;
216 result = PR_FALSE;
218 } else {
219 BandRect* lastRect = mBandList.Tail();
221 aYMost = lastRect->mBottom;
222 result = PR_TRUE;
225 return result;
229 * Internal function that returns the list of available and unavailable space
230 * within the band
232 * Note: If the clip rectangle has 0 width and is aligned exactly at
233 * aBand->mLeft or aBand->mRight, we count it as intersecting the band, and we
234 * return an unavailable-space trapezoid for the band. (The alternative would
235 * be to return a zero-width available-space trapezoid, which would make no
236 * sense. See bug 403129)
238 * @param aBand the first rect in the band
239 * @param aY the y-offset in world coordinates
240 * @param aMaxSize the size to use to constrain the band data
241 * @param aBandData the object to populate with available and unavailable space
243 nsresult
244 nsSpaceManager::GetBandAvailableSpace(const BandRect* aBand,
245 nscoord aY,
246 const nsSize& aMaxSize,
247 nsBandData& aBandData) const
249 nscoord topOfBand = aBand->mTop;
250 nscoord localY = aY - mY;
251 nscoord height = PR_MIN(aBand->mBottom - aY, aMaxSize.height);
252 nsBandTrapezoid* trapezoid = aBandData.mTrapezoids;
253 nscoord rightEdge = mX + aMaxSize.width;
255 // Initialize the band data
256 aBandData.mCount = 0;
258 // Skip any rectangles that are to the left of the local coordinate space
259 while (aBand->mTop == topOfBand) {
260 if (aBand->mRight > mX ||
261 (aMaxSize.width == 0 && aBand->mRight == mX)) {
262 break;
265 // Get the next rect in the band
266 aBand = aBand->Next();
269 // This is used to track the current x-location within the band. This is in
270 // world coordinates
271 nscoord left = mX;
273 // Process the remaining rectangles that are within the clip width
274 while ((aBand->mTop == topOfBand) &&
275 (aBand->mLeft < rightEdge ||
276 (aMaxSize.width == 0 && aBand->mLeft == mX))) {
277 // Compare the left edge of the occupied space with the current left
278 // coordinate
279 if (aBand->mLeft > left) {
280 // The rect is to the right of our current left coordinate, so we've
281 // found some available space
282 if (aBandData.mCount >= aBandData.mSize) {
283 // Not enough space in the array of trapezoids
284 aBandData.mCount += 2 * aBand->Length() + 2; // estimate the number needed
285 return NS_ERROR_FAILURE;
287 trapezoid->mFrames = nsnull;
289 // Assign the trapezoid a rectangular shape. The trapezoid must be in the
290 // local coordinate space, so convert the current left coordinate
291 *trapezoid = nsRect(left - mX, localY, aBand->mLeft - left, height);
293 // Move to the next output rect
294 trapezoid++;
295 aBandData.mCount++;
298 // The rect represents unavailable space, so add another trapezoid
299 if (aBandData.mCount >= aBandData.mSize) {
300 // Not enough space in the array of trapezoids
301 aBandData.mCount += 2 * aBand->Length() + 1; // estimate the number needed
302 return NS_ERROR_FAILURE;
304 NS_ASSERTION(aBand->mFrames.Count() > 0, "unexpected frame count");
305 trapezoid->mFrames = &aBand->mFrames;
307 nscoord x = aBand->mLeft;
308 // The first band can straddle the clip rect
309 if (x < mX) {
310 // Clip the left edge
311 x = mX;
314 // Assign the trapezoid a rectangular shape. The trapezoid must be in the
315 // local coordinate space, so convert the rects's left coordinate
316 *trapezoid = nsRect(x - mX, localY, aBand->mRight - x, height);
318 // Move to the next output rect
319 trapezoid++;
320 aBandData.mCount++;
322 // Adjust our current x-location within the band
323 left = aBand->mRight;
325 // Move to the next rect within the band
326 aBand = aBand->Next();
329 // No more rects left in the band. If we haven't yet reached the right edge,
330 // then all the remaining space is available
331 if (left < rightEdge || aBandData.mCount == 0) {
332 if (aBandData.mCount >= aBandData.mSize) {
333 // Not enough space in the array of trapezoids
334 aBandData.mCount++;
335 return NS_ERROR_FAILURE;
337 trapezoid->mFrames = nsnull;
339 // Assign the trapezoid a rectangular shape. The trapezoid must be in the
340 // local coordinate space, so convert the current left coordinate
341 *trapezoid = nsRect(left - mX, localY, rightEdge - left, height);
342 aBandData.mCount++;
345 return NS_OK;
348 nsresult
349 nsSpaceManager::GetBandData(nscoord aYOffset,
350 const nsSize& aMaxSize,
351 nsBandData& aBandData) const
353 NS_PRECONDITION(aBandData.mSize >= 1, "bad band data");
354 nsresult result = NS_OK;
356 // Convert the y-offset to world coordinates
357 nscoord y = mY + aYOffset;
359 // If there are no unavailable rects or the offset is below the bottommost
360 // band, then all the space is available
361 nscoord yMost;
362 nscoord maxHeight = aMaxSize.height == NS_UNCONSTRAINEDSIZE ? NS_UNCONSTRAINEDSIZE
363 : PR_MAX(0, aMaxSize.height - aYOffset);
365 if (!YMost(yMost) || (y >= yMost)) {
366 // All the requested space is available
367 aBandData.mCount = 1;
368 aBandData.mTrapezoids[0] = nsRect(0, aYOffset, aMaxSize.width, maxHeight);
369 aBandData.mTrapezoids[0].mFrames = nsnull;
370 } else {
371 // Find the first band that contains the y-offset or is below the y-offset
372 BandRect* band = GuessBandWithTopAbove(y);
374 aBandData.mCount = 0;
375 while (nsnull != band) {
376 if (band->mTop > y) {
377 // The band is below the y-offset. The area between the y-offset and
378 // the top of the band is available
379 aBandData.mCount = 1;
380 aBandData.mTrapezoids[0] =
381 nsRect(0, aYOffset, aMaxSize.width, PR_MIN(band->mTop - y, maxHeight));
382 aBandData.mTrapezoids[0].mFrames = nsnull;
383 break;
384 } else if (y < band->mBottom) {
385 // The band contains the y-offset. Return a list of available and
386 // unavailable rects within the band
387 return GetBandAvailableSpace(band, y, nsSize(aMaxSize.width, maxHeight), aBandData);
388 } else {
389 // Skip to the next band
390 band = GetNextBand(band);
395 NS_POSTCONDITION(aBandData.mCount > 0, "unexpected band data count");
396 return result;
400 * Skips to the start of the next band.
402 * @param aBandRect A rect within the band
403 * @returns The start of the next band, or nsnull of this is the last band.
405 nsSpaceManager::BandRect*
406 nsSpaceManager::GetNextBand(const BandRect* aBandRect) const
408 nscoord topOfBand = aBandRect->mTop;
410 aBandRect = aBandRect->Next();
411 while (aBandRect != &mBandList) {
412 // Check whether this rect is part of the same band
413 if (aBandRect->mTop != topOfBand) {
414 // We found the start of the next band
415 return (BandRect*)aBandRect;
418 aBandRect = aBandRect->Next();
421 // No bands left
422 return nsnull;
426 * Skips to the start of the previous band.
428 * @param aBandRect The first rect within a band
429 * @returns The start of the previous band, or nsnull of this is the first band.
431 nsSpaceManager::BandRect*
432 nsSpaceManager::GetPrevBand(const BandRect* aBandRect) const
434 NS_ASSERTION(aBandRect->Prev() == &mBandList ||
435 aBandRect->Prev()->mBottom <= aBandRect->mTop,
436 "aBandRect should be first rect within its band");
438 BandRect* prev = aBandRect->Prev();
439 nscoord topOfBand = prev->mTop;
441 while (prev != &mBandList) {
442 // Check whether the prev rect is part of the same band
443 if (prev->mTop != topOfBand) {
444 // We found the beginning of this band
445 return (BandRect*)aBandRect;
448 aBandRect = prev;
449 prev = aBandRect->Prev();
452 // No bands left
453 return nsnull;
457 * Divides the current band into two vertically
459 * @param aBandRect the first rect in the band
460 * @param aBottom where to split the band. This becomes the bottom of the top
461 * part
463 void
464 nsSpaceManager::DivideBand(BandRect* aBandRect, nscoord aBottom)
466 NS_PRECONDITION(aBottom < aBandRect->mBottom, "bad height");
467 nscoord topOfBand = aBandRect->mTop;
468 BandRect* nextBand = GetNextBand(aBandRect);
470 if (nsnull == nextBand) {
471 nextBand = (BandRect*)&mBandList;
474 while (topOfBand == aBandRect->mTop) {
475 // Split the band rect into two vertically
476 BandRect* bottomBandRect = aBandRect->SplitVertically(aBottom);
478 // Insert the new bottom part
479 nextBand->InsertBefore(bottomBandRect);
481 // Move to the next rect in the band
482 aBandRect = aBandRect->Next();
486 PRBool
487 nsSpaceManager::CanJoinBands(BandRect* aBand, BandRect* aPrevBand)
489 PRBool result;
490 nscoord topOfBand = aBand->mTop;
491 nscoord topOfPrevBand = aPrevBand->mTop;
493 // The bands can be joined if:
494 // - they're adjacent
495 // - they have the same number of rects
496 // - each rect has the same left and right edge as its corresponding rect, and
497 // the rects are occupied by the same frames
498 if (aPrevBand->mBottom == aBand->mTop) {
499 // Compare each of the rects in the two bands
500 while (PR_TRUE) {
501 if ((aBand->mLeft != aPrevBand->mLeft) || (aBand->mRight != aPrevBand->mRight)) {
502 // The rects have different edges
503 result = PR_FALSE;
504 break;
507 if (!aBand->HasSameFrameList(aPrevBand)) {
508 // The rects are occupied by different frames
509 result = PR_FALSE;
510 break;
513 // Move to the next rects within the bands
514 aBand = aBand->Next();
515 aPrevBand = aPrevBand->Next();
517 // Have we reached the end of either band?
518 PRBool endOfBand = aBand->mTop != topOfBand;
519 PRBool endOfPrevBand = aPrevBand->mTop != topOfPrevBand;
521 if (endOfBand || endOfPrevBand) {
522 result = endOfBand & endOfPrevBand;
523 break; // all done
527 } else {
528 // The bands aren't adjacent
529 result = PR_FALSE;
532 return result;
536 * Tries to join the two adjacent bands. Returns PR_TRUE if successful and
537 * PR_FALSE otherwise
539 * If the two bands are joined, the previous band is the band that's deleted
541 PRBool
542 nsSpaceManager::JoinBands(BandRect* aBand, BandRect* aPrevBand)
544 if (CanJoinBands(aBand, aPrevBand)) {
545 BandRect* startOfNextBand = aBand;
546 // We're going to be removing aPrevBand, so if mCachedBandPosition points
547 // to it just advance it to startOfNextBand.
548 if (mCachedBandPosition == aPrevBand) {
549 SetCachedBandPosition(startOfNextBand);
552 while (aPrevBand != startOfNextBand) {
553 // Adjust the top of the band we're keeping, and then move to the next
554 // rect within the band
555 aBand->mTop = aPrevBand->mTop;
556 aBand = aBand->Next();
558 // Delete the rect from the previous band
559 BandRect* next = aPrevBand->Next();
561 NS_ASSERTION(mCachedBandPosition != aPrevBand,
562 "Removing mCachedBandPosition BandRect?");
563 aPrevBand->Remove();
564 delete aPrevBand;
565 aPrevBand = next;
568 return PR_TRUE;
571 return PR_FALSE;
575 * Adds a new rect to a band.
577 * @param aBand the first rect in the band
578 * @param aBandRect the band rect to add to the band
580 void
581 nsSpaceManager::AddRectToBand(BandRect* aBand, BandRect* aBandRect)
583 NS_PRECONDITION((aBand->mTop == aBandRect->mTop) &&
584 (aBand->mBottom == aBandRect->mBottom), "bad band");
585 NS_PRECONDITION(1 == aBandRect->mFrames.Count(), "shared band rect");
586 nscoord topOfBand = aBand->mTop;
588 // Figure out where in the band horizontally to insert the rect
589 do {
590 // Compare the left edge of the new rect with the left edge of the existing
591 // rect
592 if (aBandRect->mLeft < aBand->mLeft) {
593 // The new rect's left edge is to the left of the existing rect's left edge.
594 // Could be any of these cases (N is new rect, E is existing rect):
596 // Case 1: left-of Case 2: overlaps Case 3: N.contains(E)
597 // --------------- ---------------- ---------------------
598 // +-----+ +-----+ +-----+ +---------+
599 // | N | | E | | N | | N |
600 // +-----+ +-----+ +-----+ +---------+
601 // +-----+ +---+
602 // | E | | E |
603 // +-----+ +---+
605 // Do the two rectangles overlap?
606 if (aBandRect->mRight <= aBand->mLeft) {
607 // No, the new rect is completely to the left of the existing rect
608 // (case #1). Insert a new rect
609 aBand->InsertBefore(aBandRect);
610 if (mCachedBandPosition == aBand) {
611 SetCachedBandPosition(aBandRect);
613 return;
616 // Yes, they overlap. Compare the right edges.
617 if (aBandRect->mRight > aBand->mRight) {
618 // The new rect's right edge is to the right of the existing rect's
619 // right edge (case #3). Split the new rect
620 BandRect* r1 = aBandRect->SplitHorizontally(aBand->mLeft);
622 // Insert the part of the new rect that's to the left of the existing
623 // rect as a new band rect
624 aBand->InsertBefore(aBandRect);
625 if (mCachedBandPosition == aBand) {
626 SetCachedBandPosition(aBandRect);
629 // Continue below with the part that overlaps the existing rect
630 aBandRect = r1;
632 } else {
633 if (aBand->mRight > aBandRect->mRight) {
634 // The existing rect extends past the new rect (case #2). Split the
635 // existing rect
636 BandRect* r1 = aBand->SplitHorizontally(aBandRect->mRight);
638 // Insert the new right half of the existing rect
639 aBand->InsertAfter(r1);
642 // Insert the part of the new rect that's to the left of the existing
643 // rect
644 aBandRect->mRight = aBand->mLeft;
645 aBand->InsertBefore(aBandRect);
647 if (mCachedBandPosition == aBand) {
648 SetCachedBandPosition(aBandRect);
651 // Mark the existing rect as shared
652 aBand->AddFrame(aBandRect->FrameAt(0));
653 return;
657 if (aBandRect->mLeft > aBand->mLeft) {
658 // The new rect's left edge is to the right of the existing rect's left
659 // edge. Could be any one of these cases:
661 // Case 4: right-of Case 5: overlaps Case 6: E.Contains(N)
662 // --------------- ---------------- ---------------------
663 // +-----+ +-----+ +-----+ +------------+
664 // | E | | N | | E | | E |
665 // +-----+ +-----+ +-----+ +------------+
666 // +-----+ +-----+
667 // | N | | N |
668 // +-----+ +-----+
670 if (aBandRect->mLeft >= aBand->mRight) {
671 // The new rect is to the right of the existing rect (case #4), so move
672 // to the next rect in the band
673 aBand = aBand->Next();
674 continue;
677 // The rects overlap, so divide the existing rect into two rects: the
678 // part to the left of the new rect, and the part that overlaps
679 BandRect* r1 = aBand->SplitHorizontally(aBandRect->mLeft);
681 // Insert the new right half of the existing rect, and make it the current
682 // rect
683 aBand->InsertAfter(r1);
684 aBand = r1;
687 // At this point the left edge of the new rect is the same as the left edge
688 // of the existing rect
689 NS_ASSERTION(aBandRect->mLeft == aBand->mLeft, "unexpected rect");
691 // Compare which rect is wider, the new rect or the existing rect
692 if (aBand->mRight > aBandRect->mRight) {
693 // The existing rect is wider (case #6). Divide the existing rect into
694 // two rects: the part that overlaps, and the part to the right of the
695 // new rect
696 BandRect* r1 = aBand->SplitHorizontally(aBandRect->mRight);
698 // Insert the new right half of the existing rect
699 aBand->InsertAfter(r1);
701 // Mark the overlap as being shared
702 aBand->AddFrame(aBandRect->FrameAt(0));
704 // We no longer need aBandRect, since the area it covers is covered by
705 // the part of aBand that SplitHorizontally left in place. Just delete
706 // it.
707 delete aBandRect;
708 return;
710 } else {
711 // Indicate the frames share the existing rect
712 aBand->AddFrame(aBandRect->FrameAt(0));
714 if (aBand->mRight == aBandRect->mRight) {
715 // The new and existing rect have the same right edge. We're all done,
716 // and the new band rect is no longer needed
717 delete aBandRect;
718 return;
719 } else {
720 // The new rect is wider than the existing rect (cases #5). Set the
721 // new rect to be the overhang, and move to the next rect within the band
722 aBandRect->mLeft = aBand->mRight;
723 aBand = aBand->Next();
724 continue;
727 } while (aBand->mTop == topOfBand);
729 // Insert a new rect. This is an insertion at the _end_ of the band, so we
730 // absolutely do not want to set mCachedBandPosition to aBandRect here.
731 aBand->InsertBefore(aBandRect);
734 // When comparing a rect to a band there are seven cases to consider.
735 // 'R' is the rect and 'B' is the band.
737 // Case 1 Case 2 Case 3 Case 4
738 // ------ ------ ------ ------
739 // +-----+ +-----+ +-----+ +-----+
740 // | R | | R | +-----+ +-----+ | | | |
741 // +-----+ +-----+ | | | R | | B | | B |
742 // +-----+ | B | +-----+ | | +-----+ | |
743 // | | | | +-----+ | R | +-----+
744 // | B | +-----+ +-----+
745 // | |
746 // +-----+
750 // Case 5 Case 6 Case 7
751 // ------ ------ ------
752 // +-----+ +-----+ +-----+ +-----+
753 // | | | R | | B | | | +-----+
754 // | B | +-----+ +-----+ | R | | B |
755 // | | | | +-----+
756 // +-----+ +-----+
757 // +-----+
758 // | R |
759 // +-----+
761 void
762 nsSpaceManager::InsertBandRect(BandRect* aBandRect)
764 // If there are no existing bands or this rect is below the bottommost
765 // band, then add a new band
766 nscoord yMost;
767 if (!YMost(yMost) || (aBandRect->mTop >= yMost)) {
768 mBandList.Append(aBandRect);
769 SetCachedBandPosition(aBandRect);
770 return;
773 // Examine each band looking for a band that intersects this rect
774 // First guess a band whose top is above aBandRect->mTop. We know
775 // aBandRect won't overlap any bands before that one.
776 BandRect* band = GuessBandWithTopAbove(aBandRect->mTop);
778 while (nsnull != band) {
779 // Compare the top edge of this rect with the top edge of the band
780 if (aBandRect->mTop < band->mTop) {
781 // The top edge of the rect is above the top edge of the band.
782 // Is there any overlap?
783 if (aBandRect->mBottom <= band->mTop) {
784 // Case #1. This rect is completely above the band, so insert a
785 // new band before the current band
786 band->InsertBefore(aBandRect);
787 SetCachedBandPosition(aBandRect);
788 break; // we're all done
791 // Case #2 and case #7. Divide this rect, creating a new rect for
792 // the part that's above the band
793 BandRect* bandRect1 = new BandRect(aBandRect->mLeft, aBandRect->mTop,
794 aBandRect->mRight, band->mTop,
795 aBandRect->mFrames);
797 // Insert bandRect1 as a new band
798 band->InsertBefore(bandRect1);
800 // Modify this rect to exclude the part above the band
801 aBandRect->mTop = band->mTop;
803 } else if (aBandRect->mTop > band->mTop) {
804 // The top edge of the rect is below the top edge of the band. Is there
805 // any overlap?
806 if (aBandRect->mTop >= band->mBottom) {
807 // Case #5. This rect is below the current band. Skip to the next band
808 band = GetNextBand(band);
809 continue;
812 // Case #3 and case #4. Divide the current band into two bands with the
813 // top band being the part that's above the rect
814 DivideBand(band, aBandRect->mTop);
816 // Skip to the bottom band that we just created
817 band = GetNextBand(band);
820 // At this point the rect and the band should have the same y-offset
821 NS_ASSERTION(aBandRect->mTop == band->mTop, "unexpected band");
823 // Is the band higher than the rect?
824 if (band->mBottom > aBandRect->mBottom) {
825 // Divide the band into two bands with the top band the same height
826 // as the rect
827 DivideBand(band, aBandRect->mBottom);
830 if (aBandRect->mBottom == band->mBottom) {
831 // Add the rect to the band
832 SetCachedBandPosition(band); // Do this before AddRectToBand
833 AddRectToBand(band, aBandRect);
834 break;
836 } else {
837 // Case #4 and case #7. The rect contains the band vertically. Divide
838 // the rect, creating a new rect for the part that overlaps the band
839 BandRect* bandRect1 = new BandRect(aBandRect->mLeft, aBandRect->mTop,
840 aBandRect->mRight, band->mBottom,
841 aBandRect->mFrames);
843 // Add bandRect1 to the band
844 AddRectToBand(band, bandRect1);
846 // Modify aBandRect to be the part below the band
847 aBandRect->mTop = band->mBottom;
849 // Continue with the next band
850 band = GetNextBand(band);
851 if (nsnull == band) {
852 // Append a new bottommost band
853 mBandList.Append(aBandRect);
854 SetCachedBandPosition(aBandRect);
855 break;
861 nsresult
862 nsSpaceManager::AddRectRegion(nsIFrame* aFrame, const nsRect& aUnavailableSpace)
864 NS_PRECONDITION(nsnull != aFrame, "null frame");
866 // Convert the frame to world coordinates
867 nsRect rect(aUnavailableSpace.x + mX, aUnavailableSpace.y + mY,
868 aUnavailableSpace.width, aUnavailableSpace.height);
870 if (rect.y > mLowestTop)
871 mLowestTop = rect.y;
873 // Create a frame info structure
874 FrameInfo* frameInfo = CreateFrameInfo(aFrame, rect);
875 if (nsnull == frameInfo) {
876 return NS_ERROR_OUT_OF_MEMORY;
879 if (aUnavailableSpace.IsEmpty())
880 return NS_OK;
882 // Allocate a band rect
883 BandRect* bandRect = new BandRect(rect.x, rect.y,
884 PR_MIN(rect.XMost(), nscoord_MAX),
885 PR_MIN(rect.YMost(), nscoord_MAX),
886 aFrame);
887 if (nsnull == bandRect) {
888 return NS_ERROR_OUT_OF_MEMORY;
891 // Insert the band rect
892 InsertBandRect(bandRect);
893 return NS_OK;
896 nsresult
897 nsSpaceManager::RemoveTrailingRegions(nsIFrame* aFrameList) {
898 nsVoidHashSet frameSet;
900 frameSet.Init(1);
901 for (nsIFrame* f = aFrameList; f; f = f->GetNextSibling()) {
902 frameSet.Put(f);
905 // Pop frame regions off as long as they're in the set of frames to
906 // remove
907 while (mFrameInfoMap && frameSet.Contains(mFrameInfoMap->mFrame)) {
908 RemoveRegion(mFrameInfoMap->mFrame);
911 #ifdef DEBUG
912 for (FrameInfo* frameInfo = mFrameInfoMap; frameInfo;
913 frameInfo = frameInfo->mNext) {
914 NS_ASSERTION(!frameSet.Contains(frameInfo->mFrame),
915 "Frame region deletion was requested but we couldn't delete it");
917 #endif
919 return NS_OK;
922 nsresult
923 nsSpaceManager::RemoveRegion(nsIFrame* aFrame)
925 // Get the frame info associated with aFrame
926 FrameInfo* frameInfo = GetFrameInfoFor(aFrame);
928 if (nsnull == frameInfo) {
929 NS_WARNING("no region associated with aFrame");
930 return NS_ERROR_INVALID_ARG;
933 if (!frameInfo->mRect.IsEmpty()) {
934 NS_ASSERTION(!mBandList.IsEmpty(), "no bands");
935 BandRect* band = mBandList.Head();
936 BandRect* prevBand = nsnull;
937 PRBool prevFoundMatchingRect = PR_FALSE;
939 // Iterate each band looking for rects tagged with aFrame
940 while (nsnull != band) {
941 BandRect* rect = band;
942 BandRect* prevRect = nsnull;
943 nscoord topOfBand = band->mTop;
944 PRBool foundMatchingRect = PR_FALSE;
945 PRBool prevIsSharedRect = PR_FALSE;
947 // Iterate each rect in the band
948 do {
949 PRBool isSharedRect = PR_FALSE;
951 if (rect->IsOccupiedBy(aFrame)) {
952 // Remember that we found a matching rect in this band
953 foundMatchingRect = PR_TRUE;
955 if (rect->mFrames.Count() > 1) {
956 // The band rect is occupied by more than one frame
957 rect->mFrames.RemoveElement(aFrame);
959 // Remember that this rect was being shared by more than one frame
960 // including aFrame
961 isSharedRect = PR_TRUE;
962 } else {
963 // The rect isn't shared so just delete it
964 BandRect* next = rect->Next();
965 rect->Remove();
966 if (rect == band) {
967 // The rect we're deleting is the start of the band
968 if (topOfBand == next->mTop) {
969 band = next;
970 } else {
971 band = nsnull;
973 if (mCachedBandPosition == rect) {
974 SetCachedBandPosition(band);
977 delete rect;
978 rect = next;
980 // We don't need to try and coalesce adjacent rects in this case
981 prevRect = nsnull;
982 prevIsSharedRect = PR_FALSE;
983 continue;
987 // If we found a shared rect occupied by aFrame, then we need to try
988 // and coalesce adjacent rects
989 if (prevIsSharedRect || (isSharedRect && (nsnull != prevRect))) {
990 NS_ASSERTION(nsnull != prevRect, "no previous rect");
991 if ((prevRect->mRight == rect->mLeft) && (prevRect->HasSameFrameList(rect))) {
992 // Modify the current rect's left edge, and delete the previous rect
993 rect->mLeft = prevRect->mLeft;
994 prevRect->Remove();
995 if (prevRect == band) {
996 // the rect we're deleting is the start of the band
997 band = rect;
998 if (mCachedBandPosition == prevRect) {
999 SetCachedBandPosition(band);
1002 delete prevRect;
1006 // Get the next rect in the band
1007 prevRect = rect;
1008 prevIsSharedRect = isSharedRect;
1009 rect = rect->Next();
1010 } while (rect->mTop == topOfBand);
1012 if (nsnull != band) {
1013 // If we found a rect occupied by aFrame in this band or the previous band
1014 // then try to join the two bands
1015 if ((nsnull != prevBand) && (foundMatchingRect || prevFoundMatchingRect)) {
1016 // Try and join this band with the previous band
1017 JoinBands(band, prevBand);
1021 // Move to the next band
1022 prevFoundMatchingRect = foundMatchingRect;
1023 prevBand = band;
1024 band = (rect == &mBandList) ? nsnull : rect;
1025 if (!mCachedBandPosition) {
1026 SetCachedBandPosition(band);
1031 DestroyFrameInfo(frameInfo);
1032 return NS_OK;
1035 void
1036 nsSpaceManager::ClearRegions()
1038 ClearFrameInfo();
1039 mBandList.Clear();
1040 mLowestTop = NSCOORD_MIN;
1041 mHaveCachedLeftYMost = mHaveCachedRightYMost = PR_TRUE;
1042 mMaximalLeftYMost = mMaximalRightYMost = nscoord_MIN;
1045 void
1046 nsSpaceManager::PushState(SavedState* aState)
1048 NS_PRECONDITION(aState, "Need a place to save state");
1050 // This is a cheap push implementation, which
1051 // only saves the (x,y) and last frame in the mFrameInfoMap
1052 // which is enough info to get us back to where we should be
1053 // when pop is called.
1055 // This push/pop mechanism is used to undo any
1056 // floats that were added during the unconstrained reflow
1057 // in nsBlockReflowContext::DoReflowBlock(). (See bug 96736)
1059 // It should also be noted that the state for mFloatDamage is
1060 // intentionally not saved or restored in PushState() and PopState(),
1061 // since that could lead to bugs where damage is missed/dropped when
1062 // we move from position A to B (during the intermediate incremental
1063 // reflow mentioned above) and then from B to C during the subsequent
1064 // reflow. In the typical case A and C will be the same, but not always.
1065 // Allowing mFloatDamage to accumulate the damage incurred during both
1066 // reflows ensures that nothing gets missed.
1067 aState->mX = mX;
1068 aState->mY = mY;
1069 aState->mLowestTop = mLowestTop;
1070 aState->mHaveCachedLeftYMost = mHaveCachedLeftYMost;
1071 aState->mHaveCachedRightYMost = mHaveCachedRightYMost;
1072 aState->mMaximalLeftYMost = mMaximalLeftYMost;
1073 aState->mMaximalRightYMost = mMaximalRightYMost;
1075 if (mFrameInfoMap) {
1076 aState->mLastFrame = mFrameInfoMap->mFrame;
1077 } else {
1078 aState->mLastFrame = nsnull;
1082 void
1083 nsSpaceManager::PopState(SavedState* aState)
1085 NS_PRECONDITION(aState, "No state to restore?");
1087 // This is a quick and dirty pop implementation, to
1088 // match the current implementation of PushState(). The
1089 // idea here is to remove any frames that have been added
1090 // to the mFrameInfoMap since the last call to PushState().
1092 // Say we don't have cached left- and right-YMost, so that we don't
1093 // try to check for it in RemoveRegion. We'll restore these from
1094 // the state anyway.
1095 mHaveCachedLeftYMost = mHaveCachedRightYMost = PR_FALSE;
1097 // mFrameInfoMap is LIFO so keep removing what it points
1098 // to until we hit mLastFrame.
1099 while (mFrameInfoMap && mFrameInfoMap->mFrame != aState->mLastFrame) {
1100 RemoveRegion(mFrameInfoMap->mFrame);
1103 // If we trip this assertion it means that someone added
1104 // PushState()/PopState() calls around code that actually
1105 // removed mLastFrame from mFrameInfoMap, which means our
1106 // state is now out of sync with what we thought it should be.
1108 NS_ASSERTION(((aState->mLastFrame && mFrameInfoMap) ||
1109 (!aState->mLastFrame && !mFrameInfoMap)),
1110 "Unexpected outcome!");
1112 mX = aState->mX;
1113 mY = aState->mY;
1114 mLowestTop = aState->mLowestTop;
1115 mHaveCachedLeftYMost = aState->mHaveCachedLeftYMost;
1116 mHaveCachedRightYMost = aState->mHaveCachedRightYMost;
1117 mMaximalLeftYMost = aState->mMaximalLeftYMost;
1118 mMaximalRightYMost = aState->mMaximalRightYMost;
1121 nscoord
1122 nsSpaceManager::GetLowestRegionTop()
1124 if (mLowestTop == NSCOORD_MIN)
1125 return mLowestTop;
1126 return mLowestTop - mY;
1129 #ifdef DEBUG
1130 void
1131 DebugListSpaceManager(nsSpaceManager *aSpaceManager)
1133 aSpaceManager->List(stdout);
1136 nsresult
1137 nsSpaceManager::List(FILE* out)
1139 nsAutoString tmp;
1141 fprintf(out, "SpaceManager@%p", this);
1142 if (mFrame) {
1143 nsIFrameDebug* frameDebug;
1145 if (NS_SUCCEEDED(mFrame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
1146 frameDebug->GetFrameName(tmp);
1147 fprintf(out, " frame=");
1148 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
1149 fprintf(out, "@%p", mFrame);
1152 fprintf(out, " xy=%d,%d <\n", mX, mY);
1153 if (mBandList.IsEmpty()) {
1154 fprintf(out, " no bands\n");
1156 else {
1157 BandRect* band = mBandList.Head();
1158 do {
1159 PRInt32 const n = band->mFrames.Count();
1160 fprintf(out, " left=%d top=%d right=%d bottom=%d count=%d frames=",
1161 band->mLeft, band->mTop, band->mRight, band->mBottom, n);
1163 for (PRInt32 i = 0; i < n; i++) {
1164 nsIFrame* frame = (nsIFrame*)band->mFrames.FastElementAt(i);
1165 if (frame) {
1166 nsIFrameDebug* frameDebug;
1168 if (NS_SUCCEEDED(frame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
1169 frameDebug->GetFrameName(tmp);
1170 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
1171 fprintf(out, "@%p ", frame);
1175 fprintf(out, "\n");
1176 band = band->Next();
1177 } while (band != mBandList.Head());
1179 fprintf(out, ">\n");
1180 return NS_OK;
1182 #endif
1184 nsSpaceManager::FrameInfo*
1185 nsSpaceManager::GetFrameInfoFor(nsIFrame* aFrame)
1187 FrameInfo* result = nsnull;
1189 for (result = mFrameInfoMap; result; result = result->mNext) {
1190 if (result->mFrame == aFrame) {
1191 break;
1195 return result;
1198 nsSpaceManager::FrameInfo*
1199 nsSpaceManager::CreateFrameInfo(nsIFrame* aFrame, const nsRect& aRect)
1201 FrameInfo* frameInfo = new FrameInfo(aFrame, aRect);
1203 if (frameInfo) {
1204 // Link it into the list
1205 frameInfo->mNext = mFrameInfoMap;
1206 mFrameInfoMap = frameInfo;
1208 // Optimize for the common case case when the frame being added is
1209 // likely to be near the bottom.
1210 nscoord ymost = aRect.YMost();
1211 PRUint8 floatType = aFrame->GetStyleDisplay()->mFloats;
1212 if (mHaveCachedLeftYMost && ymost > mMaximalLeftYMost &&
1213 floatType == NS_STYLE_FLOAT_LEFT) {
1214 mMaximalLeftYMost = ymost;
1216 else if (mHaveCachedRightYMost && ymost > mMaximalRightYMost &&
1217 floatType == NS_STYLE_FLOAT_RIGHT) {
1218 mMaximalRightYMost = ymost;
1221 return frameInfo;
1224 void
1225 nsSpaceManager::DestroyFrameInfo(FrameInfo* aFrameInfo)
1227 // See if it's at the head of the list
1228 if (mFrameInfoMap == aFrameInfo) {
1229 mFrameInfoMap = aFrameInfo->mNext;
1231 } else {
1232 FrameInfo* prev;
1234 // Find the previous node in the list
1235 for (prev = mFrameInfoMap; prev && (prev->mNext != aFrameInfo); prev = prev->mNext) {
1239 // Disconnect it from the list
1240 NS_ASSERTION(prev, "element not in list");
1241 if (prev) {
1242 prev->mNext = aFrameInfo->mNext;
1246 // Optimize for the case when the frame being removed is likely to be near
1247 // the bottom, but do nothing if we have neither cached value -- that case is
1248 // likely to be hit from PopState().
1249 if (mHaveCachedLeftYMost || mHaveCachedRightYMost) {
1250 PRUint8 floatType = aFrameInfo->mFrame->GetStyleDisplay()->mFloats;
1251 if (floatType == NS_STYLE_FLOAT_LEFT) {
1252 mHaveCachedLeftYMost = PR_FALSE;
1254 else {
1255 NS_ASSERTION(floatType == NS_STYLE_FLOAT_RIGHT, "Unexpected float type");
1256 mHaveCachedRightYMost = PR_FALSE;
1260 delete aFrameInfo;
1263 nscoord
1264 nsSpaceManager::ClearFloats(nscoord aY, PRUint8 aBreakType)
1266 nscoord bottom = aY + mY;
1268 if ((!mHaveCachedLeftYMost && aBreakType != NS_STYLE_CLEAR_RIGHT) ||
1269 (!mHaveCachedRightYMost && aBreakType != NS_STYLE_CLEAR_LEFT)) {
1270 // Recover our maximal YMost values. Might need both if this is a
1271 // NS_STYLE_CLEAR_LEFT_AND_RIGHT
1272 nscoord maximalLeftYMost = mHaveCachedLeftYMost ? mMaximalLeftYMost : nscoord_MIN;
1273 nscoord maximalRightYMost = mHaveCachedRightYMost ? mMaximalRightYMost : nscoord_MIN;
1275 // Optimize for most floats not being near the bottom
1276 for (FrameInfo *frame = mFrameInfoMap; frame; frame = frame->mNext) {
1277 nscoord ymost = frame->mRect.YMost();
1278 if (ymost > maximalLeftYMost) {
1279 if (frame->mFrame->GetStyleDisplay()->mFloats == NS_STYLE_FLOAT_LEFT) {
1280 NS_ASSERTION(!mHaveCachedLeftYMost, "Shouldn't happen");
1281 maximalLeftYMost = ymost;
1282 // No need to compare to the right ymost
1283 continue;
1287 if (ymost > maximalRightYMost) {
1288 if (frame->mFrame->GetStyleDisplay()->mFloats == NS_STYLE_FLOAT_RIGHT) {
1289 NS_ASSERTION(!mHaveCachedRightYMost, "Shouldn't happen");
1290 maximalRightYMost = ymost;
1295 mMaximalLeftYMost = maximalLeftYMost;
1296 mMaximalRightYMost = maximalRightYMost;
1297 mHaveCachedRightYMost = mHaveCachedLeftYMost = PR_TRUE;
1300 switch (aBreakType) {
1301 case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
1302 NS_ASSERTION(mHaveCachedLeftYMost && mHaveCachedRightYMost,
1303 "Need cached values!");
1304 bottom = PR_MAX(bottom, mMaximalLeftYMost);
1305 bottom = PR_MAX(bottom, mMaximalRightYMost);
1306 break;
1307 case NS_STYLE_CLEAR_LEFT:
1308 NS_ASSERTION(mHaveCachedLeftYMost, "Need cached value!");
1309 bottom = PR_MAX(bottom, mMaximalLeftYMost);
1310 break;
1311 case NS_STYLE_CLEAR_RIGHT:
1312 NS_ASSERTION(mHaveCachedRightYMost, "Need cached value!");
1313 bottom = PR_MAX(bottom, mMaximalRightYMost);
1314 break;
1315 default:
1316 // Do nothing
1317 break;
1320 bottom -= mY;
1322 return bottom;
1325 nsSpaceManager::BandRect*
1326 nsSpaceManager::GuessBandWithTopAbove(nscoord aYOffset) const
1328 NS_ASSERTION(!mBandList.IsEmpty(), "no bands");
1329 BandRect* band = nsnull;
1330 if (mCachedBandPosition) {
1331 band = mCachedBandPosition;
1332 // Now seek backward so that we're guaranteed to be the topmost
1333 // band which might contain the y-offset or be below it.
1334 while (band && band->mTop > aYOffset) {
1335 band = GetPrevBand(band);
1339 if (band) {
1340 return band;
1343 return mBandList.Head();
1346 /////////////////////////////////////////////////////////////////////////////
1347 // FrameInfo
1349 nsSpaceManager::FrameInfo::FrameInfo(nsIFrame* aFrame, const nsRect& aRect)
1350 : mFrame(aFrame), mRect(aRect), mNext(0)
1352 MOZ_COUNT_CTOR(nsSpaceManager::FrameInfo);
1355 #ifdef NS_BUILD_REFCNT_LOGGING
1356 nsSpaceManager::FrameInfo::~FrameInfo()
1358 MOZ_COUNT_DTOR(nsSpaceManager::FrameInfo);
1360 #endif
1362 /////////////////////////////////////////////////////////////////////////////
1363 // BandRect
1365 nsSpaceManager::BandRect::BandRect(nscoord aLeft,
1366 nscoord aTop,
1367 nscoord aRight,
1368 nscoord aBottom,
1369 nsIFrame* aFrame)
1371 MOZ_COUNT_CTOR(BandRect);
1372 mLeft = aLeft;
1373 mTop = aTop;
1374 mRight = aRight;
1375 mBottom = aBottom;
1376 AddFrame(aFrame);
1379 nsSpaceManager::BandRect::BandRect(nscoord aLeft,
1380 nscoord aTop,
1381 nscoord aRight,
1382 nscoord aBottom,
1383 nsSmallVoidArray& aFrames)
1385 MOZ_COUNT_CTOR(BandRect);
1386 mLeft = aLeft;
1387 mTop = aTop;
1388 mRight = aRight;
1389 mBottom = aBottom;
1390 mFrames = aFrames;
1393 nsSpaceManager::BandRect::~BandRect()
1395 MOZ_COUNT_DTOR(BandRect);
1398 nsSpaceManager::BandRect*
1399 nsSpaceManager::BandRect::SplitVertically(nscoord aBottom)
1401 NS_PRECONDITION((aBottom > mTop) && (aBottom < mBottom), "bad argument");
1403 // Create a new band rect for the bottom part
1404 BandRect* bottomBandRect = new BandRect(mLeft, aBottom, mRight, mBottom, mFrames);
1406 // This band rect becomes the top part, so adjust the bottom edge
1407 mBottom = aBottom;
1408 return bottomBandRect;
1411 nsSpaceManager::BandRect*
1412 nsSpaceManager::BandRect::SplitHorizontally(nscoord aRight)
1414 NS_PRECONDITION((aRight > mLeft) && (aRight < mRight), "bad argument");
1416 // Create a new band rect for the right part
1417 BandRect* rightBandRect = new BandRect(aRight, mTop, mRight, mBottom, mFrames);
1419 // This band rect becomes the left part, so adjust the right edge
1420 mRight = aRight;
1421 return rightBandRect;
1424 PRBool
1425 nsSpaceManager::BandRect::HasSameFrameList(const BandRect* aBandRect) const
1427 const PRInt32 count = mFrames.Count();
1429 // Check whether they're occupied by the same number of frames
1430 if (count != aBandRect->mFrames.Count()) {
1431 return PR_FALSE;
1433 // For each frame occupying this band rect check whether it also occupies
1434 // aBandRect
1435 for (PRInt32 i = 0; i < count; i++) {
1436 if (-1 == aBandRect->mFrames.IndexOf(mFrames.FastElementAt(i))) {
1437 return PR_FALSE;
1441 return PR_TRUE;
1445 * Internal helper function that counts the number of rects in this band
1446 * including the current band rect
1448 PRInt32
1449 nsSpaceManager::BandRect::Length() const
1451 PRInt32 len = 1;
1452 BandRect* bandRect = Next();
1454 // Because there's a header cell we know we'll either find the next band
1455 // (which has a different y-offset) or the header cell which has an invalid
1456 // y-offset
1457 while (bandRect->mTop == mTop) {
1458 len++;
1459 bandRect = bandRect->Next();
1462 return len;
1466 //----------------------------------------------------------------------
1468 nsAutoSpaceManager::~nsAutoSpaceManager()
1470 // Restore the old space manager in the reflow state if necessary.
1471 if (mNew) {
1472 #ifdef NOISY_SPACEMANAGER
1473 printf("restoring old space manager %p\n", mOld);
1474 #endif
1476 mReflowState.mSpaceManager = mOld;
1478 #ifdef NOISY_SPACEMANAGER
1479 if (mOld) {
1480 static_cast<nsFrame *>(mReflowState.frame)->ListTag(stdout);
1481 printf(": space-manager %p after reflow\n", mOld);
1482 mOld->List(stdout);
1484 #endif
1486 #ifdef DEBUG
1487 if (mOwns)
1488 #endif
1489 delete mNew;
1493 nsresult
1494 nsAutoSpaceManager::CreateSpaceManagerFor(nsPresContext *aPresContext, nsIFrame *aFrame)
1496 // Create a new space manager and install it in the reflow
1497 // state. `Remember' the old space manager so we can restore it
1498 // later.
1499 mNew = new nsSpaceManager(aPresContext->PresShell(), aFrame);
1500 if (! mNew)
1501 return NS_ERROR_OUT_OF_MEMORY;
1503 #ifdef NOISY_SPACEMANAGER
1504 printf("constructed new space manager %p (replacing %p)\n",
1505 mNew, mReflowState.mSpaceManager);
1506 #endif
1508 // Set the space manager in the existing reflow state
1509 mOld = mReflowState.mSpaceManager;
1510 mReflowState.mSpaceManager = mNew;
1511 return NS_OK;