2001-09-29 00:14:13 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
1998-09-15 04:19:49 +04:00
|
|
|
*
|
2001-09-29 00:14:13 +04:00
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/NPL/
|
1998-09-15 04:19:49 +04:00
|
|
|
*
|
2001-09-29 00:14:13 +04:00
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
1998-09-15 04:19:49 +04:00
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
2001-09-29 00:14:13 +04:00
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
1999-11-06 06:40:37 +03:00
|
|
|
*
|
2001-09-29 00:14:13 +04:00
|
|
|
* Contributor(s):
|
2000-04-17 18:40:46 +04:00
|
|
|
* Steve Clark <buster@netscape.com>
|
2000-02-03 01:24:56 +03:00
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
2003-01-02 02:53:20 +03:00
|
|
|
* L. David Baron <dbaron@dbaron.org>
|
2000-04-17 18:40:46 +04:00
|
|
|
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
2001-09-29 00:14:13 +04:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the NPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the NPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
1999-03-19 00:03:25 +03:00
|
|
|
#include "nsCOMPtr.h"
|
1998-09-15 04:19:49 +04:00
|
|
|
#include "nsLineLayout.h"
|
2000-08-24 08:26:43 +04:00
|
|
|
#include "nsBlockFrame.h"
|
2000-09-12 00:46:44 +04:00
|
|
|
#include "nsInlineFrame.h"
|
1998-09-15 04:19:49 +04:00
|
|
|
#include "nsStyleConsts.h"
|
1999-03-19 00:03:25 +03:00
|
|
|
#include "nsHTMLContainerFrame.h"
|
2001-10-26 09:06:07 +04:00
|
|
|
#include "nsSpaceManager.h"
|
2003-02-22 03:32:13 +03:00
|
|
|
#include "nsStyleContext.h"
|
1998-09-23 06:31:16 +04:00
|
|
|
#include "nsIPresContext.h"
|
|
|
|
#include "nsIFontMetrics.h"
|
1999-03-19 00:03:25 +03:00
|
|
|
#include "nsIRenderingContext.h"
|
1999-04-23 19:15:53 +04:00
|
|
|
#include "nsLayoutAtoms.h"
|
1999-04-25 21:01:07 +04:00
|
|
|
#include "nsPlaceholderFrame.h"
|
2002-05-10 22:22:41 +04:00
|
|
|
#include "nsReflowPath.h"
|
1999-09-03 07:47:49 +04:00
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIHTMLDocument.h"
|
|
|
|
#include "nsIContent.h"
|
2000-02-15 07:26:44 +03:00
|
|
|
#include "nsITextContent.h"
|
1999-11-19 18:33:29 +03:00
|
|
|
#include "nsIView.h"
|
|
|
|
#include "nsIViewManager.h"
|
2000-02-15 07:26:44 +03:00
|
|
|
#include "nsHTMLAtoms.h"
|
2000-04-17 18:40:46 +04:00
|
|
|
#include "nsTextFragment.h"
|
2002-02-19 23:41:32 +03:00
|
|
|
#include "nsBidiUtils.h"
|
2001-04-12 03:32:21 +04:00
|
|
|
#define FIX_FOR_BUG_40882
|
1999-09-03 07:47:49 +04:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
#undef NOISY_HORIZONTAL_ALIGN
|
|
|
|
#undef NOISY_VERTICAL_ALIGN
|
2001-04-20 01:54:35 +04:00
|
|
|
#undef REALLY_NOISY_VERTICAL_ALIGN
|
1999-03-19 00:03:25 +03:00
|
|
|
#undef NOISY_REFLOW
|
2000-04-17 18:40:46 +04:00
|
|
|
#undef REALLY_NOISY_REFLOW
|
1999-03-19 00:03:25 +03:00
|
|
|
#undef NOISY_PUSHING
|
2001-04-20 01:54:35 +04:00
|
|
|
#undef REALLY_NOISY_PUSHING
|
|
|
|
#undef DEBUG_ADD_TEXT
|
1999-03-20 22:38:50 +03:00
|
|
|
#undef NOISY_MAX_ELEMENT_SIZE
|
2001-04-20 01:54:35 +04:00
|
|
|
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
|
1999-03-24 18:41:49 +03:00
|
|
|
#undef NOISY_CAN_PLACE_FRAME
|
2001-04-20 01:54:35 +04:00
|
|
|
#undef NOISY_TRIM
|
|
|
|
#undef REALLY_NOISY_TRIM
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
1998-09-15 04:19:49 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
#define FIX_BUG_50257
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
#define PLACED_LEFT 0x1
|
|
|
|
#define PLACED_RIGHT 0x2
|
|
|
|
|
2001-08-30 02:59:09 +04:00
|
|
|
#define HACK_MEW
|
2001-09-08 23:26:34 +04:00
|
|
|
//#undef HACK_MEW
|
2001-08-30 02:59:09 +04:00
|
|
|
#ifdef HACK_MEW
|
2001-09-29 01:42:03 +04:00
|
|
|
static nscoord AccumulateImageSizes(nsIPresContext& aPresContext, nsIFrame& aFrame)
|
2001-08-30 02:59:09 +04:00
|
|
|
{
|
|
|
|
nscoord sizes = 0;
|
|
|
|
|
|
|
|
// see if aFrame is an image frame first
|
2003-10-31 23:19:18 +03:00
|
|
|
if (aFrame.GetType() == nsLayoutAtoms::imageFrame) {
|
2003-07-23 04:14:16 +04:00
|
|
|
sizes += aFrame.GetSize().width;
|
2001-08-30 02:59:09 +04:00
|
|
|
} else {
|
|
|
|
// see if there are children to process
|
|
|
|
// XXX: process alternate child lists?
|
2004-01-09 17:20:53 +03:00
|
|
|
nsIFrame* child = aFrame.GetFirstChild(nsnull);
|
2003-06-30 14:46:59 +04:00
|
|
|
while (child) {
|
2001-08-30 02:59:09 +04:00
|
|
|
// recurse: note that we already know we are in a child frame, so no need to track further
|
2001-09-29 01:42:03 +04:00
|
|
|
sizes += AccumulateImageSizes(aPresContext, *child);
|
2001-08-30 02:59:09 +04:00
|
|
|
// now next sibling
|
2003-06-30 14:46:59 +04:00
|
|
|
child = child->GetNextSibling();
|
2001-08-30 02:59:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sizes;
|
|
|
|
}
|
2001-09-08 23:26:34 +04:00
|
|
|
|
|
|
|
static PRBool InUnconstrainedTableCell(const nsHTMLReflowState& aBlockReflowState)
|
|
|
|
{
|
|
|
|
PRBool result = PR_FALSE;
|
|
|
|
|
|
|
|
// get the parent reflow state
|
|
|
|
const nsHTMLReflowState* parentReflowState = aBlockReflowState.parentReflowState;
|
|
|
|
if (parentReflowState) {
|
|
|
|
// check if the frame is a tablecell
|
|
|
|
NS_ASSERTION(parentReflowState->mStyleDisplay, "null styleDisplay in parentReflowState unexpected");
|
|
|
|
if (parentReflowState->mStyleDisplay &&
|
|
|
|
parentReflowState->mStyleDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
|
|
|
|
// see if width is unconstrained or percent
|
|
|
|
NS_ASSERTION(parentReflowState->mStylePosition, "null stylePosition in parentReflowState unexpected");
|
|
|
|
if(parentReflowState->mStylePosition) {
|
|
|
|
switch(parentReflowState->mStylePosition->mWidth.GetUnit()) {
|
|
|
|
case eStyleUnit_Auto :
|
|
|
|
case eStyleUnit_Null :
|
|
|
|
result = PR_TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2001-08-30 02:59:09 +04:00
|
|
|
#endif
|
|
|
|
|
2001-01-28 02:06:33 +03:00
|
|
|
MOZ_DECL_CTOR_COUNTER(nsLineLayout)
|
1999-10-09 00:41:19 +04:00
|
|
|
|
1999-11-24 09:03:41 +03:00
|
|
|
nsLineLayout::nsLineLayout(nsIPresContext* aPresContext,
|
2001-10-26 09:06:07 +04:00
|
|
|
nsSpaceManager* aSpaceManager,
|
1999-03-19 00:03:25 +03:00
|
|
|
const nsHTMLReflowState* aOuterReflowState,
|
2003-01-09 17:26:32 +03:00
|
|
|
PRBool aComputeMaxElementWidth)
|
1999-03-19 00:03:25 +03:00
|
|
|
: mPresContext(aPresContext),
|
|
|
|
mSpaceManager(aSpaceManager),
|
|
|
|
mBlockReflowState(aOuterReflowState),
|
1999-04-28 02:13:06 +04:00
|
|
|
mBlockRS(nsnull),/* XXX temporary */
|
1999-08-28 01:50:06 +04:00
|
|
|
mMinLineHeight(0),
|
2003-01-09 17:26:32 +03:00
|
|
|
mComputeMaxElementWidth(aComputeMaxElementWidth),
|
2002-05-14 16:55:55 +04:00
|
|
|
mTextIndent(0),
|
2002-03-20 00:57:45 +03:00
|
|
|
mWordFrames(0)
|
1998-09-15 04:19:49 +04:00
|
|
|
{
|
1999-10-09 00:41:19 +04:00
|
|
|
MOZ_COUNT_CTOR(nsLineLayout);
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Stash away some style data that we need
|
2003-05-15 07:42:21 +04:00
|
|
|
mStyleText = aOuterReflowState->frame->GetStyleText();
|
1999-03-19 00:03:25 +03:00
|
|
|
mTextAlign = mStyleText->mTextAlign;
|
1998-09-15 04:19:49 +04:00
|
|
|
mLineNumber = 0;
|
|
|
|
mColumn = 0;
|
2000-04-17 18:40:46 +04:00
|
|
|
mFlags = 0; // default all flags to false except those that follow here...
|
|
|
|
SetFlag(LL_ENDSINWHITESPACE, PR_TRUE);
|
2003-10-14 01:51:02 +04:00
|
|
|
mPlacedFloats = 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
mTotalPlacedFrames = 0;
|
|
|
|
mTopEdge = mBottomEdge = 0;
|
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
// Instead of always pre-initializing the free-lists for frames and
|
|
|
|
// spans, we do it on demand so that situations that only use a few
|
|
|
|
// frames and spans won't waste alot of time in unneeded
|
|
|
|
// initialization.
|
|
|
|
mInitialFramesFreed = mInitialSpansFreed = 0;
|
|
|
|
mFrameFreeList = nsnull;
|
|
|
|
mSpanFreeList = nsnull;
|
|
|
|
|
1999-03-30 03:46:34 +04:00
|
|
|
mCurrentSpan = mRootSpan = nsnull;
|
1999-03-19 00:03:25 +03:00
|
|
|
mSpanDepth = 0;
|
|
|
|
|
2003-12-25 00:51:50 +03:00
|
|
|
mCompatMode = mPresContext->CompatibilityMode();
|
1998-09-15 04:19:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsLineLayout::~nsLineLayout()
|
|
|
|
{
|
1999-10-09 00:41:19 +04:00
|
|
|
MOZ_COUNT_DTOR(nsLineLayout);
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
NS_ASSERTION(nsnull == mRootSpan, "bad line-layout user");
|
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
// Free up all of the per-span-data items that were allocated on the heap
|
|
|
|
PerSpanData* psd = mSpanFreeList;
|
|
|
|
while (nsnull != psd) {
|
|
|
|
PerSpanData* nextSpan = psd->mNextFreeSpan;
|
|
|
|
if ((psd < &mSpanDataBuf[0]) ||
|
|
|
|
(psd >= &mSpanDataBuf[NS_LINELAYOUT_NUM_SPANS])) {
|
|
|
|
delete psd;
|
|
|
|
}
|
|
|
|
psd = nextSpan;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free up all of the per-frame-data items that were allocated on the heap
|
|
|
|
PerFrameData* pfd = mFrameFreeList;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
PerFrameData* nextFrame = pfd->mNext;
|
|
|
|
if ((pfd < &mFrameDataBuf[0]) ||
|
|
|
|
(pfd >= &mFrameDataBuf[NS_LINELAYOUT_NUM_FRAMES])) {
|
|
|
|
delete pfd;
|
|
|
|
}
|
|
|
|
pfd = nextFrame;
|
|
|
|
}
|
1998-09-15 04:19:49 +04:00
|
|
|
}
|
|
|
|
|
2002-05-14 16:55:55 +04:00
|
|
|
// Find out if the frame has a non-null prev-in-flow, i.e., whether it
|
|
|
|
// is a continuation.
|
|
|
|
inline PRBool
|
|
|
|
HasPrevInFlow(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
nsIFrame *prevInFlow;
|
|
|
|
aFrame->GetPrevInFlow(&prevInFlow);
|
|
|
|
return prevInFlow != nsnull;
|
|
|
|
}
|
|
|
|
|
1998-09-15 04:19:49 +04:00
|
|
|
void
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
|
|
|
nscoord aWidth, nscoord aHeight,
|
2003-10-14 01:51:02 +04:00
|
|
|
PRBool aImpactedByFloats,
|
1999-03-19 00:03:25 +03:00
|
|
|
PRBool aIsTopOfPage)
|
1998-09-15 04:19:49 +04:00
|
|
|
{
|
1999-03-19 00:03:25 +03:00
|
|
|
NS_ASSERTION(nsnull == mRootSpan, "bad linelayout user");
|
|
|
|
#ifdef DEBUG
|
1999-03-21 00:55:22 +03:00
|
|
|
if ((aWidth != NS_UNCONSTRAINEDSIZE) && CRAZY_WIDTH(aWidth)) {
|
2002-12-11 05:38:33 +03:00
|
|
|
NS_NOTREACHED("bad width");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": Init: bad caller: width WAS %d(0x%x)\n",
|
1999-03-19 00:03:25 +03:00
|
|
|
aWidth, aWidth);
|
|
|
|
}
|
1999-03-21 00:55:22 +03:00
|
|
|
if ((aHeight != NS_UNCONSTRAINEDSIZE) && CRAZY_HEIGHT(aHeight)) {
|
2002-12-11 05:38:33 +03:00
|
|
|
NS_NOTREACHED("bad height");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": Init: bad caller: height WAS %d(0x%x)\n",
|
1999-03-19 00:03:25 +03:00
|
|
|
aHeight, aHeight);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": BeginLineReflow: %d,%d,%d,%d impacted=%s %s\n",
|
1999-03-19 00:03:25 +03:00
|
|
|
aX, aY, aWidth, aHeight,
|
2003-10-14 01:51:02 +04:00
|
|
|
aImpactedByFloats?"true":"false",
|
1999-03-19 00:03:25 +03:00
|
|
|
aIsTopOfPage ? "top-of-page" : "");
|
|
|
|
#endif
|
2002-08-14 17:00:16 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
mSpansAllocated = mSpansFreed = mFramesAllocated = mFramesFreed = 0;
|
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
mColumn = 0;
|
2000-04-17 18:40:46 +04:00
|
|
|
|
|
|
|
SetFlag(LL_ENDSINWHITESPACE, PR_TRUE);
|
|
|
|
SetFlag(LL_UNDERSTANDSNWHITESPACE, PR_FALSE);
|
|
|
|
SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE);
|
|
|
|
SetFlag(LL_ISTOPOFPAGE, aIsTopOfPage);
|
|
|
|
SetFlag(LL_UPDATEDBAND, PR_FALSE);
|
2003-10-14 01:51:02 +04:00
|
|
|
mPlacedFloats = 0;
|
|
|
|
SetFlag(LL_IMPACTEDBYFLOATS, aImpactedByFloats);
|
1999-03-19 00:03:25 +03:00
|
|
|
mTotalPlacedFrames = 0;
|
2003-10-14 01:51:02 +04:00
|
|
|
SetFlag(LL_CANPLACEFLOAT, PR_TRUE);
|
2000-04-17 18:40:46 +04:00
|
|
|
SetFlag(LL_LINEENDSINBR, PR_FALSE);
|
1999-03-19 00:03:25 +03:00
|
|
|
mSpanDepth = 0;
|
|
|
|
mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
|
|
|
|
|
|
|
|
ForgetWordFrames();
|
|
|
|
|
|
|
|
PerSpanData* psd;
|
|
|
|
NewPerSpanData(&psd);
|
|
|
|
mCurrentSpan = mRootSpan = psd;
|
|
|
|
psd->mReflowState = mBlockReflowState;
|
|
|
|
psd->mLeftEdge = aX;
|
|
|
|
psd->mX = aX;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aWidth) {
|
|
|
|
psd->mRightEdge = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
psd->mRightEdge = aX + aWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
mTopEdge = aY;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aHeight) {
|
|
|
|
mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mBottomEdge = aY + aHeight;
|
|
|
|
}
|
1999-03-22 23:45:09 +03:00
|
|
|
|
|
|
|
switch (mStyleText->mWhiteSpace) {
|
|
|
|
case NS_STYLE_WHITESPACE_PRE:
|
|
|
|
case NS_STYLE_WHITESPACE_NOWRAP:
|
|
|
|
psd->mNoWrap = PR_TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
psd->mNoWrap = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
2001-06-01 02:19:43 +04:00
|
|
|
psd->mDirection = mBlockReflowState->mStyleVisibility->mDirection;
|
1999-05-08 04:48:39 +04:00
|
|
|
psd->mChangedFrameDirection = PR_FALSE;
|
2001-12-11 05:45:44 +03:00
|
|
|
|
|
|
|
// If this is the first line of a block then see if the text-indent
|
|
|
|
// property amounts to anything.
|
|
|
|
|
2002-05-14 16:55:55 +04:00
|
|
|
if (0 == mLineNumber && !HasPrevInFlow(mBlockReflowState->frame)) {
|
2001-12-11 05:45:44 +03:00
|
|
|
nscoord indent = 0;
|
|
|
|
nsStyleUnit unit = mStyleText->mTextIndent.GetUnit();
|
|
|
|
if (eStyleUnit_Coord == unit) {
|
|
|
|
indent = mStyleText->mTextIndent.GetCoordValue();
|
|
|
|
}
|
|
|
|
else if (eStyleUnit_Percent == unit) {
|
|
|
|
nscoord width =
|
|
|
|
nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState->parentReflowState);
|
2002-06-03 22:35:04 +04:00
|
|
|
if ((0 != width) && (NS_UNCONSTRAINEDSIZE != width)) {
|
2001-12-11 05:45:44 +03:00
|
|
|
indent = nscoord(mStyleText->mTextIndent.GetPercentValue() * width);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-05-14 16:55:55 +04:00
|
|
|
mTextIndent = indent;
|
|
|
|
|
2001-12-11 05:45:44 +03:00
|
|
|
if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != psd->mRightEdge) {
|
|
|
|
psd->mRightEdge -= indent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
psd->mX += indent;
|
|
|
|
}
|
|
|
|
}
|
1998-09-15 04:19:49 +04:00
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::EndLineReflow()
|
1998-09-15 04:19:49 +04:00
|
|
|
{
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": EndLineReflow: width=%d\n", mRootSpan->mX - mRootSpan->mLeftEdge);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
FreeSpan(mRootSpan);
|
1999-03-30 03:46:34 +04:00
|
|
|
mCurrentSpan = mRootSpan = nsnull;
|
2002-08-14 17:00:16 +04:00
|
|
|
|
|
|
|
NS_ASSERTION(mSpansAllocated == mSpansFreed, "leak");
|
|
|
|
NS_ASSERTION(mFramesAllocated == mFramesFreed, "leak");
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static PRInt32 maxSpansAllocated = NS_LINELAYOUT_NUM_SPANS;
|
|
|
|
static PRInt32 maxFramesAllocated = NS_LINELAYOUT_NUM_FRAMES;
|
|
|
|
if (mSpansAllocated > maxSpansAllocated) {
|
|
|
|
printf("XXX: saw a line with %d spans\n", mSpansAllocated);
|
|
|
|
maxSpansAllocated = mSpansAllocated;
|
|
|
|
}
|
|
|
|
if (mFramesAllocated > maxFramesAllocated) {
|
|
|
|
printf("XXX: saw a line with %d frames\n", mFramesAllocated);
|
|
|
|
maxFramesAllocated = mFramesAllocated;
|
|
|
|
}
|
|
|
|
#endif
|
1998-09-15 04:19:49 +04:00
|
|
|
}
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
// XXX swtich to a single mAvailLineWidth that we adjust as each frame
|
|
|
|
// on the line is placed. Each span can still have a per-span mX that
|
|
|
|
// tracks where a child frame is going in its span; they don't need a
|
|
|
|
// per-span mLeftEdge?
|
|
|
|
|
1998-09-15 04:19:49 +04:00
|
|
|
void
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
|
|
|
nscoord aWidth, nscoord aHeight,
|
2003-10-14 01:51:02 +04:00
|
|
|
PRBool aPlacedLeftFloat,
|
|
|
|
nsIFrame* aFloatFrame)
|
1998-09-15 04:19:49 +04:00
|
|
|
{
|
2000-03-23 02:19:10 +03:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsLL::UpdateBand %d, %d, %d, %d, frame=%p placedLeft=%s\n will set mImpacted to PR_TRUE\n",
|
2003-10-14 01:51:02 +04:00
|
|
|
aX, aY, aWidth, aHeight, aFloatFrame, aPlacedLeftFloat?"true":"false");
|
2000-03-23 02:19:10 +03:00
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
PerSpanData* psd = mRootSpan;
|
|
|
|
NS_PRECONDITION(psd->mX == psd->mLeftEdge, "update-band called late");
|
|
|
|
#ifdef DEBUG
|
1999-03-21 00:55:22 +03:00
|
|
|
if ((aWidth != NS_UNCONSTRAINEDSIZE) && CRAZY_WIDTH(aWidth)) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": UpdateBand: bad caller: width WAS %d(0x%x)\n",
|
1999-03-19 00:03:25 +03:00
|
|
|
aWidth, aWidth);
|
|
|
|
}
|
1999-03-21 00:55:22 +03:00
|
|
|
if ((aHeight != NS_UNCONSTRAINEDSIZE) && CRAZY_HEIGHT(aHeight)) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": UpdateBand: bad caller: height WAS %d(0x%x)\n",
|
1999-03-19 00:03:25 +03:00
|
|
|
aHeight, aHeight);
|
|
|
|
}
|
|
|
|
#endif
|
1999-03-24 18:41:49 +03:00
|
|
|
|
|
|
|
// Compute the difference between last times width and the new width
|
|
|
|
nscoord deltaWidth = 0;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != psd->mRightEdge) {
|
|
|
|
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aWidth, "switched constraints");
|
|
|
|
nscoord oldWidth = psd->mRightEdge - psd->mLeftEdge;
|
|
|
|
deltaWidth = aWidth - oldWidth;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2003-10-14 01:51:02 +04:00
|
|
|
printf(": UpdateBand: %d,%d,%d,%d deltaWidth=%d %s float\n",
|
1999-03-24 18:41:49 +03:00
|
|
|
aX, aY, aWidth, aHeight, deltaWidth,
|
2003-10-14 01:51:02 +04:00
|
|
|
aPlacedLeftFloat ? "left" : "right");
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
psd->mLeftEdge = aX;
|
|
|
|
psd->mX = aX;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aWidth) {
|
|
|
|
psd->mRightEdge = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
psd->mRightEdge = aX + aWidth;
|
|
|
|
}
|
|
|
|
mTopEdge = aY;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aHeight) {
|
|
|
|
mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mBottomEdge = aY + aHeight;
|
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
SetFlag(LL_UPDATEDBAND, PR_TRUE);
|
2003-10-14 01:51:02 +04:00
|
|
|
mPlacedFloats |= (aPlacedLeftFloat ? PLACED_LEFT : PLACED_RIGHT);
|
|
|
|
SetFlag(LL_IMPACTEDBYFLOATS, PR_TRUE);
|
1999-03-24 18:41:49 +03:00
|
|
|
|
2003-10-31 23:19:18 +03:00
|
|
|
SetFlag(LL_LASTFLOATWASLETTERFRAME,
|
|
|
|
nsLayoutAtoms::letterFrame == aFloatFrame->GetType());
|
1999-10-29 18:33:26 +04:00
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
// Now update all of the open spans...
|
2003-10-14 01:51:02 +04:00
|
|
|
mRootSpan->mContainsFloat = PR_TRUE; // make sure mRootSpan gets updated too
|
1999-03-24 18:41:49 +03:00
|
|
|
psd = mCurrentSpan;
|
|
|
|
while (psd != mRootSpan) {
|
|
|
|
NS_ASSERTION(nsnull != psd, "null ptr");
|
|
|
|
if (nsnull == psd) {
|
|
|
|
break;
|
|
|
|
}
|
2003-10-14 01:51:02 +04:00
|
|
|
NS_ASSERTION(psd->mX == psd->mLeftEdge, "bad float placement");
|
1999-03-24 18:41:49 +03:00
|
|
|
if (NS_UNCONSTRAINEDSIZE == aWidth) {
|
|
|
|
psd->mRightEdge = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
psd->mRightEdge += deltaWidth;
|
|
|
|
}
|
2003-10-14 01:51:02 +04:00
|
|
|
psd->mContainsFloat = PR_TRUE;
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_REFLOW
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" span %p: oldRightEdge=%d newRightEdge=%d\n",
|
1999-09-18 03:15:31 +04:00
|
|
|
psd, psd->mRightEdge - deltaWidth, psd->mRightEdge);
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
|
|
|
psd = psd->mParent;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
// Note: Only adjust the outermost frames (the ones that are direct
|
|
|
|
// children of the block), not the ones in the child spans. The reason
|
|
|
|
// is simple: the frames in the spans have coordinates local to their
|
|
|
|
// parent therefore they are moved when their parent span is moved.
|
1999-03-19 00:03:25 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::UpdateFrames()
|
|
|
|
{
|
1999-03-22 23:45:09 +03:00
|
|
|
NS_ASSERTION(nsnull != mRootSpan, "UpdateFrames with no active spans");
|
|
|
|
|
|
|
|
PerSpanData* psd = mRootSpan;
|
|
|
|
if (NS_STYLE_DIRECTION_LTR == psd->mDirection) {
|
2003-10-14 01:51:02 +04:00
|
|
|
if (PLACED_LEFT & mPlacedFloats) {
|
1999-03-19 00:03:25 +03:00
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
pfd->mBounds.x = psd->mX;
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-10-14 01:51:02 +04:00
|
|
|
else if (PLACED_RIGHT & mPlacedFloats) {
|
1999-03-19 00:03:25 +03:00
|
|
|
// XXX handle DIR=right-to-left
|
|
|
|
}
|
1998-09-15 04:19:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::NewPerSpanData(PerSpanData** aResult)
|
1998-09-15 04:19:49 +04:00
|
|
|
{
|
2002-08-14 17:00:16 +04:00
|
|
|
PerSpanData* psd = mSpanFreeList;
|
|
|
|
if (nsnull == psd) {
|
|
|
|
if (mInitialSpansFreed < NS_LINELAYOUT_NUM_SPANS) {
|
|
|
|
// use one of the ones defined in our struct...
|
|
|
|
psd = &mSpanDataBuf[mInitialSpansFreed++];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
psd = new PerSpanData;
|
|
|
|
if (nsnull == psd) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mSpanFreeList = psd->mNextFreeSpan;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
psd->mParent = nsnull;
|
|
|
|
psd->mFrame = nsnull;
|
|
|
|
psd->mFirstFrame = nsnull;
|
|
|
|
psd->mLastFrame = nsnull;
|
2003-10-14 01:51:02 +04:00
|
|
|
psd->mContainsFloat = PR_FALSE;
|
1999-11-02 18:44:57 +03:00
|
|
|
psd->mZeroEffectiveSpanBox = PR_FALSE;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
mSpansAllocated++;
|
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
*aResult = psd;
|
|
|
|
return NS_OK;
|
1998-09-15 04:19:49 +04:00
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
nsresult
|
|
|
|
nsLineLayout::BeginSpan(nsIFrame* aFrame,
|
|
|
|
const nsHTMLReflowState* aSpanReflowState,
|
|
|
|
nscoord aLeftEdge,
|
|
|
|
nscoord aRightEdge)
|
1998-10-20 04:23:11 +04:00
|
|
|
{
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth+1);
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": BeginSpan leftEdge=%d rightEdge=%d\n", aLeftEdge, aRightEdge);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
PerSpanData* psd;
|
|
|
|
nsresult rv = NewPerSpanData(&psd);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// Link up span frame's pfd to point to its child span data
|
|
|
|
PerFrameData* pfd = mCurrentSpan->mLastFrame;
|
|
|
|
NS_ASSERTION(pfd->mFrame == aFrame, "huh?");
|
|
|
|
pfd->mSpan = psd;
|
|
|
|
|
|
|
|
// Init new span
|
|
|
|
psd->mFrame = pfd;
|
|
|
|
psd->mParent = mCurrentSpan;
|
|
|
|
psd->mReflowState = aSpanReflowState;
|
|
|
|
psd->mLeftEdge = aLeftEdge;
|
|
|
|
psd->mX = aLeftEdge;
|
|
|
|
psd->mRightEdge = aRightEdge;
|
|
|
|
|
2003-05-15 07:42:21 +04:00
|
|
|
const nsStyleText* styleText = aSpanReflowState->frame->GetStyleText();
|
1999-03-22 23:45:09 +03:00
|
|
|
switch (styleText->mWhiteSpace) {
|
|
|
|
case NS_STYLE_WHITESPACE_PRE:
|
|
|
|
case NS_STYLE_WHITESPACE_NOWRAP:
|
|
|
|
psd->mNoWrap = PR_TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
psd->mNoWrap = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
2001-06-01 02:19:43 +04:00
|
|
|
psd->mDirection = aSpanReflowState->mStyleVisibility->mDirection;
|
1999-05-08 04:48:39 +04:00
|
|
|
psd->mChangedFrameDirection = PR_FALSE;
|
1999-03-22 23:45:09 +03:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Switch to new span
|
|
|
|
mCurrentSpan = psd;
|
|
|
|
mSpanDepth++;
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsLineLayout::EndSpan(nsIFrame* aFrame,
|
|
|
|
nsSize& aSizeResult,
|
2003-01-09 17:26:32 +03:00
|
|
|
nscoord* aMaxElementWidth)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span");
|
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": EndSpan width=%d\n", mCurrentSpan->mX - mCurrentSpan->mLeftEdge);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
nscoord width = 0;
|
|
|
|
nscoord maxHeight = 0;
|
|
|
|
nscoord maxElementWidth = 0;
|
|
|
|
if (nsnull != psd->mLastFrame) {
|
|
|
|
width = psd->mX - psd->mLeftEdge;
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
2000-06-15 03:15:59 +04:00
|
|
|
/* there's one oddball case we need to guard against
|
|
|
|
* if we're reflowed with NS_UNCONSTRAINEDSIZE
|
|
|
|
* then the last frame will not contribute to the max element size height
|
|
|
|
* if it is a text frame that only contains whitespace
|
|
|
|
*/
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != psd->mRightEdge || // it's not an unconstrained reflow
|
|
|
|
pfd->mNext || // or it's not the last frame in the span
|
|
|
|
!pfd->GetFlag(PFD_ISTEXTFRAME) || // or it's not a text frame
|
|
|
|
pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME) // or it contains something other than whitespace
|
|
|
|
) {
|
|
|
|
if (pfd->mBounds.height > maxHeight) maxHeight = pfd->mBounds.height;
|
|
|
|
|
2003-01-09 17:26:32 +03:00
|
|
|
// Compute max-element-width if necessary
|
|
|
|
if (aMaxElementWidth) {
|
|
|
|
nscoord mw = pfd->mMaxElementWidth +
|
2000-06-15 03:15:59 +04:00
|
|
|
pfd->mMargin.left + pfd->mMargin.right;
|
|
|
|
if (maxElementWidth < mw) {
|
|
|
|
maxElementWidth = mw;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
aSizeResult.width = width;
|
|
|
|
aSizeResult.height = maxHeight;
|
2003-01-09 17:26:32 +03:00
|
|
|
if (aMaxElementWidth) {
|
1999-08-28 01:50:06 +04:00
|
|
|
if (psd->mNoWrap) {
|
2003-01-09 17:26:32 +03:00
|
|
|
// When we have a non-breakable span, it's max-element-width
|
1999-08-28 01:50:06 +04:00
|
|
|
// width is its entire width.
|
2003-01-09 17:26:32 +03:00
|
|
|
*aMaxElementWidth = width;
|
1999-08-28 01:50:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2003-01-09 17:26:32 +03:00
|
|
|
*aMaxElementWidth = maxElementWidth;
|
1999-08-28 01:50:06 +04:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mSpanDepth--;
|
|
|
|
mCurrentSpan->mReflowState = nsnull; // no longer valid so null it out!
|
|
|
|
mCurrentSpan = mCurrentSpan->mParent;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsLineLayout::GetCurrentSpanCount() const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
|
|
|
|
PRInt32 count = 0;
|
|
|
|
PerFrameData* pfd = mRootSpan->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
count++;
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsLineLayout::SplitLineTo(PRInt32 aNewCount)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_PUSHING
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("SplitLineTo %d (current count=%d); before:\n", aNewCount,
|
1999-03-19 00:03:25 +03:00
|
|
|
GetCurrentSpanCount());
|
|
|
|
DumpPerSpanData(mRootSpan, 1);
|
|
|
|
#endif
|
|
|
|
PerSpanData* psd = mRootSpan;
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
if (--aNewCount == 0) {
|
2002-08-14 17:00:16 +04:00
|
|
|
// Truncate list at pfd (we keep pfd, but anything following is freed)
|
|
|
|
PerFrameData* next = pfd->mNext;
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd->mNext = nsnull;
|
|
|
|
psd->mLastFrame = pfd;
|
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
// Now release all of the frames following pfd
|
|
|
|
pfd = next;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
next = pfd->mNext;
|
|
|
|
pfd->mNext = mFrameFreeList;
|
|
|
|
mFrameFreeList = pfd;
|
|
|
|
#ifdef DEBUG
|
|
|
|
mFramesFreed++;
|
|
|
|
#endif
|
|
|
|
if (nsnull != pfd->mSpan) {
|
|
|
|
FreeSpan(pfd->mSpan);
|
|
|
|
}
|
|
|
|
pfd = next;
|
|
|
|
}
|
1998-10-20 04:23:11 +04:00
|
|
|
break;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd = pfd->mNext;
|
1998-10-20 04:23:11 +04:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_PUSHING
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("SplitLineTo %d (current count=%d); after:\n", aNewCount,
|
1999-03-19 00:03:25 +03:00
|
|
|
GetCurrentSpanCount());
|
|
|
|
DumpPerSpanData(mRootSpan, 1);
|
|
|
|
#endif
|
|
|
|
}
|
1998-10-20 04:23:11 +04:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::PushFrame(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
NS_ASSERTION(psd->mLastFrame->mFrame == aFrame, "pushing non-last frame");
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_PUSHING
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("PushFrame %p, before:\n", psd);
|
1999-03-19 00:03:25 +03:00
|
|
|
DumpPerSpanData(psd, 1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Take the last frame off of the span's frame list
|
|
|
|
PerFrameData* pfd = psd->mLastFrame;
|
|
|
|
if (pfd == psd->mFirstFrame) {
|
|
|
|
// We are pushing away the only frame...empty the list
|
|
|
|
psd->mFirstFrame = nsnull;
|
|
|
|
psd->mLastFrame = nsnull;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PerFrameData* prevFrame = pfd->mPrev;
|
|
|
|
prevFrame->mNext = nsnull;
|
|
|
|
psd->mLastFrame = prevFrame;
|
|
|
|
}
|
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
// Now free it, and if it has a span, free that too
|
|
|
|
pfd->mNext = mFrameFreeList;
|
|
|
|
mFrameFreeList = pfd;
|
|
|
|
#ifdef DEBUG
|
|
|
|
mFramesFreed++;
|
|
|
|
#endif
|
|
|
|
if (nsnull != pfd->mSpan) {
|
|
|
|
FreeSpan(pfd->mSpan);
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_PUSHING
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("PushFrame: %p after:\n", psd);
|
1999-03-19 00:03:25 +03:00
|
|
|
DumpPerSpanData(psd, 1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
void
|
|
|
|
nsLineLayout::FreeSpan(PerSpanData* psd)
|
|
|
|
{
|
|
|
|
// Free its frames
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
if (nsnull != pfd->mSpan) {
|
|
|
|
FreeSpan(pfd->mSpan);
|
|
|
|
}
|
|
|
|
PerFrameData* next = pfd->mNext;
|
|
|
|
pfd->mNext = mFrameFreeList;
|
|
|
|
mFrameFreeList = pfd;
|
|
|
|
#ifdef DEBUG
|
|
|
|
mFramesFreed++;
|
|
|
|
#endif
|
|
|
|
pfd = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now put the span on the free list since its free too
|
|
|
|
psd->mNextFreeSpan = mSpanFreeList;
|
|
|
|
mSpanFreeList = psd;
|
|
|
|
#ifdef DEBUG
|
|
|
|
mSpansFreed++;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
PRBool
|
|
|
|
nsLineLayout::IsZeroHeight()
|
|
|
|
{
|
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
if (0 != pfd->mBounds.height) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsLineLayout::NewPerFrameData(PerFrameData** aResult)
|
|
|
|
{
|
2002-08-14 17:00:16 +04:00
|
|
|
PerFrameData* pfd = mFrameFreeList;
|
|
|
|
if (nsnull == pfd) {
|
|
|
|
if (mInitialFramesFreed < NS_LINELAYOUT_NUM_FRAMES) {
|
|
|
|
// use one of the ones defined in our struct...
|
|
|
|
pfd = &mFrameDataBuf[mInitialFramesFreed++];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd = new PerFrameData;
|
|
|
|
if (nsnull == pfd) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mFrameFreeList = pfd->mNext;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd->mSpan = nsnull;
|
|
|
|
pfd->mNext = nsnull;
|
1999-09-21 04:14:22 +04:00
|
|
|
pfd->mPrev = nsnull;
|
2000-02-02 10:38:23 +03:00
|
|
|
pfd->mFrame = nsnull;
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->mFlags = 0; // all flags default to false
|
2000-02-02 10:38:23 +03:00
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
pfd->mVerticalAlign = 0xFF;
|
2002-08-14 17:00:16 +04:00
|
|
|
mFramesAllocated++;
|
1999-03-22 23:45:09 +03:00
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
*aResult = pfd;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
PRBool
|
2003-10-14 01:51:02 +04:00
|
|
|
nsLineLayout::CanPlaceFloatNow() const
|
1999-03-24 18:41:49 +03:00
|
|
|
{
|
2003-10-14 01:51:02 +04:00
|
|
|
return GetFlag(LL_CANPLACEFLOAT);
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsLineLayout::LineIsBreakable() const
|
|
|
|
{
|
2003-10-14 01:51:02 +04:00
|
|
|
if ((0 != mTotalPlacedFrames) || GetFlag(LL_IMPACTEDBYFLOATS)) {
|
1999-03-24 18:41:49 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
nsresult
|
|
|
|
nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
1999-10-29 18:33:26 +04:00
|
|
|
nsReflowStatus& aReflowStatus,
|
2000-01-03 07:32:13 +03:00
|
|
|
nsHTMLReflowMetrics* aMetrics,
|
|
|
|
PRBool& aPushedFrame)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
2000-01-03 07:32:13 +03:00
|
|
|
// Initialize OUT parameter
|
|
|
|
aPushedFrame = PR_FALSE;
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
PerFrameData* pfd;
|
|
|
|
nsresult rv = NewPerFrameData(&pfd);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
psd->AppendFrame(pfd);
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p: Begin ReflowFrame pfd=%p ", psd, pfd);
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Compute the available size for the frame. This available width
|
2001-12-11 05:45:44 +03:00
|
|
|
// includes room for the side margins.
|
1999-03-19 00:03:25 +03:00
|
|
|
nsSize availSize;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == psd->mRightEdge) {
|
|
|
|
availSize.width = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
availSize.width = psd->mRightEdge - psd->mX;
|
1999-03-22 23:45:09 +03:00
|
|
|
if (psd->mNoWrap) {
|
|
|
|
// Make up a width to use for reflowing into. XXX what value to
|
|
|
|
// use? for tables, we want to limit it; for other elements
|
|
|
|
// (e.g. text) it can be unlimited...
|
2003-07-30 12:13:07 +04:00
|
|
|
availSize.width = psd->mReflowState->availableWidth;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == mBottomEdge) {
|
|
|
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
availSize.height = mBottomEdge - mTopEdge;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get reflow reason set correctly. It's possible that a child was
|
|
|
|
// created and then it was decided that it could not be reflowed
|
|
|
|
// (for example, a block frame that isn't at the start of a
|
|
|
|
// line). In this case the reason will be wrong so we need to check
|
|
|
|
// the frame state.
|
2002-05-10 22:22:41 +04:00
|
|
|
const nsHTMLReflowState* rs = psd->mReflowState;
|
1999-03-19 00:03:25 +03:00
|
|
|
nsReflowReason reason = eReflowReason_Resize;
|
2003-06-30 14:46:59 +04:00
|
|
|
if (NS_FRAME_FIRST_REFLOW & aFrame->GetStateBits()) {
|
1999-03-19 00:03:25 +03:00
|
|
|
reason = eReflowReason_Initial;
|
2000-01-12 11:28:24 +03:00
|
|
|
}
|
2002-05-10 22:22:41 +04:00
|
|
|
else if (rs->reason == eReflowReason_Incremental) { // XXX
|
|
|
|
// XXXwaterson (above) previously used mBlockReflowState rather
|
|
|
|
// than psd->mReflowState.
|
|
|
|
|
|
|
|
// If the frame we're about to reflow is on the reflow path, then
|
|
|
|
// propagate the reflow as `incremental' so it unwinds correctly
|
|
|
|
// to the target frames below us.
|
|
|
|
PRBool frameIsOnReflowPath = rs->path->HasChild(aFrame);
|
|
|
|
if (frameIsOnReflowPath)
|
|
|
|
reason = eReflowReason_Incremental;
|
|
|
|
|
|
|
|
// But...if the incremental reflow command is a StyleChanged
|
|
|
|
// reflow and its target is the current span, change the reason
|
|
|
|
// to `style change', so that it propagates through the entire
|
|
|
|
// subtree.
|
|
|
|
nsHTMLReflowCommand* rc = rs->path->mReflowCommand;
|
|
|
|
if (rc) {
|
|
|
|
nsReflowType type;
|
|
|
|
rc->GetType(type);
|
|
|
|
if (type == eReflowType_StyleChanged) {
|
|
|
|
nsIFrame* parentFrame = psd->mFrame
|
|
|
|
? psd->mFrame->mFrame
|
|
|
|
: mBlockReflowState->frame;
|
|
|
|
nsIFrame* target;
|
|
|
|
rc->GetTarget(target);
|
|
|
|
if (target == parentFrame) {
|
|
|
|
reason = eReflowReason_StyleChange;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == eReflowType_ReflowDirty &&
|
2003-06-30 14:46:59 +04:00
|
|
|
(aFrame->GetStateBits() & NS_FRAME_IS_DIRTY) &&
|
2002-05-10 22:22:41 +04:00
|
|
|
!frameIsOnReflowPath) {
|
|
|
|
reason = eReflowReason_Dirty;
|
|
|
|
}
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2002-05-10 22:22:41 +04:00
|
|
|
else if (rs->reason == eReflowReason_StyleChange) {
|
1999-10-22 00:44:58 +04:00
|
|
|
reason = eReflowReason_StyleChange;
|
|
|
|
}
|
2002-05-10 22:22:41 +04:00
|
|
|
else if (rs->reason == eReflowReason_Dirty) {
|
2003-06-30 14:46:59 +04:00
|
|
|
if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
|
2000-01-12 11:28:24 +03:00
|
|
|
reason = eReflowReason_Dirty;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Setup reflow state for reflowing the frame
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
nsHTMLReflowState reflowState(mPresContext, *psd->mReflowState,
|
2003-12-19 08:41:35 +03:00
|
|
|
aFrame, availSize, reason);
|
1999-07-20 07:51:46 +04:00
|
|
|
reflowState.mLineLayout = this;
|
2001-12-07 17:51:12 +03:00
|
|
|
reflowState.mFlags.mIsTopOfPage = GetFlag(LL_ISTOPOFPAGE);
|
2000-04-17 18:40:46 +04:00
|
|
|
SetFlag(LL_UNDERSTANDSNWHITESPACE, PR_FALSE);
|
|
|
|
mTextJustificationNumSpaces = 0;
|
|
|
|
mTextJustificationNumLetters = 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Stash copies of some of the computed state away for later
|
|
|
|
// (vertical alignment, for example)
|
|
|
|
pfd->mFrame = aFrame;
|
1999-07-20 07:41:03 +04:00
|
|
|
pfd->mMargin = reflowState.mComputedMargin;
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd->mBorderPadding = reflowState.mComputedBorderPadding;
|
1999-07-20 07:41:03 +04:00
|
|
|
pfd->mFrameType = reflowState.mFrameType;
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->SetFlag(PFD_RELATIVEPOS,
|
2001-06-01 02:19:43 +04:00
|
|
|
(reflowState.mStyleDisplay->mPosition == NS_STYLE_POSITION_RELATIVE));
|
2000-04-17 18:40:46 +04:00
|
|
|
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
|
1999-07-20 07:51:46 +04:00
|
|
|
pfd->mOffsets = reflowState.mComputedOffsets;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2001-12-11 05:45:44 +03:00
|
|
|
// NOTE: While the x coordinate remains relative to the parent span,
|
|
|
|
// the y coordinate is fixed at the top edge for the line. During
|
|
|
|
// VerticalAlignFrames we will repair this so that the y coordinate
|
|
|
|
// is properly set and relative to the appropriate span.
|
|
|
|
pfd->mBounds.x = psd->mX;
|
|
|
|
pfd->mBounds.y = mTopEdge;
|
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
// We want to guarantee that we always make progress when
|
|
|
|
// formatting. Therefore, if the object being placed on the line is
|
|
|
|
// too big for the line, but it is the only thing on the line
|
2003-10-14 01:51:02 +04:00
|
|
|
// (including counting floats) then we go ahead and place it
|
1999-03-22 23:45:09 +03:00
|
|
|
// anyway. Its also true that if the object is a part of a larger
|
|
|
|
// object (a multiple frame word) then we will place it on the line
|
|
|
|
// too.
|
|
|
|
//
|
1999-03-19 00:03:25 +03:00
|
|
|
// Capture this state *before* we reflow the frame in case it clears
|
|
|
|
// the state out. We need to know how to treat the current frame
|
|
|
|
// when breaking.
|
2003-10-14 01:51:02 +04:00
|
|
|
PRBool notSafeToBreak = CanPlaceFloatNow() || InWord();
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2002-01-31 02:28:56 +03:00
|
|
|
// Apply start margins (as appropriate) to the frame computing the
|
1999-03-19 00:03:25 +03:00
|
|
|
// new starting x,y coordinates for the frame.
|
2002-01-31 02:28:56 +03:00
|
|
|
ApplyStartMargin(pfd, reflowState);
|
1999-03-19 00:03:25 +03:00
|
|
|
|
1999-11-19 18:33:29 +03:00
|
|
|
// Let frame know that are reflowing it. Note that we don't bother
|
|
|
|
// positioning the frame yet, because we're probably going to end up
|
|
|
|
// moving it when we do the vertical alignment
|
1999-03-19 00:03:25 +03:00
|
|
|
nscoord x = pfd->mBounds.x;
|
|
|
|
nscoord y = pfd->mBounds.y;
|
|
|
|
|
1999-10-30 06:52:11 +04:00
|
|
|
aFrame->WillReflow(mPresContext);
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Adjust spacemanager coordinate system for the frame. The
|
|
|
|
// spacemanager coordinates are <b>inside</b> the current spans
|
|
|
|
// border+padding, but the x/y coordinates are not (recall that
|
|
|
|
// frame coordinates are relative to the parents origin and that the
|
|
|
|
// parents border/padding is <b>inside</b> the parent
|
|
|
|
// frame. Therefore we have to subtract out the parents
|
|
|
|
// border+padding before translating.
|
2003-01-09 17:26:32 +03:00
|
|
|
nsHTMLReflowMetrics metrics(mComputeMaxElementWidth);
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef DEBUG
|
1999-03-20 02:07:17 +03:00
|
|
|
metrics.width = nscoord(0xdeadbeef);
|
|
|
|
metrics.height = nscoord(0xdeadbeef);
|
|
|
|
metrics.ascent = nscoord(0xdeadbeef);
|
|
|
|
metrics.descent = nscoord(0xdeadbeef);
|
2003-01-09 17:26:32 +03:00
|
|
|
if (mComputeMaxElementWidth) {
|
|
|
|
metrics.mMaxElementWidth = nscoord(0xdeadbeef);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
nscoord tx = x - psd->mReflowState->mComputedBorderPadding.left;
|
|
|
|
nscoord ty = y - psd->mReflowState->mComputedBorderPadding.top;
|
|
|
|
mSpaceManager->Translate(tx, ty);
|
1999-12-10 21:41:43 +03:00
|
|
|
|
2001-04-12 03:32:21 +04:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
PRBool bidiEnabled;
|
2001-05-16 17:40:08 +04:00
|
|
|
mPresContext->GetBidiEnabled(&bidiEnabled);
|
2001-04-12 03:32:21 +04:00
|
|
|
PRInt32 start, end;
|
|
|
|
|
|
|
|
if (bidiEnabled) {
|
2003-06-30 14:46:59 +04:00
|
|
|
if (aFrame->GetStateBits() & NS_FRAME_IS_BIDI) {
|
2001-04-12 03:32:21 +04:00
|
|
|
aFrame->GetOffsets(start, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // IBMBIDI
|
|
|
|
|
2003-10-31 23:19:18 +03:00
|
|
|
nsIAtom* frameType = aFrame->GetType();
|
2002-05-29 02:50:43 +04:00
|
|
|
|
2001-04-20 01:54:35 +04:00
|
|
|
rv = aFrame->Reflow(mPresContext, metrics, reflowState, aReflowStatus);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING( "Reflow of frame failed in nsLineLayout" );
|
|
|
|
return rv;
|
|
|
|
}
|
1999-04-23 19:15:53 +04:00
|
|
|
|
2000-08-24 08:26:43 +04:00
|
|
|
// SEC: added this next block for bug 45152
|
|
|
|
// text frames don't know how to invalidate themselves on initial reflow. Do it for them here.
|
|
|
|
// This only shows up in textareas, so do a quick check to see if we're inside one
|
|
|
|
if (eReflowReason_Initial == reflowState.reason)
|
|
|
|
{
|
2003-10-31 23:19:18 +03:00
|
|
|
if (nsLayoutAtoms::textFrame == frameType)
|
2000-08-24 08:26:43 +04:00
|
|
|
{ // aFrame is a text frame, see if it's inside a text control
|
|
|
|
// although this is a bit slow, the frame tree shouldn't be too deep, it's only called
|
|
|
|
// for the text frame's initial reflow (once in the text frame's lifetime)
|
|
|
|
// and we don't make any expensive calls.
|
|
|
|
// Doing it this way shields us from knowing anything about the frame structure inside a text control.
|
|
|
|
PRBool inTextControl = PR_FALSE;
|
2003-06-30 14:46:59 +04:00
|
|
|
for (nsIFrame *parentFrame = aFrame->GetParent(); parentFrame;
|
|
|
|
parentFrame = parentFrame->GetParent())
|
2000-08-24 08:26:43 +04:00
|
|
|
{
|
2003-10-31 23:19:18 +03:00
|
|
|
if (nsLayoutAtoms::textInputFrame == parentFrame->GetType())
|
2000-08-24 08:26:43 +04:00
|
|
|
{
|
2003-10-31 23:19:18 +03:00
|
|
|
inTextControl = PR_TRUE; // found it
|
|
|
|
break;
|
2000-08-24 08:26:43 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (inTextControl)
|
|
|
|
{
|
|
|
|
nsLineBox *currentLine=nsnull;
|
2000-09-14 09:50:56 +04:00
|
|
|
// use localResult because a failure here should not be propagated to my caller
|
|
|
|
nsresult localResult = nsBlockFrame::GetCurrentLine(mBlockRS, ¤tLine);
|
|
|
|
if (NS_SUCCEEDED(localResult) && currentLine) {
|
2000-08-24 08:26:43 +04:00
|
|
|
currentLine->SetForceInvalidate(PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// end fix for bug 45152
|
|
|
|
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->mJustificationNumSpaces = mTextJustificationNumSpaces;
|
|
|
|
pfd->mJustificationNumLetters = mTextJustificationNumLetters;
|
|
|
|
|
1999-04-24 00:01:38 +04:00
|
|
|
// XXX See if the frame is a placeholderFrame and if it is process
|
2003-10-14 01:51:02 +04:00
|
|
|
// the float.
|
1999-04-23 19:15:53 +04:00
|
|
|
if (frameType) {
|
2003-10-31 23:19:18 +03:00
|
|
|
if (nsLayoutAtoms::placeholderFrame == frameType) {
|
2004-02-20 01:12:38 +03:00
|
|
|
pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, PR_TRUE);
|
1999-04-25 21:01:07 +04:00
|
|
|
nsIFrame* outOfFlowFrame = ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame();
|
|
|
|
if (outOfFlowFrame) {
|
|
|
|
// Make sure it's floated and not absolutely positioned
|
2003-05-15 07:42:21 +04:00
|
|
|
const nsStyleDisplay* display = outOfFlowFrame->GetStyleDisplay();
|
2001-06-01 02:19:43 +04:00
|
|
|
if (!display->IsAbsolutelyPositioned()) {
|
1999-04-25 21:01:07 +04:00
|
|
|
if (eReflowReason_Incremental == reason) {
|
2003-10-14 01:51:02 +04:00
|
|
|
InitFloat((nsPlaceholderFrame*)aFrame, aReflowStatus);
|
1999-04-25 21:01:07 +04:00
|
|
|
}
|
|
|
|
else {
|
2003-10-14 01:51:02 +04:00
|
|
|
AddFloat((nsPlaceholderFrame*)aFrame, aReflowStatus);
|
1999-04-25 21:01:07 +04:00
|
|
|
}
|
2003-10-31 23:19:18 +03:00
|
|
|
if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) {
|
|
|
|
SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE);
|
|
|
|
// An incomplete reflow status means we should split the
|
|
|
|
// float if the height is constrained (bug 145305). We
|
|
|
|
// never split floating first letters.
|
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus))
|
|
|
|
aReflowStatus = NS_FRAME_COMPLETE;
|
1999-04-29 04:16:09 +04:00
|
|
|
}
|
1999-04-25 21:01:07 +04:00
|
|
|
}
|
1999-04-23 19:15:53 +04:00
|
|
|
}
|
|
|
|
}
|
2003-10-31 23:19:18 +03:00
|
|
|
else if (nsLayoutAtoms::textFrame == frameType) {
|
1999-09-03 07:47:49 +04:00
|
|
|
// Note non-empty text-frames for inline frame compatability hackery
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->SetFlag(PFD_ISTEXTFRAME, PR_TRUE);
|
2000-02-15 07:26:44 +03:00
|
|
|
// XXX An empty text frame at the end of the line seems not
|
|
|
|
// to have zero width.
|
1999-09-03 07:47:49 +04:00
|
|
|
if (metrics.width) {
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->SetFlag(PFD_ISNONEMPTYTEXTFRAME, PR_TRUE);
|
2003-06-30 14:46:59 +04:00
|
|
|
nsIContent* content = pfd->mFrame->GetContent();
|
|
|
|
if (content) {
|
|
|
|
nsresult result;
|
2000-02-15 07:26:44 +03:00
|
|
|
nsCOMPtr<nsITextContent> textContent
|
|
|
|
= do_QueryInterface(content, &result);
|
|
|
|
if ((NS_SUCCEEDED(result)) && textContent) {
|
|
|
|
PRBool isWhitespace;
|
|
|
|
result = textContent->IsOnlyWhitespace(&isWhitespace);
|
|
|
|
if (NS_SUCCEEDED(result)) {
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->SetFlag(PFD_ISNONWHITESPACETEXTFRAME, !isWhitespace);
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
2001-04-12 03:32:21 +04:00
|
|
|
// fix for bug 40882
|
|
|
|
#ifdef IBMBIDI
|
|
|
|
const nsTextFragment* frag;
|
|
|
|
textContent->GetText(&frag);
|
|
|
|
if (frag && frag->Is2b() ) {
|
|
|
|
//PRBool isVisual;
|
|
|
|
//mPresContext->IsVisualMode(isVisual);
|
|
|
|
PRUnichar ch = /*(isVisual) ?
|
|
|
|
*(frag->Get2b() + frag->GetLength() - 1) :*/ *frag->Get2b();
|
|
|
|
if (IS_BIDI_DIACRITIC(ch) ) {
|
|
|
|
aFrame->SetBidiProperty(mPresContext,
|
|
|
|
nsLayoutAtoms::endsInDiacritic, (void*)ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // IBMBIDI
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
|
|
|
}
|
1999-09-03 07:47:49 +04:00
|
|
|
}
|
|
|
|
}
|
2003-10-31 23:19:18 +03:00
|
|
|
else if (nsLayoutAtoms::letterFrame==frameType) {
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->SetFlag(PFD_ISLETTERFRAME, PR_TRUE);
|
1999-10-29 18:33:26 +04:00
|
|
|
}
|
2004-02-20 01:12:38 +03:00
|
|
|
else if (nsLayoutAtoms::brFrame == frameType) {
|
|
|
|
pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, PR_TRUE);
|
|
|
|
}
|
1999-04-23 19:15:53 +04:00
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
mSpaceManager->Translate(-tx, -ty);
|
|
|
|
|
2000-10-30 07:11:59 +03:00
|
|
|
NS_ASSERTION(metrics.width>=0, "bad width");
|
|
|
|
NS_ASSERTION(metrics.height>=0,"bad height");
|
|
|
|
if (metrics.width<0) metrics.width=0;
|
|
|
|
if (metrics.height<0) metrics.height=0;
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
// Note: break-before means ignore the reflow metrics since the
|
|
|
|
// frame will be reflowed another time.
|
|
|
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
|
|
|
if (CRAZY_WIDTH(metrics.width) || CRAZY_HEIGHT(metrics.height)) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsLineLayout: ");
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" metrics=%d,%d!\n", metrics.width, metrics.height);
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
2003-01-09 17:26:32 +03:00
|
|
|
if (mComputeMaxElementWidth &&
|
|
|
|
(nscoord(0xdeadbeef) == metrics.mMaxElementWidth)) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsLineLayout: ");
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2003-01-09 17:26:32 +03:00
|
|
|
printf(" didn't set max-element-width!\n");
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
|
|
|
#ifdef REALLY_NOISY_MAX_ELEMENT_SIZE
|
|
|
|
// Note: there are common reflow situations where this *correctly*
|
|
|
|
// occurs; so only enable this debug noise when you really need to
|
|
|
|
// analyze in detail.
|
2003-01-09 17:26:32 +03:00
|
|
|
if (mComputeMaxElementWidth &&
|
|
|
|
(metrics.mMaxElementWidth > metrics.width)) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsLineLayout: ");
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2003-01-09 17:26:32 +03:00
|
|
|
printf(": WARNING: maxElementWidth=%d > metrics=%d\n",
|
|
|
|
metrics.mMaxElementWidth, metrics.width);
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if ((metrics.width == nscoord(0xdeadbeef)) ||
|
|
|
|
(metrics.height == nscoord(0xdeadbeef)) ||
|
|
|
|
(metrics.ascent == nscoord(0xdeadbeef)) ||
|
|
|
|
(metrics.descent == nscoord(0xdeadbeef))) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsLineLayout: ");
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" didn't set whad %d,%d,%d,%d!\n", metrics.width, metrics.height,
|
1999-03-24 18:41:49 +03:00
|
|
|
metrics.ascent, metrics.descent);
|
|
|
|
}
|
1999-03-20 02:07:17 +03:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
2003-01-09 17:26:32 +03:00
|
|
|
if (nsBlockFrame::gNoisyMaxElementWidth) {
|
2002-07-01 21:43:02 +04:00
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
|
|
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
2003-01-09 17:26:32 +03:00
|
|
|
if (mComputeMaxElementWidth) {
|
2002-07-01 21:43:02 +04:00
|
|
|
printf(" ");
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2003-01-09 17:26:32 +03:00
|
|
|
printf(": maxElementWidth=%d wh=%d,%d,\n",
|
|
|
|
metrics.mMaxElementWidth,
|
2002-07-01 21:43:02 +04:00
|
|
|
metrics.width, metrics.height);
|
|
|
|
}
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
1999-03-20 22:38:50 +03:00
|
|
|
}
|
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2003-06-30 14:46:59 +04:00
|
|
|
if (NS_FRAME_OUTSIDE_CHILDREN & aFrame->GetStateBits()) {
|
1999-12-06 18:49:53 +03:00
|
|
|
pfd->mCombinedArea = metrics.mOverflowArea;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mCombinedArea.x = 0;
|
|
|
|
pfd->mCombinedArea.y = 0;
|
|
|
|
pfd->mCombinedArea.width = metrics.width;
|
|
|
|
pfd->mCombinedArea.height = metrics.height;
|
|
|
|
}
|
|
|
|
pfd->mBounds.width = metrics.width;
|
|
|
|
pfd->mBounds.height = metrics.height;
|
2003-01-09 17:26:32 +03:00
|
|
|
if (mComputeMaxElementWidth) {
|
|
|
|
pfd->mMaxElementWidth = metrics.mMaxElementWidth;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2003-07-23 04:14:16 +04:00
|
|
|
// Size the frame, but |RelativePositionFrames| will size the view.
|
2003-06-30 14:46:59 +04:00
|
|
|
aFrame->SetSize(nsSize(metrics.width, metrics.height));
|
1999-03-19 00:03:25 +03:00
|
|
|
|
1999-11-19 18:33:29 +03:00
|
|
|
// Tell the frame that we're done reflowing it
|
2001-12-07 17:51:12 +03:00
|
|
|
aFrame->DidReflow(mPresContext, &reflowState, NS_FRAME_REFLOW_FINISHED);
|
1999-11-19 18:33:29 +03:00
|
|
|
|
1999-10-29 18:33:26 +04:00
|
|
|
if (aMetrics) {
|
|
|
|
*aMetrics = metrics;
|
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
|
|
|
// If frame is complete and has a next-in-flow, we need to delete
|
|
|
|
// them now. Do not do this when a break-before is signaled because
|
|
|
|
// the frame is going to get reflowed again (and may end up wanting
|
|
|
|
// a next-in-flow where it ends up).
|
|
|
|
if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
|
|
|
|
nsIFrame* kidNextInFlow;
|
|
|
|
aFrame->GetNextInFlow(&kidNextInFlow);
|
|
|
|
if (nsnull != kidNextInFlow) {
|
|
|
|
// Remove all of the childs next-in-flows. Make sure that we ask
|
|
|
|
// the right parent to do the removal (it's possible that the
|
|
|
|
// parent is not this because we are executing pullup code)
|
2003-06-30 14:46:59 +04:00
|
|
|
nsHTMLContainerFrame* parent = NS_STATIC_CAST(nsHTMLContainerFrame*,
|
|
|
|
kidNextInFlow->GetParent());
|
2002-10-09 00:35:26 +04:00
|
|
|
parent->DeleteNextInFlowChild(mPresContext, kidNextInFlow);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if we can place the frame. If we can't fit it, then we
|
|
|
|
// return now.
|
1999-11-02 18:44:57 +03:00
|
|
|
if (CanPlaceFrame(pfd, reflowState, notSafeToBreak, metrics, aReflowStatus)) {
|
1999-03-19 00:03:25 +03:00
|
|
|
// Place the frame, updating aBounds with the final size and
|
|
|
|
// location. Then apply the bottom+right margins (as
|
|
|
|
// appropriate) to the frame.
|
|
|
|
PlaceFrame(pfd, metrics);
|
|
|
|
PerSpanData* span = pfd->mSpan;
|
|
|
|
if (span) {
|
|
|
|
// The frame we just finished reflowing is an inline
|
|
|
|
// container. It needs its child frames vertically aligned,
|
|
|
|
// so do most of it now.
|
|
|
|
VerticalAlignFrames(span);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PushFrame(aFrame);
|
2000-01-03 07:32:13 +03:00
|
|
|
aPushedFrame = PR_TRUE;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PushFrame(aFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("End ReflowFrame ");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" status=%x\n", aReflowStatus);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
2001-04-12 03:32:21 +04:00
|
|
|
|
2003-06-30 14:46:59 +04:00
|
|
|
if (aFrame->GetStateBits() & NS_FRAME_IS_BIDI) {
|
2003-02-25 03:44:04 +03:00
|
|
|
// Since aReflowStatus may change, check it at the end
|
|
|
|
if (NS_INLINE_IS_BREAK_BEFORE(aReflowStatus) ) {
|
|
|
|
aFrame->AdjustOffsetsForBidi(start, end);
|
|
|
|
}
|
|
|
|
else if (!NS_FRAME_IS_COMPLETE(aReflowStatus) ) {
|
|
|
|
PRInt32 newEnd;
|
|
|
|
aFrame->GetOffsets(start, newEnd);
|
|
|
|
if (newEnd != end) {
|
|
|
|
nsIFrame* nextInFlow;
|
|
|
|
aFrame->GetNextInFlow(&nextInFlow);
|
|
|
|
if (nextInFlow) {
|
|
|
|
nextInFlow->GetOffsets(start, end);
|
|
|
|
nextInFlow->AdjustOffsetsForBidi(newEnd, end);
|
|
|
|
} // nextInFlow
|
|
|
|
} // newEnd != end
|
|
|
|
} // !NS_FRAME_IS_COMPLETE(aReflowStatus)
|
2001-04-12 03:32:21 +04:00
|
|
|
} // isBidiFrame
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-01-31 02:28:56 +03:00
|
|
|
nsLineLayout::ApplyStartMargin(PerFrameData* pfd,
|
|
|
|
nsHTMLReflowState& aReflowState)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
2002-01-31 02:28:56 +03:00
|
|
|
NS_ASSERTION(aReflowState.mStyleDisplay->mFloats == NS_STYLE_FLOAT_NONE,
|
|
|
|
"How'd we get a floated inline frame? "
|
|
|
|
"The frame ctor should've dealt with this.");
|
|
|
|
|
|
|
|
// XXXwaterson probably not the right way to get this; e.g., embeddings, etc.
|
|
|
|
PRBool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection);
|
|
|
|
|
|
|
|
// Only apply start-margin on the first-in flow for inline frames
|
2002-05-14 16:55:55 +04:00
|
|
|
if (HasPrevInFlow(pfd->mFrame)) {
|
2003-01-09 17:26:32 +03:00
|
|
|
// Zero this out so that when we compute the max-element-width of
|
2002-01-31 02:28:56 +03:00
|
|
|
// the frame we will properly avoid adding in the starting margin.
|
|
|
|
if (ltr)
|
|
|
|
pfd->mMargin.left = 0;
|
|
|
|
else
|
|
|
|
pfd->mMargin.right = 0;
|
2001-12-06 23:14:10 +03:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2003-07-30 12:13:07 +04:00
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth){
|
2002-01-31 02:28:56 +03:00
|
|
|
// Adjust available width to account for the left margin. The
|
|
|
|
// right margin will be accounted for when we finish flowing the
|
|
|
|
// frame.
|
|
|
|
aReflowState.availableWidth -= ltr ? pfd->mMargin.left : pfd->mMargin.right;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2002-01-31 02:28:56 +03:00
|
|
|
if (ltr)
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd->mBounds.x += pfd->mMargin.left;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* See if the frame can be placed now that we know it's desired size.
|
|
|
|
* We can always place the frame if the line is empty. Note that we
|
|
|
|
* know that the reflow-status is not a break-before because if it was
|
|
|
|
* ReflowFrame above would have returned false, preventing this method
|
|
|
|
* from being called. The logic in this method assumes that.
|
|
|
|
*
|
|
|
|
* Note that there is no check against the Y coordinate because we
|
|
|
|
* assume that the caller will take care of that.
|
|
|
|
*/
|
|
|
|
PRBool
|
|
|
|
nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
1999-03-22 23:45:09 +03:00
|
|
|
PRBool aNotSafeToBreak,
|
1999-03-19 00:03:25 +03:00
|
|
|
nsHTMLReflowMetrics& aMetrics,
|
|
|
|
nsReflowStatus& aStatus)
|
|
|
|
{
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
NS_PRECONDITION(pfd && pfd->mFrame, "bad args, null pointers for frame data");
|
1999-03-19 00:03:25 +03:00
|
|
|
// Compute right margin to use
|
|
|
|
if (0 != pfd->mBounds.width) {
|
2002-01-31 02:28:56 +03:00
|
|
|
NS_ASSERTION(aReflowState.mStyleDisplay->mFloats == NS_STYLE_FLOAT_NONE,
|
|
|
|
"How'd we get a floated inline frame? "
|
|
|
|
"The frame ctor should've dealt with this.");
|
1999-03-21 04:14:43 +03:00
|
|
|
|
2002-01-31 02:28:56 +03:00
|
|
|
// XXXwaterson this is probably not exactly right; e.g., embeddings, etc.
|
|
|
|
PRBool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection);
|
1999-03-21 04:14:43 +03:00
|
|
|
|
2002-01-31 02:28:56 +03:00
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
|
|
|
// Only apply end margin for the last-in-flow. Zero this out so
|
2003-01-09 17:26:32 +03:00
|
|
|
// that when we compute the max-element-width of the frame we
|
2002-01-31 02:28:56 +03:00
|
|
|
// will properly avoid adding in the end margin.
|
|
|
|
if (ltr)
|
|
|
|
pfd->mMargin.right = 0;
|
|
|
|
else
|
|
|
|
pfd->mMargin.left = 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
2002-01-31 02:28:56 +03:00
|
|
|
else {
|
|
|
|
// Don't apply margin to empty frames.
|
|
|
|
pfd->mMargin.left = pfd->mMargin.right = 0;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
if (psd->mNoWrap) {
|
1999-11-02 18:44:57 +03:00
|
|
|
// When wrapping is off, everything fits.
|
1999-03-21 04:14:43 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
|
|
|
if (nsnull != psd->mFrame) {
|
|
|
|
nsFrame::ListTag(stdout, psd->mFrame->mFrame);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": aNotSafeToBreak=%s frame=", aNotSafeToBreak ? "true" : "false");
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" frameWidth=%d\n", pfd->mBounds.XMost() + rightMargin - psd->mX);
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Set outside to PR_TRUE if the result of the reflow leads to the
|
|
|
|
// frame sticking outside of our available area.
|
2002-01-31 02:28:56 +03:00
|
|
|
PRBool outside = pfd->mBounds.XMost() + pfd->mMargin.right > psd->mRightEdge;
|
1999-03-21 04:14:43 +03:00
|
|
|
if (!outside) {
|
|
|
|
// If it fits, it fits
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> inside\n");
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
1999-03-21 04:14:43 +03:00
|
|
|
// When it doesn't fit, check for a few special conditions where we
|
|
|
|
// allow it to fit anyway.
|
2002-01-31 02:28:56 +03:00
|
|
|
if (0 == pfd->mMargin.left + pfd->mBounds.width + pfd->mMargin.right) {
|
1999-03-19 00:03:25 +03:00
|
|
|
// Empty frames always fit right where they are
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> empty frame fits\n");
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
#ifdef FIX_BUG_50257
|
|
|
|
// another special case: always place a BR
|
2003-10-31 23:19:18 +03:00
|
|
|
if (nsLayoutAtoms::brFrame == pfd->mFrame->GetType()) {
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> BR frame fits\n");
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
#endif
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
if (aNotSafeToBreak) {
|
|
|
|
// There are no frames on the line or we are in the first word on
|
2003-10-14 01:51:02 +04:00
|
|
|
// the line. If the line isn't impacted by a float then the
|
1999-03-22 23:45:09 +03:00
|
|
|
// current frame fits.
|
2003-10-14 01:51:02 +04:00
|
|
|
if (!GetFlag(LL_IMPACTEDBYFLOATS)) {
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> not-safe and not-impacted fits: ");
|
1999-03-24 18:41:49 +03:00
|
|
|
while (nsnull != psd) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("<psd=%p x=%d left=%d> ", psd, psd->mX, psd->mLeftEdge);
|
1999-03-24 18:41:49 +03:00
|
|
|
psd = psd->mParent;
|
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
1999-03-21 04:14:43 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2003-10-14 01:51:02 +04:00
|
|
|
else if (GetFlag(LL_LASTFLOATWASLETTERFRAME)) {
|
|
|
|
// Another special case: see if the float is a letter
|
1999-10-29 18:33:26 +04:00
|
|
|
// frame. If it is, then allow the frame next to it to fit.
|
2000-04-17 18:40:46 +04:00
|
|
|
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
1999-10-29 18:33:26 +04:00
|
|
|
// This must be the first piece of non-empty text (because
|
|
|
|
// aNotSafeToBreak is true) or its a piece of text that is
|
|
|
|
// part of a larger word.
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->SetFlag(PFD_ISSTICKY, PR_TRUE);
|
1999-10-29 18:33:26 +04:00
|
|
|
}
|
|
|
|
else if (pfd->mSpan) {
|
|
|
|
PerFrameData* pf = pfd->mSpan->mFirstFrame;
|
|
|
|
while (pf) {
|
2000-04-17 18:40:46 +04:00
|
|
|
if (pf->GetFlag(PFD_ISSTICKY)) {
|
1999-10-29 18:33:26 +04:00
|
|
|
// If one of the spans children was sticky then the span
|
|
|
|
// itself is sticky.
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->SetFlag(PFD_ISSTICKY, PR_TRUE);
|
1999-10-29 18:33:26 +04:00
|
|
|
}
|
|
|
|
pf = pf->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-17 18:40:46 +04:00
|
|
|
if (pfd->GetFlag(PFD_ISSTICKY)) {
|
1999-10-29 18:33:26 +04:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2003-10-14 01:51:02 +04:00
|
|
|
printf(" ==> last float was letter frame && frame is sticky\n");
|
1999-10-29 18:33:26 +04:00
|
|
|
#endif
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is a piece of text inside a letter frame...
|
2000-04-17 18:40:46 +04:00
|
|
|
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
|
|
|
if (psd->mFrame && psd->mFrame->GetFlag(PFD_ISLETTERFRAME)) {
|
1999-10-29 18:33:26 +04:00
|
|
|
nsIFrame* prevInFlow;
|
|
|
|
psd->mFrame->mFrame->GetPrevInFlow(&prevInFlow);
|
|
|
|
if (prevInFlow) {
|
|
|
|
nsIFrame* prevPrevInFlow;
|
|
|
|
prevInFlow->GetPrevInFlow(&prevPrevInFlow);
|
|
|
|
if (!prevPrevInFlow) {
|
|
|
|
// And it's the first continuation of the letter frame...
|
|
|
|
// Then make sure that the text fits
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
else if (pfd->GetFlag(PFD_ISLETTERFRAME)) {
|
1999-10-29 18:33:26 +04:00
|
|
|
// If this is the first continuation of the letter frame...
|
|
|
|
nsIFrame* prevInFlow;
|
|
|
|
pfd->mFrame->GetPrevInFlow(&prevInFlow);
|
|
|
|
if (prevInFlow) {
|
|
|
|
nsIFrame* prevPrevInFlow;
|
|
|
|
prevInFlow->GetPrevInFlow(&prevPrevInFlow);
|
|
|
|
if (!prevPrevInFlow) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
1999-11-02 18:44:57 +03:00
|
|
|
// Special check for span frames
|
2003-10-14 01:51:02 +04:00
|
|
|
if (pfd->mSpan && pfd->mSpan->mContainsFloat) {
|
|
|
|
// If the span either directly or indirectly contains a float then
|
1999-11-02 18:44:57 +03:00
|
|
|
// it fits. Why? It's kind of complicated, but here goes:
|
|
|
|
//
|
|
|
|
// 1. CanPlaceFrame is used for all frame placements on a line,
|
|
|
|
// and in a span. This includes recursively placement of frames
|
|
|
|
// inside of spans, and the span itself. Because the logic always
|
|
|
|
// checks for room before proceeding (the code above here), the
|
|
|
|
// only things on a line will be those things that "fit".
|
|
|
|
//
|
2003-10-14 01:51:02 +04:00
|
|
|
// 2. Before a float is placed on a line, the line has to be empty
|
1999-11-02 18:44:57 +03:00
|
|
|
// (otherwise its a "below current line" flaoter and will be placed
|
|
|
|
// after the line).
|
|
|
|
//
|
2003-10-14 01:51:02 +04:00
|
|
|
// Therefore, if the span directly or indirectly has a float
|
|
|
|
// then it means that at the time of the placement of the float
|
1999-11-02 18:44:57 +03:00
|
|
|
// the line was empty. Because of #1, only the frames that fit can
|
|
|
|
// be added after that point, therefore we can assume that the
|
|
|
|
// current span being placed has fit.
|
|
|
|
//
|
|
|
|
// So how do we get here and have a span that should already fit
|
|
|
|
// and yet doesn't: Simple: span's that have the no-wrap attribute
|
2003-10-14 01:51:02 +04:00
|
|
|
// set on them and contain a float and are placed where they
|
1999-11-02 18:44:57 +03:00
|
|
|
// don't naturally fit.
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> didn't fit\n");
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
1999-03-21 04:14:43 +03:00
|
|
|
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
|
|
|
return PR_FALSE;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Place the frame. Update running counters.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
|
|
|
{
|
|
|
|
// If frame is zero width then do not apply its left and right margins.
|
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
PRBool emptyFrame = PR_FALSE;
|
|
|
|
if ((0 == pfd->mBounds.width) && (0 == pfd->mBounds.height)) {
|
|
|
|
pfd->mBounds.x = psd->mX;
|
|
|
|
pfd->mBounds.y = mTopEdge;
|
|
|
|
emptyFrame = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Record ascent and update max-ascent and max-descent values
|
|
|
|
pfd->mAscent = aMetrics.ascent;
|
|
|
|
pfd->mDescent = aMetrics.descent;
|
|
|
|
|
|
|
|
// If the band was updated during the reflow of that frame then we
|
|
|
|
// need to adjust any prior frames that were reflowed.
|
2000-04-17 18:40:46 +04:00
|
|
|
if (GetFlag(LL_UPDATEDBAND) && InBlockContext()) {
|
1999-03-19 00:03:25 +03:00
|
|
|
UpdateFrames();
|
2000-04-17 18:40:46 +04:00
|
|
|
SetFlag(LL_UPDATEDBAND, PR_FALSE);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Advance to next X coordinate
|
|
|
|
psd->mX = pfd->mBounds.XMost() + pfd->mMargin.right;
|
2002-09-25 01:02:20 +04:00
|
|
|
psd->mRightEdge = PR_MAX(psd->mRightEdge, psd->mX);
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// If the frame is a not aware of white-space and it takes up some
|
1999-07-14 21:29:32 +04:00
|
|
|
// width, disable leading white-space compression for the next frame
|
1999-03-19 00:03:25 +03:00
|
|
|
// to be reflowed.
|
2000-04-17 18:40:46 +04:00
|
|
|
if ((!GetFlag(LL_UNDERSTANDSNWHITESPACE)) && pfd->mBounds.width) {
|
|
|
|
SetFlag(LL_ENDSINWHITESPACE, PR_FALSE);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
// Count the number of frames on the line...
|
|
|
|
mTotalPlacedFrames++;
|
2001-12-04 02:30:32 +03:00
|
|
|
if (psd->mX != psd->mLeftEdge || pfd->mBounds.x != psd->mLeftEdge) {
|
1999-03-24 18:41:49 +03:00
|
|
|
// As soon as a frame placed on the line advances an X coordinate
|
2003-10-14 01:51:02 +04:00
|
|
|
// of any span we can no longer place a float on the line.
|
|
|
|
SetFlag(LL_CANPLACEFLOAT, PR_FALSE);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
|
|
|
const nsHTMLReflowMetrics& aMetrics)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
|
|
|
|
|
|
|
|
PerFrameData* pfd;
|
|
|
|
nsresult rv = NewPerFrameData(&pfd);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
mRootSpan->AppendFrame(pfd);
|
|
|
|
pfd->mFrame = aFrame;
|
|
|
|
pfd->mMargin.SizeTo(0, 0, 0, 0);
|
|
|
|
pfd->mBorderPadding.SizeTo(0, 0, 0, 0);
|
|
|
|
pfd->mFrameType = NS_CSS_FRAME_TYPE_INLINE|NS_FRAME_REPLACED_ELEMENT;
|
2000-04-17 18:40:46 +04:00
|
|
|
pfd->mFlags = 0; // all flags default to false
|
|
|
|
pfd->SetFlag(PFD_ISBULLET, PR_TRUE);
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd->mAscent = aMetrics.ascent;
|
|
|
|
pfd->mDescent = aMetrics.descent;
|
1999-09-10 01:04:37 +04:00
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
// Note: y value will be updated during vertical alignment
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mBounds = aFrame->GetRect();
|
1999-12-06 18:49:53 +03:00
|
|
|
pfd->mCombinedArea = aMetrics.mOverflowArea;
|
2003-01-09 17:26:32 +03:00
|
|
|
if (mComputeMaxElementWidth) {
|
|
|
|
pfd->mMaxElementWidth = aMetrics.width;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
nsLineLayout::DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent)
|
|
|
|
{
|
|
|
|
nsFrame::IndentBy(stdout, aIndent);
|
2001-10-25 05:08:40 +04:00
|
|
|
printf("%p: left=%d x=%d right=%d\n", NS_STATIC_CAST(void*, psd),
|
|
|
|
psd->mLeftEdge, psd->mX, psd->mRightEdge);
|
1999-03-19 00:03:25 +03:00
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
nsFrame::IndentBy(stdout, aIndent+1);
|
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" %d,%d,%d,%d\n", pfd->mBounds.x, pfd->mBounds.y,
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd->mBounds.width, pfd->mBounds.height);
|
|
|
|
if (pfd->mSpan) {
|
|
|
|
DumpPerSpanData(pfd->mSpan, aIndent + 1);
|
|
|
|
}
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define VALIGN_OTHER 0
|
|
|
|
#define VALIGN_TOP 1
|
|
|
|
#define VALIGN_BOTTOM 2
|
|
|
|
|
2000-09-12 00:46:44 +04:00
|
|
|
PRBool
|
|
|
|
nsLineLayout::IsPercentageUnitSides(const nsStyleSides* aSides)
|
|
|
|
{
|
|
|
|
return eStyleUnit_Percent == aSides->GetLeftUnit()
|
|
|
|
|| eStyleUnit_Percent == aSides->GetRightUnit()
|
|
|
|
|| eStyleUnit_Percent == aSides->GetTopUnit()
|
|
|
|
|| eStyleUnit_Percent == aSides->GetBottomUnit();
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsLineLayout::IsPercentageAwareReplacedElement(nsIPresContext *aPresContext,
|
|
|
|
nsIFrame* aFrame)
|
|
|
|
{
|
2003-06-30 14:46:59 +04:00
|
|
|
if (aFrame->GetStateBits() & NS_FRAME_REPLACED_ELEMENT)
|
2000-09-12 00:46:44 +04:00
|
|
|
{
|
2003-10-31 23:19:18 +03:00
|
|
|
nsIAtom* frameType = aFrame->GetType();
|
|
|
|
if (nsLayoutAtoms::brFrame != frameType &&
|
|
|
|
nsLayoutAtoms::textFrame != frameType)
|
2000-09-12 00:46:44 +04:00
|
|
|
{
|
2003-05-15 07:42:21 +04:00
|
|
|
const nsStyleMargin* margin = aFrame->GetStyleMargin();
|
2001-02-07 12:57:26 +03:00
|
|
|
if (IsPercentageUnitSides(&margin->mMargin)) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2000-09-12 00:46:44 +04:00
|
|
|
|
2003-05-15 07:42:21 +04:00
|
|
|
const nsStylePadding* padding = aFrame->GetStylePadding();
|
2001-02-07 12:57:26 +03:00
|
|
|
if (IsPercentageUnitSides(&padding->mPadding)) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2003-05-15 07:42:21 +04:00
|
|
|
const nsStyleBorder* border = aFrame->GetStyleBorder();
|
2001-02-07 12:57:26 +03:00
|
|
|
if (IsPercentageUnitSides(&border->mBorder)) {
|
2000-09-12 00:46:44 +04:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2003-05-15 07:42:21 +04:00
|
|
|
const nsStylePosition* pos = aFrame->GetStylePosition();
|
2000-09-12 00:46:44 +04:00
|
|
|
if (eStyleUnit_Percent == pos->mWidth.GetUnit()
|
|
|
|
|| eStyleUnit_Percent == pos->mMaxWidth.GetUnit()
|
|
|
|
|| eStyleUnit_Percent == pos->mMinWidth.GetUnit()
|
|
|
|
|| eStyleUnit_Percent == pos->mHeight.GetUnit()
|
|
|
|
|| eStyleUnit_Percent == pos->mMinHeight.GetUnit()
|
|
|
|
|| eStyleUnit_Percent == pos->mMaxHeight.GetUnit()
|
|
|
|
|| IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!!
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool IsPercentageAwareFrame(nsIPresContext *aPresContext, nsIFrame *aFrame)
|
|
|
|
{
|
2003-06-30 14:46:59 +04:00
|
|
|
if (aFrame->GetStateBits() & NS_FRAME_REPLACED_ELEMENT) {
|
2000-09-12 00:46:44 +04:00
|
|
|
if (nsLineLayout::IsPercentageAwareReplacedElement(aPresContext, aFrame)) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-01-09 17:20:53 +03:00
|
|
|
nsIFrame *child = aFrame->GetFirstChild(nsnull);
|
2000-09-12 00:46:44 +04:00
|
|
|
if (child)
|
|
|
|
{ // aFrame is an inline container frame, check my frame state
|
2003-06-30 14:46:59 +04:00
|
|
|
if (aFrame->GetStateBits() & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD) {
|
2000-09-12 00:46:44 +04:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// else it's a frame we just don't care about
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-06-05 12:24:18 +04:00
|
|
|
void
|
2001-07-04 06:00:05 +04:00
|
|
|
nsLineLayout::VerticalAlignLine(nsLineBox* aLineBox,
|
2003-01-09 17:26:32 +03:00
|
|
|
nscoord* aMaxElementWidthResult)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
// Synthesize a PerFrameData for the block frame
|
|
|
|
PerFrameData rootPFD;
|
|
|
|
rootPFD.mFrame = mBlockReflowState->frame;
|
1999-07-20 07:41:03 +04:00
|
|
|
rootPFD.mFrameType = mBlockReflowState->mFrameType;
|
1999-03-19 00:03:25 +03:00
|
|
|
rootPFD.mAscent = 0;
|
|
|
|
rootPFD.mDescent = 0;
|
|
|
|
mRootSpan->mFrame = &rootPFD;
|
2000-02-15 07:26:44 +03:00
|
|
|
mLineBox = aLineBox;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Partially place the children of the block frame. The baseline for
|
|
|
|
// this operation is set to zero so that the y coordinates for all
|
|
|
|
// of the placed children will be relative to there.
|
|
|
|
PerSpanData* psd = mRootSpan;
|
|
|
|
VerticalAlignFrames(psd);
|
|
|
|
|
|
|
|
// Compute the line-height. The line-height will be the larger of:
|
|
|
|
//
|
|
|
|
// [1] maxY - minY (the distance between the highest childs top edge
|
|
|
|
// and the lowest childs bottom edge)
|
|
|
|
//
|
|
|
|
// [2] the maximum logical box height (since not every frame may have
|
|
|
|
// participated in #1; for example: top/bottom aligned frames)
|
|
|
|
//
|
|
|
|
// [3] the minimum line height (line-height property set on the
|
|
|
|
// block frame)
|
|
|
|
nscoord lineHeight = psd->mMaxY - psd->mMinY;
|
|
|
|
|
|
|
|
// Now that the line-height is computed, we need to know where the
|
|
|
|
// baseline is in the line. Position baseline so that mMinY is just
|
|
|
|
// inside the top of the line box.
|
|
|
|
nscoord baselineY;
|
|
|
|
if (psd->mMinY < 0) {
|
|
|
|
baselineY = mTopEdge - psd->mMinY;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
baselineY = mTopEdge;
|
|
|
|
}
|
|
|
|
|
|
|
|
// It's also possible that the line-height isn't tall enough because
|
|
|
|
// of top/bottom aligned elements that were not accounted for in
|
|
|
|
// min/max Y.
|
|
|
|
//
|
|
|
|
// The CSS2 spec doesn't really say what happens when to the
|
|
|
|
// baseline in this situations. What we do is if the largest top
|
|
|
|
// aligned box height is greater than the line-height then we leave
|
|
|
|
// the baseline alone. If the largest bottom aligned box is greater
|
|
|
|
// than the line-height then we slide the baseline down by the extra
|
|
|
|
// amount.
|
|
|
|
//
|
|
|
|
// Navigator 4 gives precedence to the first top/bottom aligned
|
|
|
|
// object. We just let bottom aligned objects win.
|
|
|
|
if (lineHeight < mMaxBottomBoxHeight) {
|
|
|
|
// When the line is shorter than the maximum top aligned box
|
|
|
|
nscoord extra = mMaxBottomBoxHeight - lineHeight;
|
|
|
|
baselineY += extra;
|
|
|
|
lineHeight = mMaxBottomBoxHeight;
|
|
|
|
}
|
|
|
|
if (lineHeight < mMaxTopBoxHeight) {
|
|
|
|
lineHeight = mMaxTopBoxHeight;
|
|
|
|
}
|
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [line]==> lineHeight=%d baselineY=%d\n", lineHeight, baselineY);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Now position all of the frames in the root span. We will also
|
|
|
|
// recurse over the child spans and place any top/bottom aligned
|
|
|
|
// frames we find.
|
|
|
|
// XXX PERFORMANCE: set a bit per-span to avoid the extra work
|
2001-07-04 06:00:05 +04:00
|
|
|
// (propagate it upward too)
|
1999-03-19 00:03:25 +03:00
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
nscoord maxElementWidth = 0;
|
2001-08-30 02:59:09 +04:00
|
|
|
PRBool prevFrameAccumulates = PR_FALSE;
|
|
|
|
nscoord accumulatedWidth = 0;
|
2001-09-08 23:26:34 +04:00
|
|
|
#ifdef HACK_MEW
|
|
|
|
PRBool strictMode = InStrictMode();
|
|
|
|
PRBool inUnconstrainedTable = InUnconstrainedTableCell(*mBlockReflowState);
|
|
|
|
#endif
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
2001-09-08 23:26:34 +04:00
|
|
|
int frameCount = 0;
|
|
|
|
#endif
|
2001-08-30 02:59:09 +04:00
|
|
|
|
2002-05-14 16:55:55 +04:00
|
|
|
nscoord indent = mTextIndent; // Used for the first frame.
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
while (nsnull != pfd) {
|
2001-08-30 02:59:09 +04:00
|
|
|
|
2003-01-09 17:26:32 +03:00
|
|
|
// Compute max-element-width if necessary
|
|
|
|
if (mComputeMaxElementWidth) {
|
2001-08-30 02:59:09 +04:00
|
|
|
|
2003-01-09 17:26:32 +03:00
|
|
|
nscoord mw = pfd->mMaxElementWidth +
|
2002-05-14 16:55:55 +04:00
|
|
|
pfd->mMargin.left + pfd->mMargin.right + indent;
|
|
|
|
// Zero |indent| after including the 'text-indent' only for the
|
|
|
|
// frame that is indented.
|
|
|
|
indent = 0;
|
|
|
|
|
2000-06-15 03:15:59 +04:00
|
|
|
if (psd->mNoWrap) {
|
|
|
|
maxElementWidth += mw;
|
|
|
|
}
|
|
|
|
else {
|
2001-08-30 02:59:09 +04:00
|
|
|
|
|
|
|
#ifdef HACK_MEW
|
2001-09-29 01:42:03 +04:00
|
|
|
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
2003-01-09 17:26:32 +03:00
|
|
|
if (nsBlockFrame::gNoisyMaxElementWidth)
|
2001-09-29 01:42:03 +04:00
|
|
|
frameCount++;
|
|
|
|
#endif
|
2001-09-08 23:26:34 +04:00
|
|
|
// if in Quirks mode and in a table cell with an unconstrained width, then emulate an IE
|
|
|
|
// quirk to keep consecutive images from breaking the line
|
2001-08-30 02:59:09 +04:00
|
|
|
// - see bugs 54565, 32191, and their many dups
|
|
|
|
// XXX - reconsider how textFrame text measurement happens and have it take into account
|
|
|
|
// image frames as well, thus eliminating the need for this code
|
2001-09-29 01:42:03 +04:00
|
|
|
if (!strictMode && inUnconstrainedTable ) {
|
2001-09-18 03:13:57 +04:00
|
|
|
|
2001-09-29 01:42:03 +04:00
|
|
|
nscoord imgSizes = AccumulateImageSizes(*mPresContext, *pfd->mFrame);
|
2003-07-23 04:14:16 +04:00
|
|
|
// XXXldb We should NOT be using mCombinedArea here!
|
2001-09-29 01:42:03 +04:00
|
|
|
PRBool curFrameAccumulates = (imgSizes > 0) ||
|
2003-01-09 17:26:32 +03:00
|
|
|
(pfd->mMaxElementWidth == pfd->mCombinedArea.width &&
|
2001-09-29 01:42:03 +04:00
|
|
|
pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME));
|
|
|
|
// NOTE: we check for the maxElementWidth == the CombinedAreaWidth to detect when
|
|
|
|
// a textframe has whitespace in it and thus should not be used as the basis
|
|
|
|
// for accumulating the image width
|
|
|
|
// - this is to handle images in a text run
|
|
|
|
|
|
|
|
if(prevFrameAccumulates && curFrameAccumulates) {
|
2001-09-08 23:26:34 +04:00
|
|
|
accumulatedWidth += mw;
|
2001-09-29 01:42:03 +04:00
|
|
|
} else {
|
|
|
|
accumulatedWidth = mw;
|
2001-09-08 23:26:34 +04:00
|
|
|
}
|
|
|
|
// now update the prevFrame
|
|
|
|
prevFrameAccumulates = curFrameAccumulates;
|
|
|
|
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
2003-01-09 17:26:32 +03:00
|
|
|
if (nsBlockFrame::gNoisyMaxElementWidth) {
|
2002-07-01 21:43:02 +04:00
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
|
|
|
printf("(%d) last frame's MEW=%d | Accumulated MEW=%d\n", frameCount, mw, accumulatedWidth);
|
|
|
|
}
|
|
|
|
#endif
|
2001-09-08 23:26:34 +04:00
|
|
|
|
|
|
|
mw = accumulatedWidth;
|
2001-08-30 02:59:09 +04:00
|
|
|
}
|
2001-09-08 23:26:34 +04:00
|
|
|
|
|
|
|
#endif // HACK_MEW
|
|
|
|
|
2001-08-30 02:59:09 +04:00
|
|
|
// and finally reset the max element width
|
2000-06-15 03:15:59 +04:00
|
|
|
if (maxElementWidth < mw) {
|
|
|
|
maxElementWidth = mw;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
PerSpanData* span = pfd->mSpan;
|
1999-03-22 23:45:09 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
NS_ASSERTION(0xFF != pfd->mVerticalAlign, "umr");
|
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
switch (pfd->mVerticalAlign) {
|
|
|
|
case VALIGN_TOP:
|
|
|
|
if (span) {
|
|
|
|
pfd->mBounds.y = mTopEdge - pfd->mBorderPadding.top +
|
|
|
|
span->mTopLeading;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = mTopEdge + pfd->mMargin.top;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VALIGN_BOTTOM:
|
|
|
|
if (span) {
|
|
|
|
// Compute bottom leading
|
|
|
|
pfd->mBounds.y = mTopEdge + lineHeight -
|
|
|
|
pfd->mBounds.height + pfd->mBorderPadding.bottom -
|
|
|
|
span->mBottomLeading;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = mTopEdge + lineHeight - pfd->mMargin.bottom -
|
|
|
|
pfd->mBounds.height;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VALIGN_OTHER:
|
|
|
|
pfd->mBounds.y += baselineY;
|
|
|
|
break;
|
|
|
|
}
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mFrame->SetRect(pfd->mBounds);
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [child of line]");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": y=%d\n", pfd->mBounds.y);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
if (span) {
|
|
|
|
nscoord distanceFromTop = pfd->mBounds.y - mTopEdge;
|
|
|
|
PlaceTopBottomFrames(span, distanceFromTop, lineHeight);
|
|
|
|
}
|
2000-09-12 00:46:44 +04:00
|
|
|
// check to see if the frame is an inline replace element
|
|
|
|
// and if it is percent-aware. If so, mark the line.
|
|
|
|
if ((PR_FALSE==aLineBox->ResizeReflowOptimizationDisabled()) &&
|
|
|
|
pfd->mFrameType & NS_CSS_FRAME_TYPE_INLINE)
|
|
|
|
{
|
|
|
|
if (IsPercentageAwareFrame(mPresContext, pfd->mFrame))
|
|
|
|
aLineBox->DisableResizeReflowOptimization();
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
|
2003-01-09 17:26:32 +03:00
|
|
|
// Fill in returned line-box and max-element-width data
|
2000-02-15 07:26:44 +03:00
|
|
|
aLineBox->mBounds.x = psd->mLeftEdge;
|
|
|
|
aLineBox->mBounds.y = mTopEdge;
|
|
|
|
aLineBox->mBounds.width = psd->mX - psd->mLeftEdge;
|
|
|
|
aLineBox->mBounds.height = lineHeight;
|
1999-10-13 03:27:32 +04:00
|
|
|
mFinalLineHeight = lineHeight;
|
2003-01-09 17:26:32 +03:00
|
|
|
*aMaxElementWidthResult = maxElementWidth;
|
2002-12-11 07:00:18 +03:00
|
|
|
aLineBox->SetAscent(baselineY - mTopEdge);
|
2001-07-04 06:00:05 +04:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
|
|
|
printf(
|
2003-01-09 17:26:32 +03:00
|
|
|
" [line]==> bounds{x,y,w,h}={%d,%d,%d,%d} lh=%d a=%d mew=%d\n",
|
2001-07-04 06:00:05 +04:00
|
|
|
aLineBox->mBounds.x, aLineBox->mBounds.y,
|
|
|
|
aLineBox->mBounds.width, aLineBox->mBounds.height,
|
2002-12-11 07:00:18 +03:00
|
|
|
mFinalLineHeight, aLineBox->GetAscent(),
|
2003-01-09 17:26:32 +03:00
|
|
|
*aMaxElementWidthResult);
|
2001-07-04 06:00:05 +04:00
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Undo root-span mFrame pointer to prevent brane damage later on...
|
|
|
|
mRootSpan->mFrame = nsnull;
|
2000-02-15 07:26:44 +03:00
|
|
|
mLineBox = nsnull;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd,
|
|
|
|
nscoord aDistanceFromTop,
|
|
|
|
nscoord aLineHeight)
|
|
|
|
{
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
PerSpanData* span = pfd->mSpan;
|
1999-03-22 23:45:09 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
NS_ASSERTION(0xFF != pfd->mVerticalAlign, "umr");
|
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
switch (pfd->mVerticalAlign) {
|
|
|
|
case VALIGN_TOP:
|
|
|
|
if (span) {
|
|
|
|
pfd->mBounds.y = -aDistanceFromTop - pfd->mBorderPadding.top +
|
|
|
|
span->mTopLeading;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = -aDistanceFromTop + pfd->mMargin.top;
|
|
|
|
}
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mFrame->SetRect(pfd->mBounds);
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": y=%d dTop=%d [bp.top=%d topLeading=%d]\n",
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd->mBounds.y, aDistanceFromTop,
|
|
|
|
span ? pfd->mBorderPadding.top : 0,
|
|
|
|
span ? span->mTopLeading : 0);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case VALIGN_BOTTOM:
|
|
|
|
if (span) {
|
|
|
|
// Compute bottom leading
|
|
|
|
pfd->mBounds.y = -aDistanceFromTop + aLineHeight -
|
|
|
|
pfd->mBounds.height + pfd->mBorderPadding.bottom -
|
|
|
|
span->mBottomLeading;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = -aDistanceFromTop + aLineHeight -
|
|
|
|
pfd->mMargin.bottom - pfd->mBounds.height;
|
|
|
|
}
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mFrame->SetRect(pfd->mBounds);
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": y=%d\n", pfd->mBounds.y);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (span) {
|
1999-03-20 02:07:17 +03:00
|
|
|
nscoord distanceFromTop = aDistanceFromTop + pfd->mBounds.y;
|
1999-03-19 00:03:25 +03:00
|
|
|
PlaceTopBottomFrames(span, distanceFromTop, aLineHeight);
|
|
|
|
}
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-15 07:26:44 +03:00
|
|
|
#define VERTICAL_ALIGN_FRAMES_NO_MINIMUM 32767
|
|
|
|
#define VERTICAL_ALIGN_FRAMES_NO_MAXIMUM -32768
|
2000-02-02 10:38:23 +03:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Vertically place frames within a given span. Note: this doesn't
|
|
|
|
// place top/bottom aligned frames as those have to wait until the
|
|
|
|
// entire line box height is known. This is called after the span
|
|
|
|
// frame has finished being reflowed so that we know its height.
|
|
|
|
void
|
|
|
|
nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|
|
|
{
|
|
|
|
// Get parent frame info
|
1999-11-02 01:38:17 +03:00
|
|
|
PerFrameData* spanFramePFD = psd->mFrame;
|
|
|
|
nsIFrame* spanFrame = spanFramePFD->mFrame;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Get the parent frame's font for all of the frames in this span
|
2003-02-22 03:32:13 +03:00
|
|
|
nsStyleContext* styleContext = spanFrame->GetStyleContext();
|
1999-03-19 00:03:25 +03:00
|
|
|
nsIRenderingContext* rc = mBlockReflowState->rendContext;
|
2002-05-25 00:11:14 +04:00
|
|
|
SetFontFromStyle(mBlockReflowState->rendContext, styleContext);
|
1999-09-10 01:04:37 +04:00
|
|
|
nsCOMPtr<nsIFontMetrics> fm;
|
|
|
|
rc->GetFontMetrics(*getter_AddRefs(fm));
|
|
|
|
|
|
|
|
PRBool preMode = (mStyleText->mWhiteSpace == NS_STYLE_WHITESPACE_PRE) ||
|
|
|
|
(mStyleText->mWhiteSpace == NS_STYLE_WHITESPACE_MOZ_PRE_WRAP);
|
1999-11-02 01:38:17 +03:00
|
|
|
|
|
|
|
// See if the span is an empty continuation. It's an empty continuation iff:
|
|
|
|
// - it has a prev-in-flow
|
|
|
|
// - it has no next in flow
|
|
|
|
// - it's zero sized
|
|
|
|
nsIFrame* spanNextInFlow;
|
|
|
|
spanFrame->GetNextInFlow(&spanNextInFlow);
|
|
|
|
nsIFrame* spanPrevInFlow;
|
|
|
|
spanFrame->GetPrevInFlow(&spanPrevInFlow);
|
|
|
|
PRBool emptyContinuation = spanPrevInFlow && !spanNextInFlow &&
|
|
|
|
(0 == spanFramePFD->mBounds.width) && (0 == spanFramePFD->mBounds.height);
|
|
|
|
|
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("[%sSpan]", (psd == mRootSpan)?"Root":"");
|
1999-11-02 01:38:17 +03:00
|
|
|
nsFrame::ListTag(stdout, spanFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": preMode=%s strictMode=%s w/h=%d,%d emptyContinuation=%s",
|
1999-11-02 01:38:17 +03:00
|
|
|
preMode ? "yes" : "no",
|
|
|
|
InStrictMode() ? "yes" : "no",
|
|
|
|
spanFramePFD->mBounds.width, spanFramePFD->mBounds.height,
|
|
|
|
emptyContinuation ? "yes" : "no");
|
|
|
|
if (psd != mRootSpan) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" bp=%d,%d,%d,%d margin=%d,%d,%d,%d",
|
1999-11-02 01:38:17 +03:00
|
|
|
spanFramePFD->mBorderPadding.top,
|
|
|
|
spanFramePFD->mBorderPadding.right,
|
|
|
|
spanFramePFD->mBorderPadding.bottom,
|
|
|
|
spanFramePFD->mBorderPadding.left,
|
|
|
|
spanFramePFD->mMargin.top,
|
|
|
|
spanFramePFD->mMargin.right,
|
|
|
|
spanFramePFD->mMargin.bottom,
|
|
|
|
spanFramePFD->mMargin.left);
|
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-11-02 01:38:17 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Compute the span's mZeroEffectiveSpanBox flag. What we are trying
|
|
|
|
// to determine is how we should treat the span: should it act
|
|
|
|
// "normally" according to css2 or should it effectively
|
|
|
|
// "disappear".
|
|
|
|
//
|
2002-06-26 01:16:17 +04:00
|
|
|
// In general, if the document being processed is in full standards
|
|
|
|
// mode then it should act normally (with one exception). The
|
|
|
|
// exception case is when a span is continued and yet the span is
|
|
|
|
// empty (e.g. compressed whitespace). For this kind of span we treat
|
|
|
|
// it as if it were not there so that it doesn't impact the
|
|
|
|
// line-height.
|
1999-11-02 01:38:17 +03:00
|
|
|
//
|
2002-06-26 01:16:17 +04:00
|
|
|
// In almost standards mode or quirks mode, we should sometimes make
|
|
|
|
// it disappear. The cases that matter are those where the span
|
|
|
|
// contains no real text elements that would provide an ascent and
|
|
|
|
// descent and height. However, if css style elements have been
|
|
|
|
// applied to the span (border/padding/margin) so that it's clear the
|
|
|
|
// document author is intending css2 behavior then we act as if strict
|
|
|
|
// mode is set.
|
1999-11-02 01:38:17 +03:00
|
|
|
//
|
2000-03-16 04:14:57 +03:00
|
|
|
// This code works correctly for preMode, because a blank line
|
|
|
|
// in PRE mode is encoded as a text node with a LF in it, since
|
|
|
|
// text nodes with only whitespace are considered in preMode.
|
2001-10-25 05:08:40 +04:00
|
|
|
//
|
|
|
|
// Much of this logic is shared with the various implementations of
|
|
|
|
// nsIFrame::IsEmpty since they need to duplicate the way it makes
|
|
|
|
// some lines empty. However, nsIFrame::IsEmpty can't be reused here
|
|
|
|
// since this code sets zeroEffectiveSpanBox even when there are
|
|
|
|
// non-empty children.
|
|
|
|
PRBool zeroEffectiveSpanBox = PR_FALSE;
|
2002-05-16 23:44:20 +04:00
|
|
|
// XXXldb If we really have empty continuations, then all these other
|
|
|
|
// checks don't make sense for them.
|
2003-05-15 07:36:05 +04:00
|
|
|
if ((emptyContinuation || mCompatMode != eCompatibility_FullStandards) &&
|
|
|
|
((psd == mRootSpan) ||
|
|
|
|
((0 == spanFramePFD->mBorderPadding.top) &&
|
|
|
|
(0 == spanFramePFD->mBorderPadding.right) &&
|
|
|
|
(0 == spanFramePFD->mBorderPadding.bottom) &&
|
|
|
|
(0 == spanFramePFD->mBorderPadding.left) &&
|
|
|
|
(0 == spanFramePFD->mMargin.top) &&
|
|
|
|
(0 == spanFramePFD->mMargin.right) &&
|
|
|
|
(0 == spanFramePFD->mMargin.bottom) &&
|
|
|
|
(0 == spanFramePFD->mMargin.left)))) {
|
1999-09-10 01:04:37 +04:00
|
|
|
// This code handles an issue with compatability with non-css
|
|
|
|
// conformant browsers. In particular, there are some cases
|
|
|
|
// where the font-size and line-height for a span must be
|
|
|
|
// ignored and instead the span must *act* as if it were zero
|
|
|
|
// sized. In general, if the span contains any non-compressed
|
2000-02-15 07:26:44 +03:00
|
|
|
// text then we don't use this logic.
|
2001-12-24 02:23:41 +03:00
|
|
|
// However, this is not propagated outwards, since (in compatibility
|
2000-02-15 07:26:44 +03:00
|
|
|
// mode) we don't want big line heights for things like
|
|
|
|
// <p><font size="-1">Text</font></p>
|
2002-05-01 04:42:49 +04:00
|
|
|
|
2002-12-19 03:21:07 +03:00
|
|
|
// We shouldn't include any whitespace that collapses, unless we're
|
|
|
|
// preformatted (in which case it shouldn't, but the width=0 test is
|
|
|
|
// perhaps incorrect). This includes whitespace at the beginning of
|
|
|
|
// a line and whitespace preceded (?) by other whitespace.
|
|
|
|
// See bug 134580 and bug 155333.
|
1999-09-10 01:04:37 +04:00
|
|
|
zeroEffectiveSpanBox = PR_TRUE;
|
2002-05-01 04:42:49 +04:00
|
|
|
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
2002-12-19 03:21:07 +03:00
|
|
|
if (pfd->GetFlag(PFD_ISTEXTFRAME) &&
|
|
|
|
(pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME) || preMode ||
|
|
|
|
pfd->mBounds.width != 0)) {
|
1999-09-10 01:04:37 +04:00
|
|
|
zeroEffectiveSpanBox = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
psd->mZeroEffectiveSpanBox = zeroEffectiveSpanBox;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Setup baselineY, minY, and maxY
|
|
|
|
nscoord baselineY, minY, maxY;
|
|
|
|
if (psd == mRootSpan) {
|
|
|
|
// Use a zero baselineY since we don't yet know where the baseline
|
|
|
|
// will be (until we know how tall the line is; then we will
|
|
|
|
// know). In addition, use extreme values for the minY and maxY
|
|
|
|
// values so that only the child frames will impact their values
|
|
|
|
// (since these are children of the block, there is no span box to
|
|
|
|
// provide initial values).
|
2000-02-15 07:26:44 +03:00
|
|
|
baselineY = 0;
|
|
|
|
minY = VERTICAL_ALIGN_FRAMES_NO_MINIMUM;
|
|
|
|
maxY = VERTICAL_ALIGN_FRAMES_NO_MAXIMUM;
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("[RootSpan]");
|
1999-11-02 01:38:17 +03:00
|
|
|
nsFrame::ListTag(stdout, spanFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": pass1 valign frames: topEdge=%d minLineHeight=%d zeroEffectiveSpanBox=%s\n",
|
1999-09-10 01:04:37 +04:00
|
|
|
mTopEdge, mMinLineHeight,
|
|
|
|
zeroEffectiveSpanBox ? "yes" : "no");
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
}
|
1999-09-10 01:04:37 +04:00
|
|
|
else {
|
2000-02-15 07:26:44 +03:00
|
|
|
// Compute the logical height for this span. The logical height
|
|
|
|
// is based on the line-height value, not the font-size. Also
|
|
|
|
// compute the top leading.
|
|
|
|
nscoord logicalHeight =
|
|
|
|
nsHTMLReflowState::CalcLineHeight(mPresContext, rc, spanFrame);
|
|
|
|
nscoord contentHeight = spanFramePFD->mBounds.height -
|
|
|
|
spanFramePFD->mBorderPadding.top - spanFramePFD->mBorderPadding.bottom;
|
|
|
|
nscoord leading = logicalHeight - contentHeight;
|
|
|
|
psd->mTopLeading = leading / 2;
|
|
|
|
psd->mBottomLeading = leading - psd->mTopLeading;
|
|
|
|
psd->mLogicalHeight = logicalHeight;
|
|
|
|
|
1999-09-10 01:04:37 +04:00
|
|
|
if (zeroEffectiveSpanBox) {
|
2000-02-15 07:26:44 +03:00
|
|
|
// When the span-box is to be ignored, zero out the initial
|
1999-09-10 01:04:37 +04:00
|
|
|
// values so that the span doesn't impact the final line
|
|
|
|
// height. The contents of the span can impact the final line
|
|
|
|
// height.
|
2000-02-15 07:26:44 +03:00
|
|
|
|
|
|
|
// Note that things are readjusted for this span after its children
|
|
|
|
// are reflowed
|
|
|
|
minY = VERTICAL_ALIGN_FRAMES_NO_MINIMUM;
|
|
|
|
maxY = VERTICAL_ALIGN_FRAMES_NO_MAXIMUM;
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
// The initial values for the min and max Y values are in the spans
|
|
|
|
// coordinate space, and cover the logical height of the span. If
|
|
|
|
// there are child frames in this span that stick out of this area
|
|
|
|
// then the minY and maxY are updated by the amount of logical
|
|
|
|
// height that is outside this range.
|
1999-11-02 01:38:17 +03:00
|
|
|
minY = spanFramePFD->mBorderPadding.top - psd->mTopLeading;
|
1999-09-10 01:04:37 +04:00
|
|
|
maxY = minY + psd->mLogicalHeight;
|
1999-05-04 00:54:11 +04:00
|
|
|
}
|
2000-02-15 07:26:44 +03:00
|
|
|
|
|
|
|
// This is the distance from the top edge of the parents visual
|
|
|
|
// box to the baseline. The span already computed this for us,
|
|
|
|
// so just use it.
|
|
|
|
baselineY = spanFramePFD->mAscent;
|
|
|
|
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("[%sSpan]", (psd == mRootSpan)?"Root":"");
|
1999-11-02 01:38:17 +03:00
|
|
|
nsFrame::ListTag(stdout, spanFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": baseLine=%d logicalHeight=%d topLeading=%d h=%d bp=%d,%d zeroEffectiveSpanBox=%s\n",
|
1999-09-10 01:04:37 +04:00
|
|
|
baselineY, psd->mLogicalHeight, psd->mTopLeading,
|
1999-11-02 01:38:17 +03:00
|
|
|
spanFramePFD->mBounds.height,
|
|
|
|
spanFramePFD->mBorderPadding.top, spanFramePFD->mBorderPadding.bottom,
|
1999-09-10 01:04:37 +04:00
|
|
|
zeroEffectiveSpanBox ? "yes" : "no");
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
nscoord maxTopBoxHeight = 0;
|
|
|
|
nscoord maxBottomBoxHeight = 0;
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
nsIFrame* frame = pfd->mFrame;
|
|
|
|
|
2001-11-29 03:10:31 +03:00
|
|
|
// sanity check (see bug 105168, non-reproducable crashes from null frame)
|
|
|
|
NS_ASSERTION(frame, "null frame in PerFrameData - something is very very bad");
|
|
|
|
if (!frame) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Compute the logical height of the frame
|
|
|
|
nscoord logicalHeight;
|
|
|
|
nscoord topLeading;
|
|
|
|
PerSpanData* frameSpan = pfd->mSpan;
|
|
|
|
if (frameSpan) {
|
|
|
|
// For span frames the logical-height and top-leading was
|
|
|
|
// pre-computed when the span was reflowed.
|
|
|
|
logicalHeight = frameSpan->mLogicalHeight;
|
|
|
|
topLeading = frameSpan->mTopLeading;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// For other elements the logical height is the same as the
|
|
|
|
// frames height plus its margins.
|
|
|
|
logicalHeight = pfd->mBounds.height + pfd->mMargin.top +
|
|
|
|
pfd->mMargin.bottom;
|
|
|
|
topLeading = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get vertical-align property
|
2003-05-15 07:42:21 +04:00
|
|
|
const nsStyleTextReset* textStyle = frame->GetStyleTextReset();
|
1999-03-19 00:03:25 +03:00
|
|
|
nsStyleUnit verticalAlignUnit = textStyle->mVerticalAlign.GetUnit();
|
1999-09-10 01:04:37 +04:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [frame]");
|
1999-09-10 01:04:37 +04:00
|
|
|
nsFrame::ListTag(stdout, frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": verticalAlignUnit=%d (enum == %d)\n",
|
1999-09-10 01:04:37 +04:00
|
|
|
verticalAlignUnit,
|
|
|
|
((eStyleUnit_Enumerated == verticalAlignUnit)
|
|
|
|
? textStyle->mVerticalAlign.GetIntValue()
|
|
|
|
: -1));
|
|
|
|
#endif
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
PRUint8 verticalAlignEnum;
|
|
|
|
nscoord parentAscent, parentDescent, parentXHeight;
|
|
|
|
nscoord parentSuperscript, parentSubscript;
|
|
|
|
nscoord coordOffset, percentOffset, elementLineHeight;
|
|
|
|
nscoord revisedBaselineY;
|
|
|
|
switch (verticalAlignUnit) {
|
|
|
|
case eStyleUnit_Enumerated:
|
|
|
|
default:
|
|
|
|
if (eStyleUnit_Enumerated == verticalAlignUnit) {
|
|
|
|
verticalAlignEnum = textStyle->mVerticalAlign.GetIntValue();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_BASELINE;
|
|
|
|
}
|
|
|
|
switch (verticalAlignEnum) {
|
|
|
|
default:
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_BASELINE:
|
|
|
|
// The elements baseline is aligned with the baseline of
|
|
|
|
// the parent.
|
|
|
|
if (frameSpan) {
|
|
|
|
// XXX explain
|
|
|
|
pfd->mBounds.y = baselineY - pfd->mAscent;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// For non-span elements the borders, padding and
|
|
|
|
// margins are significant. Use the visual box height
|
|
|
|
// and the bottom margin as the distance off of the
|
|
|
|
// baseline.
|
|
|
|
pfd->mBounds.y = baselineY - pfd->mAscent - pfd->mMargin.bottom;
|
|
|
|
}
|
|
|
|
pfd->mVerticalAlign = VALIGN_OTHER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_SUB:
|
|
|
|
// Lower the baseline of the box to the subscript offset
|
|
|
|
// of the parent's box. This is identical to the baseline
|
|
|
|
// alignment except for the addition of the subscript
|
|
|
|
// offset to the baseline Y.
|
|
|
|
fm->GetSubscriptOffset(parentSubscript);
|
|
|
|
revisedBaselineY = baselineY + parentSubscript;
|
|
|
|
if (frameSpan) {
|
|
|
|
pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = revisedBaselineY - pfd->mAscent -
|
|
|
|
pfd->mMargin.bottom;
|
|
|
|
}
|
|
|
|
pfd->mVerticalAlign = VALIGN_OTHER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_SUPER:
|
|
|
|
// Raise the baseline of the box to the superscript offset
|
|
|
|
// of the parent's box. This is identical to the baseline
|
|
|
|
// alignment except for the subtraction of the superscript
|
|
|
|
// offset to the baseline Y.
|
|
|
|
fm->GetSuperscriptOffset(parentSuperscript);
|
|
|
|
revisedBaselineY = baselineY - parentSuperscript;
|
|
|
|
if (frameSpan) {
|
|
|
|
pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = revisedBaselineY - pfd->mAscent -
|
|
|
|
pfd->mMargin.bottom;
|
|
|
|
}
|
|
|
|
pfd->mVerticalAlign = VALIGN_OTHER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TOP:
|
|
|
|
pfd->mVerticalAlign = VALIGN_TOP;
|
|
|
|
if (logicalHeight > maxTopBoxHeight) {
|
|
|
|
maxTopBoxHeight = logicalHeight;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
|
|
|
|
pfd->mVerticalAlign = VALIGN_BOTTOM;
|
|
|
|
if (logicalHeight > maxBottomBoxHeight) {
|
|
|
|
maxBottomBoxHeight = logicalHeight;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
|
|
|
|
// Align the midpoint of the frame with 1/2 the parents
|
|
|
|
// x-height above the baseline.
|
|
|
|
fm->GetXHeight(parentXHeight);
|
|
|
|
if (frameSpan) {
|
|
|
|
pfd->mBounds.y = baselineY -
|
|
|
|
(parentXHeight + pfd->mBounds.height)/2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = baselineY - (parentXHeight + logicalHeight)/2 +
|
|
|
|
pfd->mMargin.top;
|
|
|
|
}
|
|
|
|
pfd->mVerticalAlign = VALIGN_OTHER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
|
|
|
|
// The top of the logical box is aligned with the top of
|
|
|
|
// the parent elements text.
|
|
|
|
fm->GetMaxAscent(parentAscent);
|
|
|
|
if (frameSpan) {
|
|
|
|
pfd->mBounds.y = baselineY - parentAscent -
|
|
|
|
pfd->mBorderPadding.top + frameSpan->mTopLeading;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = baselineY - parentAscent + pfd->mMargin.top;
|
|
|
|
}
|
|
|
|
pfd->mVerticalAlign = VALIGN_OTHER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
|
|
|
|
// The bottom of the logical box is aligned with the
|
|
|
|
// bottom of the parent elements text.
|
|
|
|
fm->GetMaxDescent(parentDescent);
|
|
|
|
if (frameSpan) {
|
|
|
|
pfd->mBounds.y = baselineY + parentDescent -
|
|
|
|
pfd->mBounds.height + pfd->mBorderPadding.bottom -
|
|
|
|
frameSpan->mBottomLeading;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = baselineY + parentDescent -
|
|
|
|
pfd->mBounds.height - pfd->mMargin.bottom;
|
|
|
|
}
|
|
|
|
pfd->mVerticalAlign = VALIGN_OTHER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eStyleUnit_Coord:
|
|
|
|
// According to the CSS2 spec (10.8.1), a positive value
|
|
|
|
// "raises" the box by the given distance while a negative value
|
|
|
|
// "lowers" the box by the given distance (with zero being the
|
|
|
|
// baseline). Since Y coordinates increase towards the bottom of
|
|
|
|
// the screen we reverse the sign.
|
|
|
|
coordOffset = textStyle->mVerticalAlign.GetCoordValue();
|
|
|
|
revisedBaselineY = baselineY - coordOffset;
|
|
|
|
if (frameSpan) {
|
|
|
|
pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = revisedBaselineY - pfd->mAscent -
|
|
|
|
pfd->mMargin.bottom;
|
|
|
|
}
|
|
|
|
pfd->mVerticalAlign = VALIGN_OTHER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eStyleUnit_Percent:
|
|
|
|
// Similar to a length value (eStyleUnit_Coord) except that the
|
|
|
|
// percentage is a function of the elements line-height value.
|
|
|
|
elementLineHeight =
|
1999-09-10 01:04:37 +04:00
|
|
|
nsHTMLReflowState::CalcLineHeight(mPresContext, rc, frame);
|
1999-03-19 00:03:25 +03:00
|
|
|
percentOffset = nscoord(
|
|
|
|
textStyle->mVerticalAlign.GetPercentValue() * elementLineHeight
|
|
|
|
);
|
|
|
|
revisedBaselineY = baselineY - percentOffset;
|
|
|
|
if (frameSpan) {
|
|
|
|
pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pfd->mBounds.y = revisedBaselineY - pfd->mAscent -
|
|
|
|
pfd->mMargin.bottom;
|
|
|
|
}
|
|
|
|
pfd->mVerticalAlign = VALIGN_OTHER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1999-09-10 01:04:37 +04:00
|
|
|
// Update minY/maxY for frames that we just placed. Do not factor
|
|
|
|
// text into the equation.
|
1999-03-19 00:03:25 +03:00
|
|
|
if (pfd->mVerticalAlign == VALIGN_OTHER) {
|
1999-09-10 01:04:37 +04:00
|
|
|
// Text frames do not contribute to the min/max Y values for the
|
|
|
|
// line (instead their parent frame's font-size contributes).
|
2001-09-27 22:34:30 +04:00
|
|
|
// XXXrbs -- relax this restriction because it causes text frames
|
|
|
|
// to jam together when 'font-size-adjust' is enabled
|
|
|
|
// and layout is using dynamic font heights (bug 20394)
|
|
|
|
// -- Note #1: With this code enabled and with the fact that we are not
|
|
|
|
// using Em[Ascent|Descent] as nsDimensions for text metrics in
|
|
|
|
// GFX mean that the discussion in bug 13072 cannot hold.
|
|
|
|
// -- Note #2: We still don't want empty-text frames to interfere.
|
|
|
|
// For example in quirks mode, avoiding empty text frames prevents
|
|
|
|
// "tall" lines around elements like <hr> since the rules of <hr>
|
|
|
|
// in quirks.css have pseudo text contents with LF in them.
|
|
|
|
#if 0
|
2000-04-17 18:40:46 +04:00
|
|
|
if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
2001-09-27 22:34:30 +04:00
|
|
|
#else
|
|
|
|
// Only consider non empty text frames when line-height=normal
|
|
|
|
PRBool canUpdate = !pfd->GetFlag(PFD_ISTEXTFRAME);
|
|
|
|
if (!canUpdate && pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) {
|
2003-08-01 02:03:26 +04:00
|
|
|
nsStyleUnit lhUnit = frame->GetStyleText()->mLineHeight.GetUnit();
|
|
|
|
canUpdate = lhUnit == eStyleUnit_Normal || lhUnit == eStyleUnit_Null;
|
2001-09-27 22:34:30 +04:00
|
|
|
}
|
|
|
|
if (canUpdate) {
|
|
|
|
#endif
|
1999-09-10 01:04:37 +04:00
|
|
|
nscoord yTop, yBottom;
|
|
|
|
if (frameSpan) {
|
|
|
|
// For spans that were are now placing, use their position
|
|
|
|
// plus their already computed min-Y and max-Y values for
|
|
|
|
// computing yTop and yBottom.
|
|
|
|
yTop = pfd->mBounds.y + frameSpan->mMinY;
|
|
|
|
yBottom = pfd->mBounds.y + frameSpan->mMaxY;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
yTop = pfd->mBounds.y - pfd->mMargin.top;
|
|
|
|
yBottom = yTop + logicalHeight;
|
|
|
|
}
|
2002-08-11 22:00:07 +04:00
|
|
|
if (!preMode &&
|
|
|
|
GetCompatMode() != eCompatibility_FullStandards &&
|
|
|
|
!logicalHeight) {
|
2000-02-15 07:26:44 +03:00
|
|
|
// Check if it's a BR frame that is not alone on its line (it
|
|
|
|
// is given a height of zero to indicate this), and if so reset
|
|
|
|
// yTop and yBottom so that BR frames don't influence the line.
|
2003-10-31 23:19:18 +03:00
|
|
|
if (nsLayoutAtoms::brFrame == frame->GetType()) {
|
2000-02-15 07:26:44 +03:00
|
|
|
yTop = VERTICAL_ALIGN_FRAMES_NO_MINIMUM;
|
|
|
|
yBottom = VERTICAL_ALIGN_FRAMES_NO_MAXIMUM;
|
|
|
|
}
|
|
|
|
}
|
1999-09-10 01:04:37 +04:00
|
|
|
if (yTop < minY) minY = yTop;
|
|
|
|
if (yBottom > maxY) maxY = yBottom;
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [frame]raw: a=%d d=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n",
|
1999-09-10 01:04:37 +04:00
|
|
|
pfd->mAscent, pfd->mDescent, pfd->mBounds.height,
|
|
|
|
pfd->mBorderPadding.top, pfd->mBorderPadding.bottom,
|
|
|
|
logicalHeight,
|
|
|
|
pfd->mSpan ? topLeading : 0,
|
|
|
|
pfd->mBounds.y, minY, maxY);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
if (psd != mRootSpan) {
|
2003-06-30 14:46:59 +04:00
|
|
|
frame->SetRect(pfd->mBounds);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
1999-09-10 01:04:37 +04:00
|
|
|
|
|
|
|
// Factor in the minimum line-height when handling the root-span for
|
|
|
|
// the block.
|
|
|
|
if (psd == mRootSpan) {
|
2000-02-15 07:26:44 +03:00
|
|
|
// We should factor in the block element's minimum line-height (as
|
|
|
|
// defined in section 10.8.1 of the css2 spec) assuming that
|
|
|
|
// mZeroEffectiveSpanBox is not set on the root span. This only happens
|
|
|
|
// in some cases in quirks mode:
|
|
|
|
// (1) if the root span contains non-whitespace text directly (this
|
|
|
|
// is handled by mZeroEffectiveSpanBox
|
|
|
|
// (2) if this is the first line of an LI element (whether or not
|
|
|
|
// there is a bullet (NN4/IE5 quirk)
|
|
|
|
// (3) if this is the last line of an LI, DT, or DD element
|
|
|
|
// (The last line before a block also counts, but not before a
|
|
|
|
// BR) (NN4/IE5 quirk)
|
|
|
|
PRBool applyMinLH = !(psd->mZeroEffectiveSpanBox); // (1) above
|
|
|
|
PRBool isFirstLine = !mLineNumber; // if the line number is 0
|
2000-04-17 18:40:46 +04:00
|
|
|
PRBool isLastLine = (!mLineBox->IsLineWrapped() && !GetFlag(LL_LINEENDSINBR));
|
2000-10-04 08:17:36 +04:00
|
|
|
PRBool foundLI = PR_FALSE; // hack to fix bug 50480.
|
|
|
|
//XXX: rather than remembering if we've found an LI, we really should be checking
|
|
|
|
// for the existence of a bullet frame. Likewise, the code below should not
|
|
|
|
// be checking for any particular content tag type, but rather should
|
|
|
|
// be checking for the existence of a bullet frame to determine if it's a list element or not.
|
2000-02-15 07:26:44 +03:00
|
|
|
if (!applyMinLH && (isFirstLine || isLastLine)) {
|
2003-06-30 14:46:59 +04:00
|
|
|
nsIContent* blockContent = mRootSpan->mFrame->mFrame->GetContent();
|
|
|
|
if (blockContent) {
|
2003-11-19 04:20:56 +03:00
|
|
|
nsIAtom *blockTagAtom = blockContent->Tag();
|
|
|
|
// (2) above, if the first line of LI
|
|
|
|
if (isFirstLine && blockTagAtom == nsHTMLAtoms::li) {
|
|
|
|
// if the line is empty, then don't force the min height
|
|
|
|
// (see bug 75963)
|
|
|
|
if (!IsZeroHeight()) {
|
2000-02-15 07:26:44 +03:00
|
|
|
applyMinLH = PR_TRUE;
|
2003-11-19 04:20:56 +03:00
|
|
|
foundLI = PR_TRUE;
|
2000-03-16 04:14:57 +03:00
|
|
|
}
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
2003-11-19 04:20:56 +03:00
|
|
|
// (3) above, if the last line of LI, DT, or DD
|
|
|
|
else if (!applyMinLH && isLastLine &&
|
|
|
|
((blockTagAtom == nsHTMLAtoms::li) ||
|
|
|
|
(blockTagAtom == nsHTMLAtoms::dt) ||
|
|
|
|
(blockTagAtom == nsHTMLAtoms::dd))) {
|
|
|
|
applyMinLH = PR_TRUE;
|
|
|
|
}
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
2000-02-15 07:26:44 +03:00
|
|
|
if (applyMinLH) {
|
2000-10-04 08:17:36 +04:00
|
|
|
if ((psd->mX != psd->mLeftEdge) || preMode || foundLI) {
|
1999-09-10 01:04:37 +04:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [span]==> adjusting min/maxY: currentValues: %d,%d", minY, maxY);
|
1999-09-10 01:04:37 +04:00
|
|
|
#endif
|
2000-02-15 07:26:44 +03:00
|
|
|
nscoord minimumLineHeight = mMinLineHeight;
|
1999-09-10 01:04:37 +04:00
|
|
|
nscoord fontAscent, fontHeight;
|
|
|
|
fm->GetMaxAscent(fontAscent);
|
1999-10-13 03:27:32 +04:00
|
|
|
if (nsHTMLReflowState::UseComputedHeight()) {
|
2003-05-15 07:42:21 +04:00
|
|
|
fontHeight = spanFrame->GetStyleFont()->mFont.size;
|
1999-10-13 03:27:32 +04:00
|
|
|
}
|
2000-02-02 10:38:23 +03:00
|
|
|
else
|
|
|
|
{
|
2000-02-15 07:26:44 +03:00
|
|
|
fm->GetHeight(fontHeight);
|
1999-10-13 03:27:32 +04:00
|
|
|
}
|
2000-02-02 10:38:23 +03:00
|
|
|
|
1999-09-10 01:04:37 +04:00
|
|
|
nscoord leading = minimumLineHeight - fontHeight;
|
|
|
|
nscoord yTop = -fontAscent - leading/2;
|
|
|
|
nscoord yBottom = yTop + minimumLineHeight;
|
|
|
|
if (yTop < minY) minY = yTop;
|
|
|
|
if (yBottom > maxY) maxY = yBottom;
|
2000-02-02 10:38:23 +03:00
|
|
|
|
1999-09-10 01:04:37 +04:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" new values: %d,%d\n", minY, maxY);
|
1999-09-10 01:04:37 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// XXX issues:
|
|
|
|
// [1] BR's on empty lines stop working
|
|
|
|
// [2] May not honor css2's notion of handling empty elements
|
|
|
|
// [3] blank lines in a pre-section ("\n") (handled with preMode)
|
2000-02-19 06:42:30 +03:00
|
|
|
|
|
|
|
// XXX Are there other problems with this?
|
1999-09-10 01:04:37 +04:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [span]==> zapping min/maxY: currentValues: %d,%d newValues: 0,0\n",
|
1999-09-10 01:04:37 +04:00
|
|
|
minY, maxY);
|
|
|
|
#endif
|
|
|
|
minY = maxY = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-15 07:26:44 +03:00
|
|
|
if ((minY == VERTICAL_ALIGN_FRAMES_NO_MINIMUM) ||
|
|
|
|
(maxY == VERTICAL_ALIGN_FRAMES_NO_MINIMUM)) {
|
2000-03-16 04:14:57 +03:00
|
|
|
minY = maxY = baselineY;
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((psd != mRootSpan) && (psd->mZeroEffectiveSpanBox)) {
|
2000-02-19 06:42:30 +03:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [span]adjusting for zeroEffectiveSpanBox\n");
|
|
|
|
printf(" Original: minY=%d, maxY=%d, height=%d, ascent=%d, descent=%d, logicalHeight=%d, topLeading=%d, bottomLeading=%d\n",
|
2000-02-19 06:42:30 +03:00
|
|
|
minY, maxY, spanFramePFD->mBounds.height,
|
|
|
|
spanFramePFD->mAscent, spanFramePFD->mDescent,
|
|
|
|
psd->mLogicalHeight, psd->mTopLeading, psd->mBottomLeading);
|
|
|
|
#endif
|
2000-02-15 07:26:44 +03:00
|
|
|
nscoord goodMinY = spanFramePFD->mBorderPadding.top - psd->mTopLeading;
|
|
|
|
nscoord goodMaxY = goodMinY + psd->mLogicalHeight;
|
|
|
|
if (minY > goodMinY) {
|
|
|
|
nscoord adjust = minY - goodMinY; // positive
|
|
|
|
|
|
|
|
// shrink the logical extents
|
|
|
|
psd->mLogicalHeight -= adjust;
|
|
|
|
psd->mTopLeading -= adjust;
|
|
|
|
}
|
|
|
|
if (maxY < goodMaxY) {
|
|
|
|
nscoord adjust = goodMaxY - maxY;
|
|
|
|
psd->mLogicalHeight -= adjust;
|
|
|
|
psd->mBottomLeading -= adjust;
|
|
|
|
}
|
|
|
|
if (minY > 0) {
|
|
|
|
|
|
|
|
// shrink the content by moving its top down. This is tricky, since
|
|
|
|
// the top is the 0 for many coordinates, so what we do is
|
|
|
|
// move everything else up.
|
|
|
|
spanFramePFD->mAscent -= minY; // move the baseline up
|
|
|
|
spanFramePFD->mBounds.height -= minY; // move the bottom up
|
|
|
|
psd->mTopLeading += minY;
|
|
|
|
|
|
|
|
pfd = psd->mFirstFrame;
|
|
|
|
while (nsnull != pfd) {
|
|
|
|
pfd->mBounds.y -= minY; // move all the children back up
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mFrame->SetRect(pfd->mBounds);
|
2000-02-15 07:26:44 +03:00
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
maxY -= minY; // since minY is in the frame's own coordinate system
|
|
|
|
minY = 0;
|
|
|
|
}
|
2000-02-19 06:42:30 +03:00
|
|
|
if (maxY < spanFramePFD->mBounds.height) {
|
|
|
|
nscoord adjust = spanFramePFD->mBounds.height - maxY;
|
2000-02-15 07:26:44 +03:00
|
|
|
spanFramePFD->mBounds.height -= adjust; // move the bottom up
|
|
|
|
spanFramePFD->mDescent -= adjust;
|
|
|
|
psd->mBottomLeading += adjust;
|
|
|
|
}
|
2000-02-19 06:42:30 +03:00
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" New: minY=%d, maxY=%d, height=%d, ascent=%d, descent=%d, logicalHeight=%d, topLeading=%d, bottomLeading=%d\n",
|
2000-02-19 06:42:30 +03:00
|
|
|
minY, maxY, spanFramePFD->mBounds.height,
|
|
|
|
spanFramePFD->mAscent, spanFramePFD->mDescent,
|
|
|
|
psd->mLogicalHeight, psd->mTopLeading, psd->mBottomLeading);
|
|
|
|
#endif
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
psd->mMinY = minY;
|
|
|
|
psd->mMaxY = maxY;
|
|
|
|
#ifdef NOISY_VERTICAL_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [span]==> minY=%d maxY=%d delta=%d maxTopBoxHeight=%d maxBottomBoxHeight=%d\n",
|
1999-03-21 00:55:22 +03:00
|
|
|
minY, maxY, maxY - minY, maxTopBoxHeight, maxBottomBoxHeight);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
if (maxTopBoxHeight > mMaxTopBoxHeight) {
|
|
|
|
mMaxTopBoxHeight = maxTopBoxHeight;
|
|
|
|
}
|
|
|
|
if (maxBottomBoxHeight > mMaxBottomBoxHeight) {
|
|
|
|
mMaxBottomBoxHeight = maxBottomBoxHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-09-21 04:14:22 +04:00
|
|
|
PRBool
|
|
|
|
nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
|
|
|
|
nscoord* aDeltaWidth)
|
|
|
|
{
|
2001-04-12 03:32:21 +04:00
|
|
|
#ifndef IBMBIDI
|
1999-09-21 04:14:22 +04:00
|
|
|
// XXX what about NS_STYLE_DIRECTION_RTL?
|
|
|
|
if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
|
|
|
|
*aDeltaWidth = 0;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2001-04-12 03:32:21 +04:00
|
|
|
#endif
|
1999-09-21 04:14:22 +04:00
|
|
|
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
if (!pfd) {
|
|
|
|
*aDeltaWidth = 0;
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
pfd = pfd->Last();
|
|
|
|
while (nsnull != pfd) {
|
1999-09-24 21:23:33 +04:00
|
|
|
#ifdef REALLY_NOISY_TRIM
|
|
|
|
nsFrame::ListTag(stdout, (psd == mRootSpan
|
|
|
|
? mBlockReflowState->frame
|
|
|
|
: psd->mFrame->mFrame));
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": attempting trim of ");
|
1999-09-24 21:23:33 +04:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-09-24 21:23:33 +04:00
|
|
|
#endif
|
|
|
|
PerSpanData* childSpan = pfd->mSpan;
|
|
|
|
if (childSpan) {
|
1999-09-21 04:14:22 +04:00
|
|
|
// Maybe the child span has the trailing white-space in it?
|
1999-09-24 21:23:33 +04:00
|
|
|
if (TrimTrailingWhiteSpaceIn(childSpan, aDeltaWidth)) {
|
|
|
|
nscoord deltaWidth = *aDeltaWidth;
|
|
|
|
if (deltaWidth) {
|
|
|
|
// Adjust the child spans frame size
|
|
|
|
pfd->mBounds.width -= deltaWidth;
|
1999-09-21 04:14:22 +04:00
|
|
|
if (psd != mRootSpan) {
|
1999-09-24 21:23:33 +04:00
|
|
|
// When the child span is not a direct child of the block
|
|
|
|
// we need to update the child spans frame rectangle
|
|
|
|
// because it most likely will not be done again. Spans
|
|
|
|
// that are direct children of the block will be updated
|
|
|
|
// later, however, because the VerticalAlignFrames method
|
|
|
|
// will be run after this method.
|
|
|
|
nsIFrame* f = pfd->mFrame;
|
2003-06-30 14:46:59 +04:00
|
|
|
nsRect r = f->GetRect();
|
1999-09-24 21:23:33 +04:00
|
|
|
r.width -= deltaWidth;
|
2003-06-30 14:46:59 +04:00
|
|
|
f->SetRect(r);
|
1999-09-24 21:23:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust the right edge of the span that contains the child span
|
|
|
|
psd->mX -= deltaWidth;
|
|
|
|
|
|
|
|
// Slide any frames that follow the child span over by the
|
|
|
|
// right amount. The only thing that can follow the child
|
|
|
|
// span is empty stuff, so we are just making things
|
|
|
|
// sensible (keeping the combined area honest).
|
|
|
|
while (pfd->mNext) {
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
pfd->mBounds.x -= deltaWidth;
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
2004-02-09 04:01:06 +03:00
|
|
|
else if (!pfd->GetFlag(PFD_ISTEXTFRAME) &&
|
2004-02-20 01:12:38 +03:00
|
|
|
!pfd->GetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE)) {
|
2004-02-20 01:16:00 +03:00
|
|
|
// If we hit a frame on the end that we're not supposed to be skipping
|
|
|
|
// (not text, not a placeholder and not a br frame) then there is no
|
|
|
|
// trailing whitespace to trim. Stop the search.
|
1999-09-21 04:14:22 +04:00
|
|
|
*aDeltaWidth = 0;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
else if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
1999-09-21 04:14:22 +04:00
|
|
|
nscoord deltaWidth = 0;
|
1999-11-24 09:03:41 +03:00
|
|
|
pfd->mFrame->TrimTrailingWhiteSpace(mPresContext,
|
1999-10-30 06:52:11 +04:00
|
|
|
*mBlockReflowState->rendContext,
|
|
|
|
deltaWidth);
|
1999-09-24 21:23:33 +04:00
|
|
|
#ifdef NOISY_TRIM
|
1999-10-30 06:52:11 +04:00
|
|
|
nsFrame::ListTag(stdout, (psd == mRootSpan
|
|
|
|
? mBlockReflowState->frame
|
|
|
|
: psd->mFrame->mFrame));
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": trim of ");
|
1999-10-30 06:52:11 +04:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" returned %d\n", deltaWidth);
|
1999-09-24 21:23:33 +04:00
|
|
|
#endif
|
1999-10-30 06:52:11 +04:00
|
|
|
if (deltaWidth) {
|
2000-04-17 18:40:46 +04:00
|
|
|
if (pfd->mJustificationNumSpaces > 0) {
|
|
|
|
pfd->mJustificationNumSpaces--;
|
|
|
|
}
|
|
|
|
|
1999-10-30 06:52:11 +04:00
|
|
|
pfd->mBounds.width -= deltaWidth;
|
|
|
|
pfd->mCombinedArea.width -= deltaWidth;
|
|
|
|
if (0 == pfd->mBounds.width) {
|
2003-01-09 17:26:32 +03:00
|
|
|
pfd->mMaxElementWidth = 0;
|
1999-10-30 06:52:11 +04:00
|
|
|
}
|
1999-09-21 04:14:22 +04:00
|
|
|
|
1999-10-30 06:52:11 +04:00
|
|
|
// See if the text frame has already been placed in its parent
|
|
|
|
if (psd != mRootSpan) {
|
|
|
|
// The frame was already placed during psd's
|
|
|
|
// reflow. Update the frames rectangle now.
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mFrame->SetRect(pfd->mBounds);
|
1999-10-30 06:52:11 +04:00
|
|
|
}
|
1999-09-21 04:14:22 +04:00
|
|
|
|
1999-10-30 06:52:11 +04:00
|
|
|
// Adjust containing span's right edge
|
|
|
|
psd->mX -= deltaWidth;
|
1999-09-21 04:14:22 +04:00
|
|
|
|
1999-10-30 06:52:11 +04:00
|
|
|
// Slide any frames that follow the text frame over by the
|
|
|
|
// right amount. The only thing that can follow the text
|
|
|
|
// frame is empty stuff, so we are just making things
|
|
|
|
// sensible (keeping the combined area honest).
|
|
|
|
while (pfd->mNext) {
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
pfd->mBounds.x -= deltaWidth;
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pass up to caller so they can shrink their span
|
|
|
|
*aDeltaWidth = deltaWidth;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
pfd = pfd->mPrev;
|
|
|
|
}
|
1999-10-30 06:52:11 +04:00
|
|
|
|
1999-09-21 04:14:22 +04:00
|
|
|
*aDeltaWidth = 0;
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
1999-10-13 03:27:32 +04:00
|
|
|
PRBool
|
1999-09-21 04:14:22 +04:00
|
|
|
nsLineLayout::TrimTrailingWhiteSpace()
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
1999-09-21 04:14:22 +04:00
|
|
|
PerSpanData* psd = mRootSpan;
|
|
|
|
nscoord deltaWidth;
|
|
|
|
TrimTrailingWhiteSpaceIn(psd, &deltaWidth);
|
1999-10-13 03:27:32 +04:00
|
|
|
return 0 != deltaWidth;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2000-04-17 18:40:46 +04:00
|
|
|
void
|
|
|
|
nsLineLayout::ComputeJustificationWeights(PerSpanData* aPSD,
|
|
|
|
PRInt32* aNumSpaces,
|
|
|
|
PRInt32* aNumLetters)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aPSD, "null arg");
|
|
|
|
NS_ASSERTION(aNumSpaces, "null arg");
|
|
|
|
NS_ASSERTION(aNumLetters, "null arg");
|
|
|
|
PRInt32 numSpaces = 0;
|
|
|
|
PRInt32 numLetters = 0;
|
|
|
|
|
|
|
|
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nsnull; pfd = pfd->mNext) {
|
|
|
|
|
|
|
|
if (PR_TRUE == pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
|
|
|
numSpaces += pfd->mJustificationNumSpaces;
|
|
|
|
numLetters += pfd->mJustificationNumLetters;
|
|
|
|
}
|
|
|
|
else if (pfd->mSpan != nsnull) {
|
|
|
|
PRInt32 spanSpaces;
|
|
|
|
PRInt32 spanLetters;
|
|
|
|
|
|
|
|
ComputeJustificationWeights(pfd->mSpan, &spanSpaces, &spanLetters);
|
|
|
|
|
|
|
|
numSpaces += spanSpaces;
|
|
|
|
numLetters += spanLetters;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*aNumSpaces = numSpaces;
|
|
|
|
*aNumLetters = numLetters;
|
|
|
|
}
|
|
|
|
|
|
|
|
nscoord
|
|
|
|
nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState* aState)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aPSD, "null arg");
|
|
|
|
NS_ASSERTION(aState, "null arg");
|
|
|
|
|
|
|
|
nscoord deltaX = 0;
|
|
|
|
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nsnull; pfd = pfd->mNext) {
|
|
|
|
// Don't reposition bullets (and other frames that occur out of X-order?)
|
|
|
|
if (!pfd->GetFlag(PFD_ISBULLET)) {
|
|
|
|
nscoord dw = 0;
|
|
|
|
|
|
|
|
pfd->mBounds.x += deltaX;
|
|
|
|
|
|
|
|
if (PR_TRUE == pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
|
|
|
if (aState->mTotalWidthForSpaces > 0 &&
|
|
|
|
aState->mTotalNumSpaces > 0 && // we divide by this value, so must be non-zero
|
|
|
|
aState->mTotalNumLetters >0 // we divide by this value, so must be non-zero
|
|
|
|
) {
|
|
|
|
aState->mNumSpacesProcessed += pfd->mJustificationNumSpaces;
|
|
|
|
|
|
|
|
nscoord newAllocatedWidthForSpaces =
|
|
|
|
(aState->mTotalWidthForSpaces*aState->mNumSpacesProcessed)
|
|
|
|
/aState->mTotalNumSpaces;
|
|
|
|
|
|
|
|
dw += newAllocatedWidthForSpaces - aState->mWidthForSpacesProcessed;
|
|
|
|
|
|
|
|
aState->mWidthForSpacesProcessed = newAllocatedWidthForSpaces;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aState->mTotalWidthForLetters > 0) {
|
|
|
|
aState->mNumLettersProcessed += pfd->mJustificationNumLetters;
|
|
|
|
|
|
|
|
nscoord newAllocatedWidthForLetters =
|
|
|
|
(aState->mTotalWidthForLetters*aState->mNumLettersProcessed)
|
|
|
|
/aState->mTotalNumLetters;
|
|
|
|
|
|
|
|
dw += newAllocatedWidthForLetters - aState->mWidthForLettersProcessed;
|
|
|
|
|
|
|
|
aState->mWidthForLettersProcessed = newAllocatedWidthForLetters;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (nsnull != pfd->mSpan) {
|
|
|
|
dw += ApplyFrameJustification(pfd->mSpan, aState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pfd->mBounds.width += dw;
|
|
|
|
deltaX += dw;
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mFrame->SetRect(pfd->mBounds);
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return deltaX;
|
|
|
|
}
|
|
|
|
|
2000-01-03 07:32:13 +03:00
|
|
|
PRBool
|
|
|
|
nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
|
|
|
|
PRBool aAllowJustify,
|
|
|
|
PRBool aShrinkWrapWidth)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
PerSpanData* psd = mRootSpan;
|
|
|
|
nscoord availWidth = psd->mRightEdge;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == availWidth) {
|
|
|
|
// Don't bother horizontal aligning on pass1 table reflow
|
1999-09-24 21:23:33 +04:00
|
|
|
#ifdef NOISY_HORIZONTAL_ALIGN
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": skipping horizontal alignment in pass1 table reflow\n");
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
2000-01-03 07:32:13 +03:00
|
|
|
return PR_TRUE;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2001-04-12 03:32:21 +04:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
|
|
|
|
// This is to ensure proper indentation (e.g. of list items)
|
|
|
|
availWidth -= aLineBounds.x;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif // IBMBIDI
|
1999-03-19 00:03:25 +03:00
|
|
|
availWidth -= psd->mLeftEdge;
|
|
|
|
nscoord remainingWidth = availWidth - aLineBounds.width;
|
1999-09-24 21:23:33 +04:00
|
|
|
#ifdef NOISY_HORIZONTAL_ALIGN
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": availWidth=%d lineWidth=%d delta=%d\n",
|
1999-03-19 00:03:25 +03:00
|
|
|
availWidth, aLineBounds.width, remainingWidth);
|
|
|
|
#endif
|
2001-04-12 03:32:21 +04:00
|
|
|
#ifdef IBMBIDI
|
2002-06-12 07:27:48 +04:00
|
|
|
if (remainingWidth + aLineBounds.x > 0)
|
2001-04-12 03:32:21 +04:00
|
|
|
#else
|
2002-05-01 04:42:49 +04:00
|
|
|
// XXXldb What if it's less than 0??
|
2002-06-12 07:27:48 +04:00
|
|
|
if (remainingWidth > 0)
|
2001-04-12 03:32:21 +04:00
|
|
|
#endif
|
2002-06-12 07:27:48 +04:00
|
|
|
{
|
1999-03-19 00:03:25 +03:00
|
|
|
nscoord dx = 0;
|
2003-07-30 12:13:07 +04:00
|
|
|
switch (mTextAlign) {
|
1999-03-19 00:03:25 +03:00
|
|
|
case NS_STYLE_TEXT_ALIGN_DEFAULT:
|
1999-03-22 23:45:09 +03:00
|
|
|
if (NS_STYLE_DIRECTION_LTR == psd->mDirection) {
|
1999-03-19 00:03:25 +03:00
|
|
|
// default alignment for left-to-right is left so do nothing
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Fall through to align right case for default alignment
|
|
|
|
// used when the direction is right-to-left.
|
|
|
|
|
|
|
|
case NS_STYLE_TEXT_ALIGN_RIGHT:
|
1999-03-25 06:49:29 +03:00
|
|
|
case NS_STYLE_TEXT_ALIGN_MOZ_RIGHT:
|
2000-09-21 10:03:39 +04:00
|
|
|
{
|
|
|
|
// fix for bug 50758
|
|
|
|
// right-aligned text in a text control doesn't know how to paint itself
|
|
|
|
// so we force the invalidate here. Getting the current line is quick,
|
|
|
|
// and at worst we're invalidating more of the line (and just that line) than we need to.
|
|
|
|
nsLineBox *currentLine=nsnull;
|
|
|
|
// use localResult because a failure here should not be propagated to my caller
|
|
|
|
nsresult localResult = nsBlockFrame::GetCurrentLine(mBlockRS, ¤tLine);
|
|
|
|
if (NS_SUCCEEDED(localResult) && currentLine) {
|
|
|
|
currentLine->SetForceInvalidate(PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
dx = remainingWidth;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_TEXT_ALIGN_LEFT:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_TEXT_ALIGN_JUSTIFY:
|
|
|
|
// If this is not the last line then go ahead and justify the
|
|
|
|
// frames in the line. If it is the last line then if the
|
|
|
|
// direction is right-to-left then we right-align the frames.
|
|
|
|
if (aAllowJustify) {
|
2000-04-17 18:40:46 +04:00
|
|
|
if (!aShrinkWrapWidth) {
|
|
|
|
PRInt32 numSpaces;
|
|
|
|
PRInt32 numLetters;
|
|
|
|
|
|
|
|
ComputeJustificationWeights(psd, &numSpaces, &numLetters);
|
|
|
|
|
|
|
|
if (numSpaces > 0) {
|
|
|
|
FrameJustificationState state = { numSpaces, numLetters, remainingWidth, 0, 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
ApplyFrameJustification(psd, &state);
|
|
|
|
}
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
1999-03-22 23:45:09 +03:00
|
|
|
else if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
|
1999-03-19 00:03:25 +03:00
|
|
|
// right align the frames
|
1999-03-22 23:45:09 +03:00
|
|
|
dx = remainingWidth;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_TEXT_ALIGN_CENTER:
|
1999-03-25 06:49:29 +03:00
|
|
|
case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
|
1999-03-19 00:03:25 +03:00
|
|
|
dx = remainingWidth / 2;
|
|
|
|
break;
|
|
|
|
}
|
2001-04-12 03:32:21 +04:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
PerFrameData* lastPfd = psd->mLastFrame;
|
|
|
|
PerFrameData* bulletPfd = nsnull;
|
|
|
|
|
|
|
|
if (lastPfd->GetFlag(PFD_ISBULLET)
|
|
|
|
&& (NS_STYLE_DIRECTION_RTL == psd->mDirection) ) {
|
|
|
|
bulletPfd = lastPfd;
|
|
|
|
lastPfd = lastPfd->mPrev;
|
|
|
|
}
|
|
|
|
PRUint32 maxX = lastPfd->mBounds.XMost() + dx;
|
|
|
|
PRBool visualRTL = PR_FALSE;
|
|
|
|
|
|
|
|
if ( (NS_STYLE_DIRECTION_RTL == psd->mDirection)
|
|
|
|
&& (!psd->mChangedFrameDirection) ) {
|
|
|
|
psd->mChangedFrameDirection = PR_TRUE;
|
|
|
|
|
|
|
|
/* Assume that all frames have been right aligned.*/
|
|
|
|
if (aShrinkWrapWidth) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
mPresContext->IsVisualMode(visualRTL);
|
|
|
|
|
|
|
|
if (bulletPfd) {
|
|
|
|
bulletPfd->mBounds.x += maxX;
|
2003-06-30 14:46:59 +04:00
|
|
|
bulletPfd->mFrame->SetRect(bulletPfd->mBounds);
|
2001-04-12 03:32:21 +04:00
|
|
|
}
|
|
|
|
}
|
2002-12-11 05:38:33 +03:00
|
|
|
if ( (0 != dx) || (visualRTL) )
|
2001-04-12 03:32:21 +04:00
|
|
|
#else
|
2002-12-11 05:38:33 +03:00
|
|
|
if (0 != dx)
|
2001-04-12 03:32:21 +04:00
|
|
|
#endif // IBMBIDI
|
2002-12-11 05:38:33 +03:00
|
|
|
{
|
2000-01-03 07:32:13 +03:00
|
|
|
// If we need to move the frames but we're shrink wrapping, then
|
|
|
|
// we need to wait until the final width is known
|
|
|
|
if (aShrinkWrapWidth) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2002-12-11 05:38:33 +03:00
|
|
|
for (PerFrameData* pfd = psd->mFirstFrame; pfd
|
2001-04-12 03:32:21 +04:00
|
|
|
#ifdef IBMBIDI
|
2002-12-11 05:38:33 +03:00
|
|
|
&& bulletPfd != pfd
|
|
|
|
#endif
|
|
|
|
; pfd = pfd->mNext) {
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd->mBounds.x += dx;
|
2001-04-12 03:32:21 +04:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
if (visualRTL) {
|
2002-12-11 05:38:33 +03:00
|
|
|
// XXXldb Ugh. Could we handle this earlier so we don't get here?
|
2002-01-31 02:28:56 +03:00
|
|
|
maxX = pfd->mBounds.x = maxX - (pfd->mMargin.left + pfd->mBounds.width + pfd->mMargin.right);
|
2001-04-12 03:32:21 +04:00
|
|
|
}
|
|
|
|
#endif // IBMBIDI
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mFrame->SetRect(pfd->mBounds);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2001-04-12 03:32:21 +04:00
|
|
|
aLineBounds.x += dx;
|
1999-05-08 04:48:39 +04:00
|
|
|
}
|
2001-04-12 03:32:21 +04:00
|
|
|
#ifndef IBMBIDI
|
1999-09-21 04:14:22 +04:00
|
|
|
if ((NS_STYLE_DIRECTION_RTL == psd->mDirection) &&
|
|
|
|
!psd->mChangedFrameDirection) {
|
1999-05-08 04:48:39 +04:00
|
|
|
psd->mChangedFrameDirection = PR_TRUE;
|
|
|
|
|
|
|
|
/* Assume that all frames have been right aligned.*/
|
2000-01-03 07:32:13 +03:00
|
|
|
if (aShrinkWrapWidth) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-05-08 04:48:39 +04:00
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
PRUint32 maxX = psd->mRightEdge;
|
|
|
|
while (nsnull != pfd) {
|
2002-01-31 02:28:56 +03:00
|
|
|
pfd->mBounds.x = maxX - (pfd->mMargin.left + pfd->mBounds.width + pfd->mMargin.right);
|
2003-06-30 14:46:59 +04:00
|
|
|
pfd->mFrame->SetRect(pfd->mBounds);
|
1999-05-08 04:48:39 +04:00
|
|
|
maxX = pfd->mBounds.x;
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2001-04-12 03:32:21 +04:00
|
|
|
#endif // ndef IBMBIDI
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2000-01-03 07:32:13 +03:00
|
|
|
|
|
|
|
return PR_TRUE;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsLineLayout::RelativePositionFrames(nsRect& aCombinedArea)
|
|
|
|
{
|
|
|
|
RelativePositionFrames(mRootSpan, aCombinedArea);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
|
|
|
|
{
|
|
|
|
nsRect spanCombinedArea;
|
|
|
|
PerFrameData* pfd;
|
|
|
|
|
1999-11-02 01:38:17 +03:00
|
|
|
nscoord minX, minY, maxX, maxY;
|
1999-03-19 00:03:25 +03:00
|
|
|
if (nsnull != psd->mFrame) {
|
|
|
|
// The minimum combined area for the frames in a span covers the
|
|
|
|
// entire span frame.
|
|
|
|
pfd = psd->mFrame;
|
1999-11-02 01:38:17 +03:00
|
|
|
minX = 0;
|
|
|
|
minY = 0;
|
|
|
|
maxX = pfd->mBounds.width;
|
|
|
|
maxY = pfd->mBounds.height;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// The minimum combined area for the frames that are direct
|
|
|
|
// children of the block starts at the upper left corner of the
|
1999-10-13 03:27:32 +04:00
|
|
|
// line and is sized to match the size of the line's bounding box
|
|
|
|
// (the same size as the values returned from VerticalAlignFrames)
|
1999-11-02 01:38:17 +03:00
|
|
|
minX = psd->mLeftEdge;
|
|
|
|
maxX = psd->mX;
|
|
|
|
minY = mTopEdge;
|
|
|
|
maxY = mTopEdge + mFinalLineHeight;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2003-07-23 04:14:16 +04:00
|
|
|
for (pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nscoord x = pfd->mBounds.x;
|
|
|
|
nscoord y = pfd->mBounds.y;
|
2003-08-01 02:03:26 +04:00
|
|
|
nsIFrame* frame = pfd->mFrame;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Adjust the origin of the frame
|
2000-04-17 18:40:46 +04:00
|
|
|
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
|
2003-08-01 02:03:26 +04:00
|
|
|
// right and bottom are handled by
|
|
|
|
// nsHTMLReflowState::ComputeRelativeOffsets
|
|
|
|
nsPoint change(pfd->mOffsets.left, pfd->mOffsets.top);
|
|
|
|
frame->SetPosition(frame->GetPosition() + change);
|
|
|
|
x += change.x;
|
|
|
|
y += change.y;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2003-08-07 03:59:10 +04:00
|
|
|
// We must position the view correctly before positioning its
|
|
|
|
// descendants so that widgets are positioned properly (since only
|
|
|
|
// some views have widgets).
|
|
|
|
if (frame->HasView())
|
|
|
|
nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
|
|
|
|
frame->GetView(),
|
|
|
|
&pfd->mCombinedArea, //ignored
|
|
|
|
NS_FRAME_NO_SIZE_VIEW);
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Note: the combined area of a child is in its coordinate
|
|
|
|
// system. We adjust the childs combined area into our coordinate
|
|
|
|
// system before computing the aggregated value by adding in
|
|
|
|
// <b>x</b> and <b>y</b> which were computed above.
|
|
|
|
nsRect* r = &pfd->mCombinedArea;
|
|
|
|
if (pfd->mSpan) {
|
|
|
|
// Compute a new combined area for the child span before
|
|
|
|
// aggregating it into our combined area.
|
|
|
|
r = &spanCombinedArea;
|
|
|
|
RelativePositionFrames(pfd->mSpan, spanCombinedArea);
|
2003-08-07 03:59:10 +04:00
|
|
|
} else {
|
|
|
|
// If we have something that's not an inline but with a complex frame
|
|
|
|
// hierarchy inside that contains views, they need to be
|
|
|
|
// positioned.
|
|
|
|
// All descendant views must be repositioned even if this frame
|
|
|
|
// does have a view in case this frame's view does not have a
|
|
|
|
// widget and some of the descendant views do have widgets --
|
|
|
|
// otherwise the widgets won't be repositioned.
|
|
|
|
nsContainerFrame::PositionChildViews(mPresContext, frame);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2003-08-01 02:03:26 +04:00
|
|
|
// Do this here (rather than along with NS_FRAME_OUTSIDE_CHILDREN
|
|
|
|
// handling below) so we get leaf frames as well. No need to worry
|
|
|
|
// about the root span, since it doesn't have a frame.
|
|
|
|
if (frame->HasView())
|
|
|
|
nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
|
2003-08-07 03:59:10 +04:00
|
|
|
frame->GetView(), r,
|
|
|
|
NS_FRAME_NO_MOVE_VIEW);
|
2003-08-01 02:03:26 +04:00
|
|
|
|
2003-07-23 04:14:16 +04:00
|
|
|
nscoord xl = x + r->x;
|
|
|
|
if (xl < minX) {
|
|
|
|
minX = xl;
|
|
|
|
}
|
|
|
|
nscoord xr = x + r->XMost();
|
|
|
|
if (xr > maxX) {
|
|
|
|
maxX = xr;
|
|
|
|
}
|
|
|
|
nscoord yt = y + r->y;
|
|
|
|
if (yt < minY) {
|
|
|
|
minY = yt;
|
|
|
|
}
|
|
|
|
nscoord yb = y + r->YMost();
|
|
|
|
if (yb > maxY) {
|
|
|
|
maxY = yb;
|
1999-03-21 00:55:22 +03:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2003-07-23 04:14:16 +04:00
|
|
|
aCombinedArea.x = minX;
|
|
|
|
aCombinedArea.y = minY;
|
|
|
|
aCombinedArea.width = maxX - minX;
|
|
|
|
aCombinedArea.height = maxY - minY;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// If we just computed a spans combined area, we need to update its
|
2002-12-22 08:40:51 +03:00
|
|
|
// NS_FRAME_OUTSIDE_CHILDREN bit..
|
2003-06-30 14:46:59 +04:00
|
|
|
if (psd->mFrame) {
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd = psd->mFrame;
|
|
|
|
nsIFrame* frame = pfd->mFrame;
|
2002-12-22 08:40:51 +03:00
|
|
|
if ((minX < 0) || (minY < 0) ||
|
|
|
|
(maxX > pfd->mBounds.width) || (maxY > pfd->mBounds.height)) {
|
2003-06-30 14:46:59 +04:00
|
|
|
frame->AddStateBits(NS_FRAME_OUTSIDE_CHILDREN);
|
|
|
|
} else {
|
|
|
|
frame->RemoveStateBits(NS_FRAME_OUTSIDE_CHILDREN);
|
2002-12-22 08:40:51 +03:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsLineLayout::ForgetWordFrame(nsIFrame* aFrame)
|
|
|
|
{
|
2002-03-20 00:57:45 +03:00
|
|
|
if (0 != mWordFrames.GetSize()) {
|
|
|
|
NS_ASSERTION((void*)aFrame == mWordFrames.PeekFront(), "forget-word-frame");
|
|
|
|
mWordFrames.PopFront();
|
1998-10-20 04:23:11 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-10 08:35:01 +04:00
|
|
|
nsIFrame*
|
2000-07-27 09:16:08 +04:00
|
|
|
nsLineLayout::FindNextText(nsIPresContext* aPresContext, nsIFrame* aFrame)
|
1998-10-10 08:35:01 +04:00
|
|
|
{
|
2000-07-27 09:16:08 +04:00
|
|
|
// Grovel through the frame hierarchy to find a text frame that is
|
|
|
|
// "adjacent" to aFrame.
|
|
|
|
|
|
|
|
// So this is kind of funky. During reflow, overflow frames will
|
|
|
|
// have their parent pointers set up lazily. We assume that, on
|
|
|
|
// entry, aFrame has it's parent pointer set correctly (as do all of
|
|
|
|
// its ancestors). Starting from that, we need to make sure that as
|
|
|
|
// we traverse through frames trying to find the next text frame, we
|
|
|
|
// leave the frames with their parent pointers set correctly, so the
|
|
|
|
// *next* time we come through here, we're good to go.
|
|
|
|
|
|
|
|
// Build a path from the enclosing block frame down to aFrame. We'll
|
|
|
|
// use this to walk the frame tree. (XXXwaterson if I was clever, I
|
|
|
|
// wouldn't need to build this up before hand, and could incorporate
|
|
|
|
// this logic into the walking code directly.)
|
|
|
|
nsAutoVoidArray stack;
|
1998-10-10 08:35:01 +04:00
|
|
|
for (;;) {
|
2000-07-27 09:16:08 +04:00
|
|
|
stack.InsertElementAt(aFrame, 0);
|
|
|
|
|
2003-06-30 14:46:59 +04:00
|
|
|
aFrame = aFrame->GetParent();
|
2000-07-27 09:16:08 +04:00
|
|
|
|
2003-06-30 14:46:59 +04:00
|
|
|
NS_ASSERTION(aFrame, "wow, no block frame found");
|
2000-07-27 09:16:08 +04:00
|
|
|
if (! aFrame)
|
1998-10-10 08:35:01 +04:00
|
|
|
break;
|
|
|
|
|
2003-05-15 07:42:21 +04:00
|
|
|
if (NS_STYLE_DISPLAY_INLINE != aFrame->GetStyleDisplay()->mDisplay)
|
2000-07-27 09:16:08 +04:00
|
|
|
break;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
1998-10-10 08:35:01 +04:00
|
|
|
|
2000-07-27 09:16:08 +04:00
|
|
|
// Using the path we've built up, walk the frame tree looking for
|
|
|
|
// the text frame that follows aFrame.
|
|
|
|
PRInt32 count;
|
|
|
|
while ((count = stack.Count()) != 0) {
|
|
|
|
PRInt32 lastIndex = count - 1;
|
|
|
|
nsIFrame* top = NS_STATIC_CAST(nsIFrame*, stack.ElementAt(lastIndex));
|
1998-10-10 08:35:01 +04:00
|
|
|
|
2000-10-10 02:03:03 +04:00
|
|
|
// If this is a frame that'll break a word, then bail.
|
|
|
|
PRBool canContinue;
|
|
|
|
top->CanContinueTextRun(canContinue);
|
|
|
|
if (! canContinue)
|
2000-10-13 04:44:53 +04:00
|
|
|
return nsnull;
|
2000-10-10 02:03:03 +04:00
|
|
|
|
|
|
|
// Advance to top's next sibling
|
2003-06-30 14:46:59 +04:00
|
|
|
nsIFrame* next = top->GetNextSibling();
|
2000-07-27 09:16:08 +04:00
|
|
|
|
|
|
|
if (! next) {
|
2000-10-10 02:03:03 +04:00
|
|
|
// No more siblings. Pop the top element to walk back up the
|
|
|
|
// frame tree.
|
2000-07-27 09:16:08 +04:00
|
|
|
stack.RemoveElementAt(lastIndex);
|
|
|
|
continue;
|
1999-09-02 22:01:59 +04:00
|
|
|
}
|
2000-07-27 09:16:08 +04:00
|
|
|
|
|
|
|
// We know top's parent is good, but next's might not be. So let's
|
|
|
|
// set it to be sure.
|
2003-06-30 14:46:59 +04:00
|
|
|
next->SetParent(top->GetParent());
|
2000-07-27 09:16:08 +04:00
|
|
|
|
|
|
|
// Save next at the top of the stack...
|
|
|
|
stack.ReplaceElementAt(next, lastIndex);
|
|
|
|
|
2000-10-13 04:44:53 +04:00
|
|
|
// ...and prowl down to next's deepest child. We'll need to check
|
|
|
|
// for potential run-busters "on the way down", too.
|
2000-07-27 09:16:08 +04:00
|
|
|
for (;;) {
|
2000-10-13 04:44:53 +04:00
|
|
|
next->CanContinueTextRun(canContinue);
|
|
|
|
if (! canContinue)
|
|
|
|
return nsnull;
|
|
|
|
|
2004-01-09 17:20:53 +03:00
|
|
|
nsIFrame* child = next->GetFirstChild(nsnull);
|
2000-07-27 09:16:08 +04:00
|
|
|
|
|
|
|
if (! child)
|
|
|
|
break;
|
|
|
|
|
|
|
|
stack.AppendElement(child);
|
|
|
|
next = child;
|
1999-09-02 22:01:59 +04:00
|
|
|
}
|
2000-07-27 09:16:08 +04:00
|
|
|
|
|
|
|
// Ignore continuing frames
|
2002-05-14 16:55:55 +04:00
|
|
|
if (HasPrevInFlow(next))
|
2000-07-27 09:16:08 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// If this is a text frame, return it.
|
2003-10-31 23:19:18 +03:00
|
|
|
if (nsLayoutAtoms::textFrame == next->GetType())
|
2000-07-27 09:16:08 +04:00
|
|
|
return next;
|
1999-09-02 22:01:59 +04:00
|
|
|
}
|
|
|
|
|
2000-07-27 09:16:08 +04:00
|
|
|
// If we get here, then there are no more text frames in this block.
|
|
|
|
return nsnull;
|
1998-10-10 08:35:01 +04:00
|
|
|
}
|
|
|
|
|
2000-07-27 09:16:08 +04:00
|
|
|
|
1998-09-15 04:19:49 +04:00
|
|
|
PRBool
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::TreatFrameAsBlock(nsIFrame* aFrame)
|
1998-09-15 04:19:49 +04:00
|
|
|
{
|
2003-05-15 07:42:21 +04:00
|
|
|
const nsStyleDisplay* display = aFrame->GetStyleDisplay();
|
2001-06-01 02:19:43 +04:00
|
|
|
if (NS_STYLE_POSITION_ABSOLUTE == display->mPosition) {
|
1998-09-15 04:19:49 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
if (NS_STYLE_FLOAT_NONE != display->mFloats) {
|
1998-09-15 04:19:49 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
switch (display->mDisplay) {
|
1998-09-15 04:19:49 +04:00
|
|
|
case NS_STYLE_DISPLAY_BLOCK:
|
|
|
|
case NS_STYLE_DISPLAY_LIST_ITEM:
|
1998-11-11 06:54:47 +03:00
|
|
|
case NS_STYLE_DISPLAY_RUN_IN:
|
|
|
|
case NS_STYLE_DISPLAY_COMPACT:
|
1998-09-15 04:19:49 +04:00
|
|
|
case NS_STYLE_DISPLAY_TABLE:
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|