Changed to table incremental reflow

This commit is contained in:
troy%netscape.com 1999-08-19 03:51:25 +00:00
parent b5adb52af2
commit f901be20dc
42 changed files with 1394 additions and 1584 deletions

View File

@ -59,66 +59,6 @@ public:
static const nsIID& GetIID() { static nsIID iid = NS_IREFLOWCOMMAND_IID; return iid; }
enum ReflowType {
/**
* Reflow command generated by the style system in response to a
* ContentAppended content notification. The target frame of the reflow
* command is the container frame itself. The "child frame" is a linked
* list of newly created child frames.
*
* The target frame should insert the new frames into the specified child
* list, and then reflow the child frames using an eReflowReason_Initial
* reflow reason.
*
* ContentInserted content notifications also generate a FrameAppended reflow
* command if the container frame has no existing child frames.
*
* @see #GetTarget()
* @see #GetChildFrame()
* @see #GetChildListName()
*/
FrameAppended = 0,
/**
* Reflow command generated by the style system in response to a
* ContentInserted content notification. The target frame of the reflow
* command is the container frame itself. The "child frame" is a linked
* list of newly created child frames. The "previous sibling" frame is the
* existing frame immediately preceding where the first of the newly created
* frames should be inserted. If the newly created frames should be the
* target frame's first child frames then "previous sibling" will be nsnull.
*
* The target frame should insert the new frames immediately after the previous
* sibling frame, and then reflow the new frames using an eReflowReason_Initial
* reflow reason. Use GetChildListName() to get the name of the child list to
* which you should insert the new frames.
*
* The target frame is determined as follows:
* - find the previous existing frame and use its content parent
* - if there is no previous frame then find the frame that follows and use
* its content parent
*
* @see #GetTarget()
* @see #GetChildFrame()
* @see #GetPrevSiblingFrame()
* @see #GetChildListName()
*/
FrameInserted,
/**
* Reflow command generated by the style system in response to a
* ContentRemoved content notification. The "child frame" is the frame
* associated with the content that has been removed. The target frame
* is the content parent of the "child frame".
*
* Use GetChildListName() to get the name of the child list associated with
* the frame to be deleted
*
* @see #GetTarget()
* @see #GetChildFrame()
* @see #GetChildListName()
*/
FrameRemoved,
// This reflow command is used when a leaf node's content changes
// (e.g. some text in a text run, an image's source, etc.). The
// target of the reflow command is the frame that changed (see
@ -132,8 +72,6 @@ public:
// reflow command is the frame that changed style.
StyleChanged,
// XXX Everything below is speculative...
// When an incremental reflow operation affects a next-in-flow,
// these commands are used to get the next-in-flow to update
// itself.

View File

@ -49,7 +49,7 @@ Components {
margin-left: .5in;
border: dotted 1px black;
}
*[xml:link]:hover {
:link:hover {
background-color: blue;
color: white;
cursor: pointer;

View File

@ -1189,11 +1189,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
printf(": reflow=incremental type=%d\n", type);
#endif
switch (type) {
case nsIReflowCommand::FrameAppended:
case nsIReflowCommand::FrameInserted:
case nsIReflowCommand::FrameRemoved:
NS_NOTREACHED("invalid reflow command");
break;
case nsIReflowCommand::StyleChanged:
rv = PrepareStyleChangedReflow(state);
break;

View File

@ -1189,11 +1189,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
printf(": reflow=incremental type=%d\n", type);
#endif
switch (type) {
case nsIReflowCommand::FrameAppended:
case nsIReflowCommand::FrameInserted:
case nsIReflowCommand::FrameRemoved:
NS_NOTREACHED("invalid reflow command");
break;
case nsIReflowCommand::StyleChanged:
rv = PrepareStyleChangedReflow(state);
break;

View File

@ -1189,11 +1189,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
printf(": reflow=incremental type=%d\n", type);
#endif
switch (type) {
case nsIReflowCommand::FrameAppended:
case nsIReflowCommand::FrameInserted:
case nsIReflowCommand::FrameRemoved:
NS_NOTREACHED("invalid reflow command");
break;
case nsIReflowCommand::StyleChanged:
rv = PrepareStyleChangedReflow(state);
break;

View File

@ -604,36 +604,6 @@ nsContainerFrame::MoveOverflowToChildList()
return result;
}
nsresult
nsContainerFrame::AddFrame(const nsHTMLReflowState& aReflowState,
nsIFrame * aAddedFrame)
{
nsresult rv=NS_OK;
nsIReflowCommand::ReflowType type;
aReflowState.reflowCommand->GetType(type);
// we have a generic frame that gets inserted but doesn't effect
// reflow hook it up then ignore it
if (nsIReflowCommand::FrameAppended == type) {
// Append aAddedFrame to the list of frames
mFrames.AppendFrame(nsnull, aAddedFrame);
}
else if (nsIReflowCommand::FrameInserted == type) {
// Insert aAddedFrame into the list of frames
nsIFrame *prevSibling=nsnull;
rv = aReflowState.reflowCommand->GetPrevSiblingFrame(prevSibling);
if (NS_SUCCEEDED(rv)) {
mFrames.InsertFrame(nsnull, prevSibling, aAddedFrame);
}
}
else
{
NS_ASSERTION(PR_FALSE, "bad reflow type");
rv = NS_ERROR_UNEXPECTED;
}
return rv;
}
/////////////////////////////////////////////////////////////////////////////
// Debugging

View File

@ -122,11 +122,6 @@ protected:
*/
void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling);
/**
*/
nsresult AddFrame(const nsHTMLReflowState& aReflowState,
nsIFrame * aAddedFrame);
nsFrameList mFrames;
nsFrameList mOverflowFrames;
};

View File

@ -264,29 +264,8 @@ nsFrame::AppendFrames(nsIPresContext& aPresContext,
nsIAtom* aListName,
nsIFrame* aFrameList)
{
#if 0
NS_PRECONDITION(PR_FALSE, "not a container");
return NS_ERROR_UNEXPECTED;
#else
#ifdef NS_DEBUG
nsFrameList tmp(aFrameList);
tmp.VerifyParent(this);
#endif
// XXX temporary code until frame containers stop using the old
// reflow command api's
nsIReflowCommand* reflowCmd = nsnull;
nsresult rv;
rv = NS_NewHTMLReflowCommand(&reflowCmd, this,
nsIReflowCommand::FrameAppended,
aFrameList);
if (NS_SUCCEEDED(rv)) {
if (nsnull != aListName) {
reflowCmd->SetChildListName(aListName);
}
aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
#endif
}
NS_IMETHODIMP
@ -296,37 +275,8 @@ nsFrame::InsertFrames(nsIPresContext& aPresContext,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList)
{
#if 0
NS_PRECONDITION(PR_FALSE, "not a container");
return NS_ERROR_UNEXPECTED;
#else
#ifdef NS_DEBUG
nsFrameList tmp(aFrameList);
tmp.VerifyParent(this);
#endif
// XXX temporary code until frame containers stop using the old
// reflow command api's
// By default, the reflow command is aimed at the first-in-flow. We
// map that to the flow block that contains aPrevFrame for
// compatability.
nsIFrame* target = this;
if (nsnull != aPrevFrame) {
aPrevFrame->GetParent(&target);
}
nsIReflowCommand* reflowCmd = nsnull;
nsresult rv;
rv = NS_NewHTMLReflowCommand(&reflowCmd, target, aFrameList, aPrevFrame);
if (NS_SUCCEEDED(rv)) {
if (nsnull != aListName) {
reflowCmd->SetChildListName(aListName);
}
aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
#endif
}
NS_IMETHODIMP
@ -335,40 +285,8 @@ nsFrame::RemoveFrame(nsIPresContext& aPresContext,
nsIAtom* aListName,
nsIFrame* aOldFrame)
{
#if 0
NS_PRECONDITION(PR_FALSE, "not a container");
return NS_ERROR_UNEXPECTED;
#else
#ifdef NS_DEBUG
nsIFrame* parent;
aOldFrame->GetParent(&parent);
NS_ASSERTION(parent == this, "bad child parent");
#endif
// XXX temporary code until frame containers stop using the old
// reflow command api's
// By default, the reflow command is aimed at the first-in-flow. We
// map that to the flow block that contains aPrevFrame for
// compatability.
nsIFrame* target = this;
if (nsnull != aOldFrame) {
aOldFrame->GetParent(&target);
}
nsIReflowCommand* reflowCmd = nsnull;
nsresult rv;
rv = NS_NewHTMLReflowCommand(&reflowCmd, target,
nsIReflowCommand::FrameRemoved,
aOldFrame);
if (NS_SUCCEEDED(rv)) {
if (nsnull != aListName) {
reflowCmd->SetChildListName(aListName);
}
aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
#endif
}
NS_IMETHODIMP
@ -378,6 +296,7 @@ nsFrame::ReplaceFrame(nsIPresContext& aPresContext,
nsIFrame* aOldFrame,
nsIFrame* aNewFrame)
{
NS_PRECONDITION(PR_FALSE, "not a container");
return NS_ERROR_UNEXPECTED;
}
@ -1060,6 +979,40 @@ nsFrame::DidReflow(nsIPresContext& aPresContext,
mView->GetViewManager(vm);
vm->ResizeView(mView, mRect.width, mRect.height);
vm->MoveViewTo(mView, origin.x, origin.y);
// Clip applies to block-level and replaced elements with overflow
// set to other than 'visible'
const nsStyleDisplay* display =
(const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
if (display->IsBlockLevel()) {
if (display->mOverflow == NS_STYLE_OVERFLOW_HIDDEN) {
nscoord left, top, right, bottom;
// Start with the 'auto' values and then factor in user
// specified values
left = top = 0;
right = mRect.width;
bottom = mRect.height;
if (0 == (NS_STYLE_CLIP_TOP_AUTO & display->mClipFlags)) {
top += display->mClip.top;
}
if (0 == (NS_STYLE_CLIP_RIGHT_AUTO & display->mClipFlags)) {
right -= display->mClip.right;
}
if (0 == (NS_STYLE_CLIP_BOTTOM_AUTO & display->mClipFlags)) {
bottom -= display->mClip.bottom;
}
if (0 == (NS_STYLE_CLIP_LEFT_AUTO & display->mClipFlags)) {
left += display->mClip.left;
}
mView->SetClip(left, top, right, bottom);
} else {
// Make sure no clip is set
mView->SetClip(0, 0, 0, 0);
}
}
NS_RELEASE(vm);
}
}

View File

@ -357,11 +357,4 @@ NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult,
nsIFrame* aChildFrame = nsnull,
nsIAtom* aAttribute = nsnull);
/** Create a new HTML 'FrameInserted' reflow command */
extern nsresult
NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult,
nsIFrame* aTargetFrame,
nsIFrame* aChildFrame,
nsIFrame* aPrevSiblingFrame);
#endif /* nsHTMLParts_h___ */

View File

@ -48,25 +48,6 @@ NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult,
return cmd->QueryInterface(kIReflowCommandIID, (void**)aInstancePtrResult);
}
nsresult
NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult,
nsIFrame* aTargetFrame,
nsIFrame* aChildFrame,
nsIFrame* aPrevSiblingFrame)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
nsHTMLReflowCommand* cmd = new nsHTMLReflowCommand(aTargetFrame, aChildFrame,
aPrevSiblingFrame);
if (nsnull == cmd) {
return NS_ERROR_OUT_OF_MEMORY;
}
return cmd->QueryInterface(kIReflowCommandIID, (void**)aInstancePtrResult);
}
// Construct a reflow command given a target frame, reflow command type,
// and optional child frame
nsHTMLReflowCommand::nsHTMLReflowCommand(nsIFrame* aTargetFrame,
@ -84,16 +65,6 @@ nsHTMLReflowCommand::nsHTMLReflowCommand(nsIFrame* aTargetFrame,
NS_INIT_REFCNT();
}
nsHTMLReflowCommand::nsHTMLReflowCommand(nsIFrame* aTargetFrame,
nsIFrame* aChildFrame,
nsIFrame* aPrevSiblingFrame)
: mType(FrameInserted), mTargetFrame(aTargetFrame), mChildFrame(aChildFrame),
mPrevSiblingFrame(aPrevSiblingFrame), mAttribute(nsnull), mListName(nsnull)
{
NS_PRECONDITION(mTargetFrame != nsnull, "null target frame");
NS_INIT_REFCNT();
}
nsHTMLReflowCommand::~nsHTMLReflowCommand()
{
NS_IF_RELEASE(mAttribute);

View File

@ -38,15 +38,6 @@ public:
nsIFrame* aChildFrame = nsnull,
nsIAtom* aAttribute = nsnull);
/**
* Construct an HTML reflow command of type FrameInserted, with target
* frame aTargetFrame, and with the specified child and previous sibling
* frames.
*/
nsHTMLReflowCommand(nsIFrame* aTargetFrame,
nsIFrame* aChildFrame,
nsIFrame* aPrevSiblingFrame);
virtual ~nsHTMLReflowCommand();
// nsISupports

View File

@ -1189,11 +1189,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
printf(": reflow=incremental type=%d\n", type);
#endif
switch (type) {
case nsIReflowCommand::FrameAppended:
case nsIReflowCommand::FrameInserted:
case nsIReflowCommand::FrameRemoved:
NS_NOTREACHED("invalid reflow command");
break;
case nsIReflowCommand::StyleChanged:
rv = PrepareStyleChangedReflow(state);
break;

View File

@ -1189,11 +1189,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
printf(": reflow=incremental type=%d\n", type);
#endif
switch (type) {
case nsIReflowCommand::FrameAppended:
case nsIReflowCommand::FrameInserted:
case nsIReflowCommand::FrameRemoved:
NS_NOTREACHED("invalid reflow command");
break;
case nsIReflowCommand::StyleChanged:
rv = PrepareStyleChangedReflow(state);
break;

View File

@ -1189,11 +1189,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
printf(": reflow=incremental type=%d\n", type);
#endif
switch (type) {
case nsIReflowCommand::FrameAppended:
case nsIReflowCommand::FrameInserted:
case nsIReflowCommand::FrameRemoved:
NS_NOTREACHED("invalid reflow command");
break;
case nsIReflowCommand::StyleChanged:
rv = PrepareStyleChangedReflow(state);
break;

View File

@ -604,36 +604,6 @@ nsContainerFrame::MoveOverflowToChildList()
return result;
}
nsresult
nsContainerFrame::AddFrame(const nsHTMLReflowState& aReflowState,
nsIFrame * aAddedFrame)
{
nsresult rv=NS_OK;
nsIReflowCommand::ReflowType type;
aReflowState.reflowCommand->GetType(type);
// we have a generic frame that gets inserted but doesn't effect
// reflow hook it up then ignore it
if (nsIReflowCommand::FrameAppended == type) {
// Append aAddedFrame to the list of frames
mFrames.AppendFrame(nsnull, aAddedFrame);
}
else if (nsIReflowCommand::FrameInserted == type) {
// Insert aAddedFrame into the list of frames
nsIFrame *prevSibling=nsnull;
rv = aReflowState.reflowCommand->GetPrevSiblingFrame(prevSibling);
if (NS_SUCCEEDED(rv)) {
mFrames.InsertFrame(nsnull, prevSibling, aAddedFrame);
}
}
else
{
NS_ASSERTION(PR_FALSE, "bad reflow type");
rv = NS_ERROR_UNEXPECTED;
}
return rv;
}
/////////////////////////////////////////////////////////////////////////////
// Debugging

View File

@ -122,11 +122,6 @@ protected:
*/
void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling);
/**
*/
nsresult AddFrame(const nsHTMLReflowState& aReflowState,
nsIFrame * aAddedFrame);
nsFrameList mFrames;
nsFrameList mOverflowFrames;
};

View File

@ -25,11 +25,14 @@
/////////////////////////////////////////////////////////////////////////////
// Structure that represents a node in the DST
// Constructor
inline nsDST::Node::Node(void* aKey, void* aValue)
: mKey(aKey), mValue(aValue), mLeft(0), mRight(0)
{
}
// Helper function that returns TRUE if the node is a leaf (i.e., no left or
// right child), and FALSE otherwise
inline int nsDST::Node::IsLeaf() const
{
return !mLeft && !mRight;
@ -47,18 +50,23 @@ inline void* nsDST::Node::operator new(size_t aSize, NodeArena& aArena)
#define NS_DST_ARENA_BLOCK_SIZE 1024
// Constructor
nsDST::NodeArena::NodeArena()
: mFreeList(0)
{
PL_INIT_ARENA_POOL(&mPool, "DSTNodeArena", NS_DST_ARENA_BLOCK_SIZE);
}
// Destructor
nsDST::NodeArena::~NodeArena()
{
// Free the arena in the pool and finish using it
PL_FinishArenaPool(&mPool);
}
// Called by the nsDST::Node's overloaded placement operator when allocating
// a new node. First checks the free list. If the free list is empty, then
// it allocates memory from the arena
void*
nsDST::NodeArena::AllocNode(size_t aSize)
{
@ -74,6 +82,8 @@ nsDST::NodeArena::AllocNode(size_t aSize)
return p;
}
// Called by the DST's DestroyNode() function. Adds the node to the head
// of the free list where it can be reused by AllocateNode()
void
nsDST::NodeArena::FreeNode(void* p)
{
@ -85,26 +95,33 @@ nsDST::NodeArena::FreeNode(void* p)
mFreeList = (Node*)p;
}
// Called by the DST's Clear() function when we want to free the memory
// in the arena pool, but continue using the arena
void
nsDST::NodeArena::FreeArenaPool()
{
// Free the arena in the pool, but continue using it
PL_FreeArenaPool(&mPool);
// Clear the free list
mFreeList = 0;
}
/////////////////////////////////////////////////////////////////////////////
// Digital search tree for doing a radix-search of pointer-based keys
// Constructor
nsDST::nsDST(PtrBits aLevelZeroBit)
: mRoot(0), mLevelZeroBit(aLevelZeroBit)
{
}
// Destructor
nsDST::~nsDST()
{
}
// Removes all nodes from the tree
void
nsDST::Clear()
{
@ -112,6 +129,9 @@ nsDST::Clear()
mRoot = 0;
}
// Adds a new key to the tree. If the specified key is already in the
// tree, then the existing value is replaced by the new value. Returns
// the old value, or NULL if this is a new key
void*
nsDST::Insert(void* aKey, void* aValue)
{
@ -160,6 +180,8 @@ keepLooking:
}
}
// Called by Remove() to destroy a node. Explicitly calls the destructor
// and then asks the memory arena to free the memory
inline void
nsDST::DestroyNode(Node* aNode)
{
@ -167,6 +189,8 @@ nsDST::DestroyNode(Node* aNode)
mArena.FreeNode(aNode); // free memory
}
// Removes a key from the tree. Returns the current value, or NULL if
// the key is not in the tree
void*
nsDST::Remove(void* aKey)
{
@ -209,6 +233,8 @@ nsDST::Remove(void* aKey)
return 0;
}
// Searches the tree for a node with the specified key. Return the value
// or NULL if the key is not in the tree
void*
nsDST::Search(void* aKey) const
{
@ -226,7 +252,7 @@ nsDST::Search(void* aKey) const
}
// Non-recursive search function. Returns a pointer to the pointer to the
// node
// node. Called by Search(), Insert(), and Remove()
nsDST::Node**
nsDST::SearchTree(void* aKey) const
{
@ -248,6 +274,7 @@ nsDST::SearchTree(void* aKey) const
} else {
result = &(*result)->mRight;
}
// Move to the next bit in the key
bitMask <<= 1;
}
@ -256,6 +283,9 @@ nsDST::SearchTree(void* aKey) const
}
#ifdef NS_DEBUG
// Helper function used to verify the integrity of the tree. Does a
// depth-first search of the tree looking for a node with the specified
// key. Called by Search() if we don't find the key using the radix-search
nsDST::Node*
nsDST::DepthFirstSearch(Node* aNode, void* aKey) const
{
@ -274,7 +304,8 @@ nsDST::DepthFirstSearch(Node* aNode, void* aKey) const
}
}
// Helper function that verifies the integrity of the tree
// Helper function that verifies the integrity of the tree. Called
// by Insert() and Remove()
void
nsDST::VerifyTree(Node* aNode, int aLevel, PtrBits aLevelKeyBits) const
{

View File

@ -264,29 +264,8 @@ nsFrame::AppendFrames(nsIPresContext& aPresContext,
nsIAtom* aListName,
nsIFrame* aFrameList)
{
#if 0
NS_PRECONDITION(PR_FALSE, "not a container");
return NS_ERROR_UNEXPECTED;
#else
#ifdef NS_DEBUG
nsFrameList tmp(aFrameList);
tmp.VerifyParent(this);
#endif
// XXX temporary code until frame containers stop using the old
// reflow command api's
nsIReflowCommand* reflowCmd = nsnull;
nsresult rv;
rv = NS_NewHTMLReflowCommand(&reflowCmd, this,
nsIReflowCommand::FrameAppended,
aFrameList);
if (NS_SUCCEEDED(rv)) {
if (nsnull != aListName) {
reflowCmd->SetChildListName(aListName);
}
aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
#endif
}
NS_IMETHODIMP
@ -296,37 +275,8 @@ nsFrame::InsertFrames(nsIPresContext& aPresContext,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList)
{
#if 0
NS_PRECONDITION(PR_FALSE, "not a container");
return NS_ERROR_UNEXPECTED;
#else
#ifdef NS_DEBUG
nsFrameList tmp(aFrameList);
tmp.VerifyParent(this);
#endif
// XXX temporary code until frame containers stop using the old
// reflow command api's
// By default, the reflow command is aimed at the first-in-flow. We
// map that to the flow block that contains aPrevFrame for
// compatability.
nsIFrame* target = this;
if (nsnull != aPrevFrame) {
aPrevFrame->GetParent(&target);
}
nsIReflowCommand* reflowCmd = nsnull;
nsresult rv;
rv = NS_NewHTMLReflowCommand(&reflowCmd, target, aFrameList, aPrevFrame);
if (NS_SUCCEEDED(rv)) {
if (nsnull != aListName) {
reflowCmd->SetChildListName(aListName);
}
aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
#endif
}
NS_IMETHODIMP
@ -335,40 +285,8 @@ nsFrame::RemoveFrame(nsIPresContext& aPresContext,
nsIAtom* aListName,
nsIFrame* aOldFrame)
{
#if 0
NS_PRECONDITION(PR_FALSE, "not a container");
return NS_ERROR_UNEXPECTED;
#else
#ifdef NS_DEBUG
nsIFrame* parent;
aOldFrame->GetParent(&parent);
NS_ASSERTION(parent == this, "bad child parent");
#endif
// XXX temporary code until frame containers stop using the old
// reflow command api's
// By default, the reflow command is aimed at the first-in-flow. We
// map that to the flow block that contains aPrevFrame for
// compatability.
nsIFrame* target = this;
if (nsnull != aOldFrame) {
aOldFrame->GetParent(&target);
}
nsIReflowCommand* reflowCmd = nsnull;
nsresult rv;
rv = NS_NewHTMLReflowCommand(&reflowCmd, target,
nsIReflowCommand::FrameRemoved,
aOldFrame);
if (NS_SUCCEEDED(rv)) {
if (nsnull != aListName) {
reflowCmd->SetChildListName(aListName);
}
aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
#endif
}
NS_IMETHODIMP
@ -378,6 +296,7 @@ nsFrame::ReplaceFrame(nsIPresContext& aPresContext,
nsIFrame* aOldFrame,
nsIFrame* aNewFrame)
{
NS_PRECONDITION(PR_FALSE, "not a container");
return NS_ERROR_UNEXPECTED;
}
@ -1060,6 +979,40 @@ nsFrame::DidReflow(nsIPresContext& aPresContext,
mView->GetViewManager(vm);
vm->ResizeView(mView, mRect.width, mRect.height);
vm->MoveViewTo(mView, origin.x, origin.y);
// Clip applies to block-level and replaced elements with overflow
// set to other than 'visible'
const nsStyleDisplay* display =
(const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
if (display->IsBlockLevel()) {
if (display->mOverflow == NS_STYLE_OVERFLOW_HIDDEN) {
nscoord left, top, right, bottom;
// Start with the 'auto' values and then factor in user
// specified values
left = top = 0;
right = mRect.width;
bottom = mRect.height;
if (0 == (NS_STYLE_CLIP_TOP_AUTO & display->mClipFlags)) {
top += display->mClip.top;
}
if (0 == (NS_STYLE_CLIP_RIGHT_AUTO & display->mClipFlags)) {
right -= display->mClip.right;
}
if (0 == (NS_STYLE_CLIP_BOTTOM_AUTO & display->mClipFlags)) {
bottom -= display->mClip.bottom;
}
if (0 == (NS_STYLE_CLIP_LEFT_AUTO & display->mClipFlags)) {
left += display->mClip.left;
}
mView->SetClip(left, top, right, bottom);
} else {
// Make sure no clip is set
mView->SetClip(0, 0, 0, 0);
}
}
NS_RELEASE(vm);
}
}

View File

@ -357,11 +357,4 @@ NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult,
nsIFrame* aChildFrame = nsnull,
nsIAtom* aAttribute = nsnull);
/** Create a new HTML 'FrameInserted' reflow command */
extern nsresult
NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult,
nsIFrame* aTargetFrame,
nsIFrame* aChildFrame,
nsIFrame* aPrevSiblingFrame);
#endif /* nsHTMLParts_h___ */

View File

@ -48,25 +48,6 @@ NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult,
return cmd->QueryInterface(kIReflowCommandIID, (void**)aInstancePtrResult);
}
nsresult
NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult,
nsIFrame* aTargetFrame,
nsIFrame* aChildFrame,
nsIFrame* aPrevSiblingFrame)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
nsHTMLReflowCommand* cmd = new nsHTMLReflowCommand(aTargetFrame, aChildFrame,
aPrevSiblingFrame);
if (nsnull == cmd) {
return NS_ERROR_OUT_OF_MEMORY;
}
return cmd->QueryInterface(kIReflowCommandIID, (void**)aInstancePtrResult);
}
// Construct a reflow command given a target frame, reflow command type,
// and optional child frame
nsHTMLReflowCommand::nsHTMLReflowCommand(nsIFrame* aTargetFrame,
@ -84,16 +65,6 @@ nsHTMLReflowCommand::nsHTMLReflowCommand(nsIFrame* aTargetFrame,
NS_INIT_REFCNT();
}
nsHTMLReflowCommand::nsHTMLReflowCommand(nsIFrame* aTargetFrame,
nsIFrame* aChildFrame,
nsIFrame* aPrevSiblingFrame)
: mType(FrameInserted), mTargetFrame(aTargetFrame), mChildFrame(aChildFrame),
mPrevSiblingFrame(aPrevSiblingFrame), mAttribute(nsnull), mListName(nsnull)
{
NS_PRECONDITION(mTargetFrame != nsnull, "null target frame");
NS_INIT_REFCNT();
}
nsHTMLReflowCommand::~nsHTMLReflowCommand()
{
NS_IF_RELEASE(mAttribute);

View File

@ -38,15 +38,6 @@ public:
nsIFrame* aChildFrame = nsnull,
nsIAtom* aAttribute = nsnull);
/**
* Construct an HTML reflow command of type FrameInserted, with target
* frame aTargetFrame, and with the specified child and previous sibling
* frames.
*/
nsHTMLReflowCommand(nsIFrame* aTargetFrame,
nsIFrame* aChildFrame,
nsIFrame* aPrevSiblingFrame);
virtual ~nsHTMLReflowCommand();
// nsISupports

View File

@ -722,21 +722,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.ascent=aDesiredSize.height;
aDesiredSize.descent=0;
// if we got this far with an incremental reflow, the reflow was targeted
// at the cell's content. We should only have to redo pass1 for this cell
// then rebalance columns. The pass1 is handled by the cell's parent row.
// So here all we have to do is tell the table to rebalance.
if (eReflowReason_Incremental == aReflowState.reason)
{
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
{
tableFrame->InvalidateColumnWidths();
}
}
#ifdef NS_DEBUG
//PostReflowCheck(result);
#endif

View File

@ -2090,7 +2090,7 @@ nsTableFrame::GetSkipSides() const
return skip;
}
PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize)
PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState)
{
PRBool result = PR_TRUE;
@ -2115,49 +2115,60 @@ PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const ns
//
// Slides all the row groups following aKidFrame by the specified
// amount
//
// XXX This is kind of klunky because the InnerTableReflowState::y
// data member does not include the table's border/padding...
nsresult nsTableFrame::AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
InnerTableReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY)
{
NS_PRECONDITION(NS_UNCONSTRAINEDSIZE == aReflowState.reflowState.availableHeight,
"not in galley mode");
nsIFrame* lastKidFrame = aKidFrame;
"we're not in galley mode");
if (aDeltaY != 0) {
// Move the frames that follow aKidFrame by aDeltaY
// If it's the footer that was reflowed, then we don't need to adjust any of
// the frames, because the footer is the bottom most frame
if (aKidFrame != aReflowState.footerFrame) {
nsIFrame* kidFrame;
aKidFrame->GetNextSibling(&kidFrame);
while (nsnull != kidFrame) {
nsPoint origin;
nsIHTMLReflow* htmlReflow;
nsRect kidRect;
PRBool movedFooter = PR_FALSE;
// XXX We can't just slide the child if it has a next-in-flow
kidFrame->GetOrigin(origin);
origin.y += aDeltaY;
// XXX We need to send move notifications to the frame...
if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->WillReflow(aPresContext);
// Move the frames that follow aKidFrame by aDeltaY, and update the running
// y-offset
for (aKidFrame->GetNextSibling(&kidFrame); kidFrame; kidFrame->GetNextSibling(&kidFrame)) {
// See if it's the footer we're moving
if (kidFrame == aReflowState.footerFrame) {
movedFooter = PR_TRUE;
}
// Get the frame's bounding rect
kidFrame->GetRect(kidRect);
// Adjust the running y-offset
aReflowState.y += kidRect.height;
// Adjust the y-origin if its position actually changed
if (aDeltaY != 0) {
kidRect.y += aDeltaY;
kidFrame->MoveTo(kidRect.x, kidRect.y);
}
}
// We also need to move the footer if there is one and we haven't already
// moved it
if (aReflowState.footerFrame && !movedFooter) {
aReflowState.footerFrame->GetRect(kidRect);
// Adjust the running y-offset
aReflowState.y += kidRect.height;
if (aDeltaY != 0) {
kidRect.y += aDeltaY;
aReflowState.footerFrame->MoveTo(kidRect.x, kidRect.y);
}
kidFrame->MoveTo(origin.x, origin.y);
// Get the next frame
lastKidFrame = kidFrame;
kidFrame->GetNextSibling(&kidFrame);
}
} else {
// Get the last frame
lastKidFrame = mFrames.LastChild();
}
// Update our running y-offset to reflect the bottommost child
nsRect rect;
lastKidFrame->GetRect(rect);
aReflowState.y = rect.YMost();
return NS_OK;
}
@ -2253,7 +2264,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
}
// NeedsReflow and IsFirstPassValid take into account reflow type = Initial_Reflow
if (PR_TRUE==NeedsReflow(aReflowState, nsSize(aReflowState.availableWidth, aReflowState.availableHeight)))
if (PR_TRUE==NeedsReflow(aReflowState))
{
PRBool needsRecalc=PR_FALSE;
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: needs reflow\n");
@ -2938,6 +2949,240 @@ NS_METHOD nsTableFrame::GetBorderPlusMarginPadding(nsMargin& aResult)
return NS_OK;
}
// Sets the starting column index for aColGroupFrame and the siblings frames that
// follow
void
nsTableFrame::SetStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame,
PRInt32 aIndex)
{
while (aColGroupFrame) {
aIndex += aColGroupFrame->SetStartColumnIndex(aIndex);
aColGroupFrame->GetNextSibling((nsIFrame**)&aColGroupFrame);
}
}
// Calculate the starting column index to use for the specified col group frame
PRInt32
nsTableFrame::CalculateStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame)
{
PRInt32 index = 0;
for (nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame*)mColGroups.FirstChild();
colGroupFrame && (colGroupFrame != aColGroupFrame);
colGroupFrame->GetNextSibling((nsIFrame**)&colGroupFrame))
{
index += colGroupFrame->GetColumnCount();
}
return index;
}
NS_IMETHODIMP
nsTableFrame::AppendFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aFrameList)
{
PRInt32 startingColIndex = -1;
// Because we actually have two child lists, one for col group frames and one
// for everything else, we need to look at each frame individually
nsIFrame* f = aFrameList;
while (f) {
nsIFrame* next;
// Get the next frame and disconnect this frame from its sibling
f->GetNextSibling(&next);
f->SetNextSibling(nsnull);
// See what kind of frame we have
const nsStyleDisplay *display;
f->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) {
// Append the new col group frame
mColGroups.AppendFrame(nsnull, f);
// Set its starting column index
if (-1 == startingColIndex) {
startingColIndex = CalculateStartingColumnIndexFor((nsTableColGroupFrame*)f);
}
((nsTableColGroupFrame*)f)->SetStartColumnIndex(startingColIndex);
startingColIndex += ((nsTableColGroupFrame *)f)->GetColumnCount();
} else if (IsRowGroup(display->mDisplay)) {
// Append the new row group frame
mFrames.AppendFrame(nsnull, f);
// Add the content of the row group to the cell map
DidAppendRowGroup((nsTableRowGroupFrame*)f);
} else {
// Nothing special to do, just add the frame to our child list
mFrames.AppendFrame(nsnull, f);
}
// Move to the next frame
f = next;
}
// We'll need to do a pass-1 layout of all cells in all the rows of the
// rowgroup
InvalidateFirstPassCache();
// If we've added any columns, we need to rebuild the column cache.
InvalidateColumnCache();
// Because the number of columns may have changed invalidate the column
// cache. Note that this has the side effect of recomputing the column
// widths, so we don't need to call InvalidateColumnWidths()
InvalidateColumnWidths();
// Mark the table as dirty and generate a reflow command targeted at the
// outer table frame
nsIReflowCommand* reflowCmd;
nsresult rv;
mState |= NS_FRAME_IS_DIRTY;
rv = NS_NewHTMLReflowCommand(&reflowCmd, mParent, nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
// Add the reflow command
rv = aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
}
NS_IMETHODIMP
nsTableFrame::InsertFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList)
{
// Asssume there's only one frame being inserted. The problem is that
// row group frames and col group frames go in separate child lists and
// so if there's more than one this gets messy...
// XXX The frame construction code should be separating out child frames
// based on the type...
nsIFrame* nextSibling;
aFrameList->GetNextSibling(&nextSibling);
NS_PRECONDITION(!nextSibling, "expected only one child frame");
// See what kind of frame we have
const nsStyleDisplay *display=nsnull;
aFrameList->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) {
// Insert the column group frame
mColGroups.InsertFrame(nsnull, aPrevFrame, aFrameList);
// Set its starting column index and adjust the index of the
// col group frames that follow
SetStartingColumnIndexFor((nsTableColGroupFrame*)aFrameList,
CalculateStartingColumnIndexFor((nsTableColGroupFrame*)aFrameList));
} else if (IsRowGroup(display->mDisplay)) {
// Insert the frame
mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList);
// We'll need to do a pass-1 layout of all cells in all the rows of the
// rowgroup
InvalidateFirstPassCache();
// We need to rebuild the cell map, because currently we can't insert
// new frames except at the end (append)
InvalidateCellMap();
} else {
// Just insert the frame and don't worry about reflowing it
mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList);
return NS_OK;
}
// If we've added any columns, we need to rebuild the column cache.
InvalidateColumnCache();
// Because the number of columns may have changed invalidate the column
// cache. Note that this has the side effect of recomputing the column
// widths, so we don't need to call InvalidateColumnWidths()
InvalidateColumnWidths();
// Mark the table as dirty and generate a reflow command targeted at the
// outer table frame
nsIReflowCommand* reflowCmd;
nsresult rv;
mState |= NS_FRAME_IS_DIRTY;
rv = NS_NewHTMLReflowCommand(&reflowCmd, mParent, nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
// Add the reflow command
rv = aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
}
NS_IMETHODIMP
nsTableFrame::RemoveFrame(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame)
{
// See what kind of frame we have
const nsStyleDisplay *display=nsnull;
aOldFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) {
nsIFrame* nextColGroupFrame;
aOldFrame->GetNextSibling(&nextColGroupFrame);
// Remove the col group frame
mColGroups.DestroyFrame(aPresContext, aOldFrame);
// Adjust the starting column index of the frames that follow
SetStartingColumnIndexFor((nsTableColGroupFrame*)nextColGroupFrame,
CalculateStartingColumnIndexFor((nsTableColGroupFrame*)nextColGroupFrame));
} else if (IsRowGroup(display->mDisplay)) {
mFrames.DestroyFrame(aPresContext, aOldFrame);
// We need to rebuild the cell map, because currently we can't incrementally
// remove rows
InvalidateCellMap();
} else {
// Just remove the frame
mFrames.DestroyFrame(aPresContext, aOldFrame);
return NS_OK;
}
// Because the number of columns may have changed invalidate the column
// cache. Note that this has the side effect of recomputing the column
// widths, so we don't need to call InvalidateColumnWidths()
InvalidateColumnCache();
// Because the number of columns may have changed invalidate the column
// cache. Note that this has the side effect of recomputing the column
// widths, so we don't need to call InvalidateColumnWidths()
InvalidateColumnWidths();
// Mark the table as dirty and generate a reflow command targeted at the
// outer table frame
nsIReflowCommand* reflowCmd;
nsresult rv;
mState |= NS_FRAME_IS_DIRTY;
rv = NS_NewHTMLReflowCommand(&reflowCmd, mParent, nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
// Add the reflow command
rv = aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
}
NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
@ -2946,13 +3191,23 @@ NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
if (PR_TRUE==gsDebugIR) printf("\nTIF IR: IncrementalReflow\n");
nsresult rv = NS_OK;
// Constrain our reflow width to the computed table width. Note: this is
// based on the width of the first-in-flow
nsHTMLReflowState reflowState(aReflowState);
PRInt32 pass1Width = mRect.width;
if (mPrevInFlow) {
nsTableFrame* table = (nsTableFrame*)GetFirstInFlow();
pass1Width = table->mRect.width;
}
reflowState.availableWidth = pass1Width;
nsMargin borderPadding;
GetBorderPlusMarginPadding(borderPadding);
InnerTableReflowState state(aPresContext, aReflowState, borderPadding);
InnerTableReflowState state(aPresContext, reflowState, borderPadding);
// determine if this frame is the target or not
nsIFrame *target=nsnull;
rv = aReflowState.reflowCommand->GetTarget(target);
rv = reflowState.reflowCommand->GetTarget(target);
if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target))
{
// this is the target if target is either this or the outer table frame containing this inner frame
@ -2964,10 +3219,9 @@ NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
{
// Get the next frame in the reflow chain
nsIFrame* nextFrame;
aReflowState.reflowCommand->GetNext(nextFrame);
reflowState.reflowCommand->GetNext(nextFrame);
// Recover our reflow state
//RecoverState(state, nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, state, aStatus, nextFrame);
}
}
@ -2991,73 +3245,6 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
if (PR_TRUE==gsDebugIR) printf("TIF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameInserted :
NS_ASSERTION(nsnull!=objectFrame, "bad objectFrame");
NS_ASSERTION(nsnull!=childDisplay, "bad childDisplay");
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColGroupFrame*)objectFrame, PR_FALSE);
}
else if (IsRowGroup(childDisplay->mDisplay))
{
rv = IR_RowGroupInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
GetRowGroupFrameFor(objectFrame, childDisplay), PR_FALSE);
}
else
{
rv = AddFrame(aReflowState.reflowState, objectFrame);
}
break;
case nsIReflowCommand::FrameAppended :
if (!objectFrame)
break;
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupAppended(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColGroupFrame*)objectFrame);
}
else if (IsRowGroup(childDisplay->mDisplay))
{
rv = IR_RowGroupAppended(aPresContext, aDesiredSize, aReflowState, aStatus,
GetRowGroupFrameFor(objectFrame, childDisplay));
}
else
{ // no optimization to be done for Unknown frame types, so just reuse the Inserted method
rv = AddFrame(aReflowState.reflowState, objectFrame);
}
break;
/*
case nsIReflowCommand::FrameReplaced :
NS_ASSERTION(nsnull!=objectFrame, "bad objectFrame");
NS_ASSERTION(nsnull!=childDisplay, "bad childDisplay");
*/
case nsIReflowCommand::FrameRemoved :
if (!objectFrame)
break;
NS_ASSERTION(nsnull!=childDisplay, "bad childDisplay");
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColGroupFrame*)objectFrame);
}
else if (IsRowGroup(childDisplay->mDisplay))
{
rv = IR_RowGroupRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
GetRowGroupFrameFor(objectFrame, childDisplay));
}
else
{
rv = mFrames.DestroyFrame(aPresContext, objectFrame);
}
break;
case nsIReflowCommand::StyleChanged :
rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus);
break;
@ -3067,12 +3254,8 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
rv = NS_ERROR_ILLEGAL_VALUE;
break;
case nsIReflowCommand::PullupReflow:
case nsIReflowCommand::PushReflow:
case nsIReflowCommand::CheckPullupReflow :
case nsIReflowCommand::UserDefined :
default:
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
NS_NOTYETIMPLEMENTED("unexpected reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TIF IR: reflow command not implemented.\n");
break;
@ -3081,187 +3264,6 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aInsertedFrame,
PRBool aReplace)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_ColGroupInserted for frame %p\n", aInsertedFrame);
nsresult rv=NS_OK;
PRBool adjustStartingColIndex=PR_FALSE;
PRInt32 startingColIndex=0;
// find out what frame to insert aInsertedFrame after
nsIFrame *frameToInsertAfter=nsnull;
rv = aReflowState.reflowState.reflowCommand->GetPrevSiblingFrame(frameToInsertAfter);
// insert aInsertedFrame as the first child. Set its start col index to 0
if (nsnull==frameToInsertAfter)
{
mColGroups.InsertFrame(nsnull, nsnull, aInsertedFrame);
startingColIndex += aInsertedFrame->SetStartColumnIndex(0);
adjustStartingColIndex=PR_TRUE;
}
nsIFrame *childFrame=mColGroups.FirstChild();
nsIFrame *prevSib=nsnull;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
if ((nsnull!=frameToInsertAfter) && (childFrame==frameToInsertAfter))
{
nsIFrame *nextSib=nsnull;
frameToInsertAfter->GetNextSibling(&nextSib);
aInsertedFrame->SetNextSibling(nextSib);
frameToInsertAfter->SetNextSibling(aInsertedFrame);
// account for childFrame being a COLGROUP now
if (PR_FALSE==adjustStartingColIndex) // we haven't gotten to aDeletedFrame yet
startingColIndex += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
// skip ahead to aInsertedFrame, since we just handled the frame we inserted after
childFrame=aInsertedFrame;
adjustStartingColIndex=PR_TRUE; // now that we've inserted aInsertedFrame,
// start adjusting subsequent col groups' starting col index including aInsertedFrame
}
if (PR_FALSE==adjustStartingColIndex) // we haven't gotten to aDeletedFrame yet
startingColIndex += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
else // we've removed aDeletedFrame, now adjust the starting col index of all subsequent col groups
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
prevSib=childFrame;
rv = childFrame->GetNextSibling(&childFrame);
}
InvalidateColumnCache();
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, skip invalidating the first passs
// if so, and we can fix the first pass info
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aAppendedFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_ColGroupAppended for frame %p\n", aAppendedFrame);
nsresult rv=NS_OK;
PRInt32 startingColIndex=0;
nsIFrame *childFrame=mColGroups.FirstChild();
nsIFrame *lastChild=childFrame;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
startingColIndex += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
lastChild=childFrame;
rv = childFrame->GetNextSibling(&childFrame);
}
// append aAppendedFrame
if (nsnull!=lastChild)
lastChild->SetNextSibling(aAppendedFrame);
else
mColGroups.SetFrames(aAppendedFrame);
aAppendedFrame->SetStartColumnIndex(startingColIndex);
#if 0
we would only want to do this if manufactured col groups were invisible to the DOM. Since they
currently are visible, they should behave just as if they were content-backed "real" colgroups
If this decision is changed, the code below is a half-finished attempt to rationalize the situation.
It requires having built a list of the colGroups before we get to this point.
// look at the last col group. If it is implicit, and it's cols are implicit, then
// it and its cols were manufactured for table layout.
// Delete it if possible, otherwise move it to the end of the list
if (0<colGroupCount)
{
nsTableColGroupFrame *colGroup = (nsTableColGroupFrame *)(colGroupList.ElementAt(colGroupCount-1));
if (PR_TRUE==colGroup->IsManufactured())
{ // account for the new COLs that were added in aAppendedFrame
// first, try to delete the implicit colgroup
// if we couldn't delete it, move the implicit colgroup to the end of the list
// and adjust it's col indexes
nsIFrame *colGroupNextSib;
colGroup->GetNextSibling(colGroupNextSib);
childFrame=mColGroups.FirstChild();
nsIFrame * prevSib=nsnull;
rv = NS_OK;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
if (childFrame==colGroup)
{
if (nsnull!=prevSib) // colGroup is in the middle of the list, remove it
prevSib->SetNextSibling(colGroupNextSib);
else // colGroup was the first child, so set it's next sib to first child
mColGroups.SetFrames(colGroupNextSib);
aAppendedFrame->SetNextSibling(colGroup); // place colGroup at the end of the list
colGroup->SetNextSibling(nsnull);
break;
}
prevSib=childFrame;
rv = childFrame->GetNextSibling(childFrame);
}
}
}
#endif
InvalidateColumnCache();
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, skip invalidating the first passs
// if so, and we can fix the first pass info
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aDeletedFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_ColGroupRemoved for frame %p\n", aDeletedFrame);
nsresult rv=NS_OK;
PRBool adjustStartingColIndex=PR_FALSE;
PRInt32 startingColIndex=0;
nsIFrame *childFrame=mColGroups.FirstChild();
nsIFrame *prevSib=nsnull;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
if (childFrame==aDeletedFrame)
{
nsIFrame *deleteFrameNextSib=nsnull;
aDeletedFrame->GetNextSibling(&deleteFrameNextSib);
if (nsnull!=prevSib)
prevSib->SetNextSibling(deleteFrameNextSib);
else
mColGroups.SetFrames(deleteFrameNextSib);
childFrame=deleteFrameNextSib;
if (nsnull==childFrame)
break;
adjustStartingColIndex=PR_TRUE; // now that we've removed aDeletedFrame, start adjusting subsequent col groups' starting col index
}
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
if (PR_FALSE==adjustStartingColIndex) // we haven't gotten to aDeletedFrame yet
startingColIndex += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
else // we've removed aDeletedFrame, now adjust the starting col index of all subsequent col groups
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
}
prevSib=childFrame;
rv = childFrame->GetNextSibling(&childFrame);
}
InvalidateColumnCache();
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, skip invalidating the first passs
// if so, and we can fix the first pass info
return rv;
}
NS_METHOD nsTableFrame::IR_StyleChanged(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -3277,85 +3279,69 @@ NS_METHOD nsTableFrame::IR_StyleChanged(nsIPresContext& aPresContext,
return rv;
}
NS_METHOD nsTableFrame::IR_RowGroupInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aInsertedFrame,
PRBool aReplace)
// Recovers the reflow state to what it should be if aKidFrame is about
// to be reflowed. Restores the following:
// - availSize
// - y
// - footerFrame
// - firstBodySection
//
// In the case of the footer frame the y-offset is set to its current
// y-offset. Note that this is different from resize reflow when the
// footer is positioned higher up and then moves down as each row
// group frame is relowed
//
// XXX This is kind of klunky because the InnerTableReflowState::y
// data member does not include the table's border/padding...
nsresult
nsTableFrame::RecoverState(InnerTableReflowState& aReflowState,
nsIFrame* aKidFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_RowGroupInserted for frame %p\n", aInsertedFrame);
nsresult rv = AddFrame(aReflowState.reflowState, aInsertedFrame);
if (NS_FAILED(rv))
return rv;
// do a pass-1 layout of all the cells in all the rows of the rowgroup
rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState.reflowState, aStatus,
aInsertedFrame, eReflowReason_Initial, PR_FALSE);
if (NS_FAILED(rv))
return rv;
// Walk the list of children looking for aKidFrame
for (nsIFrame* frame = mFrames.FirstChild(); frame; frame->GetNextSibling(&frame)) {
// If this is a footer row group, remember it
const nsStyleDisplay *display;
frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
InvalidateCellMap();
InvalidateColumnCache();
// We only allow a single footer frame, and the footer frame must occur before
// any body section row groups
if ((NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == display->mDisplay) &&
!aReflowState.footerFrame && !aReflowState.firstBodySection) {
aReflowState.footerFrame = frame;
} else if ((NS_STYLE_DISPLAY_TABLE_ROW_GROUP == display->mDisplay) &&
!aReflowState.firstBodySection) {
aReflowState.firstBodySection = frame;
}
// See if this is the frame we're looking for
if (frame == aKidFrame) {
// If it's the footer, then keep going because the footer is at the
// very bottom
if (frame != aReflowState.footerFrame) {
break;
}
}
return rv;
// Get the frame's height
nsSize kidSize;
frame->GetSize(kidSize);
// If our height is constrained then update the available height. Do
// this for all frames including the footer frame
if (PR_FALSE == aReflowState.unconstrainedHeight) {
aReflowState.availSize.height -= kidSize.height;
}
// Update the running y-offset. Don't do this for the footer frame
if (frame != aReflowState.footerFrame) {
aReflowState.y += kidSize.height;
}
}
return NS_OK;
}
// since we know we're doing an append here, we can optimize
NS_METHOD nsTableFrame::IR_RowGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aAppendedFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_RowGroupAppended for frame %p\n", aAppendedFrame);
// hook aAppendedFrame into the child list
nsresult rv = AddFrame(aReflowState.reflowState, aAppendedFrame);
if (NS_FAILED(rv))
return rv;
// account for the cells in the rows that are children of aAppendedFrame
// this will add the content of the rowgroup to the cell map
rv = DidAppendRowGroup(aAppendedFrame);
if (NS_FAILED(rv))
return rv;
// do a pass-1 layout of all the cells in all the rows of the rowgroup
rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState.reflowState, aStatus,
aAppendedFrame, eReflowReason_Initial, PR_TRUE);
if (NS_FAILED(rv))
return rv;
// if we've added any columns, we need to rebuild the column cache
// XXX: it would be nice to have a mechanism to just extend the column cache, rather than rebuild it completely
InvalidateColumnCache();
// if any column widths have to change due to this, rebalance column widths
//XXX need to calculate this, but for now just do it
InvalidateColumnWidths();
return rv;
}
NS_METHOD nsTableFrame::IR_RowGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aDeletedFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_RowGroupRemoved for frame %p\n", aDeletedFrame);
nsresult rv = mFrames.DestroyFrame(aPresContext, aDeletedFrame);
InvalidateCellMap();
InvalidateColumnCache();
// if any column widths have to change due to this, rebalance column widths
//XXX need to calculate this, but for now just do it
InvalidateColumnWidths();
return rv;
}
NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -3365,6 +3351,8 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
{
nsresult rv;
if (PR_TRUE==gsDebugIR) printf("\nTIF IR: IR_TargetIsChild\n");
// Recover the state as if aNextFrame is about to be reflowed
RecoverState(aReflowState, aNextFrame);
// Remember the old rect
nsRect oldKidRect;
@ -3372,24 +3360,31 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
// Pass along the reflow command
nsHTMLReflowMetrics desiredSize(nsnull);
// XXX Correctly compute the available space...
nsSize availSpace(aReflowState.reflowState.availableWidth, aReflowState.reflowState.availableHeight);
nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
aNextFrame, availSpace);
aNextFrame, aReflowState.availSize);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Resize the row group frame
nsRect kidRect;
aNextFrame->GetRect(kidRect);
aNextFrame->SizeTo(desiredSize.width, desiredSize.height);
// Place the row group frame. Don't use PlaceChild(), because it moves
// the footer frame as well. We'll adjust the footer frame later on in
// AdjustSiblingsAfterReflow()
nscoord x = aReflowState.mBorderPadding.left;
nscoord y = aReflowState.mBorderPadding.top + aReflowState.y;
nsRect kidRect(x, y, desiredSize.width, desiredSize.height);
aNextFrame->SetRect(kidRect);
// Adjust the running y-offset
aReflowState.y += kidRect.height;
// If our height is constrained, then update the available height
if (PR_FALSE == aReflowState.unconstrainedHeight) {
aReflowState.availSize.height -= kidRect.height;
}
// If the column width info is valid, then adjust the row group frames
// that follow. Otherwise, return and we'll recompute the column widths
// and reflow all the row group frames
if (!NeedsReflow(aReflowState.reflowState,
nsSize(aReflowState.reflowState.availableWidth,
aReflowState.reflowState.availableHeight))) {
if (!NeedsReflow(aReflowState.reflowState)) {
// Adjust the row groups that follow
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);

View File

@ -95,6 +95,20 @@ public:
/** @see nsIFrame::Destroy */
NS_IMETHOD Destroy(nsIPresContext& aPresContext);
NS_IMETHOD AppendFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aFrameList);
NS_IMETHOD InsertFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList);
NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame);
/** helper method to find the table parent of any table frame object */
// TODO: today, this depends on display types. This should be changed to rely
// on stronger criteria, like an inner table frame atom
@ -439,6 +453,14 @@ protected:
* @return PR_TRUE if this table is nested inside another table.
*/
PRBool IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const;
// Sets the starting column index for aColGroupFrame and the siblings frames that
// follow
void SetStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame,
PRInt32 aIndex);
// Calculate the starting column index to use for the specified col group frame
PRInt32 CalculateStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame);
public:
/** first pass of ResizeReflow.
@ -463,6 +485,9 @@ public:
NS_IMETHOD GetTableSpecifiedHeight(nscoord& aHeight, const nsHTMLReflowState& aReflowState);
virtual PRBool RowGroupsShouldBeConstrained() { return PR_FALSE; }
/** do I need to do a reflow? */
virtual PRBool NeedsReflow(const nsHTMLReflowState& aReflowState);
protected:
/** second pass of ResizeReflow.
* lays out all table content with aMaxSize(computed_table_width, given_table_height)
@ -509,72 +534,6 @@ protected:
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus);
/** process a colgroup inserted notification
* @param aInsertedFrame the new colgroup frame
* @param aReplace PR_TRUE if aInsertedFrame is replacing an existing frame
* Not Yet Implemented.
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_ColGroupInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aInsertedFrame,
PRBool aReplace);
/** process a colgroup appended notification. This method is optimized for append.
* @param aAppendedFrame the new colgroup frame
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_ColGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aAppendedFrame);
/** process a colgroup removed notification.
* @param aDeletedFrame the colgroup frame to remove
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_ColGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aDeletedFrame);
/** process a rowgroup inserted notification
* @param aInsertedFrame the new rowgroup frame
* @param aReplace PR_TRUE if aInsertedFrame is replacing an existing frame
* Not Yet Implemented.
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_RowGroupInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aInsertedFrame,
PRBool aReplace);
/** process a rowgroup appended notification. This method is optimized for append.
* @param aAppendedFrame the new rowgroup frame
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_RowGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aAppendedFrame);
/** process a rowgroup removed notification.
* @param aDeletedFrame the rowgroup frame to remove
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_RowGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aDeletedFrame);
/** process a style chnaged notification.
* @see nsIFrameReflow::Reflow
* TODO: needs to be optimized for which attribute was actually changed.
@ -588,6 +547,9 @@ protected:
InnerTableReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY);
nsresult RecoverState(InnerTableReflowState& aReflowState,
nsIFrame* aKidFrame);
NS_METHOD AdjustForCollapsingRowGroup(nsIFrame* aRowGroupFrame,
PRInt32& aRowX);
@ -676,10 +638,6 @@ protected:
/** sets the width of the table according to the computed widths of each column. */
virtual void SetTableWidth(nsIPresContext& aPresContext);
/** given the new parent size, do I really need to do a reflow? */
virtual PRBool NeedsReflow(const nsHTMLReflowState& aReflowState,
const nsSize& aMaxSize);
/** returns PR_TRUE if the cached pass 1 data is still valid */
virtual PRBool IsFirstPassValid() const;

