Replace space manager with a more limited float manager. (Bug 191448) r+sr=roc

--HG--
rename : layout/generic/nsSpaceManager.cpp => layout/generic/nsFloatManager.cpp
rename : layout/generic/nsSpaceManager.h => layout/generic/nsFloatManager.h
This commit is contained in:
L. David Baron 2009-01-04 19:39:54 -05:00
Родитель 7d25fc9316
Коммит dbe76c825c
18 изменённых файлов: 757 добавлений и 2400 удалений

Просмотреть файл

@ -67,7 +67,7 @@
#include "nsNodeInfo.h"
#include "nsRange.h"
#include "nsRepeatService.h"
#include "nsSpaceManager.h"
#include "nsFloatManager.h"
#include "nsSprocketLayout.h"
#include "nsStackLayout.h"
#include "nsStyleSet.h"

Просмотреть файл

@ -113,7 +113,6 @@ endif
CPPSRCS = \
nsAbsoluteContainingBlock.cpp \
nsBRFrame.cpp \
nsBlockBandData.cpp \
nsBlockFrame.cpp \
nsBlockReflowContext.cpp \
nsBlockReflowState.cpp \
@ -121,6 +120,7 @@ CPPSRCS = \
nsColumnSetFrame.cpp \
nsContainerFrame.cpp \
nsFirstLetterFrame.cpp \
nsFloatManager.cpp \
nsFrame.cpp \
nsFrameFrame.cpp \
nsFrameList.cpp \
@ -144,7 +144,6 @@ CPPSRCS = \
nsPlaceholderFrame.cpp \
nsSelection.cpp \
nsSimplePageSequence.cpp \
nsSpaceManager.cpp \
nsSpacerFrame.cpp \
nsSplittableFrame.cpp \
nsTextFrameThebes.cpp \

Просмотреть файл

@ -1,270 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* code for management of floats that implements float manager interfaces */
#include "nsCOMPtr.h"
#include "nsBlockBandData.h"
#include "nsIFrame.h"
#include "nsHTMLReflowState.h"
#include "nsPresContext.h"
#include "nsIPresShell.h"
nsBlockBandData::nsBlockBandData()
: mSpaceManager(nsnull),
mSpaceManagerX(0),
mSpaceManagerY(0),
mSpace(0, 0)
{
mSize = NS_BLOCK_BAND_DATA_TRAPS;
mTrapezoids = mData;
}
nsBlockBandData::~nsBlockBandData()
{
if (mTrapezoids != mData) {
delete [] mTrapezoids;
}
}
nsresult
nsBlockBandData::Init(nsSpaceManager* aSpaceManager,
const nsSize& aSpace)
{
NS_PRECONDITION(aSpaceManager, "null pointer");
mSpaceManager = aSpaceManager;
aSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY);
mSpace = aSpace;
mLeftFloats = 0;
mRightFloats = 0;
return NS_OK;
}
// Get the available reflow space for the current y coordinate. The
// available space is relative to our coordinate system (0,0) is our
// upper left corner.
nsresult
nsBlockBandData::GetAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint,
nsRect& aResult)
{
// Get the raw band data for the given Y coordinate
nsresult rv = GetBandData(aY, aRelaxHeightConstraint);
if (NS_FAILED(rv)) { return rv; }
// Compute the bounding rect of the available space, i.e. space
// between any left and right floats.
ComputeAvailSpaceRect();
aResult = mAvailSpace;
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
printf("nsBBD %p GetAvailableSpace(%d) returning (%d, %d, %d, %d)\n",
this, aY, aResult.x, aResult.y, aResult.width, aResult.height);
#endif
return NS_OK;
}
// the code below should never loop more than a very few times.
// this is a safety valve to see if we've gone off the deep end
#define ERROR_TOO_MANY_ITERATIONS 1000
/* nsBlockBandData methods should never call mSpaceManager->GetBandData directly.
* They should always call nsBlockBandData::GetBandData() instead.
*/
nsresult
nsBlockBandData::GetBandData(nscoord aY, PRBool aRelaxHeightConstraint)
{
NS_ASSERTION(mSpaceManager, "bad state, no float manager");
PRInt32 iterations =0;
nsSize space = mSpace;
if (aRelaxHeightConstraint) {
space.height = NS_UNCONSTRAINEDSIZE;
}
nsresult rv = mSpaceManager->GetBandData(aY, space, *this);
while (NS_FAILED(rv)) {
iterations++;
if (iterations>ERROR_TOO_MANY_ITERATIONS)
{
NS_ASSERTION(PR_FALSE, "too many iterations in nsBlockBandData::GetBandData");
return NS_ERROR_FAILURE;
}
// We need more space for our bands
NS_ASSERTION(mTrapezoids, "bad state, no mTrapezoids");
if (mTrapezoids && (mTrapezoids != mData)) {
delete [] mTrapezoids;
}
PRInt32 newSize = mSize * 2;
if (newSize<mCount) {
newSize = mCount;
}
mTrapezoids = new nsBandTrapezoid[newSize];
NS_POSTCONDITION(mTrapezoids, "failure allocating mTrapezoids");
if (!mTrapezoids) {
return NS_ERROR_OUT_OF_MEMORY;
}
mSize = newSize;
rv = mSpaceManager->GetBandData(aY, space, *this);
}
NS_POSTCONDITION(mCount<=mSize, "bad state, count > size");
return NS_OK;
}
/**
* Computes the bounding rect of the available space, i.e. space
* between any left and right floats. Uses the current trapezoid
* data, see nsISpaceManager::GetBandData(). Also updates member
* data "availSpace".
*/
void
nsBlockBandData::ComputeAvailSpaceRect()
{
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
printf("nsBlockBandData::ComputeAvailSpaceRect %p with count %d\n", this, mCount);
#endif
if (0 == mCount) {
mAvailSpace.x = 0;
mAvailSpace.y = 0;
mAvailSpace.width = 0;
mAvailSpace.height = 0;
mLeftFloats = 0;
mRightFloats = 0;
return;
}
nsBandTrapezoid* trapezoid = mTrapezoids;
// The trapezoid to the left of the first right-floated trapezoid.
nsBandTrapezoid* rightTrapezoid = nsnull;
PRInt32 leftFloats = 0;
PRInt32 rightFloats = 0;
if (mCount > 1) {
// If there's more than one trapezoid that means there are floats
PRInt32 i;
// Examine each trapezoid in the band, counting up the number of
// left and right floats. Use the right-most float to
// determine where the right edge of the available space is.
NS_PRECONDITION(mCount<=mSize, "bad state, count > size");
for (i = 0; i < mCount; i++) {
trapezoid = &mTrapezoids[i];
if (trapezoid->mFrames) {
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
printf("band %p checking !Avail trap %p with frame %p\n", this, trapezoid, trapezoid->mFrames);
#endif
const nsSmallVoidArray* frames = trapezoid->mFrames;
const PRInt32 numFrames = frames->Count();
NS_ASSERTION(numFrames > 0, "bad trapezoid frame list");
for (PRInt32 j = 0; j < numFrames; j++) {
nsIFrame* f = static_cast<nsIFrame*>(frames->ElementAt(j));
const nsStyleDisplay* display = f->GetStyleDisplay();
if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
leftFloats++;
}
else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) {
rightFloats++;
if ((nsnull == rightTrapezoid) && (i > 0)) {
rightTrapezoid = &mTrapezoids[i - 1];
}
}
}
}
}
}
else if (mTrapezoids[0].mFrames) {
// We have a float using up all the available space
leftFloats = 1;
}
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
printf("band %p has floats %d, %d\n", this, leftFloats, rightFloats);
#endif
mLeftFloats = leftFloats;
mRightFloats = rightFloats;
// We look for available space in the last trapezoid before the
// first right float, or in the last trapezoid if there is no right
// float or no trapezoid before the first right float.
if (nsnull != rightTrapezoid) {
trapezoid = rightTrapezoid;
}
trapezoid->GetRect(mAvailSpace);
// When there is no available space, we still need a proper X
// coordinate to place objects that end up here anyway.
const nsSmallVoidArray* frames = trapezoid->mFrames;
if (frames) {
// It's not clear what coordinate to use when there is no
// available space and the space is multiply occupied...So: If
// any of the floats that are a part of the trapezoid are left
// floats then we move over to the right edge of the
// unavaliable space.
const PRInt32 numFrames = frames->Count();
NS_ASSERTION(numFrames > 0, "bad trapezoid frame list");
for (PRInt32 j = 0; j < numFrames; j++) {
nsIFrame* f = static_cast<nsIFrame*>(frames->ElementAt(j));
const nsStyleDisplay* display = f->GetStyleDisplay();
if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
mAvailSpace.x = mAvailSpace.XMost();
break;
}
}
mAvailSpace.width = 0;
}
// Fixup width
if (NS_UNCONSTRAINEDSIZE == mSpace.width) {
mAvailSpace.width = NS_UNCONSTRAINEDSIZE;
}
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
printf(" ComputeAvailSpaceRect settting state mAvailSpace (%d,%d,%d,%d)\n",
mAvailSpace.x, mAvailSpace.y, mAvailSpace.width, mAvailSpace.height);
#endif
}
#ifdef DEBUG
void nsBlockBandData::List()
{
printf("nsBlockBandData %p sm=%p, sm coord = (%d,%d), mSpace = (%d,%d)\n",
this, mSpaceManager, mSpaceManagerX, mSpaceManagerY,
mSpace.width, mSpace.height);
printf(" availSpace=(%d, %d, %d, %d), floats l=%d r=%d\n",
mAvailSpace.x, mAvailSpace.y, mAvailSpace.width, mAvailSpace.height,
mLeftFloats, mRightFloats);
}
#endif

