1998-06-18 20:25:41 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* NPL.
|
|
|
|
*
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*/
|
1998-09-23 06:25:26 +04:00
|
|
|
#include "nsHTMLContainerFrame.h"
|
|
|
|
#include "nsFrameReflowState.h"
|
|
|
|
#include "nsInlineReflow.h"
|
1998-09-25 04:00:55 +04:00
|
|
|
#include "nsLineLayout.h"
|
|
|
|
#include "nsHTMLAtoms.h"
|
1998-09-23 06:25:26 +04:00
|
|
|
#include "nsHTMLIIDs.h"
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-09-25 04:00:55 +04:00
|
|
|
#include "nsIPresContext.h"
|
|
|
|
#include "nsIReflowCommand.h"
|
1998-09-23 06:25:26 +04:00
|
|
|
#include "nsISpaceManager.h"
|
1998-09-25 04:00:55 +04:00
|
|
|
#include "nsIStyleContext.h"
|
|
|
|
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
struct nsInlineReflowState : nsFrameReflowState {
|
|
|
|
nsInlineReflowState(nsIPresContext& aPresContext,
|
|
|
|
const nsReflowState& aReflowState,
|
|
|
|
const nsReflowMetrics& aMetrics);
|
|
|
|
~nsInlineReflowState();
|
1998-06-25 20:33:10 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Last child we have reflowed (so far)
|
|
|
|
nsIFrame* mLastChild;
|
|
|
|
};
|
1998-06-25 20:33:10 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineReflowState::nsInlineReflowState(nsIPresContext& aPresContext,
|
|
|
|
const nsReflowState& aReflowState,
|
|
|
|
const nsReflowMetrics& aMetrics)
|
|
|
|
: nsFrameReflowState(aPresContext, aReflowState, aMetrics)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-06-24 21:52:42 +04:00
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
mLastChild = nsnull;
|
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineReflowState::~nsInlineReflowState()
|
1998-06-19 03:16:00 +04:00
|
|
|
{
|
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
class nsInlineFrame : public nsHTMLContainerFrame,
|
|
|
|
public nsIInlineReflow
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsInlineFrame(nsIContent* aContent, nsIFrame* aParent);
|
|
|
|
virtual ~nsInlineFrame();
|
|
|
|
|
|
|
|
// nsISupports
|
|
|
|
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
|
|
|
|
|
|
|
// nsIFrame
|
|
|
|
NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList);
|
|
|
|
NS_IMETHOD CreateContinuingFrame(nsIPresContext& aCX,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIStyleContext* aStyleContext,
|
|
|
|
nsIFrame*& aContinuingFrame);
|
1998-09-25 04:00:55 +04:00
|
|
|
NS_IMETHOD AttributeChanged(nsIPresShell* aShell,
|
|
|
|
nsIPresContext* aPresContext,
|
|
|
|
nsIContent* aChild,
|
|
|
|
nsIAtom* aAttribute);
|
1998-09-23 06:25:26 +04:00
|
|
|
|
|
|
|
// nsIInlineReflow
|
|
|
|
NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout,
|
|
|
|
nsIReflowCommand* aReflowCommand);
|
|
|
|
NS_IMETHOD InlineReflow(nsLineLayout& aLineLayout,
|
|
|
|
nsReflowMetrics& aDesiredSize,
|
|
|
|
const nsReflowState& aReflowState);
|
|
|
|
|
|
|
|
virtual PRIntn GetSkipSides() const;
|
|
|
|
|
|
|
|
nsresult InitialReflow(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow);
|
|
|
|
|
|
|
|
nsresult FrameAppendedReflow(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow);
|
|
|
|
|
|
|
|
nsresult ChildIncrementalReflow(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow);
|
|
|
|
|
|
|
|
nsresult ResizeReflow(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow);
|
|
|
|
|
|
|
|
void ComputeFinalSize(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow,
|
|
|
|
nsReflowMetrics& aMetrics);
|
|
|
|
|
|
|
|
PRBool ReflowMapped(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow,
|
|
|
|
nsInlineReflowStatus& aReflowStatus);
|
|
|
|
|
|
|
|
PRBool ReflowFrame(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsInlineReflowStatus& aReflowStatus);
|
|
|
|
|
|
|
|
nsInlineReflowStatus PullUpChildren(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow);
|
|
|
|
|
|
|
|
nsIFrame* PullOneChild(nsInlineFrame* aNextInFlow,
|
|
|
|
nsIFrame* aLastChild);
|
|
|
|
|
|
|
|
void PushKids(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow,
|
|
|
|
nsIFrame* aPushedChild);
|
|
|
|
|
|
|
|
void DrainOverflowLists();
|
|
|
|
|
|
|
|
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame*);
|
|
|
|
|
|
|
|
void InsertNewFrame(nsIFrame* aNewFrame, nsIFrame* aPrevSibling);
|
|
|
|
|
|
|
|
friend nsresult NS_NewInlineFrame(nsIContent* aContent,
|
|
|
|
nsIFrame* aParentFrame,
|
|
|
|
nsIFrame*& aNewFrame);
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
1998-09-17 08:07:58 +04:00
|
|
|
nsresult NS_NewInlineFrame(nsIContent* aContent, nsIFrame* aParentFrame,
|
|
|
|
nsIFrame*& aNewFrame)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-09-17 08:07:58 +04:00
|
|
|
aNewFrame = new nsInlineFrame(aContent, aParentFrame);
|
|
|
|
if (nsnull == aNewFrame) {
|
1998-06-18 20:25:41 +04:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::nsInlineFrame(nsIContent* aContent, nsIFrame* aParent)
|
|
|
|
: nsHTMLContainerFrame(aContent, aParent)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::~nsInlineFrame()
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
|
|
|
if (nsnull == aInstancePtrResult) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
if (aIID.Equals(kIInlineReflowIID)) {
|
|
|
|
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
|
|
|
}
|
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
PRIntn
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::GetSkipSides() const
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-06-19 03:16:00 +04:00
|
|
|
PRIntn skip = 0;
|
|
|
|
if (nsnull != mPrevInFlow) {
|
|
|
|
skip |= 1 << NS_SIDE_LEFT;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1998-06-19 03:16:00 +04:00
|
|
|
if (nsnull != mNextInFlow) {
|
|
|
|
skip |= 1 << NS_SIDE_RIGHT;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1998-06-19 03:16:00 +04:00
|
|
|
return skip;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-09-12 08:46:35 +04:00
|
|
|
nsresult
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineFrame::AppendNewFrames(nsIPresContext& aPresContext,
|
|
|
|
nsIFrame* aNewFrame)
|
1998-09-12 08:46:35 +04:00
|
|
|
{
|
|
|
|
nsIFrame* lastFrame;
|
|
|
|
if (nsnull == mFirstChild) {
|
|
|
|
lastFrame = nsnull;
|
|
|
|
mFirstChild = aNewFrame;
|
|
|
|
} else {
|
1998-09-21 20:35:49 +04:00
|
|
|
lastFrame = LastFrame(mFirstChild);
|
1998-09-12 08:46:35 +04:00
|
|
|
lastFrame->SetNextSibling(aNewFrame);
|
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
return WrapFrames(aPresContext, lastFrame, aNewFrame);
|
1998-09-12 08:46:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
1998-09-12 08:46:35 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull == mFirstChild, "already initialized");
|
1998-09-23 06:25:26 +04:00
|
|
|
return AppendNewFrames(aPresContext, aChildList);
|
1998-09-12 08:46:35 +04:00
|
|
|
}
|
|
|
|
|
1998-06-19 22:23:28 +04:00
|
|
|
NS_IMETHODIMP
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::CreateContinuingFrame(nsIPresContext& aCX,
|
1998-09-23 06:25:26 +04:00
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIStyleContext* aStyleContext,
|
|
|
|
nsIFrame*& aContinuingFrame)
|
1998-06-19 22:23:28 +04:00
|
|
|
{
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame* cf = new nsInlineFrame(mContent, aParent);
|
1998-06-19 22:23:28 +04:00
|
|
|
if (nsnull == cf) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
PrepareContinuingFrame(aCX, aParent, aStyleContext, cf);
|
|
|
|
aContinuingFrame = cf;
|
1998-07-01 00:14:04 +04:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 04:19:49 +04:00
|
|
|
("nsInlineFrame::CreateContinuingFrame: newFrame=%p", cf));
|
1998-06-19 22:23:28 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-09-25 04:00:55 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsInlineFrame::AttributeChanged(nsIPresShell* aShell,
|
|
|
|
nsIPresContext* aPresContext,
|
|
|
|
nsIContent* aChild,
|
|
|
|
nsIAtom* aAttribute)
|
|
|
|
{
|
1998-09-25 04:51:45 +04:00
|
|
|
nsresult result = nsHTMLContainerFrame::AttributeChanged(aShell,
|
|
|
|
aPresContext,
|
|
|
|
aChild,
|
|
|
|
aAttribute);
|
|
|
|
if (NS_OK != result) {
|
|
|
|
return result;
|
|
|
|
}
|
1998-09-25 04:00:55 +04:00
|
|
|
if (nsHTMLAtoms::color == aAttribute) {
|
|
|
|
ApplyStyleChangeToTree(*aPresContext, this);
|
|
|
|
ApplyRenderingChangeToTree(*aPresContext, this);
|
|
|
|
}
|
|
|
|
else if (nsHTMLAtoms::face == aAttribute) {
|
|
|
|
ApplyStyleChangeToTree(*aPresContext, this);
|
|
|
|
ApplyReflowChangeToTree(*aPresContext, this);
|
|
|
|
ApplyRenderingChangeToTree(*aPresContext, this);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
NS_IMETHODIMP
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout,
|
1998-09-23 06:25:26 +04:00
|
|
|
nsIReflowCommand* aReflowCommand)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-06-28 02:56:09 +04:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-23 06:25:26 +04:00
|
|
|
("enter nsInlineFrame::FindTextRuns"));
|
1998-06-28 02:56:09 +04:00
|
|
|
|
1998-07-01 00:14:04 +04:00
|
|
|
// Gather up children from the overflow lists
|
1998-09-23 06:25:26 +04:00
|
|
|
nsresult rv = NS_OK;
|
1998-07-01 00:14:04 +04:00
|
|
|
DrainOverflowLists();
|
|
|
|
|
1998-06-28 02:56:09 +04:00
|
|
|
// Ask each child frame for its text runs
|
1998-09-23 06:25:26 +04:00
|
|
|
nsIFrame* frame = mFirstChild;
|
|
|
|
while (nsnull != frame) {
|
1998-06-28 02:56:09 +04:00
|
|
|
nsIInlineReflow* inlineReflow;
|
|
|
|
if (NS_OK == frame->QueryInterface(kIInlineReflowIID,
|
|
|
|
(void**)&inlineReflow)) {
|
1998-07-01 00:14:04 +04:00
|
|
|
rv = inlineReflow->FindTextRuns(aLineLayout, aReflowCommand);
|
1998-06-28 02:56:09 +04:00
|
|
|
if (NS_OK != rv) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// A frame that doesn't implement nsIInlineReflow isn't text
|
|
|
|
// therefore it will end an open text run.
|
|
|
|
aLineLayout.EndTextRun();
|
|
|
|
}
|
|
|
|
frame->GetNextSibling(frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-23 06:25:26 +04:00
|
|
|
("exit nsInlineFrame::FindTextRuns rv=%x", rv));
|
1998-06-28 02:56:09 +04:00
|
|
|
return rv;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-09-19 08:29:36 +04:00
|
|
|
void
|
|
|
|
nsInlineFrame::InsertNewFrame(nsIFrame* aNewFrame, nsIFrame* aPrevSibling)
|
|
|
|
{
|
1998-09-23 08:45:59 +04:00
|
|
|
nsIFrame* nextSibling;
|
1998-09-19 08:29:36 +04:00
|
|
|
|
|
|
|
if (nsnull == aPrevSibling) {
|
1998-09-23 08:45:59 +04:00
|
|
|
nextSibling = mFirstChild;
|
1998-09-19 08:29:36 +04:00
|
|
|
mFirstChild = aNewFrame;
|
|
|
|
} else {
|
|
|
|
aPrevSibling->GetNextSibling(nextSibling);
|
|
|
|
aPrevSibling->SetNextSibling(aNewFrame);
|
|
|
|
}
|
|
|
|
aNewFrame->SetNextSibling(nextSibling);
|
|
|
|
}
|
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
NS_IMETHODIMP
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineFrame::InlineReflow(nsLineLayout& aLineLayout,
|
|
|
|
nsReflowMetrics& aMetrics,
|
|
|
|
const nsReflowState& aReflowState)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-09-23 06:25:26 +04:00
|
|
|
//XXX ListTag(stdout); printf(": enter (runningMargin=%d)\n", aMetrics.mCarriedInTopMargin);
|
1998-06-19 22:23:28 +04:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-23 06:25:26 +04:00
|
|
|
("enter nsInlineFrame::InlineReflow maxSize=%d,%d reason=%d nif=%p",
|
1998-06-19 22:23:28 +04:00
|
|
|
aReflowState.maxSize.width, aReflowState.maxSize.height,
|
1998-09-23 06:25:26 +04:00
|
|
|
aReflowState.reason, mNextInFlow));
|
1998-06-19 22:23:28 +04:00
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
// If this is the initial reflow, generate any synthetic content
|
|
|
|
// that needs generating.
|
|
|
|
if (eReflowReason_Initial == aReflowState.reason) {
|
|
|
|
NS_ASSERTION(0 != (NS_FRAME_FIRST_REFLOW & mState), "bad mState");
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1998-06-19 03:16:00 +04:00
|
|
|
else {
|
|
|
|
NS_ASSERTION(0 == (NS_FRAME_FIRST_REFLOW & mState), "bad mState");
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Prepare for reflow
|
|
|
|
nsInlineReflowState state(aLineLayout.mPresContext, aReflowState, aMetrics);
|
|
|
|
|
|
|
|
// If we're constrained adjust the available size so it excludes space
|
|
|
|
// needed for border/padding
|
|
|
|
nscoord width = state.maxSize.width;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != width) {
|
|
|
|
width -= state.mBorderPadding.left + state.mBorderPadding.right;
|
|
|
|
}
|
|
|
|
nscoord height = state.maxSize.height;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != height) {
|
|
|
|
height -= state.mBorderPadding.top + state.mBorderPadding.bottom;
|
|
|
|
}
|
|
|
|
const nsStyleDisplay* display;
|
|
|
|
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display);
|
|
|
|
|
|
|
|
// Prepare inline reflow engine
|
|
|
|
nsInlineReflow inlineReflow(aLineLayout, state, this);
|
|
|
|
inlineReflow.Init(state.mBorderPadding.left, state.mBorderPadding.top,
|
|
|
|
width, height);
|
|
|
|
|
|
|
|
// Now translate in by our border and padding
|
|
|
|
aLineLayout.mSpaceManager->Translate(state.mBorderPadding.left,
|
|
|
|
state.mBorderPadding.top);
|
|
|
|
|
|
|
|
// Based on the type of reflow, switch out to the appropriate
|
|
|
|
// routine.
|
1998-06-19 03:16:00 +04:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (eReflowReason_Initial == state.reason) {
|
1998-07-01 00:14:04 +04:00
|
|
|
DrainOverflowLists();
|
1998-09-23 06:25:26 +04:00
|
|
|
rv = InitialReflow(state, inlineReflow);
|
1998-06-24 21:52:42 +04:00
|
|
|
mState &= ~NS_FRAME_FIRST_REFLOW;
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
|
|
|
else if (eReflowReason_Incremental == state.reason) {
|
1998-07-03 01:26:34 +04:00
|
|
|
// XXX For now we drain our overflow list in case our parent
|
|
|
|
// reflowed our prev-in-flow and our prev-in-flow pushed some
|
|
|
|
// children forward to us (e.g. a speculative pullup from us that
|
|
|
|
// failed)
|
|
|
|
DrainOverflowLists();
|
|
|
|
|
1998-06-24 21:52:42 +04:00
|
|
|
NS_ASSERTION(nsnull == mOverflowList, "unexpected overflow list");
|
1998-06-19 03:16:00 +04:00
|
|
|
nsIFrame* target;
|
|
|
|
state.reflowCommand->GetTarget(target);
|
|
|
|
if (this == target) {
|
|
|
|
nsIReflowCommand::ReflowType type;
|
|
|
|
state.reflowCommand->GetType(type);
|
1998-09-19 08:29:36 +04:00
|
|
|
nsIFrame* newFrame;
|
|
|
|
nsIFrame* prevSibling;
|
1998-06-19 03:16:00 +04:00
|
|
|
switch (type) {
|
|
|
|
case nsIReflowCommand::FrameAppended:
|
1998-09-23 06:25:26 +04:00
|
|
|
rv = FrameAppendedReflow(state, inlineReflow);
|
1998-06-18 20:25:41 +04:00
|
|
|
break;
|
|
|
|
|
1998-09-19 08:29:36 +04:00
|
|
|
case nsIReflowCommand::FrameInserted:
|
|
|
|
// Link the new frame into the child list
|
|
|
|
state.reflowCommand->GetChildFrame(newFrame);
|
|
|
|
state.reflowCommand->GetPrevSiblingFrame(prevSibling);
|
|
|
|
InsertNewFrame(newFrame, prevSibling);
|
|
|
|
// fall thru...
|
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
default:
|
1998-06-19 22:23:28 +04:00
|
|
|
// XXX For now map the other incremental operations into full reflows
|
1998-09-23 06:25:26 +04:00
|
|
|
rv = ResizeReflow(state, inlineReflow);
|
1998-06-19 22:23:28 +04:00
|
|
|
break;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
}
|
1998-06-19 03:16:00 +04:00
|
|
|
else {
|
1998-06-26 00:51:04 +04:00
|
|
|
// Get next frame in reflow command chain
|
1998-09-23 06:25:26 +04:00
|
|
|
state.reflowCommand->GetNext(state.mNextRCFrame);
|
1998-06-26 00:51:04 +04:00
|
|
|
|
|
|
|
// Continue the reflow
|
1998-09-23 06:25:26 +04:00
|
|
|
rv = ChildIncrementalReflow(state, inlineReflow);
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
}
|
1998-06-19 03:16:00 +04:00
|
|
|
else if (eReflowReason_Resize == state.reason) {
|
1998-07-01 00:14:04 +04:00
|
|
|
DrainOverflowLists();
|
1998-09-23 06:25:26 +04:00
|
|
|
rv = ResizeReflow(state, inlineReflow);
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
ComputeFinalSize(state, inlineReflow, aMetrics);
|
|
|
|
|
|
|
|
// Now translate in by our border and padding
|
|
|
|
aLineLayout.mSpaceManager->Translate(-state.mBorderPadding.left,
|
|
|
|
-state.mBorderPadding.top);
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-06-19 22:23:28 +04:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-23 06:25:26 +04:00
|
|
|
("exit nsInlineFrame::InlineReflow size=%d,%d rv=%x nif=%p",
|
|
|
|
aMetrics.width, aMetrics.height, rv, mNextInFlow));
|
|
|
|
//XXX ListTag(stdout); printf(": exit (runningMargin=%d)\n", aMetrics.mCarriedOutBottomMargin);
|
1998-06-19 03:16:00 +04:00
|
|
|
return rv;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// XXX factor this (into nsFrameReflowState?) so that both block and
|
|
|
|
// inline can use most of the same logic
|
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
void
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::ComputeFinalSize(nsInlineReflowState& aState,
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineReflow& aInlineReflow,
|
|
|
|
nsReflowMetrics& aMetrics)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-06-19 22:23:28 +04:00
|
|
|
// Align our child frames. Note that inline frames "shrink wrap"
|
|
|
|
// around their contents therefore we need to fixup the available
|
1998-09-15 04:19:49 +04:00
|
|
|
// width in nsInlineLayout so that it doesn't do any horizontal
|
1998-06-19 22:23:28 +04:00
|
|
|
// alignment.
|
1998-06-19 03:16:00 +04:00
|
|
|
nsRect bounds;
|
1998-09-23 06:25:26 +04:00
|
|
|
aInlineReflow.VerticalAlignFrames(bounds);
|
|
|
|
aInlineReflow.RelativePositionFrames();
|
|
|
|
|
|
|
|
// Make sure that we collapse into nothingness if our content is
|
|
|
|
// zero sized
|
|
|
|
if (0 == bounds.width) {
|
|
|
|
aMetrics.width = 0;
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
1998-06-19 22:23:28 +04:00
|
|
|
else {
|
1998-09-23 06:25:26 +04:00
|
|
|
aMetrics.width = aState.mBorderPadding.left + bounds.width +
|
|
|
|
aState.mBorderPadding.right;
|
1998-06-19 22:23:28 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Compute the final height. Make sure that we collapse into
|
|
|
|
// nothingness if our content is zero sized
|
|
|
|
if (0 == bounds.height) {
|
|
|
|
aMetrics.ascent = 0;
|
|
|
|
aMetrics.descent = 0;
|
|
|
|
aMetrics.height = 0;
|
|
|
|
aMetrics.mCarriedOutBottomMargin = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// XXX tip of the iceburg: when an inline is wrapping up a block frame
|
|
|
|
// it needs to go the whole hog: provide a proper spacemanager
|
|
|
|
// coordinate system; apply horizontal alignment (in case the block
|
|
|
|
// has a width set), etc. Of course the block code knows how to do
|
|
|
|
// this already...
|
|
|
|
//XXXprintf("bounds={%d,%d,%d,%d}\n",
|
|
|
|
//XXX bounds.x, bounds.y, bounds.width, bounds.height);
|
|
|
|
if (aInlineReflow.GetIsBlock()) {
|
|
|
|
// Make sure the blocks top and bottom margins get applied; the
|
|
|
|
// top margin will be in bounds.y; the bottom margin we get from
|
|
|
|
// the inline reflow.
|
|
|
|
nscoord bottomMargin = aInlineReflow.GetBottomMargin();
|
|
|
|
nscoord newY = aState.mBorderPadding.top + bounds.YMost()
|
|
|
|
+ bottomMargin + aState.mBorderPadding.bottom;
|
|
|
|
//XXXprintf("newY=%d bounds={%d,%d,%d,%d} bottomMargin=%d\n", newY,
|
|
|
|
//XXX bounds.x, bounds.y, bounds.width, bounds.height, bottomMargin);
|
|
|
|
aMetrics.height = newY;
|
|
|
|
aMetrics.ascent = newY;
|
1998-06-19 22:23:28 +04:00
|
|
|
aMetrics.descent = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aMetrics.ascent = aState.mBorderPadding.top +
|
1998-09-23 06:25:26 +04:00
|
|
|
aInlineReflow.GetMaxAscent();
|
|
|
|
aMetrics.descent = aInlineReflow.GetMaxDescent() +
|
1998-06-19 22:23:28 +04:00
|
|
|
aState.mBorderPadding.bottom;
|
|
|
|
aMetrics.height = aMetrics.ascent + aMetrics.descent;
|
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
|
|
|
|
// Carry out to the caller the running bottom margin value
|
|
|
|
if (0 != aState.mBorderPadding.bottom) {
|
|
|
|
// Don't carry out a child margin when we have a border
|
|
|
|
aMetrics.mCarriedOutBottomMargin = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Carry out our the total child bottom margin value
|
|
|
|
aMetrics.mCarriedOutBottomMargin = aState.mRunningMargin;
|
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
if (aState.mComputeMaxElementSize) {
|
|
|
|
// Adjust max-element size if this frame's no-wrap flag is set.
|
1998-06-25 20:33:10 +04:00
|
|
|
if (aState.mNoWrap) {
|
|
|
|
aMetrics.maxElementSize->width = aMetrics.width;
|
|
|
|
aMetrics.maxElementSize->height = aMetrics.height;
|
|
|
|
}
|
|
|
|
else {
|
1998-09-23 06:25:26 +04:00
|
|
|
*aMetrics.maxElementSize = aState.mMaxElementSize;
|
1998-06-25 20:33:10 +04:00
|
|
|
}
|
1998-07-11 01:45:30 +04:00
|
|
|
|
|
|
|
// Add in our border and padding to the max-element-size so that
|
|
|
|
// we don't shrink too far.
|
|
|
|
aMetrics.maxElementSize->width += aState.mBorderPadding.left +
|
|
|
|
aState.mBorderPadding.right;
|
|
|
|
aMetrics.maxElementSize->height += aState.mBorderPadding.top +
|
|
|
|
aState.mBorderPadding.bottom;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-07-01 00:14:04 +04:00
|
|
|
nsInlineReflowStatus
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineFrame::InitialReflow(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow)
|
1998-07-01 00:14:04 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull == mNextInFlow, "bad frame-appended-reflow");
|
1998-07-03 02:55:15 +04:00
|
|
|
|
1998-07-01 00:14:04 +04:00
|
|
|
nsInlineReflowStatus rs = NS_FRAME_COMPLETE;
|
1998-09-23 06:25:26 +04:00
|
|
|
if (nsnull != mFirstChild) {
|
|
|
|
if (!ReflowMapped(aState, aInlineReflow, rs)) {
|
1998-07-01 00:14:04 +04:00
|
|
|
return rs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rs;
|
|
|
|
}
|
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
nsInlineReflowStatus
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineFrame::FrameAppendedReflow(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow)
|
1998-06-19 03:16:00 +04:00
|
|
|
{
|
1998-06-28 02:56:09 +04:00
|
|
|
NS_PRECONDITION(nsnull == mNextInFlow, "bad frame-appended-reflow");
|
1998-06-19 22:23:28 +04:00
|
|
|
|
1998-09-12 08:46:35 +04:00
|
|
|
// Get the first of the newly appended frames
|
|
|
|
nsIFrame* firstAppendedFrame;
|
|
|
|
aState.reflowCommand->GetChildFrame(firstAppendedFrame);
|
|
|
|
|
|
|
|
// Add the new frames
|
|
|
|
AppendNewFrames(aState.mPresContext, firstAppendedFrame);
|
1998-06-19 22:23:28 +04:00
|
|
|
|
1998-06-28 02:56:09 +04:00
|
|
|
nsInlineReflowStatus rs = NS_FRAME_COMPLETE;
|
1998-09-23 06:25:26 +04:00
|
|
|
if (nsnull != mFirstChild) {
|
|
|
|
if (!ReflowMapped(aState, aInlineReflow, rs)) {
|
1998-06-25 20:33:10 +04:00
|
|
|
return rs;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
}
|
1998-06-28 02:56:09 +04:00
|
|
|
return rs;
|
|
|
|
}
|
1998-06-19 22:23:28 +04:00
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
nsInlineReflowStatus
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineFrame::ChildIncrementalReflow(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-06-19 03:16:00 +04:00
|
|
|
// XXX we can do better SOMEDAY
|
1998-09-23 06:25:26 +04:00
|
|
|
return ResizeReflow(aState, aInlineReflow);
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
nsInlineReflowStatus
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineFrame::ResizeReflow(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow)
|
1998-06-19 03:16:00 +04:00
|
|
|
{
|
1998-06-28 02:56:09 +04:00
|
|
|
nsInlineReflowStatus rs = NS_FRAME_COMPLETE;
|
1998-09-23 06:25:26 +04:00
|
|
|
if (nsnull != mFirstChild) {
|
|
|
|
if (!ReflowMapped(aState, aInlineReflow, rs)) {
|
1998-06-25 20:33:10 +04:00
|
|
|
return rs;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
}
|
1998-06-19 22:23:28 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Try to fit some more children from our next in flow
|
|
|
|
if (nsnull != mNextInFlow) {
|
|
|
|
rs = PullUpChildren(aState, aInlineReflow);
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
1998-06-25 20:33:10 +04:00
|
|
|
return rs;
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-06-25 20:33:10 +04:00
|
|
|
PRBool
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::ReflowMapped(nsInlineReflowState& aState,
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineReflow& aInlineReflow,
|
|
|
|
nsInlineReflowStatus& aReflowStatus)
|
1998-06-19 03:16:00 +04:00
|
|
|
{
|
1998-09-23 06:25:26 +04:00
|
|
|
PRBool keepGoing = PR_TRUE;
|
|
|
|
aState.mLastChild = nsnull;
|
1998-06-19 03:16:00 +04:00
|
|
|
nsIFrame* child = mFirstChild;
|
1998-06-19 22:23:28 +04:00
|
|
|
while (nsnull != child) {
|
1998-09-23 06:25:26 +04:00
|
|
|
keepGoing = ReflowFrame(aState, aInlineReflow, child, aReflowStatus);
|
|
|
|
if (!keepGoing) {
|
|
|
|
break;
|
1998-06-28 02:56:09 +04:00
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
aState.mLastChild = child;
|
|
|
|
child->GetNextSibling(child);
|
1998-06-19 22:23:28 +04:00
|
|
|
}
|
1998-06-25 20:33:10 +04:00
|
|
|
return keepGoing;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineReflowStatus
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::PullUpChildren(nsInlineReflowState& aState,
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineReflow& aInlineReflow)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineReflowStatus reflowStatus = NS_FRAME_COMPLETE;
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow;
|
1998-06-19 03:16:00 +04:00
|
|
|
while (nsnull != nextInFlow) {
|
|
|
|
// Get child from our next-in-flow
|
1998-09-23 06:25:26 +04:00
|
|
|
nsIFrame* child = PullOneChild(nextInFlow, aState.mLastChild);
|
1998-06-19 03:16:00 +04:00
|
|
|
if (nsnull == child) {
|
1998-09-15 04:19:49 +04:00
|
|
|
nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow;
|
1998-06-19 03:16:00 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Reflow the new child; if it turns out we can't keep it then
|
|
|
|
// ReflowFrame will push it back down to the next-in-flow.
|
|
|
|
if (!ReflowFrame(aState, aInlineReflow, child, reflowStatus)) {
|
|
|
|
break;
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
aState.mLastChild = child;
|
|
|
|
}
|
|
|
|
return reflowStatus;
|
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
PRBool
|
|
|
|
nsInlineFrame::ReflowFrame(nsInlineReflowState& aState,
|
|
|
|
nsInlineReflow& aInlineReflow,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsInlineReflowStatus& aReflowStatus)
|
|
|
|
{
|
|
|
|
aInlineReflow.SetIsFirstChild(aFrame == mFirstChild);
|
|
|
|
aReflowStatus = aInlineReflow.ReflowFrame(aFrame);
|
|
|
|
if (NS_IS_REFLOW_ERROR(aReflowStatus)) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1998-06-28 02:56:09 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// XXX temporary code until blocks can return break-after naturally
|
|
|
|
if (aInlineReflow.GetIsBlock() &&
|
|
|
|
!NS_INLINE_IS_BREAK(aReflowStatus) &&
|
|
|
|
NS_FRAME_IS_COMPLETE(aReflowStatus)) {
|
|
|
|
// Force reflow status to be what the block code should have returned
|
|
|
|
aReflowStatus = NS_INLINE_LINE_BREAK_AFTER(NS_FRAME_COMPLETE);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
|
|
|
("nsInlineFrame::ReflowMapped: frame=%p reflowStatus=%x",
|
|
|
|
aFrame, aReflowStatus));
|
|
|
|
|
|
|
|
if (NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
|
|
|
// When breaking before a frame there is no point in creating the
|
|
|
|
// continuation because it may not be needed when the frame is
|
|
|
|
// reflowed in it's new location.
|
|
|
|
if (aFrame != mFirstChild) {
|
|
|
|
// We have other children before the child that needs the
|
|
|
|
// break-before. Therefore map the break-before from the child
|
|
|
|
// into a break-after for us, preserving the break-type in the
|
|
|
|
// process. This is important when the break type is not just a
|
|
|
|
// simple line break.
|
|
|
|
aReflowStatus = NS_FRAME_NOT_COMPLETE | NS_INLINE_BREAK |
|
|
|
|
NS_INLINE_BREAK_AFTER | (NS_INLINE_BREAK_TYPE_MASK & aReflowStatus);
|
|
|
|
PushKids(aState, aInlineReflow, aFrame);
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
else if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) {
|
|
|
|
// We may be breaking after a frame here (e.g. a child inline
|
|
|
|
// frame that contains a BR tag and more content after the BR
|
|
|
|
// tag). We will propagate that upward so that this frame gets
|
|
|
|
// continued so that it can map the childs remaining content.
|
|
|
|
|
|
|
|
// Create continuation frame for the child frame when it's not
|
|
|
|
// complete.
|
|
|
|
nsIFrame* newFrame;
|
|
|
|
nsresult rv;
|
|
|
|
rv = CreateNextInFlow(aState.mPresContext, this, aFrame, newFrame);
|
|
|
|
if (NS_OK != rv) {
|
|
|
|
aReflowStatus = nsInlineReflowStatus(rv);
|
|
|
|
return PR_FALSE;
|
1998-06-28 02:56:09 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Advance to next frame
|
|
|
|
aState.mLastChild = aFrame;
|
|
|
|
aFrame->GetNextSibling(aFrame);
|
1998-06-28 02:56:09 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Push remaining frames, if any. There may be no more frames if
|
|
|
|
// the continuation frame already existed and it belongs to
|
|
|
|
// <b>our</b> next-in-flow.
|
|
|
|
if (nsnull != aFrame) {
|
|
|
|
PushKids(aState, aInlineReflow, aFrame);
|
1998-06-28 02:56:09 +04:00
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
else if (NS_INLINE_IS_BREAK_AFTER(aReflowStatus)) {
|
|
|
|
// If we are breaking after a child that's complete, we may still
|
|
|
|
// be incomplete if we have more children that need
|
|
|
|
// reflowing. Check for this after advancing to the next frame.
|
|
|
|
aState.mLastChild = aFrame;
|
|
|
|
aFrame->GetNextSibling(aFrame);
|
|
|
|
if (nsnull != aFrame) {
|
|
|
|
PushKids(aState, aInlineReflow, aFrame);
|
|
|
|
aReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// We did the easy check for our completion status, now do the
|
|
|
|
// hard one. See if any of our next-in-flows have any frames
|
|
|
|
// left in them.
|
|
|
|
nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow;
|
|
|
|
while (nsnull != nextInFlow) {
|
|
|
|
if (nsnull != nextInFlow->mFirstChild) {
|
|
|
|
// One of our next-in-flows has a child remaining. Therefore
|
|
|
|
// we are not complete and must let our parent know so that
|
|
|
|
// our parent doesn't accidently remove our next-in-flows!
|
1998-06-28 02:56:09 +04:00
|
|
|
aReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
1998-09-23 06:25:26 +04:00
|
|
|
break;
|
1998-06-19 22:23:28 +04:00
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow;
|
1998-06-19 03:16:00 +04:00
|
|
|
}
|
1998-06-19 22:23:28 +04:00
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
return PR_FALSE;
|
1998-06-19 22:23:28 +04:00
|
|
|
}
|
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
return PR_TRUE;
|
1998-06-19 22:23:28 +04:00
|
|
|
}
|
|
|
|
|
1998-06-24 21:52:42 +04:00
|
|
|
nsIFrame*
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::PullOneChild(nsInlineFrame* aNextInFlow,
|
1998-09-24 08:12:01 +04:00
|
|
|
nsIFrame* aLastChild)
|
1998-06-24 21:52:42 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull != aNextInFlow, "null ptr");
|
|
|
|
|
|
|
|
// Get first available frame from the next-in-flow; if it's out of
|
|
|
|
// frames check it's overflow list.
|
|
|
|
nsIFrame* kidFrame = aNextInFlow->mFirstChild;
|
|
|
|
if (nsnull == kidFrame) {
|
|
|
|
if (nsnull == aNextInFlow->mOverflowList) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
|
1998-09-15 04:19:49 +04:00
|
|
|
("nsInlineFrame::PullOneChild: from overflow list, frame=%p",
|
1998-06-24 21:52:42 +04:00
|
|
|
kidFrame));
|
|
|
|
kidFrame = aNextInFlow->mOverflowList;
|
|
|
|
kidFrame->GetNextSibling(aNextInFlow->mOverflowList);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
|
1998-09-23 06:25:26 +04:00
|
|
|
("nsInlineFrame::PullOneChild: frame=%p",
|
|
|
|
kidFrame));
|
1998-06-24 21:52:42 +04:00
|
|
|
|
|
|
|
// Take the frame away from the next-in-flow. Update it's first
|
1998-07-01 00:14:04 +04:00
|
|
|
// content offset.
|
1998-06-24 21:52:42 +04:00
|
|
|
kidFrame->GetNextSibling(aNextInFlow->mFirstChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now give the frame to this container
|
|
|
|
kidFrame->SetGeometricParent(this);
|
|
|
|
nsIFrame* contentParent;
|
|
|
|
kidFrame->GetContentParent(contentParent);
|
|
|
|
if (aNextInFlow == contentParent) {
|
|
|
|
kidFrame->SetContentParent(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the frame on our list
|
|
|
|
if (nsnull == aLastChild) {
|
|
|
|
mFirstChild = kidFrame;
|
|
|
|
} else {
|
|
|
|
aLastChild->SetNextSibling(kidFrame);
|
|
|
|
}
|
|
|
|
kidFrame->SetNextSibling(nsnull);
|
|
|
|
|
|
|
|
return kidFrame;
|
|
|
|
}
|
|
|
|
|
1998-06-19 03:16:00 +04:00
|
|
|
void
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::PushKids(nsInlineReflowState& aState,
|
1998-09-23 06:25:26 +04:00
|
|
|
nsInlineReflow& aInlineReflow,
|
|
|
|
nsIFrame* aPushedChild)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-09-23 06:25:26 +04:00
|
|
|
#ifdef NS_DEBUG
|
1998-07-01 00:14:04 +04:00
|
|
|
NS_ASSERTION(nsnull == mOverflowList, "bad overflow list");
|
1998-09-23 06:25:26 +04:00
|
|
|
NS_ASSERTION(nsnull != aPushedChild, "bad pushkids call");
|
|
|
|
NS_ASSERTION(nsnull != aState.mLastChild, "bad pushkids call");
|
|
|
|
nsIFrame* nextSib;
|
|
|
|
aState.mLastChild->GetNextSibling(nextSib);
|
|
|
|
NS_ASSERTION(nextSib == aPushedChild, "bad pushkids call");
|
|
|
|
#endif
|
1998-07-01 00:14:04 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Break sibling list
|
|
|
|
aState.mLastChild->SetNextSibling(nsnull);
|
1998-07-01 00:14:04 +04:00
|
|
|
|
1998-09-23 06:25:26 +04:00
|
|
|
// Place overflow frames on our overflow list; our next-in-flow
|
|
|
|
// will pick them up when it is reflowed
|
|
|
|
mOverflowList = aPushedChild;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1998-07-01 00:14:04 +04:00
|
|
|
|
|
|
|
void
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame::DrainOverflowLists()
|
1998-07-01 00:14:04 +04:00
|
|
|
{
|
|
|
|
// Our prev-in-flows overflow list goes before my children and must
|
|
|
|
// be re-parented.
|
|
|
|
if (nsnull != mPrevInFlow) {
|
1998-09-15 04:19:49 +04:00
|
|
|
nsInlineFrame* prevInFlow = (nsInlineFrame*) mPrevInFlow;
|
1998-07-01 00:14:04 +04:00
|
|
|
if (nsnull != prevInFlow->mOverflowList) {
|
|
|
|
nsIFrame* frame = prevInFlow->mOverflowList;
|
|
|
|
nsIFrame* lastFrame = nsnull;
|
|
|
|
while (nsnull != frame) {
|
|
|
|
// Reparent the frame
|
|
|
|
frame->SetGeometricParent(this);
|
|
|
|
nsIFrame* contentParent;
|
|
|
|
frame->GetContentParent(contentParent);
|
|
|
|
if (prevInFlow == contentParent) {
|
|
|
|
frame->SetContentParent(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Advance through the list
|
|
|
|
lastFrame = frame;
|
|
|
|
frame->GetNextSibling(frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Join the two frame lists together and update our child count
|
|
|
|
nsIFrame* newFirstChild = prevInFlow->mOverflowList;
|
|
|
|
lastFrame->SetNextSibling(mFirstChild);
|
|
|
|
mFirstChild = newFirstChild;
|
|
|
|
prevInFlow->mOverflowList = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Our overflow list goes to the end of our child list
|
|
|
|
if (nsnull != mOverflowList) {
|
|
|
|
// Append the overflow list to the end of our child list
|
1998-09-19 07:24:26 +04:00
|
|
|
nsIFrame* lastFrame = LastFrame(mFirstChild);
|
1998-07-01 00:14:04 +04:00
|
|
|
if (nsnull == lastFrame) {
|
|
|
|
mFirstChild = mOverflowList;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lastFrame->SetNextSibling(mOverflowList);
|
|
|
|
}
|
|
|
|
mOverflowList = nsnull;
|
|
|
|
}
|
|
|
|
}
|