View File

@ -337,11 +337,11 @@ NS_IMETHODIMP nsTableOuterFrame::SetSelected(nsIDOMRange *aRange,PRBool aSelecte
return result;
}
PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize)
PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState)
{
PRBool result=PR_TRUE;
if (nsnull != mInnerTableFrame) {
result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aReflowState, aMaxSize);
result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aReflowState);
}
return result;
}

View File

@ -126,7 +126,7 @@ protected:
* or if the table style attributes or parent max height/width have
* changed.
*/
PRBool NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize);
PRBool NeedsReflow(const nsHTMLReflowState& aReflowState);
/** position the child frame
* @param aReflowState the state of the reflow process

View File

@ -1373,26 +1373,29 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
// size.
// XXX It would be nice if we could skip this step and the next step if the
// column width isn't dependent on the max cell width...
kidReflowState.reason = eReflowReason_Initial;
kidReflowState.reflowCommand = nsnull;
kidReflowState.availableWidth = NS_UNCONSTRAINEDSIZE;
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (gsDebug)
printf ("TR %p for cell %p Incremental Reflow: desired=%d, MES=%d\n",
this, aNextFrame, desiredSize.width, kidMaxElementSize.width);
// Update the cell layout data.
//XXX: this is a hack, shouldn't it be the case that a min size is
// never larger than a desired size?
if (kidMaxElementSize.width>desiredSize.width)
desiredSize.width = kidMaxElementSize.width;
if (kidMaxElementSize.height>desiredSize.height)
desiredSize.height = kidMaxElementSize.height;
((nsTableCellFrame *)aNextFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)aNextFrame)->SetPass1MaxElementSize(kidMaxElementSize);
// Now reflow the cell again this time constraining the width
// XXX Ignore for now the possibility that the column width has changed...
kidReflowState.availableWidth = availWidth;
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (aReflowState.tableFrame->RequiresPass1Layout()) {
kidReflowState.reason = eReflowReason_Initial;
kidReflowState.reflowCommand = nsnull;
kidReflowState.availableWidth = NS_UNCONSTRAINEDSIZE;
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (gsDebug)
printf ("TR %p for cell %p Incremental Reflow: desired=%d, MES=%d\n",
this, aNextFrame, desiredSize.width, kidMaxElementSize.width);
// Update the cell layout data.
//XXX: this is a hack, shouldn't it be the case that a min size is
// never larger than a desired size?
if (kidMaxElementSize.width>desiredSize.width)
desiredSize.width = kidMaxElementSize.width;
if (kidMaxElementSize.height>desiredSize.height)
desiredSize.height = kidMaxElementSize.height;
((nsTableCellFrame *)aNextFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)aNextFrame)->SetPass1MaxElementSize(kidMaxElementSize);
// Now reflow the cell again this time constraining the width
// XXX Ignore for now the possibility that the column width has changed...
kidReflowState.availableWidth = availWidth;
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
}
// Place the child after taking into account it's margin and attributes
// XXX We need to ask the table (or the table layout strategy) if the column
@ -1434,6 +1437,12 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
SetMaxChildHeight(aReflowState.maxCellHeight, maxCellTopMargin, maxCellBottomMargin);
// If the column widths have changed, then tell the table to rebalance
// the column widths
if (aReflowState.tableFrame->RequiresPass1Layout()) {
aReflowState.tableFrame->InvalidateColumnWidths();
}
// Return our desired size. Note that our desired width is just whatever width
// we were given by the row group frame
aDesiredSize.width = aReflowState.availSize.width;

View File

@ -361,7 +361,6 @@ void nsTableRowGroupFrame::PlaceChild(nsIPresContext& aPresContext,
if (PR_TRUE==aReflowState.firstRow)
{
aReflowState.firstRow = PR_FALSE;
aReflowState.firstRowHeight = aKidRect.height;
if (nsnull != aMaxElementSize) {
aMaxElementSize->width = aKidMaxElementSize.width;
aMaxElementSize->height = aKidMaxElementSize.height;
@ -597,14 +596,15 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
// all table cells have the same top and bottom margins, namely cellSpacingY
nscoord cellSpacingY = tableFrame->GetCellSpacingY();
// iterate children and for each row get its height
// iterate children and for each row get the height of the tallest cell
PRInt32 numRows;
GetRowCount(numRows, PR_FALSE);
PRInt32 *rowHeights = new PRInt32[numRows];
nsCRT::memset (rowHeights, 0, numRows*sizeof(PRInt32));
nscoord *rowHeights = new nscoord[numRows];
nsCRT::memset (rowHeights, 0, numRows*sizeof(nscoord));
/* Step 1: get the height of the tallest cell in the row and save it for
* pass 2
* pass 2. This height is for table cells that originate in this
* row and that don't span into the rows that follow
*/
nsIFrame* rowFrame = GetFirstFrame();
PRInt32 rowIndex = 0;
@ -649,7 +649,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
* If the cell's desired height is the larger value, resize the rows and contained
* cells by an equal percentage of the additional space.
* We go through this loop twice. The first time, we are adjusting cell heights
* and row y-offsets on the fly.
* on the fly.
* The second time through the loop, we're ensuring that subsequent row-spanning cells
* didn't change prior calculations.
* Since we are guaranteed to have found the max height spanners the first time through,
@ -661,6 +661,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
*/
PRInt32 rowGroupHeight;
nscoord deltaY = 0;
for (PRInt32 counter=0; counter<2; counter++)
{
rowGroupHeight = 0;
@ -686,90 +687,96 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex,
(nsTableCellFrame*)cellFrame);
if (rowSpan > 1)
{ // found a cell with rowspan > 1, determine its height
{ // found a cell with rowspan > 1, determine the height of the rows it
// spans
if (gsDebug) printf("TRGF CalcRowH: cell %p has rowspan=%d\n", cellFrame, rowSpan);
nscoord heightOfRowsSpanned = 0;
PRInt32 i;
for (i = 0; i < rowSpan; i++) {
heightOfRowsSpanned += rowHeights[rowIndex + i];
}
// the avail height needs to reduce by top and bottom margins
// reduce the height by top and bottom margins
nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY;
if (gsDebug) printf("TRGF CalcRowH: availHeightOfRowsSpanned=%d\n", availHeightOfRowsSpanned);
/* if the cell height fits in the rows, expand the spanning cell's height and slap it in */
// see if the cell's height fits within the rows it spans. If this is
// pass 1 then use the cell's desired height and not the current height
// of its frame. That way this works for incremental reflow, too
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
if (availHeightOfRowsSpanned > cellFrameSize.height)
if (0 == counter) {
nsSize cellDesiredSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize();
cellFrameSize.height = cellDesiredSize.height;
}
if (availHeightOfRowsSpanned >= cellFrameSize.height)
{
// yes the cell's height fits with the available space of the rows it
// spans. Set the cell frame's height
if (gsDebug) printf("TRGF CalcRowH: spanning cell fits in rows spanned, had h=%d, expanded to %d\n",
cellFrameSize.height, availHeightOfRowsSpanned);
cellFrame->SizeTo(cellFrameSize.width, availHeightOfRowsSpanned);
// Realign cell content based on new height
((nsTableCellFrame*)cellFrame)->VerticallyAlignChild();
}
/* otherwise, distribute the excess height to the rows effected.
* push all subsequent rows down by the total change in height of all the rows above it
*/
else
{
// the cell's height is larger than the available space of the rows it
// spans so distribute the excess height to the rows affected
PRInt32 excessHeight = cellFrameSize.height - availHeightOfRowsSpanned;
if (gsDebug) printf("TRGF CalcRowH: excessHeight=%d\n", excessHeight);
// for every row starting at the row with the spanning cell...
// for every row starting at the row with the spanning cell and down
// to the last row spanned by the cell
nsTableRowFrame *rowFrameToBeResized = (nsTableRowFrame *)rowFrame;
PRInt32 *excessForRow = new PRInt32[numRows];
nsCRT::memset (excessForRow, 0, numRows*sizeof(PRInt32));
nscoord excessAllocated = 0;
for (i = rowIndex; i < numRows; i++) {
for (i = rowIndex; i < (rowIndex + rowSpan); i++) {
if (gsDebug) printf("TRGF CalcRowH: for row index=%d\n", i);
// if the row is within the spanned range, resize the row
if (i < (rowIndex + rowSpan)) {
//float percent = ((float)rowHeights[i]) / ((float)availHeightOfRowsSpanned);
//excessForRow[i] = NSToCoordRound(((float)(excessHeight)) * percent);
float percent = ((float)rowHeights[i]) / ((float)heightOfRowsSpanned);
// give rows their percentage, except the last row gets the remainder
excessForRow[i] = ((i - 1) == (rowIndex + rowSpan))
? excessHeight - excessAllocated
: NSToCoordRound(((float)(excessHeight)) * percent);
excessAllocated += excessForRow[i];
if (gsDebug) printf("TRGF CalcRowH: for row %d, excessHeight=%d from percent %f\n",
i, excessForRow[i], percent);
// update the row height
rowHeights[i] += excessForRow[i];
// The amount of additional space each row gets is based on the
// percentage of space it occupies, i.e. they don't all get the
// same amount of available space
float percent = ((float)rowHeights[i]) / ((float)heightOfRowsSpanned);
// give rows their percentage, except for the last row which gets
// the remainder
nscoord excessForRow = ((i + 1) == (rowIndex + rowSpan)) ?
excessHeight - excessAllocated :
NSToCoordRound(((float)(excessHeight)) * percent);
excessAllocated += excessForRow;
if (gsDebug) printf("TRGF CalcRowH: for row %d, excessHeight=%d from percent %f\n",
i, excessForRow, percent);
// adjust the height of the row
nsSize rowFrameSize;
rowFrameToBeResized->GetSize(rowFrameSize);
rowFrameToBeResized->SizeTo(rowFrameSize.width, rowHeights[i]);
if (gsDebug) printf("TRGF CalcRowH: row %d (%p) sized to %d\n",
i, rowFrameToBeResized, rowHeights[i]);
}
// update the row height
rowHeights[i] += excessForRow;
// if we're dealing with a row below the row containing the spanning cell,
// push that row down by the amount we've expanded the cell heights by
if ((i >= rowIndex) && (i != 0))
{
nsRect rowRect;
rowFrameToBeResized->GetRect(rowRect);
nscoord delta=0;
for (PRInt32 j=0; j<i; j++)
delta += excessForRow[j];
if (delta > excessHeight)
delta = excessHeight;
rowFrameToBeResized->MoveTo(rowRect.x, rowRect.y + delta);
if (gsDebug) printf("TRGF CalcRowH: row %d (%p) moved to %d after delta %d\n",
i, rowFrameToBeResized, rowRect.y + delta, delta);
}
// Get the next row frame
GetNextRowSibling((nsIFrame**)&rowFrameToBeResized);
}
delete []excessForRow;
NS_ASSERTION(excessAllocated == excessHeight, "excess distribution failed");
}
}
}
// Get the next row child (cell frame)
cellFrame->GetNextSibling(&cellFrame);
}
// If this is pass 2 then resize the row to its final size and move the
// row's position if the previous rows have caused a shift
if (1 == counter) {
nsRect rowBounds;
rowFrame->GetRect(rowBounds);
// Move the row to the correct position
rowBounds.y += deltaY;
// Adjust our running delta
deltaY += rowHeights[rowIndex] - rowBounds.height;
// Resize the row to its final size and position
rowBounds.height = rowHeights[rowIndex];
rowFrame->SetRect(rowBounds);
}
// Update the running row group height
rowGroupHeight += rowHeights[rowIndex];
rowIndex++;
@ -780,23 +787,26 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
rowFrame->GetSize(frameSize);
rowGroupHeight += frameSize.height;
}
// Get the next rowgroup child (row frame)
GetNextFrame(rowFrame, &rowFrame);
}
}
/* step 3: finally, notify the rows of their new heights */
// step 3: notify the rows of their new heights
rowFrame = GetFirstFrame();
rowIndex = 0;
while (nsnull != rowFrame)
{
rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
{
// Notify the row of the new size
((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState);
}
// Get the next row
GetNextFrame(rowFrame, &rowFrame);
rowIndex++;
}
// Adjust our desired size
@ -806,11 +816,20 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
delete []rowHeights;
}
nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY)
// Called by IR_TargetIsChild() to adjust the sibling frames that follow
// after an incremental reflow of aKidFrame.
// This function is not used for paginated mode so we don't need to deal
// with continuing frames, and it's only called if aKidFrame has no
// cells that span into it and no cells that span across it. That way
// we don't have to deal with rowspans
nsresult
nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY)
{
NS_PRECONDITION(NS_UNCONSTRAINEDSIZE == aReflowState.reflowState.availableHeight,
"we're not in galley mode");
if (PR_TRUE==gsDebugIR) printf("\nTRGF IR: AdjustSiblingsAfterReflow\n");
nsIFrame* lastKidFrame = aKidFrame;
@ -823,11 +842,12 @@ nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aP
while (nsnull != kidFrame) {
nsPoint origin;
// XXX We can't just slide the child if it has a next-in-flow
// Adjust the y-origin
kidFrame->GetOrigin(origin);
origin.y += aDeltaY;
// XXX We need to send move notifications to the frame...
// XXX We need to send move notifications to the frame. At least see if
// views need to be repositioned
nsIHTMLReflow* htmlReflow;
if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->WillReflow(aPresContext);
@ -844,8 +864,6 @@ nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aP
lastKidFrame = GetLastFrame();
}
// XXX Deal with cells that have rowspans.
// Update our running y-offset to reflect the bottommost child
nsRect rect;
lastKidFrame->GetRect(rect);
@ -1125,8 +1143,6 @@ NS_METHOD nsTableRowGroupFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsIFrame* nextFrame;
aReflowState.reflowState.reflowCommand->GetNext(nextFrame);
// Recover our reflow state
//RecoverState(state, nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame);
}
}
@ -1429,6 +1445,51 @@ NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nscoord& aResult)
return NS_OK;
}
// Recovers the reflow state to what it should be if aKidFrame is about
// to be reflowed. Restores the following:
// - availSize
// - y
// - firstRow
nsresult
nsTableRowGroupFrame::RecoverState(RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame)
{
// Walk the list of children looking for aKidFrame
for (nsIFrame* frame = mFrames.FirstChild(); frame; frame->GetNextSibling(&frame)) {
if (frame == aKidFrame) {
break;
}
// Update the running y-offset
nsSize kidSize;
frame->GetSize(kidSize);
aReflowState.y += kidSize.height;
// If our height is constrained then update the available height
if (PR_FALSE == aReflowState.unconstrainedHeight) {
aReflowState.availSize.height -= kidSize.height;
}
// Update the maximum element size
if (aReflowState.firstRow) {
aReflowState.firstRow = PR_FALSE;
// XXX Today you can't ask for max-element-size when doing an
// incremental reflow
#if 0
if (aMaxElementSize) {
aMaxElementSize->width = aKidMaxElementSize.width;
aMaxElementSize->height = aKidMaxElementSize.height;
}
} else if (aMaxElementSize) {
aMaxElementSize->width = PR_MAX(aMaxElementSize->width, aKidMaxElementSize.width);
#endif
}
}
return NS_OK;
}
NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
@ -1438,35 +1499,53 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext& aPresConte
{
nsresult rv;
if (PR_TRUE==gsDebugIR) printf("\nTRGF IR: IR_TargetIsChild\n");
// XXX Recover state
// Recover the state as if aNextFrame is about to be reflowed
RecoverState(aReflowState, aNextFrame);
// Remember the old rect
nsRect oldKidRect;
aNextFrame->GetRect(oldKidRect);
// Pass along the reflow command
// XXX Correctly compute the available space...
nsSize availSpace(aReflowState.reflowState.availableWidth, aReflowState.reflowState.availableHeight);
nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, aNextFrame, availSpace);
nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
aNextFrame, aReflowState.availSize);
nsHTMLReflowMetrics desiredSize(nsnull);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// XXX Check aStatus to see if the frame is complete...
// Resize the row frame
nsRect kidRect;
aNextFrame->GetRect(kidRect);
aNextFrame->SizeTo(desiredSize.width, desiredSize.height);
// Place the row frame
nsSize kidMaxElementSize;
nsRect kidRect(0, aReflowState.y, desiredSize.width, desiredSize.height);
PlaceChild(aPresContext, aReflowState, aNextFrame, kidRect, nsnull,
kidMaxElementSize);
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);
// Return of desired size
// See if the table needs a reflow (e.g., if the column widths have
// changed). If so, just return and don't bother adjusting the rows
// that follow
if (!aReflowState.tableFrame->NeedsReflow(aReflowState.reflowState)) {
// Inform the row of its new height.
PRBool isJustSingleRow = PR_FALSE; /* how to determine this now? */
if (isJustSingleRow) {
((nsTableRowFrame*)aNextFrame)->DidResize(aPresContext, aReflowState.reflowState);
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);
aDesiredSize.height = aReflowState.y;
} else {
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);
// Now recalculate the row heights
CalculateRowHeights(aPresContext, aDesiredSize, aReflowState.reflowState);
}
}
// Return our desired width
aDesiredSize.width = aReflowState.reflowState.availableWidth;
aDesiredSize.height = aReflowState.y;
// XXX If we have a next-in-flow, then we're not complete
if (mNextInFlow) {
aStatus = NS_FRAME_NOT_COMPLETE;
}

