Back to index

lightning-sunbird  0.9+nobinonly
Classes | Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | Static Private Attributes
nsSpaceManager Class Reference

Class for dealing with bands of available space. More...

#include <nsSpaceManager.h>

Inheritance diagram for nsSpaceManager:
Inheritance graph
[legend]
Collaboration diagram for nsSpaceManager:
Collaboration graph
[legend]

List of all members.

Classes

struct  BandList
struct  BandRect
union  BandRect.__unnamed__
struct  FrameInfo
struct  SpaceManagerState

Public Member Functions

 nsSpaceManager (nsIPresShell *aPresShell, nsIFrame *aFrame)
 ~nsSpaceManager ()
voidoperator new (size_t aSize) CPP_THROW_NEW
void operator delete (void *aPtr, size_t aSize)
nsIFrameGetFrame () const
void Translate (nscoord aDx, nscoord aDy)
 Translate the current origin by the specified (dx, dy).
void GetTranslation (nscoord &aX, nscoord &aY) const
 Returns the current translation from local coordinate space to world coordinate space.
PRBool XMost (nscoord &aXMost) const
 Returns the x-most rect in the space manager, or 0 if there are no rects.
PRBool YMost (nscoord &aYMost) const
 Returns the y-most of the bottommost band or 0 if there are no bands.
nsresult GetBandData (nscoord aYOffset, const nsSize &aMaxSize, nsBandData &aBandData) const
 Returns a band starting at the specified y-offset.
nsresult AddRectRegion (nsIFrame *aFrame, const nsRect &aUnavailableSpace)
 Add a rectangular region of unavailable space.
nsresult RemoveTrailingRegions (nsIFrame *aFrameList)
 Remove the regions associated with this floating frame and its next-sibling list.
void ClearRegions ()
 Clears the list of regions representing the unavailable space.
PRBool HasAnyFloats ()
PRBool HasFloatDamage ()
 Methods for dealing with the propagation of float damage during reflow.
void IncludeInDamage (nscoord aIntervalBegin, nscoord aIntervalEnd)
PRBool IntersectsDamage (nscoord aIntervalBegin, nscoord aIntervalEnd)
void PushState ()
 Pushes the current state of the space manager onto a state stack.
void PopState ()
 Restores the space manager to the state at the top of the state stack, then pops this state off the stack.
void DiscardState ()
 Pops the state off the stack without restoring it.
nscoord GetLowestRegionTop ()
 Get the top of the last region placed into the space manager, to enforce the rule that a float can't be above an earlier float.
nscoord ClearFloats (nscoord aY, PRUint8 aBreakType)
 Return the coordinate of the lowest float matching aBreakType in this space manager.

Static Public Member Functions

static void Shutdown ()

Protected Member Functions

nsresult RemoveRegion (nsIFrame *aFrame)
 Remove the region associated with aFrane.
FrameInfoGetFrameInfoFor (nsIFrame *aFrame)
FrameInfoCreateFrameInfo (nsIFrame *aFrame, const nsRect &aRect)
void DestroyFrameInfo (FrameInfo *)
void ClearFrameInfo ()
void ClearBandRects ()
BandRectGetNextBand (const BandRect *aBandRect) const
 Skips to the start of the next band.
void DivideBand (BandRect *aBand, nscoord aBottom)
 Divides the current band into two vertically.
PRBool CanJoinBands (BandRect *aBand, BandRect *aPrevBand)
PRBool JoinBands (BandRect *aBand, BandRect *aPrevBand)
 Tries to join the two adjacent bands.
void AddRectToBand (BandRect *aBand, BandRect *aBandRect)
 Adds a new rect to a band.
void InsertBandRect (BandRect *aBandRect)
nsresult GetBandAvailableSpace (const BandRect *aBand, nscoord aY, const nsSize &aMaxSize, nsBandData &aAvailableSpace) const
 Internal function that returns the list of available and unavailable space within the band.

Protected Attributes

nsIFrame *const mFrame
nscoord mX
nscoord mY
BandList mBandList
nscoord mLowestTop
FrameInfomFrameInfoMap
nsIntervalSet mFloatDamage
SpaceManagerStatemSavedStates
SpaceManagerState mAutoState

Private Member Functions

 nsSpaceManager (const nsSpaceManager &)
void operator= (const nsSpaceManager &)

Static Private Attributes

static PRInt32 sCachedSpaceManagerCount = 0
static voidsCachedSpaceManagers [NS_SPACE_MANAGER_CACHE_SIZE]

Detailed Description

Class for dealing with bands of available space.

The space manager defines a coordinate space with an origin at (0, 0) that grows down and to the right.

Definition at line 164 of file nsSpaceManager.h.


Class Documentation

union nsSpaceManager::BandRect.__unnamed__

Definition at line 371 of file nsSpaceManager.h.

Class Members
nsIFrame * mFrame
nsVoidArray * mFrames
struct nsSpaceManager::SpaceManagerState

Definition at line 358 of file nsSpaceManager.h.

Collaboration diagram for nsSpaceManager::SpaceManagerState:
Class Members
nsIFrame * mLastFrame
nscoord mLowestTop
SpaceManagerState * mNext
nscoord mX
nscoord mY

Constructor & Destructor Documentation

nsSpaceManager::nsSpaceManager ( nsIPresShell aPresShell,
nsIFrame aFrame 
)

Definition at line 107 of file nsSpaceManager.cpp.

Here is the caller graph for this function:

