1998-06-18 16:25:41 +00: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-15 00:19:49 +00:00
|
|
|
#include "nsInlineFrame.h"
|
1998-06-18 16:25:41 +00:00
|
|
|
#include "nsCSSLayout.h"
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
#include "nsIReflowCommand.h"
|
|
|
|
#include "nsIStyleContext.h"
|
1998-09-12 04:46:35 +00:00
|
|
|
#include "nsPlaceholderFrame.h"
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-19 18:23:28 +00:00
|
|
|
#include "nsHTMLIIDs.h"// XXX
|
1998-09-15 00:19:49 +00:00
|
|
|
#include "nsHTMLBase.h"// XXX rename to nsBase?
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-19 18:23:28 +00:00
|
|
|
// XXX TODO:
|
1998-06-25 16:33:10 +00:00
|
|
|
|
|
|
|
// test: <b>...<br></b> : make sure that it works in pullup case and
|
|
|
|
// non-pullup case
|
|
|
|
|
1998-06-19 18:23:28 +00:00
|
|
|
// content appended INCREMENTAL reflow
|
|
|
|
// content inserted INCREMENTAL reflow
|
|
|
|
// content deleted INCREMENTAL reflow
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineReflowState::nsInlineReflowState(nsLineLayout& aLineLayout,
|
|
|
|
nsInlineFrame* aInlineFrame,
|
1998-06-18 23:16:00 +00:00
|
|
|
nsIStyleContext* aInlineSC,
|
|
|
|
const nsReflowState& aRS,
|
1998-06-25 16:33:10 +00:00
|
|
|
PRBool aComputeMaxElementSize)
|
1998-06-25 21:11:12 +00:00
|
|
|
: nsReflowState(aRS),
|
1998-06-18 23:16:00 +00:00
|
|
|
mInlineLayout(aLineLayout, aInlineFrame, aInlineSC)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-06-24 17:52:42 +00:00
|
|
|
// While we skip around the reflow state that our parent gave us so
|
|
|
|
// that the parentReflowState is linked properly, we don't want to
|
|
|
|
// skip over it's reason.
|
|
|
|
reason = aRS.reason;
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
mPresContext = aLineLayout.mPresContext;
|
|
|
|
mLastChild = nsnull;
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
const nsStyleText* styleText = (const nsStyleText*)
|
|
|
|
aInlineSC->GetStyleData(eStyleStruct_Text);
|
|
|
|
mNoWrap = PRBool(NS_STYLE_WHITESPACE_NORMAL != styleText->mWhiteSpace);
|
|
|
|
const nsStyleSpacing* styleSpacing = (const nsStyleSpacing*)
|
|
|
|
aInlineSC->GetStyleData(eStyleStruct_Spacing);
|
|
|
|
styleSpacing->CalcBorderPaddingFor(aInlineFrame, mBorderPadding);
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
// If we're constrained adjust the available size so it excludes space
|
|
|
|
// needed for border/padding
|
|
|
|
nscoord width = maxSize.width;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != width) {
|
|
|
|
width -= mBorderPadding.left + mBorderPadding.right;
|
|
|
|
}
|
|
|
|
// XXX I don't think we need this!
|
|
|
|
nscoord height = maxSize.height;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != height) {
|
|
|
|
height -= mBorderPadding.top + mBorderPadding.bottom;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
PRIntn ss = mStyleSizeFlags =
|
|
|
|
nsCSSLayout::GetStyleSize(mPresContext, *this, mStyleSize);
|
|
|
|
if (0 != (ss & NS_SIZE_HAS_WIDTH)) {
|
|
|
|
// When we are given a width, change the reflow behavior to
|
|
|
|
// unconstrained.
|
|
|
|
// XXX is this right?
|
|
|
|
width = NS_UNCONSTRAINEDSIZE;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
mInlineLayout.Init(this);
|
|
|
|
mInlineLayout.Prepare(PRBool(NS_UNCONSTRAINEDSIZE == width),
|
1998-06-25 16:33:10 +00:00
|
|
|
mNoWrap, aComputeMaxElementSize);
|
1998-06-18 23:16:00 +00:00
|
|
|
mInlineLayout.SetReflowSpace(mBorderPadding.left, mBorderPadding.top,
|
|
|
|
width, height/* XXX height??? */);
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineReflowState::~nsInlineReflowState()
|
1998-06-18 23:16:00 +00:00
|
|
|
{
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
1998-09-17 04:07:58 +00:00
|
|
|
nsresult NS_NewInlineFrame(nsIContent* aContent, nsIFrame* aParentFrame,
|
|
|
|
nsIFrame*& aNewFrame)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-09-17 04:07:58 +00:00
|
|
|
aNewFrame = new nsInlineFrame(aContent, aParentFrame);
|
|
|
|
if (nsnull == aNewFrame) {
|
1998-06-18 16:25:41 +00:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::nsInlineFrame(nsIContent* aContent, nsIFrame* aParent)
|
|
|
|
: nsHTMLContainerFrame(aContent, aParent)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::~nsInlineFrame()
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
1998-06-18 16:25:41 +00: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-18 23:16:00 +00:00
|
|
|
PRIntn
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::GetSkipSides() const
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-06-18 23:16:00 +00:00
|
|
|
PRIntn skip = 0;
|
|
|
|
if (nsnull != mPrevInFlow) {
|
|
|
|
skip |= 1 << NS_SIDE_LEFT;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
if (nsnull != mNextInFlow) {
|
|
|
|
skip |= 1 << NS_SIDE_RIGHT;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
return skip;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-09-12 04:46:35 +00:00
|
|
|
nsresult
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::AppendNewFrames(nsIPresContext* aPresContext,
|
1998-09-12 04:46:35 +00:00
|
|
|
nsIFrame* aNewFrame)
|
|
|
|
{
|
|
|
|
nsIFrame* lastFrame;
|
|
|
|
if (nsnull == mFirstChild) {
|
|
|
|
lastFrame = nsnull;
|
|
|
|
mFirstChild = aNewFrame;
|
|
|
|
} else {
|
1998-09-19 03:24:26 +00:00
|
|
|
LastFrame(mFirstChild);
|
1998-09-12 04:46:35 +00:00
|
|
|
lastFrame->SetNextSibling(aNewFrame);
|
|
|
|
}
|
|
|
|
mChildCount += LengthOf(aNewFrame);
|
|
|
|
|
|
|
|
// Now walk the new frames and check if there are any elements that want
|
|
|
|
// to be floated
|
|
|
|
nsIFrame* prevFrame = lastFrame;
|
|
|
|
for (nsIFrame* frame = aNewFrame; nsnull != frame; frame->GetNextSibling(frame)) {
|
|
|
|
const nsStyleDisplay* display;
|
|
|
|
frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display);
|
|
|
|
|
|
|
|
// See if the element wants to be floated
|
|
|
|
if (NS_STYLE_FLOAT_NONE != display->mFloats) {
|
|
|
|
// Create a placeholder frame that will serve as the anchor point.
|
1998-09-15 00:19:49 +00:00
|
|
|
nsPlaceholderFrame* placeholder =
|
|
|
|
CreatePlaceholderFrame(aPresContext, frame);
|
1998-09-12 04:46:35 +00:00
|
|
|
|
|
|
|
// Remove the floated element from the flow, and replace it with the
|
|
|
|
// placeholder frame
|
|
|
|
if (nsnull == prevFrame) {
|
|
|
|
mFirstChild = placeholder;
|
|
|
|
} else {
|
|
|
|
prevFrame->SetNextSibling(placeholder);
|
|
|
|
}
|
|
|
|
nsIFrame* nextSibling;
|
|
|
|
frame->GetNextSibling(nextSibling);
|
|
|
|
placeholder->SetNextSibling(nextSibling);
|
|
|
|
frame->SetNextSibling(nsnull);
|
|
|
|
|
|
|
|
frame = placeholder;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remember the previous frame
|
|
|
|
prevFrame = frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
1998-09-12 04:46:35 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull == mFirstChild, "already initialized");
|
|
|
|
return AppendNewFrames(&aPresContext, aChildList);
|
|
|
|
}
|
|
|
|
|
1998-06-19 18:23:28 +00:00
|
|
|
NS_IMETHODIMP
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::CreateContinuingFrame(nsIPresContext& aCX,
|
1998-06-19 18:23:28 +00:00
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIStyleContext* aStyleContext,
|
|
|
|
nsIFrame*& aContinuingFrame)
|
|
|
|
{
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame* cf = new nsInlineFrame(mContent, aParent);
|
1998-06-19 18:23:28 +00:00
|
|
|
if (nsnull == cf) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
PrepareContinuingFrame(aCX, aParent, aStyleContext, cf);
|
|
|
|
aContinuingFrame = cf;
|
1998-06-30 20:14:04 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("nsInlineFrame::CreateContinuingFrame: newFrame=%p", cf));
|
1998-06-19 18:23:28 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-06-25 16:33:10 +00:00
|
|
|
PRBool
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::DeleteNextInFlowsFor(nsIPresContext& aPresContext, nsIFrame* aChild)
|
1998-06-25 16:33:10 +00:00
|
|
|
{
|
1998-08-28 03:02:39 +00:00
|
|
|
return DeleteChildsNextInFlow(aPresContext, aChild);
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
NS_IMETHODIMP
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout,
|
1998-06-30 20:14:04 +00:00
|
|
|
nsIReflowCommand* aReflowCommand)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-06-27 22:56:09 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("enter nsInlineFrame::FindTextRuns [%d,%d,%c]",
|
1998-06-27 22:56:09 +00:00
|
|
|
mFirstContentOffset, mLastContentOffset, mLastContentIsComplete?'T':'F'));
|
|
|
|
|
|
|
|
nsIFrame* frame;
|
|
|
|
PRInt32 n;
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
1998-06-30 20:14:04 +00:00
|
|
|
// Gather up children from the overflow lists
|
|
|
|
DrainOverflowLists();
|
|
|
|
|
1998-06-27 22:56:09 +00:00
|
|
|
// Ask each child frame for its text runs
|
|
|
|
frame = mFirstChild;
|
|
|
|
n = mChildCount;
|
|
|
|
while (--n >= 0) {
|
|
|
|
nsIInlineReflow* inlineReflow;
|
|
|
|
if (NS_OK == frame->QueryInterface(kIInlineReflowIID,
|
|
|
|
(void**)&inlineReflow)) {
|
1998-06-30 20:14:04 +00:00
|
|
|
rv = inlineReflow->FindTextRuns(aLineLayout, aReflowCommand);
|
1998-06-27 22:56:09 +00: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-15 00:19:49 +00:00
|
|
|
("exit nsInlineFrame::FindTextRuns rv=%x [%d,%d,%c]",
|
1998-06-27 22:56:09 +00:00
|
|
|
rv, mFirstContentOffset, mLastContentOffset,
|
|
|
|
mLastContentIsComplete?'T':'F'));
|
|
|
|
return rv;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-09-19 04:29:36 +00:00
|
|
|
void
|
|
|
|
nsInlineFrame::InsertNewFrame(nsIFrame* aNewFrame, nsIFrame* aPrevSibling)
|
|
|
|
{
|
|
|
|
nsIFrame* nextSibling = nsnull;
|
|
|
|
|
|
|
|
if (nsnull == aPrevSibling) {
|
|
|
|
if (nsnull != mFirstChild) {
|
|
|
|
mFirstChild->GetNextSibling(nextSibling);
|
|
|
|
}
|
|
|
|
mFirstChild = aNewFrame;
|
|
|
|
} else {
|
|
|
|
aPrevSibling->GetNextSibling(nextSibling);
|
|
|
|
aPrevSibling->SetNextSibling(aNewFrame);
|
|
|
|
}
|
|
|
|
aNewFrame->SetNextSibling(nextSibling);
|
|
|
|
}
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
NS_IMETHODIMP
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::InlineReflow(nsLineLayout& aLineLayout,
|
1998-06-18 23:16:00 +00:00
|
|
|
nsReflowMetrics& aMetrics,
|
|
|
|
const nsReflowState& aReflowState)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-06-19 18:23:28 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("enter nsInlineFrame::InlineReflow maxSize=%d,%d reason=%d kids=%d nif=%p [%d,%d,%c]",
|
1998-06-19 18:23:28 +00:00
|
|
|
aReflowState.maxSize.width, aReflowState.maxSize.height,
|
1998-06-27 22:56:09 +00:00
|
|
|
aReflowState.reason, mChildCount, mNextInFlow,
|
1998-06-19 18:23:28 +00:00
|
|
|
mFirstContentOffset, mLastContentOffset, mLastContentIsComplete?'T':'F'));
|
|
|
|
|
1998-06-18 23:16:00 +00: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 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
else {
|
|
|
|
NS_ASSERTION(0 == (NS_FRAME_FIRST_REFLOW & mState), "bad mState");
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineReflowState state(aLineLayout, this, mStyleContext,
|
1998-06-25 16:33:10 +00:00
|
|
|
aReflowState,
|
|
|
|
PRBool(nsnull != aMetrics.maxElementSize));
|
1998-06-18 23:16:00 +00:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (eReflowReason_Initial == state.reason) {
|
1998-06-30 20:14:04 +00:00
|
|
|
DrainOverflowLists();
|
|
|
|
rv = InitialReflow(state);
|
1998-06-24 17:52:42 +00:00
|
|
|
mState &= ~NS_FRAME_FIRST_REFLOW;
|
1998-06-18 23:16:00 +00:00
|
|
|
}
|
|
|
|
else if (eReflowReason_Incremental == state.reason) {
|
1998-07-02 21:26:34 +00: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 17:52:42 +00:00
|
|
|
NS_ASSERTION(nsnull == mOverflowList, "unexpected overflow list");
|
1998-06-18 23:16:00 +00:00
|
|
|
nsIFrame* target;
|
|
|
|
state.reflowCommand->GetTarget(target);
|
|
|
|
if (this == target) {
|
|
|
|
nsIReflowCommand::ReflowType type;
|
|
|
|
state.reflowCommand->GetType(type);
|
1998-09-19 04:29:36 +00:00
|
|
|
nsIFrame* newFrame;
|
|
|
|
nsIFrame* prevSibling;
|
1998-06-18 23:16:00 +00:00
|
|
|
switch (type) {
|
|
|
|
case nsIReflowCommand::FrameAppended:
|
|
|
|
rv = FrameAppendedReflow(state);
|
1998-06-18 16:25:41 +00:00
|
|
|
break;
|
|
|
|
|
1998-09-19 04:29:36 +00: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-18 23:16:00 +00:00
|
|
|
default:
|
1998-06-19 18:23:28 +00:00
|
|
|
// XXX For now map the other incremental operations into full reflows
|
|
|
|
rv = ResizeReflow(state);
|
|
|
|
break;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
else {
|
1998-06-25 20:51:04 +00:00
|
|
|
// Get next frame in reflow command chain
|
|
|
|
state.reflowCommand->GetNext(state.mInlineLayout.mNextRCFrame);
|
|
|
|
|
|
|
|
// Continue the reflow
|
1998-06-18 23:16:00 +00:00
|
|
|
rv = ChildIncrementalReflow(state);
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
else if (eReflowReason_Resize == state.reason) {
|
1998-06-30 20:14:04 +00:00
|
|
|
DrainOverflowLists();
|
1998-06-18 23:16:00 +00:00
|
|
|
rv = ResizeReflow(state);
|
|
|
|
}
|
|
|
|
ComputeFinalSize(state, aMetrics);
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-19 18:23:28 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("exit nsInlineFrame::InlineReflow size=%d,%d rv=%x kids=%d nif=%p [%d,%d,%c]",
|
1998-06-27 22:56:09 +00:00
|
|
|
aMetrics.width, aMetrics.height, rv, mChildCount, mNextInFlow,
|
1998-06-19 18:23:28 +00:00
|
|
|
mFirstContentOffset, mLastContentOffset,
|
|
|
|
mLastContentIsComplete?'T':'F'));
|
1998-06-18 23:16:00 +00:00
|
|
|
return rv;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
void
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::ComputeFinalSize(nsInlineReflowState& aState,
|
1998-06-18 23:16:00 +00:00
|
|
|
nsReflowMetrics& aMetrics)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-06-19 18:23:28 +00:00
|
|
|
// Align our child frames. Note that inline frames "shrink wrap"
|
|
|
|
// around their contents therefore we need to fixup the available
|
1998-09-15 00:19:49 +00:00
|
|
|
// width in nsInlineLayout so that it doesn't do any horizontal
|
1998-06-19 18:23:28 +00:00
|
|
|
// alignment.
|
1998-06-18 23:16:00 +00:00
|
|
|
nsRect bounds;
|
1998-06-18 23:44:30 +00:00
|
|
|
aState.mInlineLayout.mAvailWidth =
|
|
|
|
aState.mInlineLayout.mX - aState.mInlineLayout.mLeftEdge;
|
1998-06-19 18:23:28 +00:00
|
|
|
aState.mInlineLayout.AlignFrames(mFirstChild, mChildCount, bounds);
|
|
|
|
|
|
|
|
// Compute the final width. Use the style width when supplied.
|
1998-06-18 23:16:00 +00:00
|
|
|
PRIntn ss = aState.mStyleSizeFlags;
|
|
|
|
if (0 != (ss & NS_SIZE_HAS_WIDTH)) {
|
1998-06-19 18:23:28 +00:00
|
|
|
// XXX check css2 spec: I think the spec dictates the size of the
|
|
|
|
// entire box, not the content area
|
1998-06-18 23:16:00 +00:00
|
|
|
aMetrics.width = aState.mBorderPadding.left + aState.mStyleSize.width +
|
|
|
|
aState.mBorderPadding.right;
|
|
|
|
}
|
1998-06-19 18:23:28 +00:00
|
|
|
else {
|
|
|
|
// Make sure that we collapse into nothingness if our content is
|
|
|
|
// zero sized
|
|
|
|
if (0 == bounds.width) {
|
|
|
|
aMetrics.width = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aMetrics.width = aState.mBorderPadding.left + bounds.width +
|
|
|
|
aState.mBorderPadding.right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the final height. Use the style height when supplied.
|
|
|
|
#if XXX_fix_me
|
1998-06-18 23:16:00 +00:00
|
|
|
if (0 != (ss & NS_SIZE_HAS_HEIGHT)) {
|
|
|
|
aMetrics.height = aState.mBorderPadding.top + aState.mStyleSize.height +
|
|
|
|
aState.mBorderPadding.bottom;
|
1998-06-19 18:23:28 +00:00
|
|
|
// XXX Apportion extra height evenly to the ascent/descent, taking
|
|
|
|
// into account roundoff properly. What about when the height is
|
|
|
|
// smaller than the computed height? Does the css2 spec say
|
|
|
|
// anything about this?
|
|
|
|
aMetrics.ascent = ?;
|
|
|
|
aMetrics.descent = ?;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aMetrics.ascent = aState.mBorderPadding.top +
|
|
|
|
aState.mInlineLayout.mMaxAscent;
|
|
|
|
aMetrics.descent = aState.mInlineLayout.mMaxDescent +
|
|
|
|
aState.mBorderPadding.bottom;
|
|
|
|
aMetrics.height = aMetrics.ascent + aMetrics.descent;
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-06-19 18:23:28 +00:00
|
|
|
// Adjust max-element size if this frame's no-wrap flag is set.
|
1998-06-25 16:33:10 +00:00
|
|
|
if (aState.mInlineLayout.mComputeMaxElementSize) {
|
|
|
|
if (aState.mNoWrap) {
|
|
|
|
aMetrics.maxElementSize->width = aMetrics.width;
|
|
|
|
aMetrics.maxElementSize->height = aMetrics.height;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*aMetrics.maxElementSize = aState.mInlineLayout.mMaxElementSize;
|
|
|
|
}
|
1998-07-10 21:45:30 +00: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 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-30 20:14:04 +00:00
|
|
|
nsInlineReflowStatus
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::InitialReflow(nsInlineReflowState& aState)
|
1998-06-30 20:14:04 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull == mNextInFlow, "bad frame-appended-reflow");
|
|
|
|
NS_PRECONDITION(mLastContentIsComplete == PR_TRUE, "bad state");
|
|
|
|
|
1998-07-02 23:44:46 +00:00
|
|
|
nsresult rv = ProcessInitialReflow(aState.mPresContext);
|
1998-07-02 22:55:15 +00:00
|
|
|
if (NS_OK != rv) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-06-30 20:14:04 +00:00
|
|
|
nsInlineReflowStatus rs = NS_FRAME_COMPLETE;
|
|
|
|
if (0 != mChildCount) {
|
|
|
|
if (!ReflowMapped(aState, rs)) {
|
|
|
|
return rs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rs;
|
|
|
|
}
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
nsInlineReflowStatus
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::FrameAppendedReflow(nsInlineReflowState& aState)
|
1998-06-18 23:16:00 +00:00
|
|
|
{
|
1998-06-27 22:56:09 +00:00
|
|
|
NS_PRECONDITION(nsnull == mNextInFlow, "bad frame-appended-reflow");
|
|
|
|
NS_PRECONDITION(mLastContentIsComplete == PR_TRUE, "bad state");
|
1998-06-19 18:23:28 +00:00
|
|
|
|
1998-09-12 04:46:35 +00: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 18:23:28 +00:00
|
|
|
|
1998-06-27 22:56:09 +00:00
|
|
|
nsInlineReflowStatus rs = NS_FRAME_COMPLETE;
|
1998-06-18 23:16:00 +00:00
|
|
|
if (0 != mChildCount) {
|
1998-06-25 16:33:10 +00:00
|
|
|
if (!ReflowMapped(aState, rs)) {
|
|
|
|
return rs;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
}
|
1998-06-27 22:56:09 +00:00
|
|
|
return rs;
|
|
|
|
}
|
1998-06-19 18:23:28 +00:00
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
nsInlineReflowStatus
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::ChildIncrementalReflow(nsInlineReflowState& aState)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-06-18 23:16:00 +00:00
|
|
|
// XXX we can do better SOMEDAY
|
|
|
|
return ResizeReflow(aState);
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
nsInlineReflowStatus
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::ResizeReflow(nsInlineReflowState& aState)
|
1998-06-18 23:16:00 +00:00
|
|
|
{
|
1998-06-27 22:56:09 +00:00
|
|
|
nsInlineReflowStatus rs = NS_FRAME_COMPLETE;
|
1998-06-18 23:16:00 +00:00
|
|
|
if (0 != mChildCount) {
|
1998-06-25 16:33:10 +00:00
|
|
|
if (!ReflowMapped(aState, rs)) {
|
|
|
|
return rs;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
}
|
1998-06-19 18:23:28 +00:00
|
|
|
|
1998-06-27 22:56:09 +00:00
|
|
|
if (NS_FRAME_IS_COMPLETE(rs)) {
|
1998-06-18 23:16:00 +00:00
|
|
|
// Try to fit some more children from our next in flow
|
|
|
|
if (nsnull != mNextInFlow) {
|
1998-06-25 16:33:10 +00:00
|
|
|
if (!PullUpChildren(aState, rs)) {
|
|
|
|
return rs;
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1998-06-25 16:33:10 +00:00
|
|
|
return rs;
|
1998-06-18 23:16:00 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-25 16:33:10 +00:00
|
|
|
PRBool
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::ReflowMapped(nsInlineReflowState& aState,
|
1998-06-25 16:33:10 +00:00
|
|
|
nsInlineReflowStatus& aReflowStatus)
|
1998-06-18 23:16:00 +00:00
|
|
|
{
|
1998-06-19 18:23:28 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("enter nsInlineFrame::ReflowMapped: childCount=%d", mChildCount));
|
1998-06-19 18:23:28 +00:00
|
|
|
|
|
|
|
nsresult rv;
|
1998-06-25 16:33:10 +00:00
|
|
|
|
|
|
|
PRBool keepGoing = PR_FALSE;
|
1998-06-18 23:16:00 +00:00
|
|
|
PRInt32 kidContentIndex = mFirstContentOffset;
|
|
|
|
nsIFrame* prevChild = nsnull;
|
|
|
|
nsIFrame* child = mFirstChild;
|
1998-06-19 18:23:28 +00:00
|
|
|
while (nsnull != child) {
|
1998-06-25 16:33:10 +00:00
|
|
|
aReflowStatus = aState.mInlineLayout.ReflowAndPlaceFrame(child);
|
1998-06-27 22:56:09 +00:00
|
|
|
if (NS_IS_REFLOW_ERROR(aReflowStatus)) {
|
1998-06-25 16:33:10 +00:00
|
|
|
return PR_FALSE;
|
1998-06-18 23:16:00 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-27 22:56:09 +00:00
|
|
|
// Update our mLastContentIsComplete flag
|
|
|
|
mLastContentIsComplete = NS_FRAME_IS_COMPLETE(aReflowStatus);
|
|
|
|
if (!mLastContentIsComplete) {
|
|
|
|
// Create a continuation frame for the child now
|
|
|
|
rv = MaybeCreateNextInFlow(aState, child);/* XXX rename method */
|
1998-06-19 18:23:28 +00:00
|
|
|
if (NS_OK != rv) {
|
1998-06-25 16:33:10 +00:00
|
|
|
aReflowStatus = nsInlineReflowStatus(rv);
|
|
|
|
return PR_FALSE;
|
1998-06-19 18:23:28 +00:00
|
|
|
}
|
1998-06-27 22:56:09 +00:00
|
|
|
}
|
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("nsInlineFrame::ReflowMapped: frame=%p c=%c kidRS=%x",
|
1998-06-27 22:56:09 +00:00
|
|
|
child, mLastContentIsComplete ? 'T' : 'F', aReflowStatus));
|
|
|
|
|
|
|
|
// See if a break is needed and if one is needed, what kind of break
|
|
|
|
if (!NS_INLINE_IS_BREAK(aReflowStatus)) {
|
|
|
|
// Advance past the child we just reflowed.
|
1998-06-18 23:16:00 +00:00
|
|
|
prevChild = child;
|
|
|
|
child->GetNextSibling(child);
|
1998-06-27 22:56:09 +00:00
|
|
|
|
|
|
|
// If child is complete then continue reflowing
|
|
|
|
if (mLastContentIsComplete) {
|
|
|
|
kidContentIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// When our child is not complete we need to push any children
|
|
|
|
// that follow to our next-in-flow.
|
1998-06-18 23:16:00 +00:00
|
|
|
PushKids(aState, prevChild, child);
|
|
|
|
mLastContentOffset = kidContentIndex;
|
|
|
|
goto done;
|
1998-06-27 22:56:09 +00:00
|
|
|
}
|
|
|
|
else if (NS_INLINE_IS_BREAK_AFTER(aReflowStatus)) {
|
|
|
|
// We need to break-after the child. We also need to return
|
|
|
|
// the break-after state to our parent because it means our
|
|
|
|
// parent needs to break-after us (and so on until the type of
|
|
|
|
// break requested is satisfied).
|
1998-06-18 23:16:00 +00:00
|
|
|
mLastContentOffset = kidContentIndex;
|
|
|
|
|
1998-06-27 22:56:09 +00:00
|
|
|
// Advance past the child we are breaking after (if it was
|
|
|
|
// incomplete then we already created its next-in-flow above)
|
1998-06-19 18:23:28 +00:00
|
|
|
prevChild = child;
|
|
|
|
child->GetNextSibling(child);
|
|
|
|
if (nsnull != child) {
|
1998-06-27 22:56:09 +00:00
|
|
|
// Push extra children to a next-in-flow (and therefore we
|
|
|
|
// know we aren't complete)
|
1998-06-18 23:16:00 +00:00
|
|
|
PushKids(aState, prevChild, child);
|
1998-06-27 22:56:09 +00:00
|
|
|
aReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-27 22:56:09 +00:00
|
|
|
else if (mLastContentIsComplete) {
|
|
|
|
// Determine our completion status. We might be complete IFF
|
|
|
|
// the child we just reflowed happens to be the last
|
|
|
|
// possible child we can contain.
|
1998-06-25 16:33:10 +00:00
|
|
|
PRInt32 lastContentIndex;
|
1998-08-29 20:20:38 +00:00
|
|
|
mContent->ChildCount(lastContentIndex);
|
1998-06-27 22:56:09 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("nsInlineFrame::ReflowMapped: HERE kidContentIndex=%d lastContentIndex=%d frame=%p c=%c kidRS=%x",
|
1998-06-27 22:56:09 +00:00
|
|
|
kidContentIndex, lastContentIndex, child, mLastContentIsComplete ? 'T' : 'F', aReflowStatus));
|
1998-06-25 16:33:10 +00:00
|
|
|
if (++kidContentIndex == lastContentIndex) {
|
1998-06-27 22:56:09 +00:00
|
|
|
// We are complete. Yippee. :-)
|
|
|
|
aReflowStatus &= ~NS_FRAME_NOT_COMPLETE;
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
|
|
|
else {
|
1998-06-27 22:56:09 +00:00
|
|
|
// We are not complete. Bummer dude.
|
|
|
|
aReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
goto done;
|
1998-06-27 22:56:09 +00:00
|
|
|
} else {
|
|
|
|
// We need to break-before the child. Unlink break-after, a
|
|
|
|
// break-before may be changed into just incomplete if there are
|
|
|
|
// children preceeding this child (because the other children we
|
|
|
|
// have do not need to be broken-before).
|
1998-06-18 23:16:00 +00:00
|
|
|
mLastContentIsComplete = PR_TRUE;
|
1998-06-27 22:56:09 +00:00
|
|
|
if (nsnull == prevChild) {
|
|
|
|
// We are breaking before our very first child
|
|
|
|
// frame. Therefore we need return the break-before status as
|
|
|
|
// it is. And by definition we are incomplete.
|
|
|
|
aReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
|
|
|
mLastContentOffset = kidContentIndex;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
else {
|
1998-06-27 22:56:09 +00:00
|
|
|
// 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);
|
|
|
|
mLastContentOffset = kidContentIndex - 1;
|
|
|
|
PushKids(aState, prevChild, child);
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
goto done;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
}
|
1998-06-19 18:23:28 +00:00
|
|
|
if (kidContentIndex == 0) {
|
|
|
|
mLastContentOffset = 0;
|
|
|
|
} else {
|
|
|
|
mLastContentOffset = kidContentIndex - 1;
|
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
mLastContentIsComplete = PR_TRUE;
|
1998-06-25 16:33:10 +00:00
|
|
|
keepGoing = PR_TRUE;
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
done:;
|
1998-06-25 16:33:10 +00:00
|
|
|
aState.mLastChild = prevChild;
|
1998-06-27 22:56:09 +00:00
|
|
|
NS_POSTCONDITION(mFirstContentOffset <= mLastContentOffset,
|
|
|
|
"bad content offsets");
|
1998-06-19 18:23:28 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("exit nsInlineFrame::ReflowMapped: childCount=%d rs=%x",
|
1998-06-25 16:33:10 +00:00
|
|
|
mChildCount, aReflowStatus));
|
|
|
|
return keepGoing;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-06-25 16:33:10 +00:00
|
|
|
PRBool
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::PullUpChildren(nsInlineReflowState& aState,
|
1998-06-25 16:33:10 +00:00
|
|
|
nsInlineReflowStatus& aReflowStatus)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-06-19 18:23:28 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("enter nsInlineFrame::PullUpChildren: childCount=%d",
|
1998-06-19 18:23:28 +00:00
|
|
|
mChildCount));
|
|
|
|
|
1998-06-19 19:57:14 +00:00
|
|
|
// Get correct kidContentIndex
|
|
|
|
PRInt32 kidContentIndex;
|
|
|
|
if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) {
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame* prev = (nsInlineFrame*)mPrevInFlow;
|
1998-06-19 19:57:14 +00:00
|
|
|
NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset,
|
|
|
|
"bad prevInFlow");
|
|
|
|
kidContentIndex = prev->NextChildOffset();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
kidContentIndex = NextChildOffset();
|
|
|
|
}
|
|
|
|
|
1998-06-25 16:33:10 +00:00
|
|
|
PRBool keepGoing = PR_FALSE;
|
1998-06-19 18:23:28 +00:00
|
|
|
nsresult rv;
|
1998-06-27 22:56:09 +00:00
|
|
|
aReflowStatus = NS_FRAME_COMPLETE;
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow;
|
1998-06-18 23:16:00 +00:00
|
|
|
nsIFrame* prevChild = aState.mLastChild;
|
1998-06-19 19:57:14 +00:00
|
|
|
#ifdef NS_DEBUG
|
|
|
|
if (nsnull == prevChild) {
|
|
|
|
NS_ASSERTION(nsnull == mFirstChild, "bad prevChild");
|
|
|
|
NS_ASSERTION(0 == mChildCount, "bad child count");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_ASSERTION(nsnull != mFirstChild, "bad prevChild");
|
|
|
|
NS_ASSERTION(0 != mChildCount, "bad child count");
|
|
|
|
}
|
|
|
|
#endif
|
1998-06-18 23:16:00 +00:00
|
|
|
while (nsnull != nextInFlow) {
|
|
|
|
// Get child from our next-in-flow
|
1998-06-24 17:52:42 +00:00
|
|
|
nsIFrame* child = PullOneChild(nextInFlow, prevChild);
|
1998-06-18 23:16:00 +00:00
|
|
|
if (nsnull == child) {
|
1998-09-15 00:19:49 +00:00
|
|
|
nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow;
|
1998-06-18 23:16:00 +00:00
|
|
|
continue;
|
|
|
|
}
|
1998-06-19 18:23:28 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_PUSH_PULL,
|
1998-09-15 00:19:49 +00:00
|
|
|
("nsInlineFrame::PullUpChildren: trying to pullup %p", child));
|
1998-06-18 23:16:00 +00:00
|
|
|
|
|
|
|
// Reflow it
|
1998-06-25 16:33:10 +00:00
|
|
|
aReflowStatus = aState.mInlineLayout.ReflowAndPlaceFrame(child);
|
1998-06-27 22:56:09 +00:00
|
|
|
if (NS_IS_REFLOW_ERROR(aReflowStatus)) {
|
1998-06-18 23:16:00 +00:00
|
|
|
goto done;
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-27 22:56:09 +00:00
|
|
|
// XXX This code is identical to ReflowMapped; maybe they should
|
|
|
|
// be one routine?
|
|
|
|
|
|
|
|
// Update our mLastContentIsComplete flag
|
|
|
|
mLastContentIsComplete = NS_FRAME_IS_COMPLETE(aReflowStatus);
|
|
|
|
if (!mLastContentIsComplete) {
|
|
|
|
// Create a continuation frame for the child now
|
|
|
|
rv = MaybeCreateNextInFlow(aState, child);/* XXX rename method */
|
1998-06-19 18:23:28 +00:00
|
|
|
if (NS_OK != rv) {
|
1998-06-25 16:33:10 +00:00
|
|
|
aReflowStatus = nsInlineReflowStatus(rv);
|
1998-06-27 22:56:09 +00:00
|
|
|
return PR_FALSE;
|
1998-06-19 18:23:28 +00:00
|
|
|
}
|
1998-06-27 22:56:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// See if a break is needed and if one is needed, what kind of break
|
|
|
|
if (!NS_INLINE_IS_BREAK(aReflowStatus)) {
|
|
|
|
// Advance past the child we just reflowed.
|
1998-06-19 18:23:28 +00:00
|
|
|
prevChild = child;
|
|
|
|
child->GetNextSibling(child);
|
1998-06-27 22:56:09 +00:00
|
|
|
|
|
|
|
// If child is complete then continue reflowing
|
|
|
|
if (mLastContentIsComplete) {
|
|
|
|
kidContentIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// When our child is not complete we need to push any children
|
|
|
|
// that follow to our next-in-flow.
|
1998-06-19 18:23:28 +00:00
|
|
|
PushKids(aState, prevChild, child);
|
1998-06-18 23:16:00 +00:00
|
|
|
mLastContentOffset = kidContentIndex;
|
|
|
|
goto done;
|
1998-06-27 22:56:09 +00:00
|
|
|
}
|
|
|
|
else if (NS_INLINE_IS_BREAK_AFTER(aReflowStatus)) {
|
|
|
|
// We need to break-after the child. We also need to return
|
|
|
|
// the break-after state to our parent because it means our
|
|
|
|
// parent needs to break-after us (and so on until the type of
|
|
|
|
// break requested is satisfied).
|
1998-06-18 23:16:00 +00:00
|
|
|
mLastContentOffset = kidContentIndex;
|
1998-06-27 22:56:09 +00:00
|
|
|
|
|
|
|
// Advance past the child we are breaking after (if it was
|
|
|
|
// incomplete then we already created its next-in-flow above)
|
|
|
|
prevChild = child;
|
|
|
|
child->GetNextSibling(child);
|
|
|
|
if (nsnull != child) {
|
|
|
|
// Push extra children to a next-in-flow (and therefore we
|
|
|
|
// know we aren't complete)
|
|
|
|
PushKids(aState, prevChild, child);
|
|
|
|
aReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
|
|
|
}
|
|
|
|
else if (mLastContentIsComplete) {
|
|
|
|
// Determine our completion status. We might be complete IFF
|
|
|
|
// the child we just reflowed happens to be the last
|
|
|
|
// possible child we can contain.
|
1998-06-19 18:23:28 +00:00
|
|
|
PRInt32 lastContentIndex;
|
1998-08-29 20:20:38 +00:00
|
|
|
mContent->ChildCount(lastContentIndex);
|
1998-06-25 16:33:10 +00:00
|
|
|
if (++kidContentIndex == lastContentIndex) {
|
1998-06-27 22:56:09 +00:00
|
|
|
// We are complete. Yippee. :-)
|
|
|
|
aReflowStatus &= ~NS_FRAME_NOT_COMPLETE;
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
|
|
|
else {
|
1998-06-27 22:56:09 +00:00
|
|
|
// We are not complete. Bummer dude.
|
|
|
|
aReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
1998-06-19 18:23:28 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
}
|
|
|
|
goto done;
|
1998-06-27 22:56:09 +00:00
|
|
|
} else {
|
|
|
|
// We need to break-before the child. Unlink break-after, a
|
|
|
|
// break-before may be changed into just incomplete if there are
|
|
|
|
// children preceeding this child (because the other children we
|
|
|
|
// have do not need to be broken-before).
|
|
|
|
if (nsnull == prevChild) {
|
|
|
|
// We are breaking before our very first child
|
|
|
|
// frame. Therefore we need return the break-before status as
|
|
|
|
// it is. And by definition we are incomplete.
|
|
|
|
aReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
|
|
|
mLastContentOffset = kidContentIndex;
|
1998-06-18 23:16:00 +00:00
|
|
|
}
|
|
|
|
else {
|
1998-06-27 22:56:09 +00:00
|
|
|
// 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);
|
|
|
|
mLastContentOffset = kidContentIndex - 1;
|
|
|
|
PushKids(aState, prevChild, child);
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-18 23:16:00 +00:00
|
|
|
goto done;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
}
|
1998-06-19 18:23:28 +00:00
|
|
|
if (kidContentIndex == 0) {
|
|
|
|
mLastContentOffset = 0;
|
|
|
|
} else {
|
|
|
|
mLastContentOffset = kidContentIndex - 1;
|
|
|
|
}
|
1998-06-19 19:57:14 +00:00
|
|
|
NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco");
|
1998-06-18 23:16:00 +00:00
|
|
|
mLastContentIsComplete = PR_TRUE;
|
1998-06-25 16:33:10 +00:00
|
|
|
keepGoing = PR_TRUE;
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
done:;
|
1998-06-30 20:14:04 +00:00
|
|
|
// XXX Why bother? Assuming our offsets are correct then our
|
|
|
|
// next-in-flow will pick up where we left off.
|
|
|
|
#if XXX
|
1998-09-15 00:19:49 +00:00
|
|
|
nextInFlow = (nsInlineFrame*) mNextInFlow;
|
1998-06-19 18:23:28 +00:00
|
|
|
if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) {
|
1998-06-27 22:56:09 +00:00
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) {
|
1998-06-19 18:23:28 +00:00
|
|
|
AdjustOffsetOfEmptyNextInFlows();
|
|
|
|
}
|
|
|
|
}
|
1998-06-30 20:14:04 +00:00
|
|
|
#endif
|
1998-06-19 18:23:28 +00:00
|
|
|
|
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("exit nsInlineFrame::PullUpChildren: childCount=%d rs=%x",
|
1998-06-25 16:33:10 +00:00
|
|
|
mChildCount, aReflowStatus));
|
|
|
|
return keepGoing;
|
1998-06-19 18:23:28 +00:00
|
|
|
}
|
|
|
|
|
1998-06-24 17:52:42 +00:00
|
|
|
nsIFrame*
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::PullOneChild(nsInlineFrame* aNextInFlow,
|
1998-06-24 17:52:42 +00:00
|
|
|
nsIFrame* aLastChild)
|
|
|
|
{
|
|
|
|
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 00:19:49 +00:00
|
|
|
("nsInlineFrame::PullOneChild: from overflow list, frame=%p",
|
1998-06-24 17:52:42 +00:00
|
|
|
kidFrame));
|
|
|
|
kidFrame = aNextInFlow->mOverflowList;
|
|
|
|
kidFrame->GetNextSibling(aNextInFlow->mOverflowList);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
|
1998-09-15 00:19:49 +00:00
|
|
|
("nsInlineFrame::PullOneChild: frame=%p (%d kids left)",
|
1998-06-24 17:52:42 +00:00
|
|
|
kidFrame, aNextInFlow->mChildCount - 1));
|
|
|
|
|
|
|
|
// Take the frame away from the next-in-flow. Update it's first
|
1998-06-30 20:14:04 +00:00
|
|
|
// content offset.
|
1998-06-24 17:52:42 +00:00
|
|
|
kidFrame->GetNextSibling(aNextInFlow->mFirstChild);
|
|
|
|
aNextInFlow->mChildCount--;
|
|
|
|
if (nsnull != aNextInFlow->mFirstChild) {
|
1998-07-10 19:04:06 +00:00
|
|
|
PRInt32 contentIndex;
|
|
|
|
aNextInFlow->mFirstChild->GetContentIndex(contentIndex);
|
|
|
|
aNextInFlow->SetFirstContentOffset(contentIndex);
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
1998-07-10 19:04:06 +00:00
|
|
|
PRInt32 contentIndex;
|
|
|
|
kidFrame->GetContentIndex(contentIndex);
|
|
|
|
SetFirstContentOffset(contentIndex);
|
1998-06-24 17:52:42 +00:00
|
|
|
} else {
|
|
|
|
NS_ASSERTION(IsLastChild(aLastChild), "bad last child");
|
|
|
|
aLastChild->SetNextSibling(kidFrame);
|
|
|
|
}
|
|
|
|
kidFrame->SetNextSibling(nsnull);
|
|
|
|
mChildCount++;
|
|
|
|
|
|
|
|
return kidFrame;
|
|
|
|
}
|
|
|
|
|
1998-06-19 18:23:28 +00:00
|
|
|
nsresult
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::MaybeCreateNextInFlow(nsInlineReflowState& aState,
|
1998-06-19 18:23:28 +00:00
|
|
|
nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
nsIFrame* nextInFlow;
|
|
|
|
nsresult rv = aState.mInlineLayout.MaybeCreateNextInFlow(aFrame, nextInFlow);
|
|
|
|
if (NS_OK != rv) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (nsnull != nextInFlow) {
|
|
|
|
mChildCount++;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
void
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::PushKids(nsInlineReflowState& aState,
|
1998-06-30 20:14:04 +00:00
|
|
|
nsIFrame* aPrevChild,
|
|
|
|
nsIFrame* aPushedChild)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-06-30 20:14:04 +00:00
|
|
|
NS_ASSERTION(nsnull == mOverflowList, "bad overflow list");
|
|
|
|
|
1998-06-18 23:16:00 +00:00
|
|
|
// Count how many children are being pushed
|
1998-06-19 18:23:28 +00:00
|
|
|
PRInt32 pushCount = mChildCount - aState.mInlineLayout.mFrameNum;
|
1998-06-18 23:16:00 +00:00
|
|
|
|
|
|
|
// Only ask container base class to push children if there is
|
|
|
|
// something to push...
|
|
|
|
if (0 != pushCount) {
|
1998-06-19 18:23:28 +00:00
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_PUSH_PULL,
|
1998-09-15 00:19:49 +00:00
|
|
|
("nsInlineFrame::PushKids: pushing %d children", pushCount));
|
1998-06-30 20:14:04 +00:00
|
|
|
// Break sibling list
|
|
|
|
aPrevChild->SetNextSibling(nsnull);
|
1998-06-18 23:16:00 +00:00
|
|
|
mChildCount -= pushCount;
|
1998-06-30 20:14:04 +00: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 16:25:41 +00:00
|
|
|
}
|
1998-06-19 18:23:28 +00:00
|
|
|
#ifdef NS_DEBUG
|
|
|
|
PRInt32 len = LengthOf(mFirstChild);
|
|
|
|
NS_ASSERTION(len == mChildCount, "child count is wrong");
|
|
|
|
#endif
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-06-30 20:14:04 +00:00
|
|
|
|
|
|
|
void
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame::DrainOverflowLists()
|
1998-06-30 20:14:04 +00:00
|
|
|
{
|
|
|
|
// Our prev-in-flows overflow list goes before my children and must
|
|
|
|
// be re-parented.
|
|
|
|
if (nsnull != mPrevInFlow) {
|
1998-09-15 00:19:49 +00:00
|
|
|
nsInlineFrame* prevInFlow = (nsInlineFrame*) mPrevInFlow;
|
1998-06-30 20:14:04 +00:00
|
|
|
if (nsnull != prevInFlow->mOverflowList) {
|
|
|
|
nsIFrame* frame = prevInFlow->mOverflowList;
|
|
|
|
nsIFrame* lastFrame = nsnull;
|
|
|
|
PRInt32 count = 0;
|
|
|
|
while (nsnull != frame) {
|
|
|
|
// Reparent the frame
|
|
|
|
frame->SetGeometricParent(this);
|
|
|
|
nsIFrame* contentParent;
|
|
|
|
frame->GetContentParent(contentParent);
|
|
|
|
if (prevInFlow == contentParent) {
|
|
|
|
frame->SetContentParent(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Advance through the list
|
|
|
|
count++;
|
|
|
|
lastFrame = frame;
|
|
|
|
frame->GetNextSibling(frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Join the two frame lists together and update our child count
|
|
|
|
#if XXX
|
|
|
|
if (nsnull == mFirstChild) {
|
|
|
|
// We are a continuation of our prev-in-flow; we assume that
|
|
|
|
// the last child was complete.
|
|
|
|
mLastContentIsComplete = PR_TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
nsIFrame* newFirstChild = prevInFlow->mOverflowList;
|
|
|
|
newFirstChild->GetContentIndex(mFirstContentOffset);
|
|
|
|
lastFrame->SetNextSibling(mFirstChild);
|
|
|
|
mFirstChild = newFirstChild;
|
|
|
|
prevInFlow->mOverflowList = nsnull;
|
|
|
|
mChildCount += count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 03:24:26 +00:00
|
|
|
nsIFrame* lastFrame = LastFrame(mFirstChild);
|
1998-06-30 20:14:04 +00:00
|
|
|
if (nsnull == lastFrame) {
|
|
|
|
mFirstChild = mOverflowList;
|
|
|
|
mFirstChild->GetContentIndex(mFirstContentOffset);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lastFrame->SetNextSibling(mOverflowList);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Count how many frames are on the overflow list and then update
|
|
|
|
// our count
|
|
|
|
nsIFrame* frame = mOverflowList;
|
|
|
|
PRInt32 count = 0;
|
|
|
|
while (nsnull != frame) {
|
|
|
|
count++;
|
|
|
|
frame->GetNextSibling(frame);
|
|
|
|
}
|
|
|
|
mChildCount += count;
|
|
|
|
mOverflowList = nsnull;
|
|
|
|
#if XXX
|
|
|
|
// We get here when we pushed some children to a potential
|
|
|
|
// next-in-flow and then our parent decided to reflow us instead
|
|
|
|
// of continuing us.
|
|
|
|
NS_ASSERTION(nsnull == mNextInFlow, "huh?");
|
|
|
|
mLastContentIsComplete = PR_TRUE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX What do we set mLastContentIsComplete to?
|
|
|
|
|
|
|
|
#ifdef NS_DEBUG
|
|
|
|
PRInt32 len = LengthOf(mFirstChild);
|
|
|
|
NS_ASSERTION(len == mChildCount, "child count is wrong");
|
|
|
|
#endif
|
|
|
|
}
|