View File

@ -44,9 +44,6 @@ struct RowGroupReflowState {
// Flag used to set maxElementSize to my first row
PRBool firstRow;
// Remember the height of the first row, because it's our maxElementHeight (plus header/footers)
nscoord firstRowHeight;
nsTableFrame *tableFrame;
RowGroupReflowState(nsIPresContext& aPresContext,
@ -61,7 +58,6 @@ struct RowGroupReflowState {
unconstrainedWidth = PRBool(reflowState.availableWidth == NS_UNCONSTRAINEDSIZE);
unconstrainedHeight = PRBool(reflowState.availableHeight == NS_UNCONSTRAINEDSIZE);
firstRow = PR_TRUE;
firstRowHeight=0;
tableFrame = aTableFrame;
}
@ -245,6 +241,9 @@ protected:
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY);
nsresult RecoverState(RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame);
/**
* Reflow the frames we've already created

View File

@ -722,21 +722,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext,
aDesiredSize.ascent=aDesiredSize.height;
aDesiredSize.descent=0;
// if we got this far with an incremental reflow, the reflow was targeted
// at the cell's content. We should only have to redo pass1 for this cell
// then rebalance columns. The pass1 is handled by the cell's parent row.
// So here all we have to do is tell the table to rebalance.
if (eReflowReason_Incremental == aReflowState.reason)
{
nsTableFrame* tableFrame=nsnull;
rv = nsTableFrame::GetTableFrame(this, tableFrame);
if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame))
{
tableFrame->InvalidateColumnWidths();
}
}
#ifdef NS_DEBUG
//PostReflowCheck(result);
#endif

View File

@ -2090,7 +2090,7 @@ nsTableFrame::GetSkipSides() const
return skip;
}
PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize)
PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState)
{
PRBool result = PR_TRUE;
@ -2115,49 +2115,60 @@ PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const ns
//
// Slides all the row groups following aKidFrame by the specified
// amount
//
// XXX This is kind of klunky because the InnerTableReflowState::y
// data member does not include the table's border/padding...
nsresult nsTableFrame::AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
InnerTableReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY)
{
NS_PRECONDITION(NS_UNCONSTRAINEDSIZE == aReflowState.reflowState.availableHeight,
"not in galley mode");
nsIFrame* lastKidFrame = aKidFrame;
"we're not in galley mode");
if (aDeltaY != 0) {
// Move the frames that follow aKidFrame by aDeltaY
// If it's the footer that was reflowed, then we don't need to adjust any of
// the frames, because the footer is the bottom most frame
if (aKidFrame != aReflowState.footerFrame) {
nsIFrame* kidFrame;
aKidFrame->GetNextSibling(&kidFrame);
while (nsnull != kidFrame) {
nsPoint origin;
nsIHTMLReflow* htmlReflow;
nsRect kidRect;
PRBool movedFooter = PR_FALSE;
// XXX We can't just slide the child if it has a next-in-flow
kidFrame->GetOrigin(origin);
origin.y += aDeltaY;
// XXX We need to send move notifications to the frame...
if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->WillReflow(aPresContext);
// Move the frames that follow aKidFrame by aDeltaY, and update the running
// y-offset
for (aKidFrame->GetNextSibling(&kidFrame); kidFrame; kidFrame->GetNextSibling(&kidFrame)) {
// See if it's the footer we're moving
if (kidFrame == aReflowState.footerFrame) {
movedFooter = PR_TRUE;
}
// Get the frame's bounding rect
kidFrame->GetRect(kidRect);
// Adjust the running y-offset
aReflowState.y += kidRect.height;
// Adjust the y-origin if its position actually changed
if (aDeltaY != 0) {
kidRect.y += aDeltaY;
kidFrame->MoveTo(kidRect.x, kidRect.y);
}
}
// We also need to move the footer if there is one and we haven't already
// moved it
if (aReflowState.footerFrame && !movedFooter) {
aReflowState.footerFrame->GetRect(kidRect);
// Adjust the running y-offset
aReflowState.y += kidRect.height;
if (aDeltaY != 0) {
kidRect.y += aDeltaY;
aReflowState.footerFrame->MoveTo(kidRect.x, kidRect.y);
}
kidFrame->MoveTo(origin.x, origin.y);
// Get the next frame
lastKidFrame = kidFrame;
kidFrame->GetNextSibling(&kidFrame);
}
} else {
// Get the last frame
lastKidFrame = mFrames.LastChild();
}
// Update our running y-offset to reflect the bottommost child
nsRect rect;
lastKidFrame->GetRect(rect);
aReflowState.y = rect.YMost();
return NS_OK;
}
@ -2253,7 +2264,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext,
}
// NeedsReflow and IsFirstPassValid take into account reflow type = Initial_Reflow
if (PR_TRUE==NeedsReflow(aReflowState, nsSize(aReflowState.availableWidth, aReflowState.availableHeight)))
if (PR_TRUE==NeedsReflow(aReflowState))
{
PRBool needsRecalc=PR_FALSE;
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: needs reflow\n");
@ -2938,6 +2949,240 @@ NS_METHOD nsTableFrame::GetBorderPlusMarginPadding(nsMargin& aResult)
return NS_OK;
}
// Sets the starting column index for aColGroupFrame and the siblings frames that
// follow
void
nsTableFrame::SetStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame,
PRInt32 aIndex)
{
while (aColGroupFrame) {
aIndex += aColGroupFrame->SetStartColumnIndex(aIndex);
aColGroupFrame->GetNextSibling((nsIFrame**)&aColGroupFrame);
}
}
// Calculate the starting column index to use for the specified col group frame
PRInt32
nsTableFrame::CalculateStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame)
{
PRInt32 index = 0;
for (nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame*)mColGroups.FirstChild();
colGroupFrame && (colGroupFrame != aColGroupFrame);
colGroupFrame->GetNextSibling((nsIFrame**)&colGroupFrame))
{
index += colGroupFrame->GetColumnCount();
}
return index;
}
NS_IMETHODIMP
nsTableFrame::AppendFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aFrameList)
{
PRInt32 startingColIndex = -1;
// Because we actually have two child lists, one for col group frames and one
// for everything else, we need to look at each frame individually
nsIFrame* f = aFrameList;
while (f) {
nsIFrame* next;
// Get the next frame and disconnect this frame from its sibling
f->GetNextSibling(&next);
f->SetNextSibling(nsnull);
// See what kind of frame we have
const nsStyleDisplay *display;
f->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) {
// Append the new col group frame
mColGroups.AppendFrame(nsnull, f);
// Set its starting column index
if (-1 == startingColIndex) {
startingColIndex = CalculateStartingColumnIndexFor((nsTableColGroupFrame*)f);
}
((nsTableColGroupFrame*)f)->SetStartColumnIndex(startingColIndex);
startingColIndex += ((nsTableColGroupFrame *)f)->GetColumnCount();
} else if (IsRowGroup(display->mDisplay)) {
// Append the new row group frame
mFrames.AppendFrame(nsnull, f);
// Add the content of the row group to the cell map
DidAppendRowGroup((nsTableRowGroupFrame*)f);
} else {
// Nothing special to do, just add the frame to our child list
mFrames.AppendFrame(nsnull, f);
}
// Move to the next frame
f = next;
}
// We'll need to do a pass-1 layout of all cells in all the rows of the
// rowgroup
InvalidateFirstPassCache();
// If we've added any columns, we need to rebuild the column cache.
InvalidateColumnCache();
// Because the number of columns may have changed invalidate the column
// cache. Note that this has the side effect of recomputing the column
// widths, so we don't need to call InvalidateColumnWidths()
InvalidateColumnWidths();
// Mark the table as dirty and generate a reflow command targeted at the
// outer table frame
nsIReflowCommand* reflowCmd;
nsresult rv;
mState |= NS_FRAME_IS_DIRTY;
rv = NS_NewHTMLReflowCommand(&reflowCmd, mParent, nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
// Add the reflow command
rv = aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
}
NS_IMETHODIMP
nsTableFrame::InsertFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList)
{
// Asssume there's only one frame being inserted. The problem is that
// row group frames and col group frames go in separate child lists and
// so if there's more than one this gets messy...
// XXX The frame construction code should be separating out child frames
// based on the type...
nsIFrame* nextSibling;
aFrameList->GetNextSibling(&nextSibling);
NS_PRECONDITION(!nextSibling, "expected only one child frame");
// See what kind of frame we have
const nsStyleDisplay *display=nsnull;
aFrameList->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) {
// Insert the column group frame
mColGroups.InsertFrame(nsnull, aPrevFrame, aFrameList);
// Set its starting column index and adjust the index of the
// col group frames that follow
SetStartingColumnIndexFor((nsTableColGroupFrame*)aFrameList,
CalculateStartingColumnIndexFor((nsTableColGroupFrame*)aFrameList));
} else if (IsRowGroup(display->mDisplay)) {
// Insert the frame
mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList);
// We'll need to do a pass-1 layout of all cells in all the rows of the
// rowgroup
InvalidateFirstPassCache();
// We need to rebuild the cell map, because currently we can't insert
// new frames except at the end (append)
InvalidateCellMap();
} else {
// Just insert the frame and don't worry about reflowing it
mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList);
return NS_OK;
}
// If we've added any columns, we need to rebuild the column cache.
InvalidateColumnCache();
// Because the number of columns may have changed invalidate the column
// cache. Note that this has the side effect of recomputing the column
// widths, so we don't need to call InvalidateColumnWidths()
InvalidateColumnWidths();
// Mark the table as dirty and generate a reflow command targeted at the
// outer table frame
nsIReflowCommand* reflowCmd;
nsresult rv;
mState |= NS_FRAME_IS_DIRTY;
rv = NS_NewHTMLReflowCommand(&reflowCmd, mParent, nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
// Add the reflow command
rv = aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
}
NS_IMETHODIMP
nsTableFrame::RemoveFrame(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame)
{
// See what kind of frame we have
const nsStyleDisplay *display=nsnull;
aOldFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) {
nsIFrame* nextColGroupFrame;
aOldFrame->GetNextSibling(&nextColGroupFrame);
// Remove the col group frame
mColGroups.DestroyFrame(aPresContext, aOldFrame);
// Adjust the starting column index of the frames that follow
SetStartingColumnIndexFor((nsTableColGroupFrame*)nextColGroupFrame,
CalculateStartingColumnIndexFor((nsTableColGroupFrame*)nextColGroupFrame));
} else if (IsRowGroup(display->mDisplay)) {
mFrames.DestroyFrame(aPresContext, aOldFrame);
// We need to rebuild the cell map, because currently we can't incrementally
// remove rows
InvalidateCellMap();
} else {
// Just remove the frame
mFrames.DestroyFrame(aPresContext, aOldFrame);
return NS_OK;
}
// Because the number of columns may have changed invalidate the column
// cache. Note that this has the side effect of recomputing the column
// widths, so we don't need to call InvalidateColumnWidths()
InvalidateColumnCache();
// Because the number of columns may have changed invalidate the column
// cache. Note that this has the side effect of recomputing the column
// widths, so we don't need to call InvalidateColumnWidths()
InvalidateColumnWidths();
// Mark the table as dirty and generate a reflow command targeted at the
// outer table frame
nsIReflowCommand* reflowCmd;
nsresult rv;
mState |= NS_FRAME_IS_DIRTY;
rv = NS_NewHTMLReflowCommand(&reflowCmd, mParent, nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
// Add the reflow command
rv = aPresShell.AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
return rv;
}
NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
@ -2946,13 +3191,23 @@ NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
if (PR_TRUE==gsDebugIR) printf("\nTIF IR: IncrementalReflow\n");
nsresult rv = NS_OK;
// Constrain our reflow width to the computed table width. Note: this is
// based on the width of the first-in-flow
nsHTMLReflowState reflowState(aReflowState);
PRInt32 pass1Width = mRect.width;
if (mPrevInFlow) {
nsTableFrame* table = (nsTableFrame*)GetFirstInFlow();
pass1Width = table->mRect.width;
}
reflowState.availableWidth = pass1Width;
nsMargin borderPadding;
GetBorderPlusMarginPadding(borderPadding);
InnerTableReflowState state(aPresContext, aReflowState, borderPadding);
InnerTableReflowState state(aPresContext, reflowState, borderPadding);
// determine if this frame is the target or not
nsIFrame *target=nsnull;
rv = aReflowState.reflowCommand->GetTarget(target);
rv = reflowState.reflowCommand->GetTarget(target);
if ((PR_TRUE==NS_SUCCEEDED(rv)) && (nsnull!=target))
{
// this is the target if target is either this or the outer table frame containing this inner frame
@ -2964,10 +3219,9 @@ NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext,
{
// Get the next frame in the reflow chain
nsIFrame* nextFrame;
aReflowState.reflowCommand->GetNext(nextFrame);
reflowState.reflowCommand->GetNext(nextFrame);
// Recover our reflow state
//RecoverState(state, nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, state, aStatus, nextFrame);
}
}
@ -2991,73 +3245,6 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
if (PR_TRUE==gsDebugIR) printf("TIF IR: IncrementalReflow_TargetIsMe with type=%d\n", type);
switch (type)
{
case nsIReflowCommand::FrameInserted :
NS_ASSERTION(nsnull!=objectFrame, "bad objectFrame");
NS_ASSERTION(nsnull!=childDisplay, "bad childDisplay");
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColGroupFrame*)objectFrame, PR_FALSE);
}
else if (IsRowGroup(childDisplay->mDisplay))
{
rv = IR_RowGroupInserted(aPresContext, aDesiredSize, aReflowState, aStatus,
GetRowGroupFrameFor(objectFrame, childDisplay), PR_FALSE);
}
else
{
rv = AddFrame(aReflowState.reflowState, objectFrame);
}
break;
case nsIReflowCommand::FrameAppended :
if (!objectFrame)
break;
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupAppended(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColGroupFrame*)objectFrame);
}
else if (IsRowGroup(childDisplay->mDisplay))
{
rv = IR_RowGroupAppended(aPresContext, aDesiredSize, aReflowState, aStatus,
GetRowGroupFrameFor(objectFrame, childDisplay));
}
else
{ // no optimization to be done for Unknown frame types, so just reuse the Inserted method
rv = AddFrame(aReflowState.reflowState, objectFrame);
}
break;
/*
case nsIReflowCommand::FrameReplaced :
NS_ASSERTION(nsnull!=objectFrame, "bad objectFrame");
NS_ASSERTION(nsnull!=childDisplay, "bad childDisplay");
*/
case nsIReflowCommand::FrameRemoved :
if (!objectFrame)
break;
NS_ASSERTION(nsnull!=childDisplay, "bad childDisplay");
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
rv = IR_ColGroupRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
(nsTableColGroupFrame*)objectFrame);
}
else if (IsRowGroup(childDisplay->mDisplay))
{
rv = IR_RowGroupRemoved(aPresContext, aDesiredSize, aReflowState, aStatus,
GetRowGroupFrameFor(objectFrame, childDisplay));
}
else
{
rv = mFrames.DestroyFrame(aPresContext, objectFrame);
}
break;
case nsIReflowCommand::StyleChanged :
rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus);
break;
@ -3067,12 +3254,8 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
rv = NS_ERROR_ILLEGAL_VALUE;
break;
case nsIReflowCommand::PullupReflow:
case nsIReflowCommand::PushReflow:
case nsIReflowCommand::CheckPullupReflow :
case nsIReflowCommand::UserDefined :
default:
NS_NOTYETIMPLEMENTED("unimplemented reflow command type");
NS_NOTYETIMPLEMENTED("unexpected reflow command type");
rv = NS_ERROR_NOT_IMPLEMENTED;
if (PR_TRUE==gsDebugIR) printf("TIF IR: reflow command not implemented.\n");
break;
@ -3081,187 +3264,6 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext& aPresContext,
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aInsertedFrame,
PRBool aReplace)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_ColGroupInserted for frame %p\n", aInsertedFrame);
nsresult rv=NS_OK;
PRBool adjustStartingColIndex=PR_FALSE;
PRInt32 startingColIndex=0;
// find out what frame to insert aInsertedFrame after
nsIFrame *frameToInsertAfter=nsnull;
rv = aReflowState.reflowState.reflowCommand->GetPrevSiblingFrame(frameToInsertAfter);
// insert aInsertedFrame as the first child. Set its start col index to 0
if (nsnull==frameToInsertAfter)
{
mColGroups.InsertFrame(nsnull, nsnull, aInsertedFrame);
startingColIndex += aInsertedFrame->SetStartColumnIndex(0);
adjustStartingColIndex=PR_TRUE;
}
nsIFrame *childFrame=mColGroups.FirstChild();
nsIFrame *prevSib=nsnull;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
if ((nsnull!=frameToInsertAfter) && (childFrame==frameToInsertAfter))
{
nsIFrame *nextSib=nsnull;
frameToInsertAfter->GetNextSibling(&nextSib);
aInsertedFrame->SetNextSibling(nextSib);
frameToInsertAfter->SetNextSibling(aInsertedFrame);
// account for childFrame being a COLGROUP now
if (PR_FALSE==adjustStartingColIndex) // we haven't gotten to aDeletedFrame yet
startingColIndex += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
// skip ahead to aInsertedFrame, since we just handled the frame we inserted after
childFrame=aInsertedFrame;
adjustStartingColIndex=PR_TRUE; // now that we've inserted aInsertedFrame,
// start adjusting subsequent col groups' starting col index including aInsertedFrame
}
if (PR_FALSE==adjustStartingColIndex) // we haven't gotten to aDeletedFrame yet
startingColIndex += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
else // we've removed aDeletedFrame, now adjust the starting col index of all subsequent col groups
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
prevSib=childFrame;
rv = childFrame->GetNextSibling(&childFrame);
}
InvalidateColumnCache();
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, skip invalidating the first passs
// if so, and we can fix the first pass info
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aAppendedFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_ColGroupAppended for frame %p\n", aAppendedFrame);
nsresult rv=NS_OK;
PRInt32 startingColIndex=0;
nsIFrame *childFrame=mColGroups.FirstChild();
nsIFrame *lastChild=childFrame;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
startingColIndex += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
lastChild=childFrame;
rv = childFrame->GetNextSibling(&childFrame);
}
// append aAppendedFrame
if (nsnull!=lastChild)
lastChild->SetNextSibling(aAppendedFrame);
else
mColGroups.SetFrames(aAppendedFrame);
aAppendedFrame->SetStartColumnIndex(startingColIndex);
#if 0
we would only want to do this if manufactured col groups were invisible to the DOM. Since they
currently are visible, they should behave just as if they were content-backed "real" colgroups
If this decision is changed, the code below is a half-finished attempt to rationalize the situation.
It requires having built a list of the colGroups before we get to this point.
// look at the last col group. If it is implicit, and it's cols are implicit, then
// it and its cols were manufactured for table layout.
// Delete it if possible, otherwise move it to the end of the list
if (0<colGroupCount)
{
nsTableColGroupFrame *colGroup = (nsTableColGroupFrame *)(colGroupList.ElementAt(colGroupCount-1));
if (PR_TRUE==colGroup->IsManufactured())
{ // account for the new COLs that were added in aAppendedFrame
// first, try to delete the implicit colgroup
// if we couldn't delete it, move the implicit colgroup to the end of the list
// and adjust it's col indexes
nsIFrame *colGroupNextSib;
colGroup->GetNextSibling(colGroupNextSib);
childFrame=mColGroups.FirstChild();
nsIFrame * prevSib=nsnull;
rv = NS_OK;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
if (childFrame==colGroup)
{
if (nsnull!=prevSib) // colGroup is in the middle of the list, remove it
prevSib->SetNextSibling(colGroupNextSib);
else // colGroup was the first child, so set it's next sib to first child
mColGroups.SetFrames(colGroupNextSib);
aAppendedFrame->SetNextSibling(colGroup); // place colGroup at the end of the list
colGroup->SetNextSibling(nsnull);
break;
}
prevSib=childFrame;
rv = childFrame->GetNextSibling(childFrame);
}
}
}
#endif
InvalidateColumnCache();
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, skip invalidating the first passs
// if so, and we can fix the first pass info
return rv;
}
NS_METHOD nsTableFrame::IR_ColGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aDeletedFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_ColGroupRemoved for frame %p\n", aDeletedFrame);
nsresult rv=NS_OK;
PRBool adjustStartingColIndex=PR_FALSE;
PRInt32 startingColIndex=0;
nsIFrame *childFrame=mColGroups.FirstChild();
nsIFrame *prevSib=nsnull;
while ((NS_SUCCEEDED(rv)) && (nsnull!=childFrame))
{
if (childFrame==aDeletedFrame)
{
nsIFrame *deleteFrameNextSib=nsnull;
aDeletedFrame->GetNextSibling(&deleteFrameNextSib);
if (nsnull!=prevSib)
prevSib->SetNextSibling(deleteFrameNextSib);
else
mColGroups.SetFrames(deleteFrameNextSib);
childFrame=deleteFrameNextSib;
if (nsnull==childFrame)
break;
adjustStartingColIndex=PR_TRUE; // now that we've removed aDeletedFrame, start adjusting subsequent col groups' starting col index
}
const nsStyleDisplay *display;
childFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display);
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay)
{
if (PR_FALSE==adjustStartingColIndex) // we haven't gotten to aDeletedFrame yet
startingColIndex += ((nsTableColGroupFrame *)childFrame)->GetColumnCount();
else // we've removed aDeletedFrame, now adjust the starting col index of all subsequent col groups
startingColIndex += ((nsTableColGroupFrame *)childFrame)->SetStartColumnIndex(startingColIndex);
}
prevSib=childFrame;
rv = childFrame->GetNextSibling(&childFrame);
}
InvalidateColumnCache();
//XXX: what we want to do here is determine if the new COL information changes anything about layout
// if not, skip invalidating the first passs
// if so, and we can fix the first pass info
return rv;
}
NS_METHOD nsTableFrame::IR_StyleChanged(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -3277,85 +3279,69 @@ NS_METHOD nsTableFrame::IR_StyleChanged(nsIPresContext& aPresContext,
return rv;
}
NS_METHOD nsTableFrame::IR_RowGroupInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aInsertedFrame,
PRBool aReplace)
// Recovers the reflow state to what it should be if aKidFrame is about
// to be reflowed. Restores the following:
// - availSize
// - y
// - footerFrame
// - firstBodySection
//
// In the case of the footer frame the y-offset is set to its current
// y-offset. Note that this is different from resize reflow when the
// footer is positioned higher up and then moves down as each row
// group frame is relowed
//
// XXX This is kind of klunky because the InnerTableReflowState::y
// data member does not include the table's border/padding...
nsresult
nsTableFrame::RecoverState(InnerTableReflowState& aReflowState,
nsIFrame* aKidFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_RowGroupInserted for frame %p\n", aInsertedFrame);
nsresult rv = AddFrame(aReflowState.reflowState, aInsertedFrame);
if (NS_FAILED(rv))
return rv;
// do a pass-1 layout of all the cells in all the rows of the rowgroup
rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState.reflowState, aStatus,
aInsertedFrame, eReflowReason_Initial, PR_FALSE);
if (NS_FAILED(rv))
return rv;
// Walk the list of children looking for aKidFrame
for (nsIFrame* frame = mFrames.FirstChild(); frame; frame->GetNextSibling(&frame)) {
// If this is a footer row group, remember it
const nsStyleDisplay *display;
frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
InvalidateCellMap();
InvalidateColumnCache();
// We only allow a single footer frame, and the footer frame must occur before
// any body section row groups
if ((NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == display->mDisplay) &&
!aReflowState.footerFrame && !aReflowState.firstBodySection) {
aReflowState.footerFrame = frame;
} else if ((NS_STYLE_DISPLAY_TABLE_ROW_GROUP == display->mDisplay) &&
!aReflowState.firstBodySection) {
aReflowState.firstBodySection = frame;
}
// See if this is the frame we're looking for
if (frame == aKidFrame) {
// If it's the footer, then keep going because the footer is at the
// very bottom
if (frame != aReflowState.footerFrame) {
break;
}
}
return rv;
// Get the frame's height
nsSize kidSize;
frame->GetSize(kidSize);
// If our height is constrained then update the available height. Do
// this for all frames including the footer frame
if (PR_FALSE == aReflowState.unconstrainedHeight) {
aReflowState.availSize.height -= kidSize.height;
}
// Update the running y-offset. Don't do this for the footer frame
if (frame != aReflowState.footerFrame) {
aReflowState.y += kidSize.height;
}
}
return NS_OK;
}
// since we know we're doing an append here, we can optimize
NS_METHOD nsTableFrame::IR_RowGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aAppendedFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_RowGroupAppended for frame %p\n", aAppendedFrame);
// hook aAppendedFrame into the child list
nsresult rv = AddFrame(aReflowState.reflowState, aAppendedFrame);
if (NS_FAILED(rv))
return rv;
// account for the cells in the rows that are children of aAppendedFrame
// this will add the content of the rowgroup to the cell map
rv = DidAppendRowGroup(aAppendedFrame);
if (NS_FAILED(rv))
return rv;
// do a pass-1 layout of all the cells in all the rows of the rowgroup
rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState.reflowState, aStatus,
aAppendedFrame, eReflowReason_Initial, PR_TRUE);
if (NS_FAILED(rv))
return rv;
// if we've added any columns, we need to rebuild the column cache
// XXX: it would be nice to have a mechanism to just extend the column cache, rather than rebuild it completely
InvalidateColumnCache();
// if any column widths have to change due to this, rebalance column widths
//XXX need to calculate this, but for now just do it
InvalidateColumnWidths();
return rv;
}
NS_METHOD nsTableFrame::IR_RowGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aDeletedFrame)
{
if (PR_TRUE==gsDebugIR) printf("TIF IR: IR_RowGroupRemoved for frame %p\n", aDeletedFrame);
nsresult rv = mFrames.DestroyFrame(aPresContext, aDeletedFrame);
InvalidateCellMap();
InvalidateColumnCache();
// if any column widths have to change due to this, rebalance column widths
//XXX need to calculate this, but for now just do it
InvalidateColumnWidths();
return rv;
}
NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
@ -3365,6 +3351,8 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
{
nsresult rv;
if (PR_TRUE==gsDebugIR) printf("\nTIF IR: IR_TargetIsChild\n");
// Recover the state as if aNextFrame is about to be reflowed
RecoverState(aReflowState, aNextFrame);
// Remember the old rect
nsRect oldKidRect;
@ -3372,24 +3360,31 @@ NS_METHOD nsTableFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
// Pass along the reflow command
nsHTMLReflowMetrics desiredSize(nsnull);
// XXX Correctly compute the available space...
nsSize availSpace(aReflowState.reflowState.availableWidth, aReflowState.reflowState.availableHeight);
nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
aNextFrame, availSpace);
aNextFrame, aReflowState.availSize);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// Resize the row group frame
nsRect kidRect;
aNextFrame->GetRect(kidRect);
aNextFrame->SizeTo(desiredSize.width, desiredSize.height);
// Place the row group frame. Don't use PlaceChild(), because it moves
// the footer frame as well. We'll adjust the footer frame later on in
// AdjustSiblingsAfterReflow()
nscoord x = aReflowState.mBorderPadding.left;
nscoord y = aReflowState.mBorderPadding.top + aReflowState.y;
nsRect kidRect(x, y, desiredSize.width, desiredSize.height);
aNextFrame->SetRect(kidRect);
// Adjust the running y-offset
aReflowState.y += kidRect.height;
// If our height is constrained, then update the available height
if (PR_FALSE == aReflowState.unconstrainedHeight) {
aReflowState.availSize.height -= kidRect.height;
}
// If the column width info is valid, then adjust the row group frames
// that follow. Otherwise, return and we'll recompute the column widths
// and reflow all the row group frames
if (!NeedsReflow(aReflowState.reflowState,
nsSize(aReflowState.reflowState.availableWidth,
aReflowState.reflowState.availableHeight))) {
if (!NeedsReflow(aReflowState.reflowState)) {
// Adjust the row groups that follow
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);

View File

@ -95,6 +95,20 @@ public:
/** @see nsIFrame::Destroy */
NS_IMETHOD Destroy(nsIPresContext& aPresContext);
NS_IMETHOD AppendFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aFrameList);
NS_IMETHOD InsertFrames(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList);
NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext,
nsIPresShell& aPresShell,
nsIAtom* aListName,
nsIFrame* aOldFrame);
/** helper method to find the table parent of any table frame object */
// TODO: today, this depends on display types. This should be changed to rely
// on stronger criteria, like an inner table frame atom
@ -439,6 +453,14 @@ protected:
* @return PR_TRUE if this table is nested inside another table.
*/
PRBool IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const;
// Sets the starting column index for aColGroupFrame and the siblings frames that
// follow
void SetStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame,
PRInt32 aIndex);
// Calculate the starting column index to use for the specified col group frame
PRInt32 CalculateStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFrame);
public:
/** first pass of ResizeReflow.
@ -463,6 +485,9 @@ public:
NS_IMETHOD GetTableSpecifiedHeight(nscoord& aHeight, const nsHTMLReflowState& aReflowState);
virtual PRBool RowGroupsShouldBeConstrained() { return PR_FALSE; }
/** do I need to do a reflow? */
virtual PRBool NeedsReflow(const nsHTMLReflowState& aReflowState);
protected:
/** second pass of ResizeReflow.
* lays out all table content with aMaxSize(computed_table_width, given_table_height)
@ -509,72 +534,6 @@ protected:
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus);
/** process a colgroup inserted notification
* @param aInsertedFrame the new colgroup frame
* @param aReplace PR_TRUE if aInsertedFrame is replacing an existing frame
* Not Yet Implemented.
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_ColGroupInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aInsertedFrame,
PRBool aReplace);
/** process a colgroup appended notification. This method is optimized for append.
* @param aAppendedFrame the new colgroup frame
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_ColGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aAppendedFrame);
/** process a colgroup removed notification.
* @param aDeletedFrame the colgroup frame to remove
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_ColGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableColGroupFrame * aDeletedFrame);
/** process a rowgroup inserted notification
* @param aInsertedFrame the new rowgroup frame
* @param aReplace PR_TRUE if aInsertedFrame is replacing an existing frame
* Not Yet Implemented.
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_RowGroupInserted(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aInsertedFrame,
PRBool aReplace);
/** process a rowgroup appended notification. This method is optimized for append.
* @param aAppendedFrame the new rowgroup frame
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_RowGroupAppended(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aAppendedFrame);
/** process a rowgroup removed notification.
* @param aDeletedFrame the rowgroup frame to remove
* @see nsIFrameReflow::Reflow
*/
NS_IMETHOD IR_RowGroupRemoved(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
InnerTableReflowState& aReflowState,
nsReflowStatus& aStatus,
nsTableRowGroupFrame * aDeletedFrame);
/** process a style chnaged notification.
* @see nsIFrameReflow::Reflow
* TODO: needs to be optimized for which attribute was actually changed.
@ -588,6 +547,9 @@ protected:
InnerTableReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY);
nsresult RecoverState(InnerTableReflowState& aReflowState,
nsIFrame* aKidFrame);
NS_METHOD AdjustForCollapsingRowGroup(nsIFrame* aRowGroupFrame,
PRInt32& aRowX);
@ -676,10 +638,6 @@ protected:
/** sets the width of the table according to the computed widths of each column. */
virtual void SetTableWidth(nsIPresContext& aPresContext);
/** given the new parent size, do I really need to do a reflow? */
virtual PRBool NeedsReflow(const nsHTMLReflowState& aReflowState,
const nsSize& aMaxSize);
/** returns PR_TRUE if the cached pass 1 data is still valid */
virtual PRBool IsFirstPassValid() const;