Definition at line 128 of file nsSpaceManager.cpp.

{
  MOZ_COUNT_DTOR(nsSpaceManager);
  mBandList.Clear();
  ClearFrameInfo();

  NS_ASSERTION(!mSavedStates, "states remaining on state stack");

  while (mSavedStates && mSavedStates != &mAutoState){
    SpaceManagerState *state = mSavedStates;
    mSavedStates = state->mNext;
    delete state;
  }
}

Here is the call graph for this function:


Member Function Documentation

nsresult nsSpaceManager::AddRectRegion ( nsIFrame aFrame,
const nsRect aUnavailableSpace 
)

Add a rectangular region of unavailable space.

The space is relative to the local coordinate system.

The region is tagged with a frame

Parameters:
aFramethe frame used to identify the region. Must not be NULL
aUnavailableSpacethe bounding rect of the unavailable space
Returns:
NS_OK if successful NS_ERROR_FAILURE if there is already a region tagged with aFrame

Definition at line 806 of file nsSpaceManager.cpp.

{
  NS_PRECONDITION(nsnull != aFrame, "null frame");
  NS_PRECONDITION(aUnavailableSpace.width >= 0 &&
                  aUnavailableSpace.height >= 0,
                  "Negative dimensions not allowed");

  // See if there is already a region associated with aFrame
  FrameInfo*  frameInfo = GetFrameInfoFor(aFrame);

  if (nsnull != frameInfo) {
    NS_WARNING("aFrame is already associated with a region");
    return NS_ERROR_FAILURE;
  }

  // Convert the frame to world coordinates
  nsRect  rect(aUnavailableSpace.x + mX, aUnavailableSpace.y + mY,
               aUnavailableSpace.width, aUnavailableSpace.height);

  if (rect.y > mLowestTop)
    mLowestTop = rect.y;

  // Create a frame info structure
  frameInfo = CreateFrameInfo(aFrame, rect);
  if (nsnull == frameInfo) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  if (aUnavailableSpace.height <= 0)
    return NS_OK;

  // Allocate a band rect
  BandRect* bandRect = new BandRect(rect.x, rect.y, rect.XMost(), rect.YMost(), aFrame);
  if (nsnull == bandRect) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  // Insert the band rect
  InsertBandRect(bandRect);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsSpaceManager::AddRectToBand ( BandRect aBand,
BandRect aBandRect 
) [protected]

Adds a new rect to a band.

Parameters:
aBandthe first rect in the band
aBandRectthe band rect to add to the band

Definition at line 546 of file nsSpaceManager.cpp.

{
  NS_PRECONDITION((aBand->mTop == aBandRect->mTop) &&
                  (aBand->mBottom == aBandRect->mBottom), "bad band");
  NS_PRECONDITION(1 == aBandRect->mNumFrames, "shared band rect");
  nscoord topOfBand = aBand->mTop;

  // Figure out where in the band horizontally to insert the rect
  do {
    // Compare the left edge of the new rect with the left edge of the existing
    // rect
    if (aBandRect->mLeft < aBand->mLeft) {
      // The new rect's left edge is to the left of the existing rect's left edge.
      // Could be any of these cases (N is new rect, E is existing rect):
      //
      //   Case 1: left-of      Case 2: overlaps     Case 3: N.contains(E)
      //   ---------------      ----------------     ---------------------
      //   +-----+ +-----+      +-----+              +---------+
      //   |  N  | |  E  |      |  N  |              |    N    |
      //   +-----+ +-----+      +-----+              +---------+
      //                           +-----+              +---+
      //                           |  E  |              | E |
      //                           +-----+              +---+
      //
      // Do the two rectangles overlap?
      if (aBandRect->mRight <= aBand->mLeft) {
        // No, the new rect is completely to the left of the existing rect
        // (case #1). Insert a new rect
        aBand->InsertBefore(aBandRect);
        return;
      }

      // Yes, they overlap. Compare the right edges.
      if (aBandRect->mRight > aBand->mRight) {
        // The new rect's right edge is to the right of the existing rect's
        // right edge (case #3). Split the new rect
        BandRect* r1 = aBandRect->SplitHorizontally(aBand->mLeft);

        // Insert the part of the new rect that's to the left of the existing
        // rect as a new band rect
        aBand->InsertBefore(aBandRect);

        // Continue below with the part that overlaps the existing rect
        aBandRect = r1;

      } else {
        if (aBand->mRight > aBandRect->mRight) {
          // The existing rect extends past the new rect (case #2). Split the
          // existing rect
          BandRect* r1 = aBand->SplitHorizontally(aBandRect->mRight);

          // Insert the new right half of the existing rect
          aBand->InsertAfter(r1);
        }

        // Insert the part of the new rect that's to the left of the existing
        // rect
        aBandRect->mRight = aBand->mLeft;
        aBand->InsertBefore(aBandRect);

        // Mark the existing rect as shared
        aBand->AddFrame(aBandRect->mFrame);
        return;
      }
    }
      
    if (aBandRect->mLeft > aBand->mLeft) {
      // The new rect's left edge is to the right of the existing rect's left
      // edge. Could be any one of these cases:
      //
      //   Case 4: right-of    Case 5: overlaps     Case 6: E.Contains(N)
      //   ---------------    ----------------     ---------------------
      //   +-----+ +-----+    +-----+              +------------+
      //   |  E  | |  N  |    |  E  |              |      E     |
      //   +-----+ +-----+    +-----+              +------------+
      //                         +-----+              +-----+
      //                         |  N  |              |  N  |
      //                         +-----+              +-----+
      //
      if (aBandRect->mLeft >= aBand->mRight) {
        // The new rect is to the right of the existing rect (case #4), so move
        // to the next rect in the band
        aBand = aBand->Next();
        continue;
      }

      // The rects overlap, so divide the existing rect into two rects: the
      // part to the left of the new rect, and the part that overlaps
      BandRect* r1 = aBand->SplitHorizontally(aBandRect->mLeft);

      // Insert the new right half of the existing rect, and make it the current
      // rect
      aBand->InsertAfter(r1);
      aBand = r1;
    }

    // At this point the left edge of the new rect is the same as the left edge
    // of the existing rect
    NS_ASSERTION(aBandRect->mLeft == aBand->mLeft, "unexpected rect");

    // Compare which rect is wider, the new rect or the existing rect
    if (aBand->mRight > aBandRect->mRight) {
      // The existing rect is wider (case #6). Divide the existing rect into
      // two rects: the part that overlaps, and the part to the right of the
      // new rect
      BandRect* r1 = aBand->SplitHorizontally(aBandRect->mRight);

      // Insert the new right half of the existing rect
      aBand->InsertAfter(r1);

      // Mark the overlap as being shared
      aBand->AddFrame(aBandRect->mFrame);
      return;

    } else {
      // Indicate the frames share the existing rect
      aBand->AddFrame(aBandRect->mFrame);

      if (aBand->mRight == aBandRect->mRight) {
        // The new and existing rect have the same right edge. We're all done,
        // and the new band rect is no longer needed
        delete aBandRect;
        return;
      } else {
        // The new rect is wider than the existing rect (cases #5). Set the
        // new rect to be the overhang, and move to the next rect within the band
        aBandRect->mLeft = aBand->mRight;
        aBand = aBand->Next();
        continue;
      }
    }
  } while (aBand->mTop == topOfBand);

  // Insert a new rect
  aBand->InsertBefore(aBandRect);
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsSpaceManager::CanJoinBands ( BandRect aBand,
BandRect aPrevBand 
) [protected]

Definition at line 459 of file nsSpaceManager.cpp.

{
  PRBool  result;
  nscoord topOfBand = aBand->mTop;
  nscoord topOfPrevBand = aPrevBand->mTop;

  // The bands can be joined if:
  // - they're adjacent
  // - they have the same number of rects
  // - each rect has the same left and right edge as its corresponding rect, and
  //   the rects are occupied by the same frames
  if (aPrevBand->mBottom == aBand->mTop) {
    // Compare each of the rects in the two bands
    while (PR_TRUE) {
      if ((aBand->mLeft != aPrevBand->mLeft) || (aBand->mRight != aPrevBand->mRight)) {
        // The rects have different edges
        result = PR_FALSE;
        break;
      }

      if (!aBand->HasSameFrameList(aPrevBand)) {
        // The rects are occupied by different frames
        result = PR_FALSE;
        break;
      }

      // Move to the next rects within the bands
      aBand = aBand->Next();
      aPrevBand = aPrevBand->Next();

      // Have we reached the end of either band?
      PRBool  endOfBand = aBand->mTop != topOfBand;
      PRBool  endOfPrevBand = aPrevBand->mTop != topOfPrevBand;

      if (endOfBand || endOfPrevBand) {
        result = endOfBand & endOfPrevBand;
        break;  // all done
      }
    }

  } else {
    // The bands aren't adjacent
    result = PR_FALSE;
  }

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return the coordinate of the lowest float matching aBreakType in this space manager.

Returns aY if there are no matching floats.

Definition at line 1252 of file nsSpaceManager.cpp.

{
  nscoord bottom = aY + mY;

  for (FrameInfo *frame = mFrameInfoMap; frame; frame = frame->mNext) {
    if (ShouldClearFrame(frame->mFrame, aBreakType)) {
      if (frame->mRect.YMost() > bottom) {
        bottom = frame->mRect.YMost();
      }
    }
  }

  bottom -= mY;

  return bottom;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 119 of file nsSpaceManager.cpp.

{
  while (mFrameInfoMap) {
    FrameInfo*  next = mFrameInfoMap->mNext;
    delete mFrameInfoMap;
    mFrameInfoMap = next;
  }
}

Here is the caller graph for this function:

Clears the list of regions representing the unavailable space.

Definition at line 979 of file nsSpaceManager.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1193 of file nsSpaceManager.cpp.

{
  FrameInfo*  frameInfo = new FrameInfo(aFrame, aRect);

  if (frameInfo) {
    // Link it into the list
    frameInfo->mNext = mFrameInfoMap;
    mFrameInfoMap = frameInfo;
  }
  return frameInfo;
}

Here is the caller graph for this function:

void nsSpaceManager::DestroyFrameInfo ( FrameInfo aFrameInfo) [protected]

Definition at line 1206 of file nsSpaceManager.cpp.

{
  // See if it's at the head of the list
  if (mFrameInfoMap == aFrameInfo) {
    mFrameInfoMap = aFrameInfo->mNext;

  } else {
    FrameInfo*  prev;
    
    // Find the previous node in the list
    for (prev = mFrameInfoMap; prev && (prev->mNext != aFrameInfo); prev = prev->mNext) {
      ;
    }

    // Disconnect it from the list
    NS_ASSERTION(prev, "element not in list");
    if (prev) {
      prev->mNext = aFrameInfo->mNext;
    }
  }

  delete aFrameInfo;
}

Here is the caller graph for this function:

Pops the state off the stack without restoring it.

Useful for speculative reflow where we're not sure if we're going to keep the result.

Definition at line 1086 of file nsSpaceManager.cpp.

{
  NS_ASSERTION(mSavedStates, "Invalid call to DiscardState()!");

  if (!mSavedStates) {
    return;
  }

  SpaceManagerState *state = mSavedStates;
  mSavedStates = mSavedStates->mNext;
  if(state != &mAutoState) {
    delete state;
  }
}

Here is the caller graph for this function:

void nsSpaceManager::DivideBand ( BandRect aBandRect,
nscoord  aBottom 
) [protected]

Divides the current band into two vertically.

Parameters:
aBandRectthe first rect in the band
aBottomwhere to split the band. This becomes the bottom of the top part

Definition at line 436 of file nsSpaceManager.cpp.

{
  NS_PRECONDITION(aBottom < aBandRect->mBottom, "bad height");
  nscoord   topOfBand = aBandRect->mTop;
  BandRect* nextBand = GetNextBand(aBandRect);

  if (nsnull == nextBand) {
    nextBand = (BandRect*)&mBandList;
  }

  while (topOfBand == aBandRect->mTop) {
    // Split the band rect into two vertically
    BandRect* bottomBandRect = aBandRect->SplitVertically(aBottom);

    // Insert the new bottom part
    nextBand->InsertBefore(bottomBandRect);

    // Move to the next rect in the band
    aBandRect = aBandRect->Next();
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsSpaceManager::GetBandAvailableSpace ( const BandRect aBand,
nscoord  aY,
const nsSize aMaxSize,
nsBandData aBandData 
) const [protected]

Internal function that returns the list of available and unavailable space within the band.

Parameters:
aBandthe first rect in the band
aYthe y-offset in world coordinates
aMaxSizethe size to use to constrain the band data
aAvailableBand

Definition at line 239 of file nsSpaceManager.cpp.

{
  nscoord          topOfBand = aBand->mTop;
  nscoord          localY = aY - mY;
  nscoord          height = PR_MIN(aBand->mBottom - aY, aMaxSize.height);
  nsBandTrapezoid* trapezoid = aBandData.mTrapezoids;
  nscoord          rightEdge = mX + aMaxSize.width;

  // Initialize the band data
  aBandData.mCount = 0;

  // Skip any rectangles that are to the left of the local coordinate space
  while (aBand->mTop == topOfBand) {
    if (aBand->mRight > mX) {
      break;
    }

    // Get the next rect in the band
    aBand = aBand->Next();
  }

  // This is used to track the current x-location within the band. This is in
  // world coordinates
  nscoord   left = mX;

  // Process the remaining rectangles that are within the clip width
  while ((aBand->mTop == topOfBand) && (aBand->mLeft < rightEdge)) {
    // Compare the left edge of the occupied space with the current left
    // coordinate
    if (aBand->mLeft > left) {
      // The rect is to the right of our current left coordinate, so we've
      // found some available space
      if (aBandData.mCount >= aBandData.mSize) {
        // Not enough space in the array of trapezoids
        aBandData.mCount += 2 * aBand->Length() + 2;  // estimate the number needed
        return NS_ERROR_FAILURE;
      }
      trapezoid->mState = nsBandTrapezoid::Available;
      trapezoid->mFrame = nsnull;

      // Assign the trapezoid a rectangular shape. The trapezoid must be in the
      // local coordinate space, so convert the current left coordinate
      *trapezoid = nsRect(left - mX, localY, aBand->mLeft - left, height);

      // Move to the next output rect
      trapezoid++;
      aBandData.mCount++;
    }

    // The rect represents unavailable space, so add another trapezoid
    if (aBandData.mCount >= aBandData.mSize) {
      // Not enough space in the array of trapezoids
      aBandData.mCount += 2 * aBand->Length() + 1;  // estimate the number needed
      return NS_ERROR_FAILURE;
    }
    if (1 == aBand->mNumFrames) {
      trapezoid->mState = nsBandTrapezoid::Occupied;
      trapezoid->mFrame = aBand->mFrame;
    } else {
      NS_ASSERTION(aBand->mNumFrames > 1, "unexpected frame count");
      trapezoid->mState = nsBandTrapezoid::OccupiedMultiple;
      trapezoid->mFrames = aBand->mFrames;
    }

    nscoord x = aBand->mLeft;
    // The first band can straddle the clip rect
    if (x < mX) {
      // Clip the left edge
      x = mX;
    }

    // Assign the trapezoid a rectangular shape. The trapezoid must be in the
    // local coordinate space, so convert the rects's left coordinate
    *trapezoid = nsRect(x - mX, localY, aBand->mRight - x, height);

    // Move to the next output rect
    trapezoid++;
    aBandData.mCount++;

    // Adjust our current x-location within the band
    left = aBand->mRight;

    // Move to the next rect within the band
    aBand = aBand->Next();
  }

  // No more rects left in the band. If we haven't yet reached the right edge,
  // then all the remaining space is available
  if (left < rightEdge || aBandData.mCount == 0) {
    if (aBandData.mCount >= aBandData.mSize) {
      // Not enough space in the array of trapezoids
      aBandData.mCount++;
      return NS_ERROR_FAILURE;
    }
    trapezoid->mState = nsBandTrapezoid::Available;
    trapezoid->mFrame = nsnull;

    // Assign the trapezoid a rectangular shape. The trapezoid must be in the
    // local coordinate space, so convert the current left coordinate
    *trapezoid = nsRect(left - mX, localY, rightEdge - left, height);
    aBandData.mCount++;
  }

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsSpaceManager::GetBandData ( nscoord  aYOffset,
const nsSize aMaxSize,
nsBandData aBandData 
) const

Returns a band starting at the specified y-offset.

The band data indicates which parts of the band are available, and which parts are unavailable

The band data that is returned is in the coordinate space of the local coordinate system.

The local coordinate space origin, the y-offset, and the max size describe a rectangle that's used to clip the underlying band of available space, i.e. {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local coordinate space

Parameters:
aYOffsetthe y-offset of where the band begins. The coordinate is relative to the upper-left corner of the local coordinate space
aMaxSizethe size to use to constrain the band data
aBandData[in,out] used to return the list of trapezoids that describe the available space and the unavailable space
Returns:
NS_OK if successful and NS_ERROR_FAILURE if the band data is not not large enough. The 'count' member of the band data struct indicates how large the array of trapezoids needs to be

Definition at line 349 of file nsSpaceManager.cpp.

{
  NS_PRECONDITION(aBandData.mSize >= 1, "bad band data");
  nsresult  result = NS_OK;

  // Convert the y-offset to world coordinates
  nscoord   y = mY + aYOffset;

  // If there are no unavailable rects or the offset is below the bottommost
  // band, then all the space is available
  nscoord yMost;
  nscoord maxHeight = aMaxSize.height == NS_UNCONSTRAINEDSIZE ? NS_UNCONSTRAINEDSIZE 
    : PR_MAX(0, aMaxSize.height - aYOffset);

  if (!YMost(yMost) || (y >= yMost)) {
    // All the requested space is available
    aBandData.mCount = 1;
    aBandData.mTrapezoids[0] = nsRect(0, aYOffset, aMaxSize.width, maxHeight);
    aBandData.mTrapezoids[0].mState = nsBandTrapezoid::Available;
    aBandData.mTrapezoids[0].mFrame = nsnull;
  } else {
    // Find the first band that contains the y-offset or is below the y-offset
    NS_ASSERTION(!mBandList.IsEmpty(), "no bands");
    BandRect* band = mBandList.Head();

    aBandData.mCount = 0;
    while (nsnull != band) {
      if (band->mTop > y) {
        // The band is below the y-offset. The area between the y-offset and
        // the top of the band is available
        aBandData.mCount = 1;
        aBandData.mTrapezoids[0] =
          nsRect(0, aYOffset, aMaxSize.width, PR_MIN(band->mTop - y, maxHeight));
        aBandData.mTrapezoids[0].mState = nsBandTrapezoid::Available;
        aBandData.mTrapezoids[0].mFrame = nsnull;
        break;
      } else if (y < band->mBottom) {
        // The band contains the y-offset. Return a list of available and
        // unavailable rects within the band
        return GetBandAvailableSpace(band, y, nsSize(aMaxSize.width, maxHeight), aBandData);
      } else {
        // Skip to the next band
        band = GetNextBand(band);
      }
    }
  }

  NS_POSTCONDITION(aBandData.mCount > 0, "unexpected band data count");
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsIFrame* nsSpaceManager::GetFrame ( ) const [inline]

Definition at line 182 of file nsSpaceManager.h.

{ return mFrame; }

Definition at line 1179 of file nsSpaceManager.cpp.

{
  FrameInfo*  result = nsnull;

  for (result = mFrameInfoMap; result; result = result->mNext) {
    if (result->mFrame == aFrame) {
      break;
    }
  }

  return result;
}

Here is the caller graph for this function:

Get the top of the last region placed into the space manager, to enforce the rule that a float can't be above an earlier float.

Returns the minimum nscoord value if there are no regions.

Definition at line 1102 of file nsSpaceManager.cpp.

{
  if (mLowestTop == NSCOORD_MIN)
    return mLowestTop;
  return mLowestTop - mY;
}

Here is the caller graph for this function:

Skips to the start of the next band.

Parameters:
aBandRectA rect within the band
Returns:
The start of the next band, or nsnull of this is the last band.

Definition at line 409 of file nsSpaceManager.cpp.

{
  nscoord topOfBand = aBandRect->mTop;

  aBandRect = aBandRect->Next();
  while (aBandRect != &mBandList) {
    // Check whether this rect is part of the same band
    if (aBandRect->mTop != topOfBand) {
      // We found the start of the next band
      return (BandRect*)aBandRect;
    }

    aBandRect = aBandRect->Next();
  }

  // No bands left
  return nsnull;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsSpaceManager::GetTranslation ( nscoord aX,
nscoord aY 
) const [inline]

Returns the current translation from local coordinate space to world coordinate space.

This represents the accumulated calls to Translate().

Definition at line 196 of file nsSpaceManager.h.

{ aX = mX; aY = mY; }

Here is the caller graph for this function:

Definition at line 284 of file nsSpaceManager.h.

{ return mFrameInfoMap != nsnull; }

Here is the caller graph for this function:

Methods for dealing with the propagation of float damage during reflow.

Definition at line 290 of file nsSpaceManager.h.

  {
    return !mFloatDamage.IsEmpty();
  }

Here is the call graph for this function:

void nsSpaceManager::IncludeInDamage ( nscoord  aIntervalBegin,
nscoord  aIntervalEnd 
) [inline]

Definition at line 295 of file nsSpaceManager.h.

  {
    mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
  }

Here is the call graph for this function:

Here is the caller graph for this function:

void nsSpaceManager::InsertBandRect ( BandRect aBandRect) [protected]

Definition at line 711 of file nsSpaceManager.cpp.

{
  // If there are no existing bands or this rect is below the bottommost
  // band, then add a new band
  nscoord yMost;
  if (!YMost(yMost) || (aBandRect->mTop >= yMost)) {
    mBandList.Append(aBandRect);
    return;
  }

  // Examine each band looking for a band that intersects this rect
  NS_ASSERTION(!mBandList.IsEmpty(), "no bands");
  BandRect* band = mBandList.Head();

  while (nsnull != band) {
    // Compare the top edge of this rect with the top edge of the band
    if (aBandRect->mTop < band->mTop) {
      // The top edge of the rect is above the top edge of the band.
      // Is there any overlap?
      if (aBandRect->mBottom <= band->mTop) {
        // Case #1. This rect is completely above the band, so insert a
        // new band before the current band
        band->InsertBefore(aBandRect);
        break;  // we're all done
      }

      // Case #2 and case #7. Divide this rect, creating a new rect for
      // the part that's above the band
      BandRect* bandRect1 = new BandRect(aBandRect->mLeft, aBandRect->mTop,
                                         aBandRect->mRight, band->mTop,
                                         aBandRect->mFrame);

      // Insert bandRect1 as a new band
      band->InsertBefore(bandRect1);

      // Modify this rect to exclude the part above the band
      aBandRect->mTop = band->mTop;

    } else if (aBandRect->mTop > band->mTop) {
      // The top edge of the rect is below the top edge of the band. Is there
      // any overlap?
      if (aBandRect->mTop >= band->mBottom) {
        // Case #5. This rect is below the current band. Skip to the next band
        band = GetNextBand(band);
        continue;
      }

      // Case #3 and case #4. Divide the current band into two bands with the
      // top band being the part that's above the rect
      DivideBand(band, aBandRect->mTop);

      // Skip to the bottom band that we just created
      band = GetNextBand(band);
    }

    // At this point the rect and the band should have the same y-offset
    NS_ASSERTION(aBandRect->mTop == band->mTop, "unexpected band");

    // Is the band higher than the rect?
    if (band->mBottom > aBandRect->mBottom) {
      // Divide the band into two bands with the top band the same height
      // as the rect
      DivideBand(band, aBandRect->mBottom);
    }

    if (aBandRect->mBottom == band->mBottom) {
      // Add the rect to the band
      AddRectToBand(band, aBandRect);
      break;

    } else {
      // Case #4 and case #7. The rect contains the band vertically. Divide
      // the rect, creating a new rect for the part that overlaps the band
      BandRect* bandRect1 = new BandRect(aBandRect->mLeft, aBandRect->mTop,
                                         aBandRect->mRight, band->mBottom,
                                         aBandRect->mFrame);

      // Add bandRect1 to the band
      AddRectToBand(band, bandRect1);

      // Modify aBandRect to be the part below the band
      aBandRect->mTop = band->mBottom;

      // Continue with the next band
      band = GetNextBand(band);
      if (nsnull == band) {
        // Append a new bottommost band
        mBandList.Append(aBandRect);
        break;
      }
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsSpaceManager::IntersectsDamage ( nscoord  aIntervalBegin,
nscoord  aIntervalEnd 
) [inline]

Definition at line 300 of file nsSpaceManager.h.

  {
    return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
  }

Here is the call graph for this function:

PRBool nsSpaceManager::JoinBands ( BandRect aBand,
BandRect aPrevBand 
) [protected]

Tries to join the two adjacent bands.

Returns PR_TRUE if successful and PR_FALSE otherwise

If the two bands are joined, the previous band is the the band that's deleted

Definition at line 514 of file nsSpaceManager.cpp.

{
  if (CanJoinBands(aBand, aPrevBand)) {
    BandRect* startOfNextBand = aBand;

    while (aPrevBand != startOfNextBand) {
      // Adjust the top of the band we're keeping, and then move to the next
      // rect within the band
      aBand->mTop = aPrevBand->mTop;
      aBand = aBand->Next();

      // Delete the rect from the previous band
      BandRect* next = aPrevBand->Next();

      aPrevBand->Remove();
      delete aPrevBand;
      aPrevBand = next;
    }

    return PR_TRUE;
  }

  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsSpaceManager::operator delete ( void aPtr,
size_t  aSize 
)

Definition at line 158 of file nsSpaceManager.cpp.

{
  if (!aPtr)
    return;
  // This space manager is no longer used, if there's still room in
  // the cache we'll cache this space manager, unless the layout
  // module was already shut down.

  if (sCachedSpaceManagerCount < NS_SPACE_MANAGER_CACHE_SIZE &&
      sCachedSpaceManagerCount >= 0) {
    // There's still space in the cache for more instances, put this
    // instance in the cache in stead of deleting it.

    sCachedSpaceManagers[sCachedSpaceManagerCount++] = aPtr;
    return;
  }

  // The cache is full, or the layout module has been shut down,
  // delete this space manager.
  nsMemory::Free(aPtr);
}
void * nsSpaceManager::operator new ( size_t  aSize)

Definition at line 144 of file nsSpaceManager.cpp.

{
  if (sCachedSpaceManagerCount > 0) {
    // We have cached unused instances of this class, return a cached
    // instance in stead of always creating a new one.
    return sCachedSpaceManagers[--sCachedSpaceManagerCount];
  }

  // The cache is empty, this means we haveto create a new instance using
  // the global |operator new|.
  return nsMemory::Alloc(aSize);
}

Here is the call graph for this function:

void nsSpaceManager::operator= ( const nsSpaceManager ) [private]

Restores the space manager to the state at the top of the state stack, then pops this state off the stack.

Definition at line 1041 of file nsSpaceManager.cpp.

{
  // This is a quick and dirty pop implementation, to
  // match the current implementation of PushState(). The
  // idea here is to remove any frames that have been added
  // to the mFrameInfoMap since the last call to PushState().

  NS_ASSERTION(mSavedStates, "Invalid call to PopState()!");

  if (!mSavedStates) {
    return;
  }

  // mFrameInfoMap is LIFO so keep removing what it points
  // to until we hit mLastFrame.

  while (mFrameInfoMap && mFrameInfoMap->mFrame != mSavedStates->mLastFrame) {
    RemoveRegion(mFrameInfoMap->mFrame);
  }

  // If we trip this assertion it means that someone added
  // PushState()/PopState() calls around code that actually
  // removed mLastFrame from mFrameInfoMap, which means our
  // state is now out of sync with what we thought it should be.

  NS_ASSERTION(((mSavedStates->mLastFrame && mFrameInfoMap) ||
               (!mSavedStates->mLastFrame && !mFrameInfoMap)),
               "Unexpected outcome!");

  mX = mSavedStates->mX;
  mY = mSavedStates->mY;
  mLowestTop = mSavedStates->mLowestTop;

  // Now that we've restored our state, pop the topmost
  // state and delete it.  Make sure not to delete the mAutoState element
  // as it is embedded in this class

  SpaceManagerState *state = mSavedStates;
  mSavedStates = mSavedStates->mNext;
  if(state != &mAutoState) {
    delete state;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Pushes the current state of the space manager onto a state stack.

Definition at line 987 of file nsSpaceManager.cpp.

{
  // This is a quick and dirty push implementation, which
  // only saves the (x,y) and last frame in the mFrameInfoMap
  // which is enough info to get us back to where we should be
  // when pop is called.
  //
  // The alternative would be to make full copies of the contents
  // of mBandList and mFrameInfoMap and restore them when pop is
  // called, but I'm not sure it's worth the effort/bloat at this
  // point, since this push/pop mechanism is only used to undo any
  // floats that were added during the unconstrained reflow
  // in nsBlockReflowContext::DoReflowBlock(). (See bug 96736)
  //
  // It should also be noted that the state for mFloatDamage is
  // intentionally not saved or restored in PushState() and PopState(),
  // since that could lead to bugs where damage is missed/dropped when
  // we move from position A to B (during the intermediate incremental
  // reflow mentioned above) and then from B to C during the subsequent
  // reflow. In the typical case A and C will be the same, but not always.
  // Allowing mFloatDamage to accumulate the damage incurred during both
  // reflows ensures that nothing gets missed.

  SpaceManagerState *state;

  if(mSavedStates) {
    state = new SpaceManagerState;
  } else {
    state = &mAutoState;
  }

  NS_ASSERTION(state, "PushState() failed!");

  if (!state) {
    return;
  }

  state->mX = mX;
  state->mY = mY;
  state->mLowestTop = mLowestTop;

  if (mFrameInfoMap) {
    state->mLastFrame = mFrameInfoMap->mFrame;
  } else {
    state->mLastFrame = nsnull;
  }

  // Now that we've saved our state, add it to mSavedStates.

  state->mNext = mSavedStates;
  mSavedStates = state;
}

Here is the caller graph for this function:

nsresult nsSpaceManager::RemoveRegion ( nsIFrame aFrame) [protected]

Remove the region associated with aFrane.

doesn't work in the general case!

Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region tagged with aFrame

Definition at line 875 of file nsSpaceManager.cpp.

{
  // Get the frame info associated with aFrame
  FrameInfo*  frameInfo = GetFrameInfoFor(aFrame);

  if (nsnull == frameInfo) {
    NS_WARNING("no region associated with aFrame");
    return NS_ERROR_INVALID_ARG;
  }

  if (frameInfo->mRect.height > 0) {
    NS_ASSERTION(!mBandList.IsEmpty(), "no bands");
    BandRect* band = mBandList.Head();
    BandRect* prevBand = nsnull;
    PRBool    prevFoundMatchingRect = PR_FALSE;

    // Iterate each band looking for rects tagged with aFrame
    while (nsnull != band) {
      BandRect* rect = band;
      BandRect* prevRect = nsnull;
      nscoord   topOfBand = band->mTop;
      PRBool    foundMatchingRect = PR_FALSE;
      PRBool    prevIsSharedRect = PR_FALSE;

      // Iterate each rect in the band
      do {
        PRBool  isSharedRect = PR_FALSE;

        if (rect->IsOccupiedBy(aFrame)) {
          // Remember that we found a matching rect in this band
          foundMatchingRect = PR_TRUE;

          if (rect->mNumFrames > 1) {
            // The band rect is occupied by more than one frame
            rect->RemoveFrame(aFrame);

            // Remember that this rect was being shared by more than one frame
            // including aFrame
            isSharedRect = PR_TRUE;
          } else {
            // The rect isn't shared so just delete it
            BandRect* next = rect->Next();
            rect->Remove();
            if (rect == band) {
              // The rect we're deleting is the start of the band
              if (topOfBand == next->mTop) {
                band = next;
              } else {
                band = nsnull;
              }
            }
            delete rect;
            rect = next;

            // We don't need to try and coalesce adjacent rects in this case
            prevRect = nsnull;
            prevIsSharedRect = PR_FALSE;
            continue;
          }
        }
           
        // If we found a shared rect occupied by aFrame, then we need to try
        // and coalesce adjacent rects
        if (prevIsSharedRect || (isSharedRect && (nsnull != prevRect))) {
          NS_ASSERTION(nsnull != prevRect, "no previous rect");
          if ((prevRect->mRight == rect->mLeft) && (prevRect->HasSameFrameList(rect))) {
            // Modify the current rect's left edge, and delete the previous rect
            rect->mLeft = prevRect->mLeft;
            prevRect->Remove();
            if (prevRect == band) {
              // the rect we're deleting is the start of the band
              band = rect;
            }
            delete prevRect;
          }
        }

        // Get the next rect in the band
        prevRect = rect;
        prevIsSharedRect = isSharedRect;
        rect = rect->Next();
      } while (rect->mTop == topOfBand);

      if (nsnull != band) {
        // If we found a rect occupied by aFrame in this band or the previous band
        // then try to join the two bands
        if ((nsnull != prevBand) && (foundMatchingRect || prevFoundMatchingRect)) {
          // Try and join this band with the previous band
          JoinBands(band, prevBand);
        }
      }

      // Move to the next band
      prevFoundMatchingRect = foundMatchingRect;
      prevBand = band;
      band = (rect == &mBandList) ? nsnull : rect;
    }
  }

  DestroyFrameInfo(frameInfo);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Remove the regions associated with this floating frame and its next-sibling list.

Some of the frames may never have been added; we just skip those. This is not fully general; it only works as long as the N frames to be removed are the last N frames to have been added; if there's a frame in the middle of them that should not be removed, YOU LOSE.

This can only be done at the end of the life of this space manager. The only methods it is safe to call after this are XMost() and YMost().

Definition at line 849 of file nsSpaceManager.cpp.

                                                          {
  nsVoidHashSet frameSet;

  frameSet.Init(1);
  for (nsIFrame* f = aFrameList; f; f = f->GetNextSibling()) {
    frameSet.Put(f);
  }

  // Pop frame regions off as long as they're in the set of frames to
  // remove
  while (mFrameInfoMap && frameSet.Contains(mFrameInfoMap->mFrame)) {
    RemoveRegion(mFrameInfoMap->mFrame);
  }

#ifdef DEBUG
  for (FrameInfo* frameInfo = mFrameInfoMap; frameInfo;
       frameInfo = frameInfo->mNext) {
    NS_ASSERTION(!frameSet.Contains(frameInfo->mFrame),
                 "Frame region deletion was requested but we couldn't delete it");
  }
#endif

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 182 of file nsSpaceManager.cpp.

{
  // The layout module is being shut down, clean up the cache and
  // disable further caching.

  PRInt32 i;

  for (i = 0; i < sCachedSpaceManagerCount; i++) {
    void* spaceManager = sCachedSpaceManagers[i];
    if (spaceManager)
      nsMemory::Free(spaceManager);
  }

  // Disable futher caching.
  sCachedSpaceManagerCount = -1;
}
void nsSpaceManager::Translate ( nscoord  aDx,
nscoord  aDy 
) [inline]

Translate the current origin by the specified (dx, dy).

This creates a new local coordinate space relative to the current coordinate space.

Definition at line 189 of file nsSpaceManager.h.

{ mX += aDx; mY += aDy; }

Here is the caller graph for this function:

PRBool nsSpaceManager::XMost ( nscoord aXMost) const

Returns the x-most rect in the space manager, or 0 if there are no rects.

Returns:
PR_TRUE if there are bands and PR_FALSE if there are no bands

Definition at line 200 of file nsSpaceManager.cpp.

{
  nscoord xMost = 0;
  for (FrameInfo* fi = mFrameInfoMap; fi; fi = fi->mNext) {
    xMost = PR_MAX(xMost, fi->mRect.XMost());
  }
  aXMost = xMost;
  return !mBandList.IsEmpty();
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsSpaceManager::YMost ( nscoord aYMost) const

Returns the y-most of the bottommost band or 0 if there are no bands.

Returns:
PR_TRUE if there are bands and PR_FALSE if there are no bands

Definition at line 211 of file nsSpaceManager.cpp.

{
  PRBool result;

  if (mBandList.IsEmpty()) {
    aYMost = 0;
    result = PR_FALSE;

  } else {
    BandRect* lastRect = mBandList.Tail();

    aYMost = lastRect->mBottom;
    result = PR_TRUE;
  }

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 438 of file nsSpaceManager.h.

Definition at line 432 of file nsSpaceManager.h.

Definition at line 435 of file nsSpaceManager.h.

Definition at line 430 of file nsSpaceManager.h.

Definition at line 434 of file nsSpaceManager.h.

Definition at line 433 of file nsSpaceManager.h.

Definition at line 437 of file nsSpaceManager.h.

Definition at line 431 of file nsSpaceManager.h.

Definition at line 431 of file nsSpaceManager.h.

Definition at line 461 of file nsSpaceManager.h.

Definition at line 462 of file nsSpaceManager.h.


The documentation for this class was generated from the following files: