diff --git a/mozilla/layout/base/src/nsContainerFrame.cpp b/mozilla/layout/base/src/nsContainerFrame.cpp index df12feb1dc2..ebb7c189d4b 100644 --- a/mozilla/layout/base/src/nsContainerFrame.cpp +++ b/mozilla/layout/base/src/nsContainerFrame.cpp @@ -37,6 +37,7 @@ static NS_DEFINE_IID(kIStyleSpacingSID, NS_STYLESPACING_SID); static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); +static NS_DEFINE_IID(kStyleDisplaySID, NS_STYLEDISPLAY_SID); nsContainerFrame::nsContainerFrame(nsIContent* aContent, PRInt32 aIndexInParent, @@ -451,29 +452,54 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, // nsBlockFrame since it already has band data, and it's probably the only // one who calls this routine anyway nsBandData bandData; - nsBandTrapezoid trapezoids[7]; - nsBandTrapezoid* availSpace = trapezoids; + nsBandTrapezoid trapezoids[12]; + nsBandTrapezoid* trapezoid = trapezoids; + nsRect availBand; nsSize availSize = aMaxSize; bandData.trapezoids = trapezoids; - bandData.size = 7; + bandData.size = 12; aSpaceManager->GetBandData(0, aMaxSize, bandData); - // If there's more than one trapezoid then figure out which one determines the - // available reflow area - if (bandData.count == 2) { - nsRect r0, r1; + if (bandData.count > 1) { + // If there's more than one trapezoid that means there are floaters + PRInt32 i; - trapezoids[0].GetRect(r0); - trapezoids[1].GetRect(r1); + // Stop when we get to space occupied by a right floater + for (i = 0; i < bandData.count; i++) { + nsBandTrapezoid* trapezoid = &trapezoids[i]; - // Either a left or right floater. Use whichever space is larger - if (r1.width > r0.width) { - availSpace = &trapezoids[1]; + if (trapezoid->state != nsBandTrapezoid::smAvailable) { + nsStyleDisplay* display; + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { + break; + } + } } - } else if (bandData.count == 3) { - // Assume there are floaters on the left and right, and use the middle rect - availSpace = &trapezoids[1]; + + if (i > 0) { + trapezoid = &trapezoids[i - 1]; + } + } + + if (nsBandTrapezoid::smAvailable == trapezoid->state) { + // The trapezoid is available + trapezoid->GetRect(availBand); + } else { + nsStyleDisplay* display; + + // The trapezoid is occupied. That means there's no available space + trapezoid->GetRect(availBand); + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { + availBand.x = availBand.XMost(); + } + availBand.width = 0; } // Does the child frame want to do continuation-based runaround? @@ -482,20 +508,17 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, aKidFrame->IsSplittable(isSplittable); if (isSplittable == frSplittableNonRectangular) { // Reduce the max height to the band height. - availSize.height = availSpace->yBottom - availSpace->yTop; + availSize.height = availBand.height; } - // Get the bounding rect of the available trapezoid - nsRect rect; - nsIStyleContext* kidSC; - aKidFrame->GetStyleContext(aPresContext, kidSC); - nsStyleSpacing* spacing = (nsStyleSpacing*)kidSC->GetData(kIStyleSpacingSID); + nsStyleSpacing* spacing; + + aKidFrame->GetStyleData(kIStyleSpacingSID, (nsStyleStruct*&)spacing); - availSpace->GetRect(rect); if (aMaxSize.width != NS_UNCONSTRAINEDSIZE) { - if ((rect.x > 0) || (rect.XMost() < aMaxSize.width)) { + if ((availBand.x > 0) || (availBand.XMost() < aMaxSize.width)) { // There are left/right floaters. - availSize.width = rect.width; + availSize.width = availBand.width; } // Reduce the available width by the kid's left/right margin @@ -505,7 +528,7 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, // Does the child frame support interface nsIRunaround? if (NS_OK == aKidFrame->QueryInterface(kIRunaroundIID, (void**)&reflowRunaround)) { // Yes, the child frame wants to interact directly with the space manager. - nscoord tx = rect.x + spacing->mMargin.left; + nscoord tx = availBand.x + spacing->mMargin.left; // Translate the local coordinate space to the current left edge plus any // left margin the child wants @@ -513,7 +536,7 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, reflowRunaround->ResizeReflow(aPresContext, aSpaceManager, availSize, aDesiredRect, aMaxElementSize, status); - aDesiredRect.x += rect.x; + aDesiredRect.x += availBand.x; // Translate back aSpaceManager->Translate(-tx, 0); @@ -526,7 +549,7 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, aMaxElementSize, status); // Return the desired rect - aDesiredRect.x = rect.x; + aDesiredRect.x = availBand.x; aDesiredRect.y = 0; aDesiredRect.width = desiredSize.width; aDesiredRect.height = desiredSize.height; @@ -547,7 +570,6 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, } } - NS_RELEASE(kidSC); return status; } diff --git a/mozilla/layout/base/src/nsSpaceManager.cpp b/mozilla/layout/base/src/nsSpaceManager.cpp index 2906abc65d5..780bedf1d40 100644 --- a/mozilla/layout/base/src/nsSpaceManager.cpp +++ b/mozilla/layout/base/src/nsSpaceManager.cpp @@ -62,7 +62,8 @@ nscoord SpaceManager::YMost() const } /** - * Internal function that returns the available space within the band + * Internal function that returns the list of available and unavailable space + * within the band * * @param aBand the first rect in the band * @param aIndex aBand's index in the rect array @@ -70,25 +71,24 @@ nscoord SpaceManager::YMost() const * @param aMaxSize the size to use to constrain the band data * @param aAvailableBand */ -PRInt32 SpaceManager::GetBandAvailableSpace(const nsRect* aBand, - PRInt32 aIndex, - nscoord aY, - const nsSize& aMaxSize, - nsBandData& aAvailableSpace) const +PRInt32 SpaceManager::GetBandAvailableSpace(const nsBandRect* aBand, + PRInt32 aIndex, + nscoord aY, + const nsSize& aMaxSize, + nsBandData& aBandData) const { PRInt32 numRects = LengthOfBand(aBand, aIndex); nscoord localY = aY - mY; nscoord height = PR_MIN(aBand->YMost() - aY, aMaxSize.height); - nsBandTrapezoid* trapezoid = aAvailableSpace.trapezoids; + nsBandTrapezoid* trapezoid = aBandData.trapezoids; nscoord rightEdge = mX + aMaxSize.width; // Initialize the band data - aAvailableSpace.count = 0; - trapezoid->xTopLeft = mX; + aBandData.count = 0; // Skip any rectangles that are to the left of the local coordinate space while (numRects > 0) { - if (aBand->XMost() >= mX) { + if (aBand->XMost() > mX) { break; } @@ -97,60 +97,74 @@ PRInt32 SpaceManager::GetBandAvailableSpace(const nsRect* aBand, numRects--; } - // Process all the remaining rectangles that are within the clip width + // 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 ((numRects > 0) && (aBand->x < rightEdge)) { - if (aBand->x > trapezoid->xTopLeft) { - // We found some available space - trapezoid->xTopRight = trapezoid->xBottomRight = aBand->x; - - // Convert from world to local coordinates - trapezoid->xTopLeft -= mX; - trapezoid->xTopRight -= mX; - trapezoid->xBottomLeft = trapezoid->xTopLeft; - trapezoid->xBottomRight = trapezoid->xTopRight; - - trapezoid->yTop = localY; - trapezoid->yBottom = localY + height; + // Compare the left edge of the occupied space with the current left + // coordinate + if (aBand->x > left) { + // The rect is to the right of our current left coordinate, so we've + // found some available space trapezoid->state = nsBandTrapezoid::smAvailable; trapezoid->frame = 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->x - left, height); + // Move to the next output rect trapezoid++; - aAvailableSpace.count++; + aBandData.count++; } - trapezoid->xTopLeft = aBand->XMost(); + // The rect represents unavailable space, so add another trapezoid + trapezoid->state = nsBandTrapezoid::smOccupied; + trapezoid->frame = aBand->frame; - // Move to the next rect in the band + nscoord x = aBand->x; + // 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->XMost() - x, height); + + // Move to the next output rect + trapezoid++; + aBandData.count++; + + // Adjust our current x-location within the band + left = aBand->XMost(); + + // Move to the next rect within the band numRects--; aBand++; } // No more rects left in the band. If we haven't yet reached the right edge, // then all the remaining space is available - if (trapezoid->xTopLeft < rightEdge) { - trapezoid->xTopRight = rightEdge; - - // Convert from world to local coordinates - trapezoid->xTopLeft -= mX; - trapezoid->xTopRight -= mX; - trapezoid->xBottomLeft = trapezoid->xTopLeft; - trapezoid->xBottomRight = trapezoid->xTopRight; - - trapezoid->yTop = localY; - trapezoid->yBottom = localY + height; + if (left < rightEdge) { trapezoid->state = nsBandTrapezoid::smAvailable; trapezoid->frame = nsnull; - aAvailableSpace.count++; + // 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.count++; } - return aAvailableSpace.count; + return aBandData.count; } PRInt32 SpaceManager::GetBandData(nscoord aYOffset, const nsSize& aMaxSize, - nsBandData& aAvailableSpace) const + nsBandData& aBandData) const { // Convert the y-offset to world coordinates nscoord y = mY + aYOffset; @@ -158,35 +172,29 @@ PRInt32 SpaceManager::GetBandData(nscoord aYOffset, // If there are no unavailable rects or the offset is below the bottommost // band then all the space is available if ((0 == mRectArray.mCount) || (y >= mRectArray.YMost())) { - aAvailableSpace.count = 1; - - nsBandTrapezoid& trapezoid = aAvailableSpace.trapezoids[0]; - - trapezoid.xTopLeft = trapezoid.xBottomLeft = 0; - trapezoid.yTop = aYOffset; - trapezoid.xTopRight = trapezoid.xBottomRight = aMaxSize.width; - trapezoid.yBottom = aYOffset + aMaxSize.height; - trapezoid.state = nsBandTrapezoid::smAvailable; - trapezoid.frame = nsnull; + // All the requested space is available + aBandData.count = 1; + aBandData.trapezoids[0] = nsRect(0, aYOffset, aMaxSize.width, aMaxSize.height); + aBandData.trapezoids[0].state = nsBandTrapezoid::smAvailable; + aBandData.trapezoids[0].frame = nsnull; } else { // Find the first band that contains the y-offset or is below the y-offset - nsRect* band = mRectArray.mRects; + nsBandRect* band = mRectArray.mRects; for (PRInt32 i = 0; i < mRectArray.mCount; ) { if (band->y > y) { - // The band is below the y-offset - nsBandTrapezoid& trapezoid = aAvailableSpace.trapezoids[0]; - - trapezoid.xTopLeft = trapezoid.xBottomLeft = 0; - trapezoid.yTop = aYOffset; - trapezoid.xTopRight = trapezoid.xBottomRight = aMaxSize.width; - trapezoid.yBottom = aYOffset + PR_MIN(band->y - y, aMaxSize.height); - trapezoid.state = nsBandTrapezoid::smAvailable; - trapezoid.frame = nsnull; + // The band is below the y-offset. The area between the y-offset and + // the top of the band is available + aBandData.count = 1; + aBandData.trapezoids[0] = + nsRect(0, aYOffset, aMaxSize.width, PR_MIN(band->y - y, aMaxSize.height)); + aBandData.trapezoids[0].state = nsBandTrapezoid::smAvailable; + aBandData.trapezoids[0].frame = nsnull; break; } else if (y < band->YMost()) { - // The band contains the y-offset - return GetBandAvailableSpace(band, i, y, aMaxSize, aAvailableSpace); + // The band contains the y-offset. Return a list of available and + // unavailable rects within the band + return GetBandAvailableSpace(band, i, y, aMaxSize, aBandData); } else { // Skip to the next band GetNextBand(band, i); @@ -194,7 +202,7 @@ PRInt32 SpaceManager::GetBandData(nscoord aYOffset, } } - return aAvailableSpace.count; + return aBandData.count; } /** @@ -207,7 +215,7 @@ PRInt32 SpaceManager::GetBandData(nscoord aYOffset, * next band. If there is no next band then aRect is undefined * and aIndex is set to the number of rects in the rect array */ -PRBool SpaceManager::GetNextBand(nsRect*& aRect, PRInt32& aIndex) const +PRBool SpaceManager::GetNextBand(nsBandRect*& aRect, PRInt32& aIndex) const { nscoord topOfBand = aRect->y; @@ -231,7 +239,7 @@ PRBool SpaceManager::GetNextBand(nsRect*& aRect, PRInt32& aIndex) const * @param aBand the first rect in the band * @param aIndex aBand's index in the rect array */ -PRInt32 SpaceManager::LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const +PRInt32 SpaceManager::LengthOfBand(const nsBandRect* aBand, PRInt32 aIndex) const { nscoord topOfBand = aBand->y; PRInt32 result = 1; @@ -252,36 +260,48 @@ PRInt32 SpaceManager::LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const } /** - * Tries to coalesce horizontally overlapping rectangles within a band + * Tries to coalesce adjoining rectangles within a band. Returns PR_TRUE if any + * of the rects are coalesced and PR_FALSE otherwise * - * @param aRect a rect in the band - * @param aIndex aRect's index in the rect array + * @param aRect the first rect in the band + * @param aIndex aBand's index in the rect array */ -void SpaceManager::CoalesceBand(nsRect* aRect, PRInt32 aIndex) +PRBool SpaceManager::CoalesceBand(nsBandRect* aBand, PRInt32 aIndex) { + PRBool result = PR_FALSE; + while ((aIndex + 1) < mRectArray.mCount) { // Is there another rect in this band? - nsRect* nextRect = aRect + 1; + nsBandRect* nextRect = aBand + 1; - if (nextRect->y == aRect->y) { - // Yes. Do the two rects overlap horizontally? - if (aRect->XMost() > nextRect->x) { - // Yes. Extend the right edge of aRect - aRect->width = nextRect->XMost() - aRect->x; + if (nextRect->y == aBand->y) { + // The rects must not be overlapping + NS_ASSERTION(nextRect->x >= aBand->XMost(), "overlapping rects"); + + // Are the two rects adjoining and have the same tagged frame? + if ((aBand->XMost() == nextRect->x) && (aBand->frame == nextRect->frame)) { + // Yes. Extend the right edge of the current rect + aBand->width = nextRect->XMost() - aBand->x; // Remove the next rect mRectArray.RemoveAt(aIndex + 1); - aRect = mRectArray.mRects + aIndex; // memory may have changed... + aBand = mRectArray.mRects + aIndex; // memory may have changed... + + // Continue through the loop trying to coalesce this rect + result = PR_TRUE; } else { - // No. We're all done - break; + // No. Move to the next rect within the band + aBand++; + aIndex++; } } else { // The next rect is part of a different band, so we're all done break; } } + + return result; } /** @@ -291,7 +311,7 @@ void SpaceManager::CoalesceBand(nsRect* aRect, PRInt32 aIndex) * @param aIndex aBand's index in the rect array * @param aB1Height the height of the new band to create */ -void SpaceManager::DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height) +void SpaceManager::DivideBand(nsBandRect* aBand, PRInt32 aIndex, nscoord aB1Height) { NS_PRECONDITION(aB1Height < aBand->height, "bad height"); @@ -305,7 +325,7 @@ void SpaceManager::DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height) // Insert a new bottom band nsRect r(aBand->x, aBand->y + aB1Height, aBand->width, aB2Height); - mRectArray.InsertAt(r, insertAt); + mRectArray.InsertAt(r, insertAt, aBand->frame); aBand = mRectArray.mRects + aIndex; // memory may have changed... // Adjust the height of the top band @@ -322,62 +342,127 @@ void SpaceManager::DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height) * * @param aBand the first rect in the band * @param aIndex aBand's index in the rect array - * @param aRect the rect to add to the band + * @param aRect the rect to add to the band. It's in world coordinates * @returns PR_TRUE if successful and PR_FALSE if this is the last band */ -void SpaceManager::AddRectToBand(nsRect* aBand, +void SpaceManager::AddRectToBand(nsBandRect* aBand, PRInt32 aIndex, - const nsRect& aRect) + const nsRect& aRect, + nsIFrame* aFrame) { NS_PRECONDITION((aBand->y == aRect.y) && (aBand->height == aRect.height), "bad band"); nscoord topOfBand = aBand->y; + nsRect rect(aRect); - // Figure out where in the band to horizontally insert the rect. Try and - // coalesce it with an existing rect if possible. + // Figure out where in the band horizontally to insert the rect. Try and + // coalesce it with an existing rect if possible. We can only do this if + // they're tagged with the same frame do { // Compare the left edge of the new rect with the left edge of the existing // rect - if (aRect.x <= aBand->x) { - // The new rect's left edge is to the left of the existing rect's left - // edge. Does the new rect overlap the existing rect? - if (aRect.XMost() >= aBand->x) { - // Yes. Extend the existing rect - if (aRect.XMost() > aBand->XMost()) { - aBand->x = aRect.x; - aBand->width = aRect.width; - - // We're extending the right edge of the existing rect which may - // cause the rect to overlap the remaining rects in the band - CoalesceBand(aBand, aIndex); - } else { - aBand->width = aBand->XMost() - aRect.x; - aBand->x = aRect.x; - } - } else { - // No, it's completely to the left of the existing rect. Insert a new - // rect - mRectArray.InsertAt(aRect, aIndex); + if (rect.x < aBand->x) { + // 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 (rect.XMost() <= aBand->x) { + // No, the new rect is completely to the left of the existing rect + // (case #1). Insert a new rect + mRectArray.InsertAt(rect, aIndex, aFrame); + return; } - return; - } else if (aRect.x <= aBand->XMost()) { - // The two rects are overlapping or adjoining. Extend the right edge of - // the existing rect - aBand->width = aRect.XMost() - aBand->x; + // Yes, they overlap. Insert a new rect for the part that's to the left + // of the existing rect + nsRect r1(rect.x, rect.y, aBand->x - rect.x, rect.height); - // Since we extended the right edge of the existing rect it may now - // overlap the remaining rects in the band - CoalesceBand(aBand, aIndex); + mRectArray.InsertAt(r1, aIndex, aFrame); + aIndex++; + aBand = mRectArray.mRects + aIndex; // memory may have changed... + + // Adjust rect to reflect the overlap + rect.width = rect.XMost() - aBand->x; + rect.x = aBand->x; + + } else if (rect.x > aBand->x) { + // 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 (rect.x >= aBand->XMost()) { + // The new rect is to the right of the existing rect (case #4), so move + // to the next rect in the band + aBand++; aIndex++; + 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 + nsRect r1(rect.x, aBand->y, aBand->XMost() - rect.x, aBand->height); + + // Modify the left half of the existing rect + aBand->width = rect.x - aBand->x; + + // Insert the new right half of the existing rect, and make it the current + // rect + aIndex++; + mRectArray.InsertAt(r1, aIndex, aBand->frame); + aBand = mRectArray.mRects + aIndex; // memory may have changed... + } + + // At this point the left edge of the new rect is the same as the left edge + // of the existing rect + NS_ASSERTION(rect.x == aBand->x, "unexpected rect"); + + // Compare which rect is wider, the new rect or the existing rect + if (aBand->width > rect.width) { + // The existing rect is wider (cases 2 and 6). Divide the existing rect + // into two rects: the part that overlaps, and the part to the right of + // the new rect + nsRect r1(rect.XMost(), aBand->y, aBand->XMost() - rect.XMost(), aBand->height); + + // Modify the left half of the existing rect + aBand->width = r1.x - aBand->x; + + // Insert the new right half of the existing rect + mRectArray.InsertAt(r1, aIndex, aBand->frame); + aBand = mRectArray.mRects + aIndex; // memory may have changed... + } + + // XXX Mark the existing rect as being shared by the two frames... + + if (rect.width == aBand->width) { + // We're all done return; } - // Move to the next rect in the band + // The new rect is wider than the existing rect (cases 3 and 5). Set rect + // to be the overhang and move to the next rect within the band + rect.width = rect.XMost() - aBand->XMost(); + rect.x = aBand->XMost(); aBand++; aIndex++; } while ((aIndex < mRectArray.mCount) && (aBand->y == topOfBand)); // Insert a new rect - mRectArray.InsertAt(aRect, aIndex); + mRectArray.InsertAt(aRect, aIndex, aFrame); } // When comparing a rect to a band there are seven cases to consider. @@ -417,12 +502,12 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra // then add a new band if ((0 == mRectArray.mCount) || (rect.y >= mRectArray.YMost())) { // Append a new bottommost band - mRectArray.Append(rect); + mRectArray.Append(rect, aFrame); return; } // Examine each band looking for a band that intersects this rect - nsRect* band = mRectArray.mRects; + nsBandRect* band = mRectArray.mRects; for (PRInt32 i = 0; i < mRectArray.mCount; ) { // Compare the top edge of this rect with the top edge of the band @@ -432,7 +517,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra if (rect.YMost() <= band->y) { // Case #1. This rect is completely above the band, so insert a // new band - mRectArray.InsertAt(rect, i); + mRectArray.InsertAt(rect, i, aFrame); break; // we're all done } @@ -441,7 +526,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra nsRect r1(rect.x, rect.y, rect.width, band->y - rect.y); // Insert r1 as a new band - mRectArray.InsertAt(r1, i); + mRectArray.InsertAt(r1, i, aFrame); i++; band = mRectArray.mRects + i; // memory may have changed... @@ -480,7 +565,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra if (rect.height == band->height) { // Add the rect to the band - AddRectToBand(band, i, rect); + AddRectToBand(band, i, rect, aFrame); break; } else { @@ -489,7 +574,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra nsRect r1(rect.x, rect.y, rect.width, band->YMost() - rect.y); // Add r1 to the band - AddRectToBand(band, i, r1); + AddRectToBand(band, i, r1, aFrame); band = mRectArray.mRects + i; // memory may have changed... // Modify rect to be the part below the band @@ -499,7 +584,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra // Continue with the next band if (!GetNextBand(band, i)) { // Append a new bottommost band - mRectArray.Append(rect); + mRectArray.Append(rect, aFrame); break; } } @@ -532,29 +617,40 @@ nscoord SpaceManager::RectArray::YMost() const return mRects[mCount - 1].YMost(); } -void SpaceManager::RectArray::Append(const nsRect& aRect) +void SpaceManager::RectArray::Append(const nsRect& aRect, nsIFrame* aFrame) { // Ensure there's enough capacity if (mCount >= mMax) { mMax += 8; - mRects = (nsRect*)realloc(mRects, mMax * sizeof(nsRect)); + mRects = (nsBandRect*)realloc(mRects, mMax * sizeof(nsBandRect)); } - mRects[mCount++] = aRect; + mRects[mCount].x = aRect.x; + mRects[mCount].y = aRect.y; + mRects[mCount].width = aRect.width; + mRects[mCount].height = aRect.height; + mRects[mCount].frame = aFrame; + mCount++; } -void SpaceManager::RectArray::InsertAt(const nsRect& aRect, PRInt32 aIndex) +void SpaceManager::RectArray::InsertAt(const nsRect& aRect, + PRInt32 aIndex, + nsIFrame* aFrame) { NS_PRECONDITION(aIndex <= mCount, "bad index"); // no holes in the array // Ensure there's enough capacity if (mCount >= mMax) { mMax += 8; - mRects = (nsRect*)realloc(mRects, mMax * sizeof(nsRect)); + mRects = (nsBandRect*)realloc(mRects, mMax * sizeof(nsBandRect)); } - memmove(&mRects[aIndex + 1], &mRects[aIndex], (mCount - aIndex) * sizeof(nsRect)); - mRects[aIndex] = aRect; + memmove(&mRects[aIndex + 1], &mRects[aIndex], (mCount - aIndex) * sizeof(nsBandRect)); + mRects[aIndex].x = aRect.x; + mRects[aIndex].y = aRect.y; + mRects[aIndex].width = aRect.width; + mRects[aIndex].height = aRect.height; + mRects[aIndex].frame = aFrame; mCount++; } @@ -564,7 +660,7 @@ void SpaceManager::RectArray::RemoveAt(PRInt32 aIndex) mCount--; if (aIndex < mCount) { - memmove(&mRects[aIndex], &mRects[aIndex + 1], (mCount - aIndex) * sizeof(nsRect)); + memmove(&mRects[aIndex], &mRects[aIndex + 1], (mCount - aIndex) * sizeof(nsBandRect)); } } diff --git a/mozilla/layout/base/src/nsSpaceManager.h b/mozilla/layout/base/src/nsSpaceManager.h index fe0d3f789b7..0c01d5a5dcf 100644 --- a/mozilla/layout/base/src/nsSpaceManager.h +++ b/mozilla/layout/base/src/nsSpaceManager.h @@ -38,19 +38,23 @@ public: virtual nscoord YMost() const; virtual PRInt32 GetBandData(nscoord aYOffset, const nsSize& aMaxSize, - nsBandData& aAvailableSpace) const; + nsBandData& aBandData) const; virtual void AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFrame); virtual void ClearRegions(); protected: + struct nsBandRect : nsRect { + nsIFrame* frame; + }; + class RectArray { public: RectArray(); ~RectArray(); // Functions to add rects - void Append(const nsRect& aRect); - void InsertAt(const nsRect& aRect, PRInt32 aIndex); + void Append(const nsRect& aRect, nsIFrame* aFrame); + void InsertAt(const nsRect& aRect, PRInt32 aIndex, nsIFrame* aFrame); void RemoveAt(PRInt32 aIndex); // Clear the list of rectangles @@ -61,9 +65,9 @@ protected: public: // Access to the underlying storage - nsRect* mRects; // y-x banded array of rectangles of unavailable space - PRInt32 mCount; // current number of rects - PRInt32 mMax; // capacity of rect array + nsBandRect* mRects; // y-x banded array of rectangles of unavailable space + PRInt32 mCount; // current number of rects + PRInt32 mMax; // capacity of rect array }; nsIFrame* const mFrame; // frame associated with the space manager @@ -71,16 +75,17 @@ protected: RectArray mRectArray; // y-x banded array of rectangles of unavailable space protected: - PRBool GetNextBand(nsRect*& aRect, PRInt32& aIndex) const; - PRInt32 LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const; - void CoalesceBand(nsRect* aBand, PRInt32 aIndex); - void DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height); - void AddRectToBand(nsRect* aBand, PRInt32 aIndex, const nsRect& aRect); - PRInt32 GetBandAvailableSpace(const nsRect* aBand, - PRInt32 aIndex, - nscoord aY, - const nsSize& aMaxSize, - nsBandData& aAvailableSpace) const; + PRBool GetNextBand(nsBandRect*& aRect, PRInt32& aIndex) const; + PRInt32 LengthOfBand(const nsBandRect* aBand, PRInt32 aIndex) const; + PRBool CoalesceBand(nsBandRect* aBand, PRInt32 aIndex); + void DivideBand(nsBandRect* aBand, PRInt32 aIndex, nscoord aB1Height); + void AddRectToBand(nsBandRect* aBand, PRInt32 aIndex, + const nsRect& aRect, nsIFrame* aFrame); + PRInt32 GetBandAvailableSpace(const nsBandRect* aBand, + PRInt32 aIndex, + nscoord aY, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const; private: SpaceManager(const SpaceManager&); // no implementation diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 2764b8d626a..6b45fe72cab 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -59,11 +59,68 @@ NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIContent); struct BlockBandData : public nsBandData { - nsBandTrapezoid data[5]; + nsBandTrapezoid data[12]; - BlockBandData() {size = 5; trapezoids = data;} + // Bounding rect of available space between any left and right floaters + nsRect availSpace; + + // Constructor + BlockBandData() {size = 12; trapezoids = data;} + + // Computes the bounding rect of the available space, i.e. space between + // any left and right floaters + // + // Uses the current trapezoid data, see nsISpaceManager::GetBandData(). + // Updates member data "availSpace" + void ComputeAvailSpaceRect(); }; +void BlockBandData::ComputeAvailSpaceRect() +{ + nsBandTrapezoid* trapezoid = data; + + if (count > 1) { + // If there's more than one trapezoid that means there are floaters + PRInt32 i; + + // Stop when we get to space occupied by a right floater + for (i = 0; i < count; i++) { + nsBandTrapezoid* trapezoid = &data[i]; + + if (trapezoid->state != nsBandTrapezoid::smAvailable) { + nsStyleDisplay* display; + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { + break; + } + } + } + + if (i > 0) { + trapezoid = &data[i - 1]; + } + } + + if (nsBandTrapezoid::smAvailable == trapezoid->state) { + // The trapezoid is available + trapezoid->GetRect(availSpace); + } else { + nsStyleDisplay* display; + + // The trapezoid is occupied. That means there's no available space + trapezoid->GetRect(availSpace); + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { + availSpace.x = availSpace.XMost(); + } + availSpace.width = 0; + } +} + // XXX Bugs // 1. right to left reflow can generate negative x coordinates. @@ -366,13 +423,13 @@ void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, styleContext->GetData(kStyleDisplaySID); floater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... @@ -682,9 +739,9 @@ void nsBlockFrame::GetAvailSize(nsSize& aResult, aResult.width = NS_UNCONSTRAINEDSIZE; } else if (aIsInline) { if (NS_STYLE_DIRECTION_LTR == aState.styleDisplay->mDirection) { - aResult.width = aState.currentBand->trapezoids[0].xTopRight - aState.x; + aResult.width = aState.currentBand->availSpace.XMost() - aState.x; } else { - aResult.width = aState.x - aState.currentBand->trapezoids[0].xTopLeft; + aResult.width = aState.x - aState.currentBand->availSpace.x; } } else { // It's a block. Don't adjust for the left/right margin here. That happens @@ -767,31 +824,11 @@ void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) aState.spaceManager->Translate(aState.borderPadding.left, 0); aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); - // XXX This is hack code that needs to change when the space manager interface - // changes to return both the available and unavailable space - // - // We'll get back anywhere between 1 and 3 rects depending on how many floaters - // there are. Actually the way it currently works we could get back zero rects - // if there are overlapping left and right floaters occupying all the space - if (aState.currentBand->count > 1) { - // If there are three rects then let's assume that there are floaters on the - // left and right and that only the middle rect is available - if (aState.currentBand->count == 3) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } else { - nsRect r0, r1; - - // There are two rects. That means either a left or right floater. Just use - // whichever space is larger. - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r1.width > r0.width) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } - } - } + // Compute the bounding rect of the available space, i.e. space between any + // left and right floaters + aState.currentBand->ComputeAvailSpaceRect(); aState.spaceManager->Translate(-aState.borderPadding.left, 0); - aState.x = aState.currentBand->trapezoids[0].xTopLeft; + aState.x = aState.currentBand->availSpace.x; } void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) @@ -807,39 +844,22 @@ getBand: // Get a band of available space aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); - if (aState.currentBand->count == 1) { - nsRect rect; + // Scan the trapezoids looking for left and right floaters + nsBandTrapezoid* trapezoid = aState.currentBand->trapezoids; + for (PRInt32 i = 0; i < aState.currentBand->count; i++) { + // XXX Handle multiply occupied + if (nsBandTrapezoid::smOccupied == trapezoid->state) { + nsStyleDisplay* display; - aState.currentBand->trapezoids[0].GetRect(rect); - if (rect.width != aState.availSize.width) { - // Some of the space is taken up by floaters - if (rect.x > 0) { + trapezoid->frame->GetStyleData(kStylePositionSID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { isLeftFloater = PR_TRUE; - } - - if (rect.XMost() < aState.availSize.width) { + } else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { isRightFloater = PR_TRUE; } } - } else if (aState.currentBand->count == 2) { - nsRect r0, r1; - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r0.width > r1.width) { - isRightFloater = PR_TRUE; - } else { - isLeftFloater = PR_TRUE; - - // There may also be a right floater - if (r1.XMost() < aState.availSize.width) { - isRightFloater = PR_TRUE; - } - } - } else { - // Must be both left and right floaters - isLeftFloater = PR_TRUE; - isRightFloater = PR_TRUE; + trapezoid++; } if (isLeftFloater) { @@ -1988,13 +2008,13 @@ void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, nsRect region; aFloater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index 2764b8d626a..6b45fe72cab 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -59,11 +59,68 @@ NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIContent); struct BlockBandData : public nsBandData { - nsBandTrapezoid data[5]; + nsBandTrapezoid data[12]; - BlockBandData() {size = 5; trapezoids = data;} + // Bounding rect of available space between any left and right floaters + nsRect availSpace; + + // Constructor + BlockBandData() {size = 12; trapezoids = data;} + + // Computes the bounding rect of the available space, i.e. space between + // any left and right floaters + // + // Uses the current trapezoid data, see nsISpaceManager::GetBandData(). + // Updates member data "availSpace" + void ComputeAvailSpaceRect(); }; +void BlockBandData::ComputeAvailSpaceRect() +{ + nsBandTrapezoid* trapezoid = data; + + if (count > 1) { + // If there's more than one trapezoid that means there are floaters + PRInt32 i; + + // Stop when we get to space occupied by a right floater + for (i = 0; i < count; i++) { + nsBandTrapezoid* trapezoid = &data[i]; + + if (trapezoid->state != nsBandTrapezoid::smAvailable) { + nsStyleDisplay* display; + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { + break; + } + } + } + + if (i > 0) { + trapezoid = &data[i - 1]; + } + } + + if (nsBandTrapezoid::smAvailable == trapezoid->state) { + // The trapezoid is available + trapezoid->GetRect(availSpace); + } else { + nsStyleDisplay* display; + + // The trapezoid is occupied. That means there's no available space + trapezoid->GetRect(availSpace); + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { + availSpace.x = availSpace.XMost(); + } + availSpace.width = 0; + } +} + // XXX Bugs // 1. right to left reflow can generate negative x coordinates. @@ -366,13 +423,13 @@ void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, styleContext->GetData(kStyleDisplaySID); floater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... @@ -682,9 +739,9 @@ void nsBlockFrame::GetAvailSize(nsSize& aResult, aResult.width = NS_UNCONSTRAINEDSIZE; } else if (aIsInline) { if (NS_STYLE_DIRECTION_LTR == aState.styleDisplay->mDirection) { - aResult.width = aState.currentBand->trapezoids[0].xTopRight - aState.x; + aResult.width = aState.currentBand->availSpace.XMost() - aState.x; } else { - aResult.width = aState.x - aState.currentBand->trapezoids[0].xTopLeft; + aResult.width = aState.x - aState.currentBand->availSpace.x; } } else { // It's a block. Don't adjust for the left/right margin here. That happens @@ -767,31 +824,11 @@ void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) aState.spaceManager->Translate(aState.borderPadding.left, 0); aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); - // XXX This is hack code that needs to change when the space manager interface - // changes to return both the available and unavailable space - // - // We'll get back anywhere between 1 and 3 rects depending on how many floaters - // there are. Actually the way it currently works we could get back zero rects - // if there are overlapping left and right floaters occupying all the space - if (aState.currentBand->count > 1) { - // If there are three rects then let's assume that there are floaters on the - // left and right and that only the middle rect is available - if (aState.currentBand->count == 3) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } else { - nsRect r0, r1; - - // There are two rects. That means either a left or right floater. Just use - // whichever space is larger. - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r1.width > r0.width) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } - } - } + // Compute the bounding rect of the available space, i.e. space between any + // left and right floaters + aState.currentBand->ComputeAvailSpaceRect(); aState.spaceManager->Translate(-aState.borderPadding.left, 0); - aState.x = aState.currentBand->trapezoids[0].xTopLeft; + aState.x = aState.currentBand->availSpace.x; } void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) @@ -807,39 +844,22 @@ getBand: // Get a band of available space aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); - if (aState.currentBand->count == 1) { - nsRect rect; + // Scan the trapezoids looking for left and right floaters + nsBandTrapezoid* trapezoid = aState.currentBand->trapezoids; + for (PRInt32 i = 0; i < aState.currentBand->count; i++) { + // XXX Handle multiply occupied + if (nsBandTrapezoid::smOccupied == trapezoid->state) { + nsStyleDisplay* display; - aState.currentBand->trapezoids[0].GetRect(rect); - if (rect.width != aState.availSize.width) { - // Some of the space is taken up by floaters - if (rect.x > 0) { + trapezoid->frame->GetStyleData(kStylePositionSID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { isLeftFloater = PR_TRUE; - } - - if (rect.XMost() < aState.availSize.width) { + } else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { isRightFloater = PR_TRUE; } } - } else if (aState.currentBand->count == 2) { - nsRect r0, r1; - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r0.width > r1.width) { - isRightFloater = PR_TRUE; - } else { - isLeftFloater = PR_TRUE; - - // There may also be a right floater - if (r1.XMost() < aState.availSize.width) { - isRightFloater = PR_TRUE; - } - } - } else { - // Must be both left and right floaters - isLeftFloater = PR_TRUE; - isRightFloater = PR_TRUE; + trapezoid++; } if (isLeftFloater) { @@ -1988,13 +2008,13 @@ void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, nsRect region; aFloater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index 2764b8d626a..6b45fe72cab 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -59,11 +59,68 @@ NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIContent); struct BlockBandData : public nsBandData { - nsBandTrapezoid data[5]; + nsBandTrapezoid data[12]; - BlockBandData() {size = 5; trapezoids = data;} + // Bounding rect of available space between any left and right floaters + nsRect availSpace; + + // Constructor + BlockBandData() {size = 12; trapezoids = data;} + + // Computes the bounding rect of the available space, i.e. space between + // any left and right floaters + // + // Uses the current trapezoid data, see nsISpaceManager::GetBandData(). + // Updates member data "availSpace" + void ComputeAvailSpaceRect(); }; +void BlockBandData::ComputeAvailSpaceRect() +{ + nsBandTrapezoid* trapezoid = data; + + if (count > 1) { + // If there's more than one trapezoid that means there are floaters + PRInt32 i; + + // Stop when we get to space occupied by a right floater + for (i = 0; i < count; i++) { + nsBandTrapezoid* trapezoid = &data[i]; + + if (trapezoid->state != nsBandTrapezoid::smAvailable) { + nsStyleDisplay* display; + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { + break; + } + } + } + + if (i > 0) { + trapezoid = &data[i - 1]; + } + } + + if (nsBandTrapezoid::smAvailable == trapezoid->state) { + // The trapezoid is available + trapezoid->GetRect(availSpace); + } else { + nsStyleDisplay* display; + + // The trapezoid is occupied. That means there's no available space + trapezoid->GetRect(availSpace); + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { + availSpace.x = availSpace.XMost(); + } + availSpace.width = 0; + } +} + // XXX Bugs // 1. right to left reflow can generate negative x coordinates. @@ -366,13 +423,13 @@ void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, styleContext->GetData(kStyleDisplaySID); floater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... @@ -682,9 +739,9 @@ void nsBlockFrame::GetAvailSize(nsSize& aResult, aResult.width = NS_UNCONSTRAINEDSIZE; } else if (aIsInline) { if (NS_STYLE_DIRECTION_LTR == aState.styleDisplay->mDirection) { - aResult.width = aState.currentBand->trapezoids[0].xTopRight - aState.x; + aResult.width = aState.currentBand->availSpace.XMost() - aState.x; } else { - aResult.width = aState.x - aState.currentBand->trapezoids[0].xTopLeft; + aResult.width = aState.x - aState.currentBand->availSpace.x; } } else { // It's a block. Don't adjust for the left/right margin here. That happens @@ -767,31 +824,11 @@ void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) aState.spaceManager->Translate(aState.borderPadding.left, 0); aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); - // XXX This is hack code that needs to change when the space manager interface - // changes to return both the available and unavailable space - // - // We'll get back anywhere between 1 and 3 rects depending on how many floaters - // there are. Actually the way it currently works we could get back zero rects - // if there are overlapping left and right floaters occupying all the space - if (aState.currentBand->count > 1) { - // If there are three rects then let's assume that there are floaters on the - // left and right and that only the middle rect is available - if (aState.currentBand->count == 3) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } else { - nsRect r0, r1; - - // There are two rects. That means either a left or right floater. Just use - // whichever space is larger. - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r1.width > r0.width) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } - } - } + // Compute the bounding rect of the available space, i.e. space between any + // left and right floaters + aState.currentBand->ComputeAvailSpaceRect(); aState.spaceManager->Translate(-aState.borderPadding.left, 0); - aState.x = aState.currentBand->trapezoids[0].xTopLeft; + aState.x = aState.currentBand->availSpace.x; } void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) @@ -807,39 +844,22 @@ getBand: // Get a band of available space aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); - if (aState.currentBand->count == 1) { - nsRect rect; + // Scan the trapezoids looking for left and right floaters + nsBandTrapezoid* trapezoid = aState.currentBand->trapezoids; + for (PRInt32 i = 0; i < aState.currentBand->count; i++) { + // XXX Handle multiply occupied + if (nsBandTrapezoid::smOccupied == trapezoid->state) { + nsStyleDisplay* display; - aState.currentBand->trapezoids[0].GetRect(rect); - if (rect.width != aState.availSize.width) { - // Some of the space is taken up by floaters - if (rect.x > 0) { + trapezoid->frame->GetStyleData(kStylePositionSID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { isLeftFloater = PR_TRUE; - } - - if (rect.XMost() < aState.availSize.width) { + } else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { isRightFloater = PR_TRUE; } } - } else if (aState.currentBand->count == 2) { - nsRect r0, r1; - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r0.width > r1.width) { - isRightFloater = PR_TRUE; - } else { - isLeftFloater = PR_TRUE; - - // There may also be a right floater - if (r1.XMost() < aState.availSize.width) { - isRightFloater = PR_TRUE; - } - } - } else { - // Must be both left and right floaters - isLeftFloater = PR_TRUE; - isRightFloater = PR_TRUE; + trapezoid++; } if (isLeftFloater) { @@ -1988,13 +2008,13 @@ void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, nsRect region; aFloater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... diff --git a/mozilla/layout/generic/nsSpaceManager.cpp b/mozilla/layout/generic/nsSpaceManager.cpp index 2906abc65d5..780bedf1d40 100644 --- a/mozilla/layout/generic/nsSpaceManager.cpp +++ b/mozilla/layout/generic/nsSpaceManager.cpp @@ -62,7 +62,8 @@ nscoord SpaceManager::YMost() const } /** - * Internal function that returns the available space within the band + * Internal function that returns the list of available and unavailable space + * within the band * * @param aBand the first rect in the band * @param aIndex aBand's index in the rect array @@ -70,25 +71,24 @@ nscoord SpaceManager::YMost() const * @param aMaxSize the size to use to constrain the band data * @param aAvailableBand */ -PRInt32 SpaceManager::GetBandAvailableSpace(const nsRect* aBand, - PRInt32 aIndex, - nscoord aY, - const nsSize& aMaxSize, - nsBandData& aAvailableSpace) const +PRInt32 SpaceManager::GetBandAvailableSpace(const nsBandRect* aBand, + PRInt32 aIndex, + nscoord aY, + const nsSize& aMaxSize, + nsBandData& aBandData) const { PRInt32 numRects = LengthOfBand(aBand, aIndex); nscoord localY = aY - mY; nscoord height = PR_MIN(aBand->YMost() - aY, aMaxSize.height); - nsBandTrapezoid* trapezoid = aAvailableSpace.trapezoids; + nsBandTrapezoid* trapezoid = aBandData.trapezoids; nscoord rightEdge = mX + aMaxSize.width; // Initialize the band data - aAvailableSpace.count = 0; - trapezoid->xTopLeft = mX; + aBandData.count = 0; // Skip any rectangles that are to the left of the local coordinate space while (numRects > 0) { - if (aBand->XMost() >= mX) { + if (aBand->XMost() > mX) { break; } @@ -97,60 +97,74 @@ PRInt32 SpaceManager::GetBandAvailableSpace(const nsRect* aBand, numRects--; } - // Process all the remaining rectangles that are within the clip width + // 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 ((numRects > 0) && (aBand->x < rightEdge)) { - if (aBand->x > trapezoid->xTopLeft) { - // We found some available space - trapezoid->xTopRight = trapezoid->xBottomRight = aBand->x; - - // Convert from world to local coordinates - trapezoid->xTopLeft -= mX; - trapezoid->xTopRight -= mX; - trapezoid->xBottomLeft = trapezoid->xTopLeft; - trapezoid->xBottomRight = trapezoid->xTopRight; - - trapezoid->yTop = localY; - trapezoid->yBottom = localY + height; + // Compare the left edge of the occupied space with the current left + // coordinate + if (aBand->x > left) { + // The rect is to the right of our current left coordinate, so we've + // found some available space trapezoid->state = nsBandTrapezoid::smAvailable; trapezoid->frame = 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->x - left, height); + // Move to the next output rect trapezoid++; - aAvailableSpace.count++; + aBandData.count++; } - trapezoid->xTopLeft = aBand->XMost(); + // The rect represents unavailable space, so add another trapezoid + trapezoid->state = nsBandTrapezoid::smOccupied; + trapezoid->frame = aBand->frame; - // Move to the next rect in the band + nscoord x = aBand->x; + // 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->XMost() - x, height); + + // Move to the next output rect + trapezoid++; + aBandData.count++; + + // Adjust our current x-location within the band + left = aBand->XMost(); + + // Move to the next rect within the band numRects--; aBand++; } // No more rects left in the band. If we haven't yet reached the right edge, // then all the remaining space is available - if (trapezoid->xTopLeft < rightEdge) { - trapezoid->xTopRight = rightEdge; - - // Convert from world to local coordinates - trapezoid->xTopLeft -= mX; - trapezoid->xTopRight -= mX; - trapezoid->xBottomLeft = trapezoid->xTopLeft; - trapezoid->xBottomRight = trapezoid->xTopRight; - - trapezoid->yTop = localY; - trapezoid->yBottom = localY + height; + if (left < rightEdge) { trapezoid->state = nsBandTrapezoid::smAvailable; trapezoid->frame = nsnull; - aAvailableSpace.count++; + // 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.count++; } - return aAvailableSpace.count; + return aBandData.count; } PRInt32 SpaceManager::GetBandData(nscoord aYOffset, const nsSize& aMaxSize, - nsBandData& aAvailableSpace) const + nsBandData& aBandData) const { // Convert the y-offset to world coordinates nscoord y = mY + aYOffset; @@ -158,35 +172,29 @@ PRInt32 SpaceManager::GetBandData(nscoord aYOffset, // If there are no unavailable rects or the offset is below the bottommost // band then all the space is available if ((0 == mRectArray.mCount) || (y >= mRectArray.YMost())) { - aAvailableSpace.count = 1; - - nsBandTrapezoid& trapezoid = aAvailableSpace.trapezoids[0]; - - trapezoid.xTopLeft = trapezoid.xBottomLeft = 0; - trapezoid.yTop = aYOffset; - trapezoid.xTopRight = trapezoid.xBottomRight = aMaxSize.width; - trapezoid.yBottom = aYOffset + aMaxSize.height; - trapezoid.state = nsBandTrapezoid::smAvailable; - trapezoid.frame = nsnull; + // All the requested space is available + aBandData.count = 1; + aBandData.trapezoids[0] = nsRect(0, aYOffset, aMaxSize.width, aMaxSize.height); + aBandData.trapezoids[0].state = nsBandTrapezoid::smAvailable; + aBandData.trapezoids[0].frame = nsnull; } else { // Find the first band that contains the y-offset or is below the y-offset - nsRect* band = mRectArray.mRects; + nsBandRect* band = mRectArray.mRects; for (PRInt32 i = 0; i < mRectArray.mCount; ) { if (band->y > y) { - // The band is below the y-offset - nsBandTrapezoid& trapezoid = aAvailableSpace.trapezoids[0]; - - trapezoid.xTopLeft = trapezoid.xBottomLeft = 0; - trapezoid.yTop = aYOffset; - trapezoid.xTopRight = trapezoid.xBottomRight = aMaxSize.width; - trapezoid.yBottom = aYOffset + PR_MIN(band->y - y, aMaxSize.height); - trapezoid.state = nsBandTrapezoid::smAvailable; - trapezoid.frame = nsnull; + // The band is below the y-offset. The area between the y-offset and + // the top of the band is available + aBandData.count = 1; + aBandData.trapezoids[0] = + nsRect(0, aYOffset, aMaxSize.width, PR_MIN(band->y - y, aMaxSize.height)); + aBandData.trapezoids[0].state = nsBandTrapezoid::smAvailable; + aBandData.trapezoids[0].frame = nsnull; break; } else if (y < band->YMost()) { - // The band contains the y-offset - return GetBandAvailableSpace(band, i, y, aMaxSize, aAvailableSpace); + // The band contains the y-offset. Return a list of available and + // unavailable rects within the band + return GetBandAvailableSpace(band, i, y, aMaxSize, aBandData); } else { // Skip to the next band GetNextBand(band, i); @@ -194,7 +202,7 @@ PRInt32 SpaceManager::GetBandData(nscoord aYOffset, } } - return aAvailableSpace.count; + return aBandData.count; } /** @@ -207,7 +215,7 @@ PRInt32 SpaceManager::GetBandData(nscoord aYOffset, * next band. If there is no next band then aRect is undefined * and aIndex is set to the number of rects in the rect array */ -PRBool SpaceManager::GetNextBand(nsRect*& aRect, PRInt32& aIndex) const +PRBool SpaceManager::GetNextBand(nsBandRect*& aRect, PRInt32& aIndex) const { nscoord topOfBand = aRect->y; @@ -231,7 +239,7 @@ PRBool SpaceManager::GetNextBand(nsRect*& aRect, PRInt32& aIndex) const * @param aBand the first rect in the band * @param aIndex aBand's index in the rect array */ -PRInt32 SpaceManager::LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const +PRInt32 SpaceManager::LengthOfBand(const nsBandRect* aBand, PRInt32 aIndex) const { nscoord topOfBand = aBand->y; PRInt32 result = 1; @@ -252,36 +260,48 @@ PRInt32 SpaceManager::LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const } /** - * Tries to coalesce horizontally overlapping rectangles within a band + * Tries to coalesce adjoining rectangles within a band. Returns PR_TRUE if any + * of the rects are coalesced and PR_FALSE otherwise * - * @param aRect a rect in the band - * @param aIndex aRect's index in the rect array + * @param aRect the first rect in the band + * @param aIndex aBand's index in the rect array */ -void SpaceManager::CoalesceBand(nsRect* aRect, PRInt32 aIndex) +PRBool SpaceManager::CoalesceBand(nsBandRect* aBand, PRInt32 aIndex) { + PRBool result = PR_FALSE; + while ((aIndex + 1) < mRectArray.mCount) { // Is there another rect in this band? - nsRect* nextRect = aRect + 1; + nsBandRect* nextRect = aBand + 1; - if (nextRect->y == aRect->y) { - // Yes. Do the two rects overlap horizontally? - if (aRect->XMost() > nextRect->x) { - // Yes. Extend the right edge of aRect - aRect->width = nextRect->XMost() - aRect->x; + if (nextRect->y == aBand->y) { + // The rects must not be overlapping + NS_ASSERTION(nextRect->x >= aBand->XMost(), "overlapping rects"); + + // Are the two rects adjoining and have the same tagged frame? + if ((aBand->XMost() == nextRect->x) && (aBand->frame == nextRect->frame)) { + // Yes. Extend the right edge of the current rect + aBand->width = nextRect->XMost() - aBand->x; // Remove the next rect mRectArray.RemoveAt(aIndex + 1); - aRect = mRectArray.mRects + aIndex; // memory may have changed... + aBand = mRectArray.mRects + aIndex; // memory may have changed... + + // Continue through the loop trying to coalesce this rect + result = PR_TRUE; } else { - // No. We're all done - break; + // No. Move to the next rect within the band + aBand++; + aIndex++; } } else { // The next rect is part of a different band, so we're all done break; } } + + return result; } /** @@ -291,7 +311,7 @@ void SpaceManager::CoalesceBand(nsRect* aRect, PRInt32 aIndex) * @param aIndex aBand's index in the rect array * @param aB1Height the height of the new band to create */ -void SpaceManager::DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height) +void SpaceManager::DivideBand(nsBandRect* aBand, PRInt32 aIndex, nscoord aB1Height) { NS_PRECONDITION(aB1Height < aBand->height, "bad height"); @@ -305,7 +325,7 @@ void SpaceManager::DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height) // Insert a new bottom band nsRect r(aBand->x, aBand->y + aB1Height, aBand->width, aB2Height); - mRectArray.InsertAt(r, insertAt); + mRectArray.InsertAt(r, insertAt, aBand->frame); aBand = mRectArray.mRects + aIndex; // memory may have changed... // Adjust the height of the top band @@ -322,62 +342,127 @@ void SpaceManager::DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height) * * @param aBand the first rect in the band * @param aIndex aBand's index in the rect array - * @param aRect the rect to add to the band + * @param aRect the rect to add to the band. It's in world coordinates * @returns PR_TRUE if successful and PR_FALSE if this is the last band */ -void SpaceManager::AddRectToBand(nsRect* aBand, +void SpaceManager::AddRectToBand(nsBandRect* aBand, PRInt32 aIndex, - const nsRect& aRect) + const nsRect& aRect, + nsIFrame* aFrame) { NS_PRECONDITION((aBand->y == aRect.y) && (aBand->height == aRect.height), "bad band"); nscoord topOfBand = aBand->y; + nsRect rect(aRect); - // Figure out where in the band to horizontally insert the rect. Try and - // coalesce it with an existing rect if possible. + // Figure out where in the band horizontally to insert the rect. Try and + // coalesce it with an existing rect if possible. We can only do this if + // they're tagged with the same frame do { // Compare the left edge of the new rect with the left edge of the existing // rect - if (aRect.x <= aBand->x) { - // The new rect's left edge is to the left of the existing rect's left - // edge. Does the new rect overlap the existing rect? - if (aRect.XMost() >= aBand->x) { - // Yes. Extend the existing rect - if (aRect.XMost() > aBand->XMost()) { - aBand->x = aRect.x; - aBand->width = aRect.width; - - // We're extending the right edge of the existing rect which may - // cause the rect to overlap the remaining rects in the band - CoalesceBand(aBand, aIndex); - } else { - aBand->width = aBand->XMost() - aRect.x; - aBand->x = aRect.x; - } - } else { - // No, it's completely to the left of the existing rect. Insert a new - // rect - mRectArray.InsertAt(aRect, aIndex); + if (rect.x < aBand->x) { + // 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 (rect.XMost() <= aBand->x) { + // No, the new rect is completely to the left of the existing rect + // (case #1). Insert a new rect + mRectArray.InsertAt(rect, aIndex, aFrame); + return; } - return; - } else if (aRect.x <= aBand->XMost()) { - // The two rects are overlapping or adjoining. Extend the right edge of - // the existing rect - aBand->width = aRect.XMost() - aBand->x; + // Yes, they overlap. Insert a new rect for the part that's to the left + // of the existing rect + nsRect r1(rect.x, rect.y, aBand->x - rect.x, rect.height); - // Since we extended the right edge of the existing rect it may now - // overlap the remaining rects in the band - CoalesceBand(aBand, aIndex); + mRectArray.InsertAt(r1, aIndex, aFrame); + aIndex++; + aBand = mRectArray.mRects + aIndex; // memory may have changed... + + // Adjust rect to reflect the overlap + rect.width = rect.XMost() - aBand->x; + rect.x = aBand->x; + + } else if (rect.x > aBand->x) { + // 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 (rect.x >= aBand->XMost()) { + // The new rect is to the right of the existing rect (case #4), so move + // to the next rect in the band + aBand++; aIndex++; + 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 + nsRect r1(rect.x, aBand->y, aBand->XMost() - rect.x, aBand->height); + + // Modify the left half of the existing rect + aBand->width = rect.x - aBand->x; + + // Insert the new right half of the existing rect, and make it the current + // rect + aIndex++; + mRectArray.InsertAt(r1, aIndex, aBand->frame); + aBand = mRectArray.mRects + aIndex; // memory may have changed... + } + + // At this point the left edge of the new rect is the same as the left edge + // of the existing rect + NS_ASSERTION(rect.x == aBand->x, "unexpected rect"); + + // Compare which rect is wider, the new rect or the existing rect + if (aBand->width > rect.width) { + // The existing rect is wider (cases 2 and 6). Divide the existing rect + // into two rects: the part that overlaps, and the part to the right of + // the new rect + nsRect r1(rect.XMost(), aBand->y, aBand->XMost() - rect.XMost(), aBand->height); + + // Modify the left half of the existing rect + aBand->width = r1.x - aBand->x; + + // Insert the new right half of the existing rect + mRectArray.InsertAt(r1, aIndex, aBand->frame); + aBand = mRectArray.mRects + aIndex; // memory may have changed... + } + + // XXX Mark the existing rect as being shared by the two frames... + + if (rect.width == aBand->width) { + // We're all done return; } - // Move to the next rect in the band + // The new rect is wider than the existing rect (cases 3 and 5). Set rect + // to be the overhang and move to the next rect within the band + rect.width = rect.XMost() - aBand->XMost(); + rect.x = aBand->XMost(); aBand++; aIndex++; } while ((aIndex < mRectArray.mCount) && (aBand->y == topOfBand)); // Insert a new rect - mRectArray.InsertAt(aRect, aIndex); + mRectArray.InsertAt(aRect, aIndex, aFrame); } // When comparing a rect to a band there are seven cases to consider. @@ -417,12 +502,12 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra // then add a new band if ((0 == mRectArray.mCount) || (rect.y >= mRectArray.YMost())) { // Append a new bottommost band - mRectArray.Append(rect); + mRectArray.Append(rect, aFrame); return; } // Examine each band looking for a band that intersects this rect - nsRect* band = mRectArray.mRects; + nsBandRect* band = mRectArray.mRects; for (PRInt32 i = 0; i < mRectArray.mCount; ) { // Compare the top edge of this rect with the top edge of the band @@ -432,7 +517,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra if (rect.YMost() <= band->y) { // Case #1. This rect is completely above the band, so insert a // new band - mRectArray.InsertAt(rect, i); + mRectArray.InsertAt(rect, i, aFrame); break; // we're all done } @@ -441,7 +526,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra nsRect r1(rect.x, rect.y, rect.width, band->y - rect.y); // Insert r1 as a new band - mRectArray.InsertAt(r1, i); + mRectArray.InsertAt(r1, i, aFrame); i++; band = mRectArray.mRects + i; // memory may have changed... @@ -480,7 +565,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra if (rect.height == band->height) { // Add the rect to the band - AddRectToBand(band, i, rect); + AddRectToBand(band, i, rect, aFrame); break; } else { @@ -489,7 +574,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra nsRect r1(rect.x, rect.y, rect.width, band->YMost() - rect.y); // Add r1 to the band - AddRectToBand(band, i, r1); + AddRectToBand(band, i, r1, aFrame); band = mRectArray.mRects + i; // memory may have changed... // Modify rect to be the part below the band @@ -499,7 +584,7 @@ void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFra // Continue with the next band if (!GetNextBand(band, i)) { // Append a new bottommost band - mRectArray.Append(rect); + mRectArray.Append(rect, aFrame); break; } } @@ -532,29 +617,40 @@ nscoord SpaceManager::RectArray::YMost() const return mRects[mCount - 1].YMost(); } -void SpaceManager::RectArray::Append(const nsRect& aRect) +void SpaceManager::RectArray::Append(const nsRect& aRect, nsIFrame* aFrame) { // Ensure there's enough capacity if (mCount >= mMax) { mMax += 8; - mRects = (nsRect*)realloc(mRects, mMax * sizeof(nsRect)); + mRects = (nsBandRect*)realloc(mRects, mMax * sizeof(nsBandRect)); } - mRects[mCount++] = aRect; + mRects[mCount].x = aRect.x; + mRects[mCount].y = aRect.y; + mRects[mCount].width = aRect.width; + mRects[mCount].height = aRect.height; + mRects[mCount].frame = aFrame; + mCount++; } -void SpaceManager::RectArray::InsertAt(const nsRect& aRect, PRInt32 aIndex) +void SpaceManager::RectArray::InsertAt(const nsRect& aRect, + PRInt32 aIndex, + nsIFrame* aFrame) { NS_PRECONDITION(aIndex <= mCount, "bad index"); // no holes in the array // Ensure there's enough capacity if (mCount >= mMax) { mMax += 8; - mRects = (nsRect*)realloc(mRects, mMax * sizeof(nsRect)); + mRects = (nsBandRect*)realloc(mRects, mMax * sizeof(nsBandRect)); } - memmove(&mRects[aIndex + 1], &mRects[aIndex], (mCount - aIndex) * sizeof(nsRect)); - mRects[aIndex] = aRect; + memmove(&mRects[aIndex + 1], &mRects[aIndex], (mCount - aIndex) * sizeof(nsBandRect)); + mRects[aIndex].x = aRect.x; + mRects[aIndex].y = aRect.y; + mRects[aIndex].width = aRect.width; + mRects[aIndex].height = aRect.height; + mRects[aIndex].frame = aFrame; mCount++; } @@ -564,7 +660,7 @@ void SpaceManager::RectArray::RemoveAt(PRInt32 aIndex) mCount--; if (aIndex < mCount) { - memmove(&mRects[aIndex], &mRects[aIndex + 1], (mCount - aIndex) * sizeof(nsRect)); + memmove(&mRects[aIndex], &mRects[aIndex + 1], (mCount - aIndex) * sizeof(nsBandRect)); } } diff --git a/mozilla/layout/generic/nsSpaceManager.h b/mozilla/layout/generic/nsSpaceManager.h index fe0d3f789b7..0c01d5a5dcf 100644 --- a/mozilla/layout/generic/nsSpaceManager.h +++ b/mozilla/layout/generic/nsSpaceManager.h @@ -38,19 +38,23 @@ public: virtual nscoord YMost() const; virtual PRInt32 GetBandData(nscoord aYOffset, const nsSize& aMaxSize, - nsBandData& aAvailableSpace) const; + nsBandData& aBandData) const; virtual void AddRectRegion(const nsRect& aUnavailableSpace, nsIFrame* aFrame); virtual void ClearRegions(); protected: + struct nsBandRect : nsRect { + nsIFrame* frame; + }; + class RectArray { public: RectArray(); ~RectArray(); // Functions to add rects - void Append(const nsRect& aRect); - void InsertAt(const nsRect& aRect, PRInt32 aIndex); + void Append(const nsRect& aRect, nsIFrame* aFrame); + void InsertAt(const nsRect& aRect, PRInt32 aIndex, nsIFrame* aFrame); void RemoveAt(PRInt32 aIndex); // Clear the list of rectangles @@ -61,9 +65,9 @@ protected: public: // Access to the underlying storage - nsRect* mRects; // y-x banded array of rectangles of unavailable space - PRInt32 mCount; // current number of rects - PRInt32 mMax; // capacity of rect array + nsBandRect* mRects; // y-x banded array of rectangles of unavailable space + PRInt32 mCount; // current number of rects + PRInt32 mMax; // capacity of rect array }; nsIFrame* const mFrame; // frame associated with the space manager @@ -71,16 +75,17 @@ protected: RectArray mRectArray; // y-x banded array of rectangles of unavailable space protected: - PRBool GetNextBand(nsRect*& aRect, PRInt32& aIndex) const; - PRInt32 LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const; - void CoalesceBand(nsRect* aBand, PRInt32 aIndex); - void DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height); - void AddRectToBand(nsRect* aBand, PRInt32 aIndex, const nsRect& aRect); - PRInt32 GetBandAvailableSpace(const nsRect* aBand, - PRInt32 aIndex, - nscoord aY, - const nsSize& aMaxSize, - nsBandData& aAvailableSpace) const; + PRBool GetNextBand(nsBandRect*& aRect, PRInt32& aIndex) const; + PRInt32 LengthOfBand(const nsBandRect* aBand, PRInt32 aIndex) const; + PRBool CoalesceBand(nsBandRect* aBand, PRInt32 aIndex); + void DivideBand(nsBandRect* aBand, PRInt32 aIndex, nscoord aB1Height); + void AddRectToBand(nsBandRect* aBand, PRInt32 aIndex, + const nsRect& aRect, nsIFrame* aFrame); + PRInt32 GetBandAvailableSpace(const nsBandRect* aBand, + PRInt32 aIndex, + nscoord aY, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const; private: SpaceManager(const SpaceManager&); // no implementation diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index 2764b8d626a..6b45fe72cab 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -59,11 +59,68 @@ NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIContent); struct BlockBandData : public nsBandData { - nsBandTrapezoid data[5]; + nsBandTrapezoid data[12]; - BlockBandData() {size = 5; trapezoids = data;} + // Bounding rect of available space between any left and right floaters + nsRect availSpace; + + // Constructor + BlockBandData() {size = 12; trapezoids = data;} + + // Computes the bounding rect of the available space, i.e. space between + // any left and right floaters + // + // Uses the current trapezoid data, see nsISpaceManager::GetBandData(). + // Updates member data "availSpace" + void ComputeAvailSpaceRect(); }; +void BlockBandData::ComputeAvailSpaceRect() +{ + nsBandTrapezoid* trapezoid = data; + + if (count > 1) { + // If there's more than one trapezoid that means there are floaters + PRInt32 i; + + // Stop when we get to space occupied by a right floater + for (i = 0; i < count; i++) { + nsBandTrapezoid* trapezoid = &data[i]; + + if (trapezoid->state != nsBandTrapezoid::smAvailable) { + nsStyleDisplay* display; + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { + break; + } + } + } + + if (i > 0) { + trapezoid = &data[i - 1]; + } + } + + if (nsBandTrapezoid::smAvailable == trapezoid->state) { + // The trapezoid is available + trapezoid->GetRect(availSpace); + } else { + nsStyleDisplay* display; + + // The trapezoid is occupied. That means there's no available space + trapezoid->GetRect(availSpace); + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { + availSpace.x = availSpace.XMost(); + } + availSpace.width = 0; + } +} + // XXX Bugs // 1. right to left reflow can generate negative x coordinates. @@ -366,13 +423,13 @@ void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, styleContext->GetData(kStyleDisplaySID); floater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... @@ -682,9 +739,9 @@ void nsBlockFrame::GetAvailSize(nsSize& aResult, aResult.width = NS_UNCONSTRAINEDSIZE; } else if (aIsInline) { if (NS_STYLE_DIRECTION_LTR == aState.styleDisplay->mDirection) { - aResult.width = aState.currentBand->trapezoids[0].xTopRight - aState.x; + aResult.width = aState.currentBand->availSpace.XMost() - aState.x; } else { - aResult.width = aState.x - aState.currentBand->trapezoids[0].xTopLeft; + aResult.width = aState.x - aState.currentBand->availSpace.x; } } else { // It's a block. Don't adjust for the left/right margin here. That happens @@ -767,31 +824,11 @@ void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) aState.spaceManager->Translate(aState.borderPadding.left, 0); aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); - // XXX This is hack code that needs to change when the space manager interface - // changes to return both the available and unavailable space - // - // We'll get back anywhere between 1 and 3 rects depending on how many floaters - // there are. Actually the way it currently works we could get back zero rects - // if there are overlapping left and right floaters occupying all the space - if (aState.currentBand->count > 1) { - // If there are three rects then let's assume that there are floaters on the - // left and right and that only the middle rect is available - if (aState.currentBand->count == 3) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } else { - nsRect r0, r1; - - // There are two rects. That means either a left or right floater. Just use - // whichever space is larger. - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r1.width > r0.width) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } - } - } + // Compute the bounding rect of the available space, i.e. space between any + // left and right floaters + aState.currentBand->ComputeAvailSpaceRect(); aState.spaceManager->Translate(-aState.borderPadding.left, 0); - aState.x = aState.currentBand->trapezoids[0].xTopLeft; + aState.x = aState.currentBand->availSpace.x; } void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) @@ -807,39 +844,22 @@ getBand: // Get a band of available space aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); - if (aState.currentBand->count == 1) { - nsRect rect; + // Scan the trapezoids looking for left and right floaters + nsBandTrapezoid* trapezoid = aState.currentBand->trapezoids; + for (PRInt32 i = 0; i < aState.currentBand->count; i++) { + // XXX Handle multiply occupied + if (nsBandTrapezoid::smOccupied == trapezoid->state) { + nsStyleDisplay* display; - aState.currentBand->trapezoids[0].GetRect(rect); - if (rect.width != aState.availSize.width) { - // Some of the space is taken up by floaters - if (rect.x > 0) { + trapezoid->frame->GetStyleData(kStylePositionSID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { isLeftFloater = PR_TRUE; - } - - if (rect.XMost() < aState.availSize.width) { + } else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { isRightFloater = PR_TRUE; } } - } else if (aState.currentBand->count == 2) { - nsRect r0, r1; - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r0.width > r1.width) { - isRightFloater = PR_TRUE; - } else { - isLeftFloater = PR_TRUE; - - // There may also be a right floater - if (r1.XMost() < aState.availSize.width) { - isRightFloater = PR_TRUE; - } - } - } else { - // Must be both left and right floaters - isLeftFloater = PR_TRUE; - isRightFloater = PR_TRUE; + trapezoid++; } if (isLeftFloater) { @@ -1988,13 +2008,13 @@ void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, nsRect region; aFloater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index 2764b8d626a..6b45fe72cab 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -59,11 +59,68 @@ NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIContent); struct BlockBandData : public nsBandData { - nsBandTrapezoid data[5]; + nsBandTrapezoid data[12]; - BlockBandData() {size = 5; trapezoids = data;} + // Bounding rect of available space between any left and right floaters + nsRect availSpace; + + // Constructor + BlockBandData() {size = 12; trapezoids = data;} + + // Computes the bounding rect of the available space, i.e. space between + // any left and right floaters + // + // Uses the current trapezoid data, see nsISpaceManager::GetBandData(). + // Updates member data "availSpace" + void ComputeAvailSpaceRect(); }; +void BlockBandData::ComputeAvailSpaceRect() +{ + nsBandTrapezoid* trapezoid = data; + + if (count > 1) { + // If there's more than one trapezoid that means there are floaters + PRInt32 i; + + // Stop when we get to space occupied by a right floater + for (i = 0; i < count; i++) { + nsBandTrapezoid* trapezoid = &data[i]; + + if (trapezoid->state != nsBandTrapezoid::smAvailable) { + nsStyleDisplay* display; + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { + break; + } + } + } + + if (i > 0) { + trapezoid = &data[i - 1]; + } + } + + if (nsBandTrapezoid::smAvailable == trapezoid->state) { + // The trapezoid is available + trapezoid->GetRect(availSpace); + } else { + nsStyleDisplay* display; + + // The trapezoid is occupied. That means there's no available space + trapezoid->GetRect(availSpace); + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { + availSpace.x = availSpace.XMost(); + } + availSpace.width = 0; + } +} + // XXX Bugs // 1. right to left reflow can generate negative x coordinates. @@ -366,13 +423,13 @@ void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, styleContext->GetData(kStyleDisplaySID); floater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... @@ -682,9 +739,9 @@ void nsBlockFrame::GetAvailSize(nsSize& aResult, aResult.width = NS_UNCONSTRAINEDSIZE; } else if (aIsInline) { if (NS_STYLE_DIRECTION_LTR == aState.styleDisplay->mDirection) { - aResult.width = aState.currentBand->trapezoids[0].xTopRight - aState.x; + aResult.width = aState.currentBand->availSpace.XMost() - aState.x; } else { - aResult.width = aState.x - aState.currentBand->trapezoids[0].xTopLeft; + aResult.width = aState.x - aState.currentBand->availSpace.x; } } else { // It's a block. Don't adjust for the left/right margin here. That happens @@ -767,31 +824,11 @@ void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) aState.spaceManager->Translate(aState.borderPadding.left, 0); aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); - // XXX This is hack code that needs to change when the space manager interface - // changes to return both the available and unavailable space - // - // We'll get back anywhere between 1 and 3 rects depending on how many floaters - // there are. Actually the way it currently works we could get back zero rects - // if there are overlapping left and right floaters occupying all the space - if (aState.currentBand->count > 1) { - // If there are three rects then let's assume that there are floaters on the - // left and right and that only the middle rect is available - if (aState.currentBand->count == 3) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } else { - nsRect r0, r1; - - // There are two rects. That means either a left or right floater. Just use - // whichever space is larger. - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r1.width > r0.width) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } - } - } + // Compute the bounding rect of the available space, i.e. space between any + // left and right floaters + aState.currentBand->ComputeAvailSpaceRect(); aState.spaceManager->Translate(-aState.borderPadding.left, 0); - aState.x = aState.currentBand->trapezoids[0].xTopLeft; + aState.x = aState.currentBand->availSpace.x; } void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) @@ -807,39 +844,22 @@ getBand: // Get a band of available space aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); - if (aState.currentBand->count == 1) { - nsRect rect; + // Scan the trapezoids looking for left and right floaters + nsBandTrapezoid* trapezoid = aState.currentBand->trapezoids; + for (PRInt32 i = 0; i < aState.currentBand->count; i++) { + // XXX Handle multiply occupied + if (nsBandTrapezoid::smOccupied == trapezoid->state) { + nsStyleDisplay* display; - aState.currentBand->trapezoids[0].GetRect(rect); - if (rect.width != aState.availSize.width) { - // Some of the space is taken up by floaters - if (rect.x > 0) { + trapezoid->frame->GetStyleData(kStylePositionSID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { isLeftFloater = PR_TRUE; - } - - if (rect.XMost() < aState.availSize.width) { + } else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { isRightFloater = PR_TRUE; } } - } else if (aState.currentBand->count == 2) { - nsRect r0, r1; - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r0.width > r1.width) { - isRightFloater = PR_TRUE; - } else { - isLeftFloater = PR_TRUE; - - // There may also be a right floater - if (r1.XMost() < aState.availSize.width) { - isRightFloater = PR_TRUE; - } - } - } else { - // Must be both left and right floaters - isLeftFloater = PR_TRUE; - isRightFloater = PR_TRUE; + trapezoid++; } if (isLeftFloater) { @@ -1988,13 +2008,13 @@ void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, nsRect region; aFloater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index 2764b8d626a..6b45fe72cab 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -59,11 +59,68 @@ NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIContent); struct BlockBandData : public nsBandData { - nsBandTrapezoid data[5]; + nsBandTrapezoid data[12]; - BlockBandData() {size = 5; trapezoids = data;} + // Bounding rect of available space between any left and right floaters + nsRect availSpace; + + // Constructor + BlockBandData() {size = 12; trapezoids = data;} + + // Computes the bounding rect of the available space, i.e. space between + // any left and right floaters + // + // Uses the current trapezoid data, see nsISpaceManager::GetBandData(). + // Updates member data "availSpace" + void ComputeAvailSpaceRect(); }; +void BlockBandData::ComputeAvailSpaceRect() +{ + nsBandTrapezoid* trapezoid = data; + + if (count > 1) { + // If there's more than one trapezoid that means there are floaters + PRInt32 i; + + // Stop when we get to space occupied by a right floater + for (i = 0; i < count; i++) { + nsBandTrapezoid* trapezoid = &data[i]; + + if (trapezoid->state != nsBandTrapezoid::smAvailable) { + nsStyleDisplay* display; + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { + break; + } + } + } + + if (i > 0) { + trapezoid = &data[i - 1]; + } + } + + if (nsBandTrapezoid::smAvailable == trapezoid->state) { + // The trapezoid is available + trapezoid->GetRect(availSpace); + } else { + nsStyleDisplay* display; + + // The trapezoid is occupied. That means there's no available space + trapezoid->GetRect(availSpace); + + // XXX Handle the case of multiple frames + trapezoid->frame->GetStyleData(kStyleDisplaySID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { + availSpace.x = availSpace.XMost(); + } + availSpace.width = 0; + } +} + // XXX Bugs // 1. right to left reflow can generate negative x coordinates. @@ -366,13 +423,13 @@ void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, styleContext->GetData(kStyleDisplaySID); floater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins... @@ -682,9 +739,9 @@ void nsBlockFrame::GetAvailSize(nsSize& aResult, aResult.width = NS_UNCONSTRAINEDSIZE; } else if (aIsInline) { if (NS_STYLE_DIRECTION_LTR == aState.styleDisplay->mDirection) { - aResult.width = aState.currentBand->trapezoids[0].xTopRight - aState.x; + aResult.width = aState.currentBand->availSpace.XMost() - aState.x; } else { - aResult.width = aState.x - aState.currentBand->trapezoids[0].xTopLeft; + aResult.width = aState.x - aState.currentBand->availSpace.x; } } else { // It's a block. Don't adjust for the left/right margin here. That happens @@ -767,31 +824,11 @@ void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) aState.spaceManager->Translate(aState.borderPadding.left, 0); aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); - // XXX This is hack code that needs to change when the space manager interface - // changes to return both the available and unavailable space - // - // We'll get back anywhere between 1 and 3 rects depending on how many floaters - // there are. Actually the way it currently works we could get back zero rects - // if there are overlapping left and right floaters occupying all the space - if (aState.currentBand->count > 1) { - // If there are three rects then let's assume that there are floaters on the - // left and right and that only the middle rect is available - if (aState.currentBand->count == 3) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } else { - nsRect r0, r1; - - // There are two rects. That means either a left or right floater. Just use - // whichever space is larger. - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r1.width > r0.width) { - aState.currentBand->trapezoids[0] = aState.currentBand->trapezoids[1]; - } - } - } + // Compute the bounding rect of the available space, i.e. space between any + // left and right floaters + aState.currentBand->ComputeAvailSpaceRect(); aState.spaceManager->Translate(-aState.borderPadding.left, 0); - aState.x = aState.currentBand->trapezoids[0].xTopLeft; + aState.x = aState.currentBand->availSpace.x; } void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) @@ -807,39 +844,22 @@ getBand: // Get a band of available space aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); - if (aState.currentBand->count == 1) { - nsRect rect; + // Scan the trapezoids looking for left and right floaters + nsBandTrapezoid* trapezoid = aState.currentBand->trapezoids; + for (PRInt32 i = 0; i < aState.currentBand->count; i++) { + // XXX Handle multiply occupied + if (nsBandTrapezoid::smOccupied == trapezoid->state) { + nsStyleDisplay* display; - aState.currentBand->trapezoids[0].GetRect(rect); - if (rect.width != aState.availSize.width) { - // Some of the space is taken up by floaters - if (rect.x > 0) { + trapezoid->frame->GetStyleData(kStylePositionSID, (nsStyleStruct*&)display); + if (NS_STYLE_FLOAT_LEFT == display->mFloats) { isLeftFloater = PR_TRUE; - } - - if (rect.XMost() < aState.availSize.width) { + } else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { isRightFloater = PR_TRUE; } } - } else if (aState.currentBand->count == 2) { - nsRect r0, r1; - aState.currentBand->trapezoids[0].GetRect(r0); - aState.currentBand->trapezoids[1].GetRect(r1); - if (r0.width > r1.width) { - isRightFloater = PR_TRUE; - } else { - isLeftFloater = PR_TRUE; - - // There may also be a right floater - if (r1.XMost() < aState.availSize.width) { - isRightFloater = PR_TRUE; - } - } - } else { - // Must be both left and right floaters - isLeftFloater = PR_TRUE; - isRightFloater = PR_TRUE; + trapezoid++; } if (isLeftFloater) { @@ -1988,13 +2008,13 @@ void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, nsRect region; aFloater->GetRect(region); - region.y = mCurrentState->currentBand->trapezoids[0].yTop; + region.y = mCurrentState->currentBand->availSpace.y; if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = mCurrentState->currentBand->trapezoids[0].xTopLeft; + region.x = mCurrentState->currentBand->availSpace.x; } else { NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, "bad float type"); - region.x = mCurrentState->currentBand->trapezoids[0].xTopRight - region.width; + region.x = mCurrentState->currentBand->availSpace.XMost() - region.width; } // XXX Don't forget the floater's margins...