View File

@ -337,11 +337,11 @@ NS_IMETHODIMP nsTableOuterFrame::SetSelected(nsIDOMRange *aRange,PRBool aSelecte
return result;
}
PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize)
PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState)
{
PRBool result=PR_TRUE;
if (nsnull != mInnerTableFrame) {
result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aReflowState, aMaxSize);
result = ((nsTableFrame *)mInnerTableFrame)->NeedsReflow(aReflowState);
}
return result;
}

View File

@ -126,7 +126,7 @@ protected:
* or if the table style attributes or parent max height/width have
* changed.
*/
PRBool NeedsReflow(const nsHTMLReflowState& aReflowState, const nsSize& aMaxSize);
PRBool NeedsReflow(const nsHTMLReflowState& aReflowState);
/** position the child frame
* @param aReflowState the state of the reflow process

View File

@ -1373,26 +1373,29 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
// size.
// XXX It would be nice if we could skip this step and the next step if the
// column width isn't dependent on the max cell width...
kidReflowState.reason = eReflowReason_Initial;
kidReflowState.reflowCommand = nsnull;
kidReflowState.availableWidth = NS_UNCONSTRAINEDSIZE;
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (gsDebug)
printf ("TR %p for cell %p Incremental Reflow: desired=%d, MES=%d\n",
this, aNextFrame, desiredSize.width, kidMaxElementSize.width);
// Update the cell layout data.
//XXX: this is a hack, shouldn't it be the case that a min size is
// never larger than a desired size?
if (kidMaxElementSize.width>desiredSize.width)
desiredSize.width = kidMaxElementSize.width;
if (kidMaxElementSize.height>desiredSize.height)
desiredSize.height = kidMaxElementSize.height;
((nsTableCellFrame *)aNextFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)aNextFrame)->SetPass1MaxElementSize(kidMaxElementSize);
// Now reflow the cell again this time constraining the width
// XXX Ignore for now the possibility that the column width has changed...
kidReflowState.availableWidth = availWidth;
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (aReflowState.tableFrame->RequiresPass1Layout()) {
kidReflowState.reason = eReflowReason_Initial;
kidReflowState.reflowCommand = nsnull;
kidReflowState.availableWidth = NS_UNCONSTRAINEDSIZE;
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
if (gsDebug)
printf ("TR %p for cell %p Incremental Reflow: desired=%d, MES=%d\n",
this, aNextFrame, desiredSize.width, kidMaxElementSize.width);
// Update the cell layout data.
//XXX: this is a hack, shouldn't it be the case that a min size is
// never larger than a desired size?
if (kidMaxElementSize.width>desiredSize.width)
desiredSize.width = kidMaxElementSize.width;
if (kidMaxElementSize.height>desiredSize.height)
desiredSize.height = kidMaxElementSize.height;
((nsTableCellFrame *)aNextFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)aNextFrame)->SetPass1MaxElementSize(kidMaxElementSize);
// Now reflow the cell again this time constraining the width
// XXX Ignore for now the possibility that the column width has changed...
kidReflowState.availableWidth = availWidth;
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
}
// Place the child after taking into account it's margin and attributes
// XXX We need to ask the table (or the table layout strategy) if the column
@ -1434,6 +1437,12 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
SetMaxChildHeight(aReflowState.maxCellHeight, maxCellTopMargin, maxCellBottomMargin);
// If the column widths have changed, then tell the table to rebalance
// the column widths
if (aReflowState.tableFrame->RequiresPass1Layout()) {
aReflowState.tableFrame->InvalidateColumnWidths();
}
// Return our desired size. Note that our desired width is just whatever width
// we were given by the row group frame
aDesiredSize.width = aReflowState.availSize.width;

View File

@ -361,7 +361,6 @@ void nsTableRowGroupFrame::PlaceChild(nsIPresContext& aPresContext,
if (PR_TRUE==aReflowState.firstRow)
{
aReflowState.firstRow = PR_FALSE;
aReflowState.firstRowHeight = aKidRect.height;
if (nsnull != aMaxElementSize) {
aMaxElementSize->width = aKidMaxElementSize.width;
aMaxElementSize->height = aKidMaxElementSize.height;
@ -597,14 +596,15 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
// all table cells have the same top and bottom margins, namely cellSpacingY
nscoord cellSpacingY = tableFrame->GetCellSpacingY();
// iterate children and for each row get its height
// iterate children and for each row get the height of the tallest cell
PRInt32 numRows;
GetRowCount(numRows, PR_FALSE);
PRInt32 *rowHeights = new PRInt32[numRows];
nsCRT::memset (rowHeights, 0, numRows*sizeof(PRInt32));
nscoord *rowHeights = new nscoord[numRows];
nsCRT::memset (rowHeights, 0, numRows*sizeof(nscoord));
/* Step 1: get the height of the tallest cell in the row and save it for
* pass 2
* pass 2. This height is for table cells that originate in this
* row and that don't span into the rows that follow
*/
nsIFrame* rowFrame = GetFirstFrame();
PRInt32 rowIndex = 0;
@ -649,7 +649,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
* If the cell's desired height is the larger value, resize the rows and contained
* cells by an equal percentage of the additional space.
* We go through this loop twice. The first time, we are adjusting cell heights
* and row y-offsets on the fly.
* on the fly.
* The second time through the loop, we're ensuring that subsequent row-spanning cells
* didn't change prior calculations.
* Since we are guaranteed to have found the max height spanners the first time through,
@ -661,6 +661,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
*/
PRInt32 rowGroupHeight;
nscoord deltaY = 0;
for (PRInt32 counter=0; counter<2; counter++)
{
rowGroupHeight = 0;
@ -686,90 +687,96 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex,
(nsTableCellFrame*)cellFrame);
if (rowSpan > 1)
{ // found a cell with rowspan > 1, determine its height
{ // found a cell with rowspan > 1, determine the height of the rows it
// spans
if (gsDebug) printf("TRGF CalcRowH: cell %p has rowspan=%d\n", cellFrame, rowSpan);
nscoord heightOfRowsSpanned = 0;
PRInt32 i;
for (i = 0; i < rowSpan; i++) {
heightOfRowsSpanned += rowHeights[rowIndex + i];
}
// the avail height needs to reduce by top and bottom margins
// reduce the height by top and bottom margins
nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY;
if (gsDebug) printf("TRGF CalcRowH: availHeightOfRowsSpanned=%d\n", availHeightOfRowsSpanned);
/* if the cell height fits in the rows, expand the spanning cell's height and slap it in */
// see if the cell's height fits within the rows it spans. If this is
// pass 1 then use the cell's desired height and not the current height
// of its frame. That way this works for incremental reflow, too
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
if (availHeightOfRowsSpanned > cellFrameSize.height)
if (0 == counter) {
nsSize cellDesiredSize = ((nsTableCellFrame*)cellFrame)->GetDesiredSize();
cellFrameSize.height = cellDesiredSize.height;
}
if (availHeightOfRowsSpanned >= cellFrameSize.height)
{
// yes the cell's height fits with the available space of the rows it
// spans. Set the cell frame's height
if (gsDebug) printf("TRGF CalcRowH: spanning cell fits in rows spanned, had h=%d, expanded to %d\n",
cellFrameSize.height, availHeightOfRowsSpanned);
cellFrame->SizeTo(cellFrameSize.width, availHeightOfRowsSpanned);
// Realign cell content based on new height
((nsTableCellFrame*)cellFrame)->VerticallyAlignChild();
}
/* otherwise, distribute the excess height to the rows effected.
* push all subsequent rows down by the total change in height of all the rows above it
*/
else
{
// the cell's height is larger than the available space of the rows it
// spans so distribute the excess height to the rows affected
PRInt32 excessHeight = cellFrameSize.height - availHeightOfRowsSpanned;
if (gsDebug) printf("TRGF CalcRowH: excessHeight=%d\n", excessHeight);
// for every row starting at the row with the spanning cell...
// for every row starting at the row with the spanning cell and down
// to the last row spanned by the cell
nsTableRowFrame *rowFrameToBeResized = (nsTableRowFrame *)rowFrame;
PRInt32 *excessForRow = new PRInt32[numRows];
nsCRT::memset (excessForRow, 0, numRows*sizeof(PRInt32));
nscoord excessAllocated = 0;
for (i = rowIndex; i < numRows; i++) {
for (i = rowIndex; i < (rowIndex + rowSpan); i++) {
if (gsDebug) printf("TRGF CalcRowH: for row index=%d\n", i);
// if the row is within the spanned range, resize the row
if (i < (rowIndex + rowSpan)) {
//float percent = ((float)rowHeights[i]) / ((float)availHeightOfRowsSpanned);
//excessForRow[i] = NSToCoordRound(((float)(excessHeight)) * percent);
float percent = ((float)rowHeights[i]) / ((float)heightOfRowsSpanned);
// give rows their percentage, except the last row gets the remainder
excessForRow[i] = ((i - 1) == (rowIndex + rowSpan))
? excessHeight - excessAllocated
: NSToCoordRound(((float)(excessHeight)) * percent);
excessAllocated += excessForRow[i];
if (gsDebug) printf("TRGF CalcRowH: for row %d, excessHeight=%d from percent %f\n",
i, excessForRow[i], percent);
// update the row height
rowHeights[i] += excessForRow[i];
// The amount of additional space each row gets is based on the
// percentage of space it occupies, i.e. they don't all get the
// same amount of available space
float percent = ((float)rowHeights[i]) / ((float)heightOfRowsSpanned);
// give rows their percentage, except for the last row which gets
// the remainder
nscoord excessForRow = ((i + 1) == (rowIndex + rowSpan)) ?
excessHeight - excessAllocated :
NSToCoordRound(((float)(excessHeight)) * percent);
excessAllocated += excessForRow;
if (gsDebug) printf("TRGF CalcRowH: for row %d, excessHeight=%d from percent %f\n",
i, excessForRow, percent);
// adjust the height of the row
nsSize rowFrameSize;
rowFrameToBeResized->GetSize(rowFrameSize);
rowFrameToBeResized->SizeTo(rowFrameSize.width, rowHeights[i]);
if (gsDebug) printf("TRGF CalcRowH: row %d (%p) sized to %d\n",
i, rowFrameToBeResized, rowHeights[i]);
}
// update the row height
rowHeights[i] += excessForRow;
// if we're dealing with a row below the row containing the spanning cell,
// push that row down by the amount we've expanded the cell heights by
if ((i >= rowIndex) && (i != 0))
{
nsRect rowRect;
rowFrameToBeResized->GetRect(rowRect);
nscoord delta=0;
for (PRInt32 j=0; j<i; j++)
delta += excessForRow[j];
if (delta > excessHeight)
delta = excessHeight;
rowFrameToBeResized->MoveTo(rowRect.x, rowRect.y + delta);
if (gsDebug) printf("TRGF CalcRowH: row %d (%p) moved to %d after delta %d\n",
i, rowFrameToBeResized, rowRect.y + delta, delta);
}
// Get the next row frame
GetNextRowSibling((nsIFrame**)&rowFrameToBeResized);
}
delete []excessForRow;
NS_ASSERTION(excessAllocated == excessHeight, "excess distribution failed");
}
}
}
// Get the next row child (cell frame)
cellFrame->GetNextSibling(&cellFrame);
}
// If this is pass 2 then resize the row to its final size and move the
// row's position if the previous rows have caused a shift
if (1 == counter) {
nsRect rowBounds;
rowFrame->GetRect(rowBounds);
// Move the row to the correct position
rowBounds.y += deltaY;
// Adjust our running delta
deltaY += rowHeights[rowIndex] - rowBounds.height;
// Resize the row to its final size and position
rowBounds.height = rowHeights[rowIndex];
rowFrame->SetRect(rowBounds);
}
// Update the running row group height
rowGroupHeight += rowHeights[rowIndex];
rowIndex++;
@ -780,23 +787,26 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
rowFrame->GetSize(frameSize);
rowGroupHeight += frameSize.height;
}
// Get the next rowgroup child (row frame)
GetNextFrame(rowFrame, &rowFrame);
}
}
/* step 3: finally, notify the rows of their new heights */
// step 3: notify the rows of their new heights
rowFrame = GetFirstFrame();
rowIndex = 0;
while (nsnull != rowFrame)
{
rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay)
{
// Notify the row of the new size
((nsTableRowFrame *)rowFrame)->DidResize(aPresContext, aReflowState);
}
// Get the next row
GetNextFrame(rowFrame, &rowFrame);
rowIndex++;
}
// Adjust our desired size
@ -806,11 +816,20 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext,
delete []rowHeights;
}
nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY)
// Called by IR_TargetIsChild() to adjust the sibling frames that follow
// after an incremental reflow of aKidFrame.
// This function is not used for paginated mode so we don't need to deal
// with continuing frames, and it's only called if aKidFrame has no
// cells that span into it and no cells that span across it. That way
// we don't have to deal with rowspans
nsresult
nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aPresContext,
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY)
{
NS_PRECONDITION(NS_UNCONSTRAINEDSIZE == aReflowState.reflowState.availableHeight,
"we're not in galley mode");
if (PR_TRUE==gsDebugIR) printf("\nTRGF IR: AdjustSiblingsAfterReflow\n");
nsIFrame* lastKidFrame = aKidFrame;
@ -823,11 +842,12 @@ nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aP
while (nsnull != kidFrame) {
nsPoint origin;
// XXX We can't just slide the child if it has a next-in-flow
// Adjust the y-origin
kidFrame->GetOrigin(origin);
origin.y += aDeltaY;
// XXX We need to send move notifications to the frame...
// XXX We need to send move notifications to the frame. At least see if
// views need to be repositioned
nsIHTMLReflow* htmlReflow;
if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
htmlReflow->WillReflow(aPresContext);
@ -844,8 +864,6 @@ nsresult nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsIPresContext& aP
lastKidFrame = GetLastFrame();
}
// XXX Deal with cells that have rowspans.
// Update our running y-offset to reflect the bottommost child
nsRect rect;
lastKidFrame->GetRect(rect);
@ -1125,8 +1143,6 @@ NS_METHOD nsTableRowGroupFrame::IncrementalReflow(nsIPresContext& aPresContext,
nsIFrame* nextFrame;
aReflowState.reflowState.reflowCommand->GetNext(nextFrame);
// Recover our reflow state
//RecoverState(state, nextFrame);
rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame);
}
}
@ -1429,6 +1445,51 @@ NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nscoord& aResult)
return NS_OK;
}
// Recovers the reflow state to what it should be if aKidFrame is about
// to be reflowed. Restores the following:
// - availSize
// - y
// - firstRow
nsresult
nsTableRowGroupFrame::RecoverState(RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame)
{
// Walk the list of children looking for aKidFrame
for (nsIFrame* frame = mFrames.FirstChild(); frame; frame->GetNextSibling(&frame)) {
if (frame == aKidFrame) {
break;
}
// Update the running y-offset
nsSize kidSize;
frame->GetSize(kidSize);
aReflowState.y += kidSize.height;
// If our height is constrained then update the available height
if (PR_FALSE == aReflowState.unconstrainedHeight) {
aReflowState.availSize.height -= kidSize.height;
}
// Update the maximum element size
if (aReflowState.firstRow) {
aReflowState.firstRow = PR_FALSE;
// XXX Today you can't ask for max-element-size when doing an
// incremental reflow
#if 0
if (aMaxElementSize) {
aMaxElementSize->width = aKidMaxElementSize.width;
aMaxElementSize->height = aKidMaxElementSize.height;
}
} else if (aMaxElementSize) {
aMaxElementSize->width = PR_MAX(aMaxElementSize->width, aKidMaxElementSize.width);
#endif
}
}
return NS_OK;
}
NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
RowGroupReflowState& aReflowState,
@ -1438,35 +1499,53 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext& aPresConte
{
nsresult rv;
if (PR_TRUE==gsDebugIR) printf("\nTRGF IR: IR_TargetIsChild\n");
// XXX Recover state
// Recover the state as if aNextFrame is about to be reflowed
RecoverState(aReflowState, aNextFrame);
// Remember the old rect
nsRect oldKidRect;
aNextFrame->GetRect(oldKidRect);
// Pass along the reflow command
// XXX Correctly compute the available space...
nsSize availSpace(aReflowState.reflowState.availableWidth, aReflowState.reflowState.availableHeight);
nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, aNextFrame, availSpace);
nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
aNextFrame, aReflowState.availSize);
nsHTMLReflowMetrics desiredSize(nsnull);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, aStatus);
// XXX Check aStatus to see if the frame is complete...
// Resize the row frame
nsRect kidRect;
aNextFrame->GetRect(kidRect);
aNextFrame->SizeTo(desiredSize.width, desiredSize.height);
// Place the row frame
nsSize kidMaxElementSize;
nsRect kidRect(0, aReflowState.y, desiredSize.width, desiredSize.height);
PlaceChild(aPresContext, aReflowState, aNextFrame, kidRect, nsnull,
kidMaxElementSize);
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);
// Return of desired size
// See if the table needs a reflow (e.g., if the column widths have
// changed). If so, just return and don't bother adjusting the rows
// that follow
if (!aReflowState.tableFrame->NeedsReflow(aReflowState.reflowState)) {
// Inform the row of its new height.
PRBool isJustSingleRow = PR_FALSE; /* how to determine this now? */
if (isJustSingleRow) {
((nsTableRowFrame*)aNextFrame)->DidResize(aPresContext, aReflowState.reflowState);
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);
aDesiredSize.height = aReflowState.y;
} else {
// Adjust the frames that follow...
AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame, desiredSize.height -
oldKidRect.height);
// Now recalculate the row heights
CalculateRowHeights(aPresContext, aDesiredSize, aReflowState.reflowState);
}
}
// Return our desired width
aDesiredSize.width = aReflowState.reflowState.availableWidth;
aDesiredSize.height = aReflowState.y;
// XXX If we have a next-in-flow, then we're not complete
if (mNextInFlow) {
aStatus = NS_FRAME_NOT_COMPLETE;
}