Просмотреть файл

@ -1,126 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* code for management of floats that implements float manager interfaces */
#ifndef nsBlockBandData_h___
#define nsBlockBandData_h___
#include "nsSpaceManager.h"
class nsPresContext;
// Number of builtin nsBandTrapezoid's
#define NS_BLOCK_BAND_DATA_TRAPS 6
/**
* Class used to manage processing of the space-manager band data.
* Provides HTML/CSS specific behavior to the raw data.
*/
class nsBlockBandData : public nsBandData {
public:
nsBlockBandData();
~nsBlockBandData();
// Initialize. This must be called before any of the other methods.
nsresult Init(nsSpaceManager* aSpaceManager, const nsSize& aSpace);
// Get some available space. Note that aY is relative to the current
// float manager translation.
nsresult GetAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint,
nsRect& aResult);
// Get the raw trapezoid count for this band.
PRInt32 GetTrapezoidCount() const {
return mCount;
}
const nsBandTrapezoid* GetTrapezoid(PRInt32 aIndex) const {
return &mTrapezoids[aIndex];
}
// Get the number of floats that are impacting the current
// band. Note that this value is relative to the current translation
// in the float manager which means that some floats may be hidden
// by the translation and therefore won't be in the count.
PRInt32 GetFloatCount() const {
return mLeftFloats + mRightFloats;
}
PRInt32 GetLeftFloatCount() const {
return mLeftFloats;
}
PRInt32 GetRightFloatCount() const {
return mRightFloats;
}
#ifdef DEBUG
void List();
#endif
protected:
/** utility method to calculate the band data at aY.
* nsBlockBandData methods should never call
* mSpaceManager->GetBandData directly.
* They should always call this method instead so data members
* mTrapezoid, mCount, and mSize all get managed properly.
*/
nsresult GetBandData(nscoord aY, PRBool aRelaxHeightConstraint);
// The spacemanager we are getting space from
nsSpaceManager* mSpaceManager;
nscoord mSpaceManagerX, mSpaceManagerY;
// Limit to the available space (set by Init)
nsSize mSpace;
// Trapezoids used during band processing
nsBandTrapezoid mData[NS_BLOCK_BAND_DATA_TRAPS];
// Bounding rect of available space between any left and right floats
nsRect mAvailSpace;
// Number of left/right floats in the current band. Note that this
// number may be less than the total number of floats present in
// the band, if our translation in the float manager "hides" some
// floats.
PRInt32 mLeftFloats, mRightFloats;
void ComputeAvailSpaceRect();
};
#endif /* nsBlockBandData_h___ */

Просмотреть файл

@ -51,7 +51,7 @@
#undef NOISY_VERTICAL_MARGINS
#undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested
#undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete"
#undef NOISY_FLOATMANAGER // enables debug output for float manager use, useful for analysing reflow of floats and positioned elements
#undef NOISY_FLOATMANAGER // enables debug output for float manager use, useful for analysing reflow of floats
#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate
#undef REALLY_NOISY_REFLOW // some extra debug info

Просмотреть файл

@ -50,7 +50,6 @@
#include "nsBlockFrame.h"
#include "nsBlockReflowContext.h"
#include "nsBlockReflowState.h"
#include "nsBlockBandData.h"
#include "nsBulletFrame.h"
#include "nsLineBox.h"
#include "nsInlineFrame.h"
@ -70,7 +69,7 @@
#include "prprf.h"
#include "nsStyleChangeList.h"
#include "nsFrameSelection.h"
#include "nsSpaceManager.h"
#include "nsFloatManager.h"
#include "nsIntervalSet.h"
#include "prenv.h"
#include "plstr.h"

Просмотреть файл

@ -41,7 +41,7 @@
#include "nsBlockReflowContext.h"
#include "nsLineLayout.h"
#include "nsSpaceManager.h"
#include "nsFloatManager.h"
#include "nsIFontMetrics.h"
#include "nsPresContext.h"
#include "nsFrameManager.h"