View File

@ -44,9 +44,6 @@ struct RowGroupReflowState {
// Flag used to set maxElementSize to my first row
PRBool firstRow;
// Remember the height of the first row, because it's our maxElementHeight (plus header/footers)
nscoord firstRowHeight;
nsTableFrame *tableFrame;
RowGroupReflowState(nsIPresContext& aPresContext,
@ -61,7 +58,6 @@ struct RowGroupReflowState {
unconstrainedWidth = PRBool(reflowState.availableWidth == NS_UNCONSTRAINEDSIZE);
unconstrainedHeight = PRBool(reflowState.availableHeight == NS_UNCONSTRAINEDSIZE);
firstRow = PR_TRUE;
firstRowHeight=0;
tableFrame = aTableFrame;
}
@ -245,6 +241,9 @@ protected:
RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nscoord aDeltaY);
nsresult RecoverState(RowGroupReflowState& aReflowState,
nsIFrame* aKidFrame);
/**
* Reflow the frames we've already created

View File

@ -38,6 +38,7 @@
#include "nsSpaceManager.h"
#include "nsHTMLParts.h"
#include "nsIViewManager.h"
#include "nsIPresShell.h"
#define CONSTANT float(0.0)
#define DEBUG_REFLOW 0
@ -1137,6 +1138,25 @@ nsBoxFrame::LayoutChildrenInRect(nsRect& size)
}
}
// Marks the frame as dirty and generates an incremental reflow
// command targeted at this frame
nsresult
nsBoxFrame::GenerateDirtyReflowCommand(nsIPresContext& aPresContext,
nsIPresShell& aPresShell)
{
nsCOMPtr<nsIReflowCommand> reflowCmd;
nsresult rv;
mState |= NS_FRAME_IS_DIRTY;
rv = NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this,
nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
// Add the reflow command
rv = aPresShell.AppendReflowCommand(reflowCmd);
}
return rv;
}
NS_IMETHODIMP
nsBoxFrame::RemoveFrame(nsIPresContext& aPresContext,
@ -1149,9 +1169,10 @@ nsBoxFrame::RemoveFrame(nsIPresContext& aPresContext,
mSprings[i].clear();
// remove the child frame
nsresult rv = nsHTMLContainerFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
mFrames.DestroyFrame(aPresContext, aOldFrame);
return rv;
// mark us dirty and generate a reflow command
return GenerateDirtyReflowCommand(aPresContext, aPresShell);
}
NS_IMETHODIMP
@ -1166,7 +1187,9 @@ nsBoxFrame::InsertFrames(nsIPresContext& aPresContext,
mSprings[i].clear();
mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
return nsHTMLContainerFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame, aFrameList);
// mark us dirty and generate a reflow command
return GenerateDirtyReflowCommand(aPresContext, aPresShell);
}
NS_IMETHODIMP
@ -1181,7 +1204,9 @@ nsBoxFrame::AppendFrames(nsIPresContext& aPresContext,
mSprings[i].clear();
mFrames.AppendFrames(nsnull, aFrameList);
return nsHTMLContainerFrame::AppendFrames(aPresContext, aPresShell, aListName, aFrameList);
// mark us dirty and generate a reflow command
return GenerateDirtyReflowCommand(aPresContext, aPresShell);
}

View File

@ -144,6 +144,9 @@ protected:
virtual void GetInset(nsMargin& margin);
nsresult GenerateDirtyReflowCommand(nsIPresContext& aPresContext,
nsIPresShell& aPresShell);
PRBool mHorizontal;
nsCalculatedBoxInfo mSprings[100];
nscoord mSpringCount;

View File

@ -979,14 +979,17 @@ nsMenuFrame::RemoveFrame(nsIPresContext& aPresContext,
for (int i=0; i < mSpringCount; i++)
mSprings[i].clear();
nsresult rv;
if (mPopupFrames.ContainsFrame(aOldFrame)) {
// Go ahead and remove this frame.
nsHTMLContainerFrame::RemoveFrame(aPresContext, aPresShell, nsLayoutAtoms::popupList, aOldFrame);
mPopupFrames.DestroyFrame(aPresContext, aOldFrame);
return NS_OK;
rv = GenerateDirtyReflowCommand(aPresContext, aPresShell);
} else {
rv = nsBoxFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
}
return nsBoxFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
return rv;
}
NS_IMETHODIMP
@ -1004,11 +1007,17 @@ nsMenuFrame::InsertFrames(nsIPresContext& aPresContext,
aFrameList->GetContent(getter_AddRefs(frameChild));
nsCOMPtr<nsIAtom> tag;
nsresult rv;
frameChild->GetTag(*getter_AddRefs(tag));
if (tag && tag.get() == nsXULAtoms::menupopup) {
mPopupFrames.InsertFrames(nsnull, nsnull, aFrameList);
rv = GenerateDirtyReflowCommand(aPresContext, aPresShell);
} else {
rv = nsBoxFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame, aFrameList);
}
return nsHTMLContainerFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame, aFrameList);
return rv;
}
NS_IMETHODIMP
@ -1028,10 +1037,15 @@ nsMenuFrame::AppendFrames(nsIPresContext& aPresContext,
aFrameList->GetContent(getter_AddRefs(frameChild));
nsCOMPtr<nsIAtom> tag;
nsresult rv;
frameChild->GetTag(*getter_AddRefs(tag));
if (tag && tag.get() == nsXULAtoms::menupopup) {
mPopupFrames.AppendFrames(nsnull, aFrameList);
rv = GenerateDirtyReflowCommand(aPresContext, aPresShell);
} else {
rv = nsBoxFrame::AppendFrames(aPresContext, aPresShell, aListName, aFrameList);
}
return nsHTMLContainerFrame::AppendFrames(aPresContext, aPresShell, aListName, aFrameList);
return rv;
}

View File

@ -286,14 +286,17 @@ nsPopupSetFrame::RemoveFrame(nsIPresContext& aPresContext,
for (int i=0; i < mSpringCount; i++)
mSprings[i].clear();
nsresult rv;
if (mPopupFrames.ContainsFrame(aOldFrame)) {
// Go ahead and remove this frame.
nsHTMLContainerFrame::RemoveFrame(aPresContext, aPresShell, nsLayoutAtoms::popupList, aOldFrame);
mPopupFrames.DestroyFrame(aPresContext, aOldFrame);
return NS_OK;
rv = GenerateDirtyReflowCommand(aPresContext, aPresShell);
} else {
rv = nsBoxFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
}
return nsBoxFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
return rv;
}
NS_IMETHODIMP
@ -310,11 +313,16 @@ nsPopupSetFrame::InsertFrames(nsIPresContext& aPresContext,
nsCOMPtr<nsIContent> frameChild;
aFrameList->GetContent(getter_AddRefs(frameChild));
nsCOMPtr<nsIAtom> tag;
nsresult rv;
frameChild->GetTag(*getter_AddRefs(tag));
if (tag && tag.get() == nsXULAtoms::menupopup) {
mPopupFrames.InsertFrames(nsnull, nsnull, aFrameList);
rv = GenerateDirtyReflowCommand(aPresContext, aPresShell);
} else {
rv = nsBoxFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame, aFrameList);
}
return nsHTMLContainerFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame, aFrameList);
return rv;
}
NS_IMETHODIMP
@ -334,10 +342,15 @@ nsPopupSetFrame::AppendFrames(nsIPresContext& aPresContext,
aFrameList->GetContent(getter_AddRefs(frameChild));
nsCOMPtr<nsIAtom> tag;
nsresult rv;
frameChild->GetTag(*getter_AddRefs(tag));
if (tag && tag.get() == nsXULAtoms::menupopup) {
mPopupFrames.AppendFrames(nsnull, aFrameList);
rv = GenerateDirtyReflowCommand(aPresContext, aPresShell);
} else {
rv = nsBoxFrame::AppendFrames(aPresContext, aPresShell, aListName, aFrameList);
}
return nsHTMLContainerFrame::AppendFrames(aPresContext, aPresShell, aListName, aFrameList);
return rv;
}

View File

@ -971,11 +971,21 @@ void nsTreeRowGroupFrame::OnContentAdded(nsIPresContext& aPresContext)
if (IsLazy() && !treeFrame->IsSlatedForReflow()) {
treeFrame->SlateForReflow();
// Schedule a reflow for us.
nsCOMPtr<nsIReflowCommand> reflowCmd;
// Mark the table frame as dirty
nsFrameState frameState;
nsresult rv = NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), treeFrame,
nsIReflowCommand::FrameAppended, nsnull);
treeFrame->GetFrameState(&frameState);
frameState |= NS_FRAME_IS_DIRTY;
treeFrame->SetFrameState(frameState);
// Schedule a reflow for us
nsCOMPtr<nsIReflowCommand> reflowCmd;
nsIFrame* outerTableFrame;
nsresult rv;
treeFrame->GetParent(&outerTableFrame);
rv = NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), outerTableFrame,
nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPresShell> presShell;
aPresContext.GetShell(getter_AddRefs(presShell));
@ -1007,11 +1017,21 @@ void nsTreeRowGroupFrame::OnContentRemoved(nsIPresContext& aPresContext,
if (IsLazy() && !treeFrame->IsSlatedForReflow()) {
treeFrame->SlateForReflow();
// Mark the table frame as dirty
nsFrameState frameState;
treeFrame->GetFrameState(&frameState);
frameState |= NS_FRAME_IS_DIRTY;
treeFrame->SetFrameState(frameState);
// Schedule a reflow for us.
nsCOMPtr<nsIReflowCommand> reflowCmd;
nsresult rv = NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), treeFrame,
nsIReflowCommand::FrameRemoved, nsnull);
nsIFrame* outerTableFrame;
nsresult rv;
treeFrame->GetParent(&outerTableFrame);
rv = NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), treeFrame,
nsIReflowCommand::ReflowDirty);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPresShell> presShell;
aPresContext.GetShell(getter_AddRefs(presShell));