Просмотреть файл

@ -134,7 +134,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
}
mY = borderPadding.top;
mBand.Init(mFloatManager, mContentArea);
mPrevChild = nsnull;
mCurrentLine = aFrame->end_lines();
@ -257,8 +256,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
nsRect& aResult)
{
#ifdef REALLY_NOISY_REFLOW
printf("CBAS frame=%p has float count %d\n", aFrame, mBand.GetFloatCount());
mBand.List();
printf("CBAS frame=%p has floats %d\n", aFrame, mBandHasFloats);
#endif
aResult.y = mY;
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
@ -286,7 +284,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
!aBlockAvoidsFloats,
"unexpected replaced width");
if (!aBlockAvoidsFloats) {
if (mBand.GetFloatCount()) {
if (mBandHasFloats) {
// Use the float-edge property to determine how the child block
// will interact with the float.
const nsStyleBorder* borderStyle = aFrame->GetStyleBorder();
@ -347,16 +345,22 @@ nsBlockReflowState::GetAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint)
"bad coord system");
#endif
mBand.GetAvailableSpace(aY - BorderPadding().top, aRelaxHeightConstraint,
mAvailSpaceRect);
PRBool hasFloats;
mAvailSpaceRect =
mFloatManager->GetBand(aY - BorderPadding().top,
aRelaxHeightConstraint ? nscoord_MAX
: mContentArea.height,
mContentArea.width,
&hasFloats);
mBandHasFloats = hasFloats;
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n",
printf("GetAvailableSpace: band=%d,%d,%d,%d hasfloats=%d\n",
mAvailSpaceRect.x, mAvailSpaceRect.y,
mAvailSpaceRect.width, mAvailSpaceRect.height,
mBand.GetTrapezoidCount());
mBandHasFloats);
}
#endif
}
@ -439,7 +443,7 @@ nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine,
fc->mRegion.width, fc->mRegion.height);
}
#endif
mFloatManager->AddRectRegion(floatFrame, fc->mRegion);
mFloatManager->AddFloat(floatFrame, fc->mRegion);
fc = fc->Next();
}
} else if (aLine->IsBlock()) {
@ -522,9 +526,9 @@ nsBlockReflowState::IsImpactedByFloat() const
{
#ifdef REALLY_NOISY_REFLOW
printf("nsBlockReflowState::IsImpactedByFloat %p returned %d\n",
this, mBand.GetFloatCount());
this, mBandHasFloats);
#endif
return mBand.GetFloatCount() > 0;
return mBandHasFloats;
}
@ -659,7 +663,7 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
// If the current Y coordinate is not impacted by any floats
// then by definition the float fits.
PRBool result = PR_TRUE;
if (0 != mBand.GetFloatCount()) {
if (mBandHasFloats) {
// XXX We should allow overflow by up to half a pixel here (bug 21193).
if (mAvailSpaceRect.width < aFloatSize.width) {
// The available width is too narrow (and its been impacted by a
@ -725,7 +729,7 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
mY += mAvailSpaceRect.height;
GetAvailableSpace(mY, aForceFit);
if (0 != mBand.GetFloatCount()) {
if (mBandHasFloats) {
if ((xa < mAvailSpaceRect.x) || (xb > mAvailSpaceRect.XMost())) {
// The float can't go here.
result = PR_FALSE;
@ -775,7 +779,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
// Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
// ``above'' another float that preceded it in the flow.
mY = NS_MAX(mFloatManager->GetLowestRegionTop() + BorderPadding().top, mY);
mY = NS_MAX(mFloatManager->GetLowestFloatTop() + BorderPadding().top, mY);
// See if the float should clear any preceding floats...
// XXX We need to mark this float somehow so that it gets reflowed
@ -944,7 +948,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
#ifdef DEBUG
nsresult rv =
#endif
mFloatManager->AddRectRegion(floatFrame, region);
mFloatManager->AddFloat(floatFrame, region);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad float placement");
// Save away the floats region in the spacemanager, after making
@ -973,7 +977,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
nscoord tx, ty;
mFloatManager->GetTranslation(tx, ty);
nsFrame::ListTag(stdout, mBlock);
printf(": FlowAndPlaceFloat: AddRectRegion: txy=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
printf(": FlowAndPlaceFloat: AddFloat: txy=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
tx, ty, mFloatManagerX, mFloatManagerY,
aFloatCache->mRegion.x, aFloatCache->mRegion.y,
aFloatCache->mRegion.width, aFloatCache->mRegion.height);
@ -1101,7 +1105,7 @@ nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType,
GetAvailableSpace(newY, PR_FALSE);
nsBlockFrame::ReplacedElementWidthToClear replacedWidth =
nsBlockFrame::WidthToClearPastFloats(*this, aReplacedBlock);
if (mBand.GetFloatCount() == 0 ||
if (!mBandHasFloats ||
PR_MAX(mAvailSpaceRect.x, replacedWidth.marginLeft) +
replacedWidth.borderBoxWidth +
PR_MAX(mContentArea.width -
@ -1124,8 +1128,8 @@ nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType,
newY += 1;
}
}
// Restore mBand and mAvailSpaceRect to the way they were. This may
// well not be needed, and we should probably come up with
// Restore mBandHasFloats and mAvailSpaceRect to the way they were.
// This may well not be needed, and we should probably come up with
// well-defined rules about when these members are valid so that
// it's clearly not needed.
GetAvailableSpace();

Просмотреть файл

@ -43,7 +43,7 @@
#ifndef nsBlockReflowState_h__
#define nsBlockReflowState_h__
#include "nsBlockBandData.h"
#include "nsFloatManager.h"
#include "nsLineBox.h"
#include "nsFrameList.h"
#include "nsBlockFrame.h"
@ -194,7 +194,7 @@ public:
nsFloatManager* mFloatManager;
// The coordinates within the spacemanager where the block is being
// The coordinates within the float manager where the block is being
// placed <b>after</b> taking into account the blocks border and
// padding. This, therefore, represents the inner "content area" (in
// spacemanager coordinates) where child frames will be placed,
@ -272,9 +272,6 @@ public:
// this to the next next-in-flow.
nsBlockFrame* mNextInFlow;
// The current band data for the current Y coordinate
nsBlockBandData mBand;
//----------------------------------------
// Temporary line-reflow state. This state is used during the reflow
@ -299,6 +296,11 @@ public:
PRUint8 mFloatBreakType;
// The number of floats on the sides of mAvailSpaceRect, including
// floats that do not reduce mAvailSpaceRect because they are in the
// margins.
PRPackedBool mBandHasFloats;
void SetFlag(PRUint32 aFlag, PRBool aValue)
{
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");

Просмотреть файл

@ -0,0 +1,465 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* class that manages rules for positioning floats */
#include "nsFloatManager.h"
#include "nsIPresShell.h"
#include "nsMemory.h"
#include "nsHTMLReflowState.h"
#include "nsHashSets.h"
#include "nsBlockDebugFlags.h"
PRInt32 nsFloatManager::sCachedFloatManagerCount = 0;
void* nsFloatManager::sCachedFloatManagers[NS_FLOAT_MANAGER_CACHE_SIZE];
/////////////////////////////////////////////////////////////////////////////
// PresShell Arena allocate callback (for nsIntervalSet use below)
static void*
PSArenaAllocCB(size_t aSize, void* aClosure)
{
return static_cast<nsIPresShell*>(aClosure)->AllocateFrame(aSize);
}
// PresShell Arena free callback (for nsIntervalSet use below)
static void
PSArenaFreeCB(size_t aSize, void* aPtr, void* aClosure)
{
static_cast<nsIPresShell*>(aClosure)->FreeFrame(aSize, aPtr);
}
/////////////////////////////////////////////////////////////////////////////
// nsFloatManager
nsFloatManager::nsFloatManager(nsIPresShell* aPresShell)
: mX(0), mY(0),
mFloatDamage(PSArenaAllocCB, PSArenaFreeCB, aPresShell)
{
MOZ_COUNT_CTOR(nsFloatManager);
}
nsFloatManager::~nsFloatManager()
{
MOZ_COUNT_DTOR(nsFloatManager);
}
// static
void* nsFloatManager::operator new(size_t aSize) CPP_THROW_NEW
{
if (sCachedFloatManagerCount > 0) {
// We have cached unused instances of this class, return a cached
// instance in stead of always creating a new one.
return sCachedFloatManagers[--sCachedFloatManagerCount];
}
// The cache is empty, this means we haveto create a new instance using
// the global |operator new|.
return nsMemory::Alloc(aSize);
}
void
nsFloatManager::operator delete(void* aPtr, size_t aSize)
{
if (!aPtr)
return;
// This float manager is no longer used, if there's still room in
// the cache we'll cache this float manager, unless the layout
// module was already shut down.
if (sCachedFloatManagerCount < NS_FLOAT_MANAGER_CACHE_SIZE &&
sCachedFloatManagerCount >= 0) {
// There's still space in the cache for more instances, put this
// instance in the cache in stead of deleting it.
sCachedFloatManagers[sCachedFloatManagerCount++] = aPtr;
return;
}
// The cache is full, or the layout module has been shut down,
// delete this float manager.
nsMemory::Free(aPtr);
}
/* static */
void nsFloatManager::Shutdown()
{
// The layout module is being shut down, clean up the cache and
// disable further caching.
PRInt32 i;
for (i = 0; i < sCachedFloatManagerCount; i++) {
void* floatManager = sCachedFloatManagers[i];
if (floatManager)
nsMemory::Free(floatManager);
}
// Disable further caching.
sCachedFloatManagerCount = -1;
}
nsRect
nsFloatManager::GetBand(nscoord aYOffset,
nscoord aMaxHeight,
nscoord aContentAreaWidth,
PRBool* aHasFloats) const
{
NS_ASSERTION(aMaxHeight >= 0, "unexpected max height");
NS_ASSERTION(aContentAreaWidth >= 0, "unexpected content area width");
nscoord top = aYOffset + mY;
if (top < nscoord_MIN) {
NS_NOTREACHED("bad value");
top = nscoord_MIN;
}
// If there are no floats at all, or we're below the last one, return
// quickly.
PRUint32 floatCount = mFloats.Length();
if (floatCount == 0 ||
(mFloats[floatCount-1].mLeftYMost <= top &&
mFloats[floatCount-1].mRightYMost <= top)) {
*aHasFloats = PR_FALSE;
return nsRect(0, aYOffset, aContentAreaWidth, aMaxHeight);
}
nscoord bottom;
if (aMaxHeight == nscoord_MAX) {
bottom = nscoord_MAX;
} else {
bottom = top + aMaxHeight;
if (bottom < top || bottom > nscoord_MAX) {
NS_NOTREACHED("bad value");
bottom = nscoord_MAX;
}
}
nscoord left = mX;
nscoord right = aContentAreaWidth + mX;
if (right < left) {
NS_NOTREACHED("bad value");
right = left;
}
// Walk backwards through the floats until we either hit the front of
// the list or we're above |top|.
PRBool haveFloats = PR_FALSE;
for (PRUint32 i = mFloats.Length(); i > 0; --i) {
const FloatInfo &fi = mFloats[i-1];
if (fi.mLeftYMost <= top && fi.mRightYMost <= top) {
// There aren't any more floats that could intersect this band.
break;
}
if (fi.mRect.IsEmpty()) {
// For compatibility, ignore floats with empty rects, even though it
// disagrees with the spec. (We might want to fix this in the
// future, though.)
continue;
}
nscoord floatTop = fi.mRect.y, floatBottom = fi.mRect.YMost();
if (floatTop > top) {
// This float is below our band. Shrink our band's height if needed.
if (floatTop < bottom) {
bottom = floatTop;
}
} else if (floatBottom > top) {
// This float is in our band.
haveFloats = PR_TRUE;
// Shrink our band's height if needed.
if (floatBottom < bottom) {
bottom = floatBottom;
}
// Shrink our band's width if needed.
if (fi.mFrame->GetStyleDisplay()->mFloats == NS_STYLE_FLOAT_LEFT) {
// A left float.
nscoord rightEdge = fi.mRect.XMost();
if (rightEdge > left) {
left = rightEdge;
}
} else {
// A right float.
nscoord leftEdge = fi.mRect.x;
if (leftEdge < right) {
right = leftEdge;
}
}
}
}
*aHasFloats = haveFloats;
nscoord height = (bottom == nscoord_MAX) ? nscoord_MAX : (bottom - top);
return nsRect(left - mX, top - mY, right - left, height);
}
nsresult
nsFloatManager::AddFloat(nsIFrame* aFloatFrame, const nsRect& aMarginRect)
{
NS_ASSERTION(aMarginRect.width >= 0, "negative width!");
NS_ASSERTION(aMarginRect.height >= 0, "negative height!");
FloatInfo info(aFloatFrame, aMarginRect + nsPoint(mX, mY));
// Set mLeftYMost and mRightYMost.
if (HasAnyFloats()) {
FloatInfo &tail = mFloats[mFloats.Length() - 1];
info.mLeftYMost = tail.mLeftYMost;
info.mRightYMost = tail.mRightYMost;
} else {
info.mLeftYMost = nscoord_MIN;
info.mRightYMost = nscoord_MIN;
}
PRUint8 floatStyle = aFloatFrame->GetStyleDisplay()->mFloats;
NS_ASSERTION(floatStyle == NS_STYLE_FLOAT_LEFT ||
floatStyle == NS_STYLE_FLOAT_RIGHT, "unexpected float");
nscoord& sideYMost = (floatStyle == NS_STYLE_FLOAT_LEFT) ? info.mLeftYMost
: info.mRightYMost;
nscoord thisYMost = info.mRect.YMost();
if (thisYMost > sideYMost)
sideYMost = thisYMost;
if (!mFloats.AppendElement(info))
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
nsresult
nsFloatManager::RemoveTrailingRegions(nsIFrame* aFrameList)
{
if (!aFrameList) {
return NS_OK;
}
// This could be a good bit simpler if we could guarantee that the
// floats given were at the end of our list, so we could just search
// for the head of aFrameList. (But we can't;
// layout/reftests/bugs/421710-1.html crashes.)
nsVoidHashSet frameSet;
frameSet.Init(1);
for (nsIFrame* f = aFrameList; f; f = f->GetNextSibling()) {
frameSet.Put(f);
}
PRUint32 newLength = mFloats.Length();
while (newLength > 0) {
if (!frameSet.Contains(mFloats[newLength - 1].mFrame)) {
break;
}
--newLength;
}
mFloats.RemoveElementsAt(newLength, mFloats.Length() - newLength);
#ifdef DEBUG
for (PRUint32 i = 0; i < mFloats.Length(); ++i) {
NS_ASSERTION(!frameSet.Contains(mFloats[i].mFrame),
"Frame region deletion was requested but we couldn't delete it");
}
#endif
return NS_OK;
}
void
nsFloatManager::PushState(SavedState* aState)
{
NS_PRECONDITION(aState, "Need a place to save state");
// This is a cheap push implementation, which
// only saves the (x,y) and last frame in the mFrameInfoMap
// which is enough info to get us back to where we should be
// when pop is called.
//
// This push/pop mechanism is used to undo any
// floats that were added during the unconstrained reflow
// in nsBlockReflowContext::DoReflowBlock(). (See bug 96736)
//
// It should also be noted that the state for mFloatDamage is
// intentionally not saved or restored in PushState() and PopState(),
// since that could lead to bugs where damage is missed/dropped when
// we move from position A to B (during the intermediate incremental
// reflow mentioned above) and then from B to C during the subsequent
// reflow. In the typical case A and C will be the same, but not always.
// Allowing mFloatDamage to accumulate the damage incurred during both
// reflows ensures that nothing gets missed.
aState->mX = mX;
aState->mY = mY;
aState->mFloatInfoCount = mFloats.Length();
}
void
nsFloatManager::PopState(SavedState* aState)
{
NS_PRECONDITION(aState, "No state to restore?");
mX = aState->mX;
mY = aState->mY;
NS_ASSERTION(aState->mFloatInfoCount <= mFloats.Length(),
"somebody misused PushState/PopState");
mFloats.RemoveElementsAt(aState->mFloatInfoCount,
mFloats.Length() - aState->mFloatInfoCount);
}
nscoord
nsFloatManager::GetLowestFloatTop() const
{
if (!HasAnyFloats()) {
return nscoord_MIN;
}
return mFloats[mFloats.Length() - 1].mRect.y - mY;
}
#ifdef DEBUG
void
DebugListFloatManager(const nsFloatManager *aFloatManager)
{
aFloatManager->List(stdout);
}
nsresult
nsFloatManager::List(FILE* out) const
{
if (!HasAnyFloats())
return NS_OK;
for (PRUint32 i = 0; i < mFloats.Length(); ++i) {
const FloatInfo &fi = mFloats[i];
printf("Float %u: frame=%p rect={%d,%d,%d,%d} ymost={l:%d, r:%d}\n",
i, static_cast<void*>(fi.mFrame),
fi.mRect.x, fi.mRect.y, fi.mRect.width, fi.mRect.height,
fi.mLeftYMost, fi.mRightYMost);
}
return NS_OK;
}
#endif
nscoord
nsFloatManager::ClearFloats(nscoord aY, PRUint8 aBreakType) const
{
if (!HasAnyFloats()) {
return aY;
}
nscoord bottom = aY + mY;
const FloatInfo &tail = mFloats[mFloats.Length() - 1];
switch (aBreakType) {
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
bottom = PR_MAX(bottom, tail.mLeftYMost);
bottom = PR_MAX(bottom, tail.mRightYMost);
break;
case NS_STYLE_CLEAR_LEFT:
bottom = PR_MAX(bottom, tail.mLeftYMost);
break;
case NS_STYLE_CLEAR_RIGHT:
bottom = PR_MAX(bottom, tail.mRightYMost);
break;
default:
// Do nothing
break;
}
bottom -= mY;
return bottom;
}
/////////////////////////////////////////////////////////////////////////////
// FloatInfo
nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame, const nsRect& aRect)
: mFrame(aFrame), mRect(aRect)
{
MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsFloatManager::FloatInfo::~FloatInfo()
{
MOZ_COUNT_DTOR(nsFloatManager::FloatInfo);
}
#endif
//----------------------------------------------------------------------
nsAutoFloatManager::~nsAutoFloatManager()
{
// Restore the old float manager in the reflow state if necessary.
if (mNew) {
#ifdef NOISY_FLOATMANAGER
printf("restoring old float manager %p\n", mOld);
#endif
mReflowState.mFloatManager = mOld;
#ifdef NOISY_FLOATMANAGER
if (mOld) {
static_cast<nsFrame *>(mReflowState.frame)->ListTag(stdout);
printf(": space-manager %p after reflow\n", mOld);
mOld->List(stdout);
}
#endif
delete mNew;
}
}
nsresult
nsAutoFloatManager::CreateFloatManager(nsPresContext *aPresContext)
{
// Create a new float manager and install it in the reflow
// state. `Remember' the old float manager so we can restore it
// later.
mNew = new nsFloatManager(aPresContext->PresShell());
if (! mNew)
return NS_ERROR_OUT_OF_MEMORY;
#ifdef NOISY_FLOATMANAGER
printf("constructed new float manager %p (replacing %p)\n",
mNew, mReflowState.mFloatManager);
#endif
// Set the float manager in the existing reflow state
mOld = mReflowState.mFloatManager;
mReflowState.mFloatManager = mNew;
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,256 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim:cindent:ts=2:et:sw=2:
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* class that manages rules for positioning floats */
#ifndef nsFloatManager_h_
#define nsFloatManager_h_
#include "nsIntervalSet.h"
#include "nsCoord.h"
#include "nsRect.h"
#include "nsTArray.h"
class nsIPresShell;
class nsIFrame;
struct nsHTMLReflowState;
class nsPresContext;
#define NS_FLOAT_MANAGER_CACHE_SIZE 4
class nsFloatManager {
public:
nsFloatManager(nsIPresShell* aPresShell);
~nsFloatManager();
void* operator new(size_t aSize) CPP_THROW_NEW;
void operator delete(void* aPtr, size_t aSize);
static void Shutdown();
/**
* Translate the current origin by the specified (dx, dy). This
* creates a new local coordinate space relative to the current
* coordinate space.
*/
void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
/**
* Returns the current translation from local coordinate space to
* world coordinate space. This represents the accumulated calls to
* Translate().
*/
void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
/**
* Get information about the band containing vertical coordinate |aY|,
* but up to at most |aMaxHeight| (which may be nscoord_MAX). This
* will return the tallest rectangle whose top is |aY| and in which
* there are no changes in what floats are on the sides of that
* rectangle, but will limit the height of the rectangle to
* |aMaxHeight|. The left and right edges of the rectangle give the
* area available for line boxes in that space.
*
* @param aY [in] vertical coordinate for top of available space
* desired
* @param aMaxHeight [in] maximum height of available space desired
* @param aContentAreaWidth [in] the width of the content area (whose left
* edge must be zero in the current translation)
* @param aHasFloats [out] whether there are floats at the sides of
* the return value including those that do not
* reduce the line box width at all (because they
* are entirely in the margins)
* @return the resulting rectangle for line boxes. It will not go
* left of 0, nor right of aContentAreaWidth, but will be
* narrower when floats are present.
*
* aY and aAvailSpace are positioned relative to the current translation
*/
nsRect GetBand(nscoord aY, nscoord aMaxHeight, nscoord aContentAreaWidth,
PRBool* aHasFloats) const;
/**
* Add a float that comes after all floats previously added. Its top
* must be even with or below the top of all previous floats.
*
* aMarginRect is relative to the current translation. The caller
* must ensure aMarginRect.height >= 0 and aMarginRect.width >= 0.
*/
nsresult AddFloat(nsIFrame* aFloatFrame, const nsRect& aMarginRect);
/**
* Remove the regions associated with this floating frame and its
* next-sibling list. Some of the frames may never have been added;
* we just skip those. This is not fully general; it only works as
* long as the N frames to be removed are the last N frames to have
* been added; if there's a frame in the middle of them that should
* not be removed, YOU LOSE.
*/
nsresult RemoveTrailingRegions(nsIFrame* aFrameList);
private:
struct FloatInfo;
public:
// Structure that stores the current state of a frame manager for
// Save/Restore purposes.
struct SavedState;
friend struct SavedState;
struct SavedState {
private:
PRUint32 mFloatInfoCount;
nscoord mX, mY;
friend class nsFloatManager;
};
PRBool HasAnyFloats() const { return !mFloats.IsEmpty(); }
/**
* Methods for dealing with the propagation of float damage during
* reflow.
*/
PRBool HasFloatDamage() const
{
return !mFloatDamage.IsEmpty();
}
void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{
mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
}
PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd) const
{
return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
}
/**
* Saves the current state of the float manager into aState.
*/
void PushState(SavedState* aState);
/**
* Restores the float manager to the saved state.
*
* These states must be managed using stack discipline. PopState can only
* be used after PushState has been used to save the state, and it can only
* be used once --- although it can be omitted; saved states can be ignored.
* States must be popped in the reverse order they were pushed.
*/
void PopState(SavedState* aState);
/**
* Get the top of the last float placed into the float manager, to
* enforce the rule that a float can't be above an earlier float.
* Returns the minimum nscoord value if there are no floats.
*
* The result is relative to the current translation.
*/
nscoord GetLowestFloatTop() const;
/**
* Return the coordinate of the lowest float matching aBreakType in this
* float manager. Returns aY if there are no matching floats.
*
* Both aY and the result are relative to the current translation.
*/
nscoord ClearFloats(nscoord aY, PRUint8 aBreakType) const;
#ifdef DEBUG
/**
* Dump the state of the float manager out to a file.
*/
nsresult List(FILE* out) const;
#endif
private:
struct FloatInfo {
nsIFrame *const mFrame;
nsRect mRect;
// The lowest bottoms of left/right floats up to and including this one.
nscoord mLeftYMost, mRightYMost;
FloatInfo(nsIFrame* aFrame, const nsRect& aRect);
#ifdef NS_BUILD_REFCNT_LOGGING
~FloatInfo();
#endif
};
nscoord mX, mY; // translation from local to global coordinate space
nsTArray<FloatInfo> mFloats;
nsIntervalSet mFloatDamage;
static PRInt32 sCachedFloatManagerCount;
static void* sCachedFloatManagers[NS_FLOAT_MANAGER_CACHE_SIZE];
nsFloatManager(const nsFloatManager&); // no implementation
void operator=(const nsFloatManager&); // no implementation
};
/**
* A helper class to manage maintenance of the float manager during
* nsBlockFrame::Reflow. It automatically restores the old float
* manager in the reflow state when the object goes out of scope.
*/
class nsAutoFloatManager {
public:
nsAutoFloatManager(nsHTMLReflowState& aReflowState)
: mReflowState(aReflowState),
mNew(nsnull),
mOld(nsnull) {}
~nsAutoFloatManager();
/**
* Create a new float manager for the specified frame. This will
* `remember' the old float manager, and install the new float
* manager in the reflow state.
*/
nsresult
CreateFloatManager(nsPresContext *aPresContext);
protected:
nsHTMLReflowState &mReflowState;
nsFloatManager *mNew;
nsFloatManager *mOld;
};
#endif /* !defined(nsFloatManager_h_) */

Просмотреть файл

@ -41,7 +41,6 @@
/* representation of one line within a block frame, a CSS line box */
#include "nsLineBox.h"
#include "nsSpaceManager.h"
#include "nsLineLayout.h"
#include "prprf.h"
#include "nsBlockFrame.h"

Просмотреть файл

@ -46,7 +46,6 @@
#include "nsPlaceholderFrame.h"
#include "nsILineIterator.h"
class nsFloatManager;
class nsLineBox;
class nsFloatCache;
class nsFloatCacheList;

Просмотреть файл

@ -52,7 +52,7 @@
#include "nsInlineFrame.h"
#include "nsStyleConsts.h"
#include "nsHTMLContainerFrame.h"
#include "nsSpaceManager.h"
#include "nsFloatManager.h"
#include "nsStyleContext.h"
#include "nsPresContext.h"
#include "nsIFontMetrics.h"

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,491 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim:cindent:ts=2:et:sw=2:
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* class that manages regions of 2-D space, originally designed
* generally but actually specific to space occupied by floats
*/
#ifndef nsSpaceManager_h___
#define nsSpaceManager_h___
#include "prclist.h"
#include "nsIntervalSet.h"
#include "nsISupports.h"
#include "nsCoord.h"
#include "nsRect.h"
#include "nsVoidArray.h"
class nsIPresShell;
class nsIFrame;
struct nsSize;
struct nsHTMLReflowState;
class nsPresContext;
#define NS_SPACE_MANAGER_CACHE_SIZE 4
/**
* Information about a particular trapezoid within a band. The space described
* by the trapezoid is in one of three states:
* <ul>
* <li>available
* <li>occupied by one frame
* <li>occupied by more than one frame
* </ul>
*/
struct nsBandTrapezoid {
nscoord mTopY, mBottomY; // top and bottom y-coordinates
nscoord mTopLeftX, mBottomLeftX; // left edge x-coordinates
nscoord mTopRightX, mBottomRightX; // right edge x-coordinates
const nsSmallVoidArray* mFrames; // list of frames occupying the space
// Get the height of the trapezoid
nscoord GetHeight() const {return mBottomY - mTopY;}
// Get the bounding rect of the trapezoid
inline void GetRect(nsRect& aRect) const;
// Set the trapezoid from a rectangle
inline void operator=(const nsRect& aRect);
// Do these trapezoids have the same geometry?
inline PRBool EqualGeometry(const nsBandTrapezoid& aTrap) const;
nsBandTrapezoid()
: mTopY(0),
mBottomY(0),
mTopLeftX(0),
mBottomLeftX(0),
mTopRightX(0),
mBottomRightX(0),
mFrames(nsnull)
{
}
};
inline void nsBandTrapezoid::GetRect(nsRect& aRect) const
{
aRect.x = PR_MIN(mTopLeftX, mBottomLeftX);
aRect.y = mTopY;
aRect.width = PR_MAX(mTopRightX, mBottomRightX);
if (NS_MAXSIZE != aRect.width) {
aRect.width -= aRect.x;
}
aRect.height = (NS_MAXSIZE == mBottomY) ? NS_MAXSIZE : mBottomY - mTopY;
}
inline void nsBandTrapezoid::operator=(const nsRect& aRect)
{
mTopLeftX = mBottomLeftX = aRect.x;
mTopRightX = mBottomRightX = aRect.XMost();
mTopY = aRect.y;
mBottomY = aRect.YMost();
}
inline PRBool nsBandTrapezoid::EqualGeometry(const nsBandTrapezoid& aTrap) const
{
return (
mTopLeftX == aTrap.mTopLeftX &&
mBottomLeftX == aTrap.mBottomLeftX &&
mTopRightX == aTrap.mTopRightX &&
mBottomRightX == aTrap.mBottomRightX &&
mTopY == aTrap.mTopY &&
mBottomY == aTrap.mBottomY
);
}
/**
* Structure used for describing the space within a band.
* @see #GetBandData()
*/
struct nsBandData {
PRInt32 mCount; // [out] actual number of trapezoids in the band data
PRInt32 mSize; // [in] the size of the array (number of trapezoids)
nsBandTrapezoid* mTrapezoids; // [out] array of length 'size'
};
/**
* Class for dealing with bands of available space. The float manager
* defines a coordinate space (relative to the frame that created the
* float manager) with an origin at (0, 0) that grows down and to the
* right.
*/
class nsFloatManager {
public:
nsFloatManager(nsIPresShell* aPresShell);
~nsFloatManager();
void* operator new(size_t aSize) CPP_THROW_NEW;
void operator delete(void* aPtr, size_t aSize);
static void Shutdown();
/**
* Translate the current origin by the specified (dx, dy). This
* creates a new local coordinate space relative to the current
* coordinate space.
*/
void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
/**
* Returns the current translation from local coordinate space to
* world coordinate space. This represents the accumulated calls to
* Translate().
*/
void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
/**
* Returns the y-most of the bottommost band or 0 if there are no bands.
*
* @return PR_TRUE if there are bands and PR_FALSE if there are no bands
*/
PRBool YMost(nscoord& aYMost) const;
/**
* Returns a band starting at the specified y-offset. The band data
* indicates which parts of the band are available, and which parts
* are unavailable
*
* The band data that is returned is in the coordinate space of the
* local coordinate system.
*
* The local coordinate space origin, the y-offset, and the max size
* describe a rectangle that's used to clip the underlying band of
* available space, i.e.
* {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
* coordinate space
*
* @param aYOffset the y-offset of where the band begins. The coordinate is
* relative to the upper-left corner of the local coordinate space
* @param aMaxSize the size to use to constrain the band data
* @param aBandData [in,out] used to return the list of trapezoids that
* describe the available space and the unavailable space
* @return NS_OK if successful and NS_ERROR_FAILURE if the band data is not
* not large enough. The 'count' member of the band data struct
* indicates how large the array of trapezoids needs to be
*/
nsresult GetBandData(nscoord aYOffset,
const nsSize& aMaxSize,
nsBandData& aBandData) const;
/**
* Add a rectangular region of unavailable space. The space is
* relative to the local coordinate system.
*
* The region is tagged with a frame
*
* @param aFrame the frame used to identify the region. Must not be NULL
* @param aUnavailableSpace the bounding rect of the unavailable space
* @return NS_OK if successful
* NS_ERROR_FAILURE if there is already a region tagged with aFrame
*/
nsresult AddRectRegion(nsIFrame* aFrame,
const nsRect& aUnavailableSpace);
/**
* Remove the regions associated with this floating frame and its
* next-sibling list. Some of the frames may never have been added;
* we just skip those. This is not fully general; it only works as
* long as the N frames to be removed are the last N frames to have
* been added; if there's a frame in the middle of them that should
* not be removed, YOU LOSE.
*
* This can only be done at the end of the life of this float manager. The only
* methods it is safe to call after this are XMost() and YMost().
*/
nsresult RemoveTrailingRegions(nsIFrame* aFrameList);
protected:
/**
* Remove the region associated with aFrane.
*
* doesn't work in the general case!
*
* Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
* tagged with aFrame
*/
nsresult RemoveRegion(nsIFrame* aFrame);
public:
// Structure that stores the current state of a frame manager for
// Save/Restore purposes.
struct SavedState {
private:
nsIFrame *mLastFrame;
nscoord mX, mY;
nscoord mLowestTop;
nscoord mMaximalLeftYMost;
nscoord mMaximalRightYMost;
PRPackedBool mHaveCachedLeftYMost;
PRPackedBool mHaveCachedRightYMost;
friend class nsFloatManager;
};
PRBool HasAnyFloats() { return mFrameInfoMap != nsnull; }
/**
* Methods for dealing with the propagation of float damage during
* reflow.
*/
PRBool HasFloatDamage()
{
return !mFloatDamage.IsEmpty();
}
void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{
mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
}
PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{
return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
}
/**
* Saves the current state of the float manager into aState.
*/
void PushState(SavedState* aState);
/**
* Restores the float manager to the saved state.
*
* These states must be managed using stack discipline. PopState can only
* be used after PushState has been used to save the state, and it can only
* be used once --- although it can be omitted; saved states can be ignored.
* States must be popped in the reverse order they were pushed.
*/
void PopState(SavedState* aState);
/**
* Get the top of the last region placed into the float manager, to
* enforce the rule that a float can't be above an earlier float.
* Returns the minimum nscoord value if there are no regions.
*/
nscoord GetLowestRegionTop();
/**
* Return the coordinate of the lowest float matching aBreakType in this
* float manager. Returns aY if there are no matching floats.
*/
nscoord ClearFloats(nscoord aY, PRUint8 aBreakType);
#ifdef DEBUG
/**
* Dump the state of the spacemanager out to a file
*/
nsresult List(FILE* out);
#endif
protected:
// Structure that maintains information about the region associated
// with a particular frame
struct FrameInfo {
nsIFrame* const mFrame;
nsRect mRect; // rectangular region
FrameInfo* mNext;
FrameInfo(nsIFrame* aFrame, const nsRect& aRect);
#ifdef NS_BUILD_REFCNT_LOGGING
~FrameInfo();
#endif
};
public:
// Doubly linked list of band rects
struct BandRect : PRCListStr {
nscoord mLeft, mTop;
nscoord mRight, mBottom;
nsSmallVoidArray mFrames; // list of frames occupying the space
BandRect(nscoord aLeft, nscoord aTop,
nscoord aRight, nscoord aBottom,
nsIFrame* aFrame);
BandRect(nscoord aLeft, nscoord aTop,
nscoord aRight, nscoord aBottom,
nsSmallVoidArray& frames);
~BandRect();
// List operations
BandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
void InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
void InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
void Remove() {PR_REMOVE_LINK(this);}
// Split the band rect into two vertically, with this band rect becoming
// the top part, and a new band rect being allocated and returned for the
// bottom part
//
// Does not insert the new band rect into the linked list
BandRect* SplitVertically(nscoord aBottom);
// Split the band rect into two horizontally, with this band rect becoming
// the left part, and a new band rect being allocated and returned for the
// right part
//
// Does not insert the new band rect into the linked list
BandRect* SplitHorizontally(nscoord aRight);
// Accessor functions
PRBool IsOccupiedBy(const nsIFrame* aFrame) const {
return (mFrames.IndexOf((void*)aFrame) != -1);
}
void AddFrame(const nsIFrame* aFrame) {
mFrames.AppendElement((void*)aFrame);
}
void RemoveFrame(const nsIFrame* aFrame) {
mFrames.RemoveElement((void*)aFrame);
}
nsIFrame * FrameAt(PRInt32 index) {
return static_cast<nsIFrame*>(mFrames.FastElementAt(index));
}
PRBool HasSameFrameList(const BandRect* aBandRect) const;
PRInt32 Length() const;
};
// Circular linked list of band rects
struct BandList : BandRect {
BandList();
// Accessors
PRBool IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}
// Operations
void Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}
// Remove and delete all the band rects in the list
void Clear();
};
protected:
nscoord mX, mY; // translation from local to global coordinate space
BandList mBandList; // header/sentinel for circular linked list of band rects
nscoord mLowestTop; // the lowest *top*
FrameInfo* mFrameInfoMap;
nsIntervalSet mFloatDamage;
PRPackedBool mHaveCachedLeftYMost; // If true, mMaximalLeftYMost is set
PRPackedBool mHaveCachedRightYMost; // If true, mMaximalRightYMost is set
nscoord mMaximalLeftYMost; // The maximal YMost of our FrameInfo
// rects for left floats. Only makes
// sense when mHaveCachedLeftYMost is
// true.
nscoord mMaximalRightYMost; // The maximal YMost of our FrameInfo
// rects for right floats. Only makes
// sense when mHaveCachedLeftYMost is
// true.
// We keep track of the last BandRect* we worked with so that we can
// make use of locality of reference in situations where people want
// to do a bunch of operations in a row.
BandRect* mCachedBandPosition;
protected:
FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect& aRect);
void DestroyFrameInfo(FrameInfo*);
void ClearFrameInfo();
BandRect* GetNextBand(const BandRect* aBandRect) const;
BandRect* GetPrevBand(const BandRect* aBandRect) const;
void DivideBand(BandRect* aBand, nscoord aBottom);
PRBool CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
PRBool JoinBands(BandRect* aBand, BandRect* aPrevBand);
void AddRectToBand(BandRect* aBand, BandRect* aBandRect);
void InsertBandRect(BandRect* aBandRect);
nsresult GetBandAvailableSpace(const BandRect* aBand,
nscoord aY,
const nsSize& aMaxSize,
nsBandData& aAvailableSpace) const;
// Return a band guaranteed to have its top at or above aYOffset or the first
// band if there is no band with its top above aYOffset. This method will
// use mCachedBandPosition to maybe get such a band that's not too far up.
// This function should not be called if there are no bands.
// This function never returns null.
BandRect* GuessBandWithTopAbove(nscoord aYOffset) const;
void SetCachedBandPosition(BandRect* aBandRect) {
NS_ASSERTION(!aBandRect ||
aBandRect == mBandList.Head() ||
aBandRect->Prev()->mBottom != aBandRect->mBottom,
"aBandRect should be first rect within its band");
mCachedBandPosition = aBandRect;
}
private:
static PRInt32 sCachedFloatManagerCount;
static void* sCachedFloatManagers[NS_SPACE_MANAGER_CACHE_SIZE];
nsFloatManager(const nsFloatManager&); // no implementation
void operator=(const nsFloatManager&); // no implementation
};
/**
* A helper class to manage maintenance of the float manager during
* nsBlockFrame::Reflow. It automatically restores the old space
* manager in the reflow state when the object goes out of scope.
*/
class nsAutoFloatManager {
public:
nsAutoFloatManager(nsHTMLReflowState& aReflowState)
: mReflowState(aReflowState),
mNew(nsnull),
mOld(nsnull) {}
~nsAutoFloatManager();
/**
* Create a new float manager for the specified frame. This will
* `remember' the old float manager, and install the new space
* manager in the reflow state.
*/
nsresult
CreateFloatManager(nsPresContext *aPresContext);
protected:
nsHTMLReflowState &mReflowState;
nsFloatManager *mNew;
nsFloatManager *mOld;
};
#endif /* nsSpaceManager_h___ */

Просмотреть файл

@ -41,7 +41,6 @@
#include "nsIDOMSVGForeignObjectElem.h"
#include "nsIDOMSVGMatrix.h"
#include "nsIDOMSVGSVGElement.h"
#include "nsSpaceManager.h"
#include "nsSVGOuterSVGFrame.h"
#include "nsRegion.h"
#include "nsGkAtoms.h"

Просмотреть файл

@ -72,7 +72,6 @@
#include "nsINameSpaceManager.h"
#include "nsGkAtoms.h"
#include "nsIContent.h"
#include "nsSpaceManager.h"
#include "nsHTMLParts.h"
#include "nsIViewManager.h"
#include "nsIView.h"